@@ -40,9 +40,6 @@ struct OptValue<'gc> {
40
40
// should only be set if class is numeric.
41
41
pub contains_valid_unsigned : bool ,
42
42
43
- // Whether the class of this object is its exact type.
44
- pub is_exact_class : bool ,
45
-
46
43
// TODO: FP actually has a separate `null` type just for this, this can be observed in VerifyErrors
47
44
// (a separate type would also prevent accidental "null int" values)
48
45
pub null_state : NullState ,
@@ -53,7 +50,6 @@ impl<'gc> OptValue<'gc> {
53
50
class : None ,
54
51
contains_valid_integer : false ,
55
52
contains_valid_unsigned : false ,
56
- is_exact_class : false ,
57
53
null_state : NullState :: MaybeNull ,
58
54
}
59
55
}
@@ -73,14 +69,6 @@ impl<'gc> OptValue<'gc> {
73
69
}
74
70
}
75
71
76
- pub fn of_type_exact ( class : Class < ' gc > ) -> Self {
77
- Self {
78
- class : Some ( class) ,
79
- is_exact_class : true ,
80
- ..Self :: any ( )
81
- }
82
- }
83
-
84
72
pub fn vtable ( self ) -> Option < VTable < ' gc > > {
85
73
self . class . filter ( |c| !c. is_interface ( ) ) . map ( |c| c. vtable ( ) )
86
74
}
@@ -104,14 +92,6 @@ impl<'gc> OptValue<'gc> {
104
92
|| self . class == Some ( class_defs. void )
105
93
}
106
94
107
- pub fn exact_class ( self ) -> Option < Class < ' gc > > {
108
- if self . is_exact_class || self . class . is_some_and ( |c| c. is_final ( ) ) {
109
- self . class
110
- } else {
111
- None
112
- }
113
- }
114
-
115
95
pub fn merged_with (
116
96
self ,
117
97
activation : & mut Activation < ' _ , ' gc > ,
@@ -159,10 +139,6 @@ impl<'gc> OptValue<'gc> {
159
139
created_value. contains_valid_unsigned = true ;
160
140
}
161
141
162
- if self . is_exact_class && other. is_exact_class {
163
- created_value. is_exact_class = true ;
164
- }
165
-
166
142
if self . null_state == other. null_state {
167
143
created_value. null_state = self . null_state ;
168
144
}
@@ -278,16 +254,6 @@ impl<'gc> Stack<'gc> {
278
254
Ok ( ( ) )
279
255
}
280
256
281
- fn push_class_exact (
282
- & mut self ,
283
- activation : & mut Activation < ' _ , ' gc > ,
284
- class : Class < ' gc > ,
285
- ) -> Result < ( ) , Error < ' gc > > {
286
- self . push ( activation, OptValue :: of_type_exact ( class) ) ?;
287
-
288
- Ok ( ( ) )
289
- }
290
-
291
257
fn push_class_not_null (
292
258
& mut self ,
293
259
activation : & mut Activation < ' _ , ' gc > ,
@@ -301,19 +267,6 @@ impl<'gc> Stack<'gc> {
301
267
Ok ( ( ) )
302
268
}
303
269
304
- fn push_class_exact_not_null (
305
- & mut self ,
306
- activation : & mut Activation < ' _ , ' gc > ,
307
- class : Class < ' gc > ,
308
- ) -> Result < ( ) , Error < ' gc > > {
309
- let mut value = OptValue :: of_type_exact ( class) ;
310
- value. null_state = NullState :: NotNull ;
311
-
312
- self . push ( activation, value) ?;
313
-
314
- Ok ( ( ) )
315
- }
316
-
317
270
fn push_any ( & mut self , activation : & mut Activation < ' _ , ' gc > ) -> Result < ( ) , Error < ' gc > > {
318
271
self . push ( activation, OptValue :: any ( ) ) ?;
319
272
@@ -615,7 +568,6 @@ pub fn optimize<'gc>(
615
568
class : this_class,
616
569
contains_valid_integer : false ,
617
570
contains_valid_unsigned : false ,
618
- is_exact_class : true ,
619
571
null_state : NullState :: NotNull ,
620
572
} ;
621
573
@@ -1011,7 +963,7 @@ fn abstract_interpret_ops<'gc>(
1011
963
Op :: NewObject { num_args } => {
1012
964
stack. popn ( activation, num_args * 2 ) ?;
1013
965
1014
- stack. push_class_exact_not_null ( activation, types. object ) ?;
966
+ stack. push_class_not_null ( activation, types. object ) ?;
1015
967
}
1016
968
Op :: NewFunction { .. } => {
1017
969
stack. push_class_not_null ( activation, types. function ) ?;
@@ -1175,7 +1127,7 @@ fn abstract_interpret_ops<'gc>(
1175
1127
. get_unchecked ( index)
1176
1128
. values ( )
1177
1129
. instance_class ( activation) ;
1178
- stack. push_class_exact ( activation, class) ?;
1130
+ stack. push_class ( activation, class) ?;
1179
1131
}
1180
1132
Op :: Pop => {
1181
1133
stack. pop ( activation) ?;
@@ -1228,19 +1180,25 @@ fn abstract_interpret_ops<'gc>(
1228
1180
stack_push_done = true ;
1229
1181
stack. push_any ( activation) ?;
1230
1182
break ;
1231
- } else if let Some ( class) = checked_scope. 0 . exact_class ( ) {
1232
- if class. vtable ( ) . has_trait ( & multiname) {
1183
+ } else if let Some ( vtable) = checked_scope. 0 . vtable ( ) {
1184
+ // NOTE: There is a subtle issue with this logic;
1185
+ // if pushing an object of type `Subclass` that was
1186
+ // declared to be of type `Superclass` with a coerce,
1187
+ // the scope optimizer may "skip" traits that were on
1188
+ // `Subclass` when it assumes the value is of type
1189
+ // `Superclass`. However, this matches avmplus's
1190
+ // behavior- see the test `avm2/scope_optimizations`.
1191
+ if vtable. has_trait ( & multiname) {
1233
1192
optimize_op_to ! ( Op :: GetScopeObject { index: i } ) ;
1234
1193
1235
1194
stack_push_done = true ;
1236
- stack. push_class_not_null ( activation, class ) ?;
1195
+ stack. push ( activation, checked_scope . 0 ) ?;
1237
1196
break ;
1238
1197
}
1239
1198
} else {
1240
- // We don't know the exact class
1241
- stack_push_done = true ;
1242
- stack. push_any ( activation) ?;
1243
- break ;
1199
+ // We don't know the class...but to match avmplus,
1200
+ // we keep descending the scope stack, assuming that
1201
+ // the trait wasn't found on this scope.
1244
1202
}
1245
1203
}
1246
1204
@@ -1253,7 +1211,7 @@ fn abstract_interpret_ops<'gc>(
1253
1211
optimize_op_to ! ( Op :: GetOuterScope { index } ) ;
1254
1212
1255
1213
stack_push_done = true ;
1256
- stack. push_class_exact_not_null ( activation, class) ?;
1214
+ stack. push_class_not_null ( activation, class) ?;
1257
1215
} else {
1258
1216
// If `get_entry_for_multiname` returned `Some(None)`, there was
1259
1217
// a `with` scope in the outer ScopeChain- abort optimization.
@@ -1275,7 +1233,7 @@ fn abstract_interpret_ops<'gc>(
1275
1233
optimize_op_to ! ( Op :: GetScriptGlobals { script } ) ;
1276
1234
1277
1235
stack_push_done = true ;
1278
- stack. push_class_exact_not_null ( activation, script. global_class ( ) ) ?;
1236
+ stack. push_class_not_null ( activation, script. global_class ( ) ) ?;
1279
1237
}
1280
1238
}
1281
1239
@@ -1530,7 +1488,7 @@ fn abstract_interpret_ops<'gc>(
1530
1488
if let Some ( instance_class) = slot_class. i_class ( ) {
1531
1489
// ConstructProp on a c_class will construct its i_class
1532
1490
stack_push_done = true ;
1533
- stack. push_class_exact ( activation, instance_class) ?;
1491
+ stack. push_class ( activation, instance_class) ?;
1534
1492
}
1535
1493
}
1536
1494
}
0 commit comments