@@ -161,33 +161,83 @@ impl<'gc> Avm1Function<'gc> {
161
161
}
162
162
163
163
fn load_this ( & self , frame : & mut Activation < ' _ , ' gc , ' _ > , this : Value < ' gc > , preload_r : & mut u8 ) {
164
- if self . flags . contains ( FunctionFlags :: PRELOAD_THIS ) {
165
- //TODO: What happens if you specify both suppress and
166
- //preload for this?
164
+ let preload = self . flags . contains ( FunctionFlags :: PRELOAD_THIS ) ;
165
+ let suppress = self . flags . contains ( FunctionFlags :: SUPPRESS_THIS ) ;
166
+
167
+ if preload {
168
+ // The register is set to undefined if both flags are set.
169
+ let this = if suppress { Value :: Undefined } else { this } ;
167
170
frame. set_local_register ( * preload_r, this) ;
168
171
* preload_r += 1 ;
169
172
}
170
173
}
171
174
172
- fn load_arguments ( & self , frame : & mut Activation < ' _ , ' gc , ' _ > , arguments : Value < ' gc > , preload_r : & mut u8 ) {
173
- if self . flags . contains ( FunctionFlags :: PRELOAD_ARGUMENTS ) {
174
- //TODO: What happens if you specify both suppress and
175
- //preload for arguments?
175
+ fn load_arguments (
176
+ & self ,
177
+ frame : & mut Activation < ' _ , ' gc , ' _ > ,
178
+ args : & [ Value < ' gc > ] ,
179
+ caller : Option < Object < ' gc > > ,
180
+ preload_r : & mut u8 ,
181
+ ) {
182
+ let preload = self . flags . contains ( FunctionFlags :: PRELOAD_ARGUMENTS ) ;
183
+ let suppress = self . flags . contains ( FunctionFlags :: SUPPRESS_ARGUMENTS ) ;
184
+
185
+ if suppress && !preload {
186
+ return ;
187
+ }
188
+
189
+ let arguments = ArrayObject :: new (
190
+ frame. context . gc_context ,
191
+ frame. context . avm1 . prototypes ( ) . array ,
192
+ args. iter ( ) . cloned ( ) ,
193
+ ) ;
194
+
195
+ arguments. define_value (
196
+ frame. context . gc_context ,
197
+ "callee" ,
198
+ frame. callee . unwrap ( ) . into ( ) ,
199
+ Attribute :: DONT_ENUM ,
200
+ ) ;
201
+
202
+ arguments. define_value (
203
+ frame. context . gc_context ,
204
+ "caller" ,
205
+ caller. map ( Value :: from) . unwrap_or ( Value :: Null ) ,
206
+ Attribute :: DONT_ENUM ,
207
+ ) ;
208
+
209
+ let arguments = Value :: from ( arguments) ;
210
+
211
+ // Contrarily to `this` and `super`, setting both flags is equivalent to just setting `preload`.
212
+ if preload {
176
213
frame. set_local_register ( * preload_r, arguments) ;
177
214
* preload_r += 1 ;
215
+ } else {
216
+ frame. force_define_local ( "arguments" . into ( ) , arguments) ;
178
217
}
179
218
}
180
219
181
- fn load_super ( & self , frame : & mut Activation < ' _ , ' gc , ' _ > , super_object : Option < Object < ' gc > > , preload_r : & mut u8 ) {
182
- if let Some ( super_object) = super_object {
183
- if self . flags . contains ( FunctionFlags :: PRELOAD_SUPER ) {
184
- frame. set_local_register ( * preload_r, super_object. into ( ) ) ;
185
- //TODO: What happens if you specify both suppress and
186
- //preload for super?
187
- * preload_r += 1 ;
188
- } else {
189
- frame. force_define_local ( "super" . into ( ) , super_object. into ( ) ) ;
190
- }
220
+ fn load_super (
221
+ & self ,
222
+ frame : & mut Activation < ' _ , ' gc , ' _ > ,
223
+ this : Option < Object < ' gc > > ,
224
+ depth : u8 ,
225
+ preload_r : & mut u8 ,
226
+ ) {
227
+ let preload = self . flags . contains ( FunctionFlags :: PRELOAD_SUPER ) ;
228
+ let suppress = self . flags . contains ( FunctionFlags :: SUPPRESS_SUPER ) ;
229
+
230
+ // TODO: `super` should only be defined if this was a method call (depth > 0?)
231
+ // `f[""]()` emits a CallMethod op, causing `this` to be undefined, but `super` is a function; what is it?
232
+ let zuper = this
233
+ . filter ( |_| !suppress)
234
+ . map ( |this| SuperObject :: new ( frame, this, depth) . into ( ) ) ;
235
+
236
+ if preload {
237
+ // The register is set to undefined if both flags are set.
238
+ frame. set_local_register ( * preload_r, zuper. unwrap_or ( Value :: Undefined ) ) ;
239
+ } else if let Some ( zuper) = zuper {
240
+ frame. force_define_local ( "super" . into ( ) , zuper) ;
191
241
}
192
242
}
193
243
@@ -309,15 +359,14 @@ impl<'gc> Executable<'gc> {
309
359
310
360
let target = activation. target_clip_or_root ( ) ;
311
361
let is_closure = activation. swf_version ( ) >= 6 ;
312
- let base_clip = if ( is_closure || reason == ExecutionReason :: Special )
313
- && !af. base_clip . removed ( )
314
- {
315
- af. base_clip
316
- } else {
317
- this_obj
318
- . and_then ( |this| this. as_display_object ( ) )
319
- . unwrap_or ( target)
320
- } ;
362
+ let base_clip =
363
+ if ( is_closure || reason == ExecutionReason :: Special ) && !af. base_clip . removed ( ) {
364
+ af. base_clip
365
+ } else {
366
+ this_obj
367
+ . and_then ( |this| this. as_display_object ( ) )
368
+ . unwrap_or ( target)
369
+ } ;
321
370
let ( swf_version, parent_scope) = if is_closure {
322
371
// Function calls in a v6+ SWF are proper closures, and "close" over the scope that defined the function:
323
372
// * Use the SWF version from the SWF that defined the function.
@@ -355,45 +404,24 @@ impl<'gc> Executable<'gc> {
355
404
Scope :: new_local_scope ( parent_scope, activation. context . gc_context ) ,
356
405
) ;
357
406
358
- let arguments = if af. flags . contains ( FunctionFlags :: SUPPRESS_ARGUMENTS ) {
359
- ArrayObject :: empty ( activation)
360
- } else {
361
- ArrayObject :: new (
362
- activation. context . gc_context ,
363
- activation. context . avm1 . prototypes ( ) . array ,
364
- args. iter ( ) . cloned ( ) ,
365
- )
366
- } ;
367
- arguments. define_value (
368
- activation. context . gc_context ,
369
- "callee" ,
370
- callee. into ( ) ,
371
- Attribute :: DONT_ENUM ,
372
- ) ;
373
407
// The caller is the previous callee.
374
- arguments. define_value (
375
- activation. context . gc_context ,
376
- "caller" ,
377
- activation. callee . map ( Value :: from) . unwrap_or ( Value :: Null ) ,
378
- Attribute :: DONT_ENUM ,
379
- ) ;
380
-
381
- // TODO: `super` should only be defined if this was a method call (depth > 0?)
382
- // `f[""]()` emits a CallMethod op, causing `this` to be undefined, but `super` is a function; what is it?
383
- let super_object: Option < Object < ' gc > > = this_obj. and_then ( |this| {
384
- if !af. flags . contains ( FunctionFlags :: SUPPRESS_SUPER ) {
385
- Some ( SuperObject :: new ( activation, this, depth) . into ( ) )
386
- } else {
387
- None
388
- }
389
- } ) ;
408
+ let arguments_caller = activation. callee ;
390
409
391
410
let name = if cfg ! ( feature = "avm_debug" ) {
392
411
Cow :: Owned ( af. debug_string_for_call ( name, args) )
393
412
} else {
394
413
Cow :: Borrowed ( "[Anonymous]" )
395
414
} ;
396
415
416
+ let is_this_inherited = af
417
+ . flags
418
+ . intersects ( FunctionFlags :: PRELOAD_THIS | FunctionFlags :: SUPPRESS_THIS ) ;
419
+ let local_this = if is_this_inherited {
420
+ activation. this_cell ( )
421
+ } else {
422
+ this
423
+ } ;
424
+
397
425
let max_recursion_depth = activation. context . avm1 . max_recursion_depth ( ) ;
398
426
let mut frame = Activation :: from_action (
399
427
activation. context . reborrow ( ) ,
@@ -402,17 +430,16 @@ impl<'gc> Executable<'gc> {
402
430
child_scope,
403
431
af. constant_pool ,
404
432
base_clip,
405
- this ,
433
+ local_this ,
406
434
Some ( callee) ,
407
- Some ( arguments. into ( ) ) ,
408
435
) ;
409
436
410
437
frame. allocate_local_registers ( af. register_count ( ) , frame. context . gc_context ) ;
411
438
412
439
let mut preload_r = 1 ;
413
440
af. load_this ( & mut frame, this, & mut preload_r) ;
414
- af. load_arguments ( & mut frame, arguments . into ( ) , & mut preload_r) ;
415
- af. load_super ( & mut frame, super_object , & mut preload_r) ;
441
+ af. load_arguments ( & mut frame, args , arguments_caller , & mut preload_r) ;
442
+ af. load_super ( & mut frame, this_obj , depth , & mut preload_r) ;
416
443
af. load_root ( & mut frame, & mut preload_r) ;
417
444
af. load_parent ( & mut frame, & mut preload_r) ;
418
445
af. load_global ( & mut frame, & mut preload_r) ;
0 commit comments