Skip to content

Commit 03c34c1

Browse files
Lord-McSweeneyLord-McSweeney
authored andcommitted
avm2: Make local scope optimizations match avmplus
1 parent 2e1baa2 commit 03c34c1

File tree

1 file changed

+18
-60
lines changed

1 file changed

+18
-60
lines changed

core/src/avm2/optimizer/optimize.rs

Lines changed: 18 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -40,9 +40,6 @@ struct OptValue<'gc> {
4040
// should only be set if class is numeric.
4141
pub contains_valid_unsigned: bool,
4242

43-
// Whether the class of this object is its exact type.
44-
pub is_exact_class: bool,
45-
4643
// TODO: FP actually has a separate `null` type just for this, this can be observed in VerifyErrors
4744
// (a separate type would also prevent accidental "null int" values)
4845
pub null_state: NullState,
@@ -53,7 +50,6 @@ impl<'gc> OptValue<'gc> {
5350
class: None,
5451
contains_valid_integer: false,
5552
contains_valid_unsigned: false,
56-
is_exact_class: false,
5753
null_state: NullState::MaybeNull,
5854
}
5955
}
@@ -73,14 +69,6 @@ impl<'gc> OptValue<'gc> {
7369
}
7470
}
7571

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-
8472
pub fn vtable(self) -> Option<VTable<'gc>> {
8573
self.class.filter(|c| !c.is_interface()).map(|c| c.vtable())
8674
}
@@ -104,14 +92,6 @@ impl<'gc> OptValue<'gc> {
10492
|| self.class == Some(class_defs.void)
10593
}
10694

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-
11595
pub fn merged_with(
11696
self,
11797
activation: &mut Activation<'_, 'gc>,
@@ -159,10 +139,6 @@ impl<'gc> OptValue<'gc> {
159139
created_value.contains_valid_unsigned = true;
160140
}
161141

162-
if self.is_exact_class && other.is_exact_class {
163-
created_value.is_exact_class = true;
164-
}
165-
166142
if self.null_state == other.null_state {
167143
created_value.null_state = self.null_state;
168144
}
@@ -278,16 +254,6 @@ impl<'gc> Stack<'gc> {
278254
Ok(())
279255
}
280256

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-
291257
fn push_class_not_null(
292258
&mut self,
293259
activation: &mut Activation<'_, 'gc>,
@@ -301,19 +267,6 @@ impl<'gc> Stack<'gc> {
301267
Ok(())
302268
}
303269

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-
317270
fn push_any(&mut self, activation: &mut Activation<'_, 'gc>) -> Result<(), Error<'gc>> {
318271
self.push(activation, OptValue::any())?;
319272

@@ -615,7 +568,6 @@ pub fn optimize<'gc>(
615568
class: this_class,
616569
contains_valid_integer: false,
617570
contains_valid_unsigned: false,
618-
is_exact_class: true,
619571
null_state: NullState::NotNull,
620572
};
621573

@@ -1011,7 +963,7 @@ fn abstract_interpret_ops<'gc>(
1011963
Op::NewObject { num_args } => {
1012964
stack.popn(activation, num_args * 2)?;
1013965

1014-
stack.push_class_exact_not_null(activation, types.object)?;
966+
stack.push_class_not_null(activation, types.object)?;
1015967
}
1016968
Op::NewFunction { .. } => {
1017969
stack.push_class_not_null(activation, types.function)?;
@@ -1175,7 +1127,7 @@ fn abstract_interpret_ops<'gc>(
11751127
.get_unchecked(index)
11761128
.values()
11771129
.instance_class(activation);
1178-
stack.push_class_exact(activation, class)?;
1130+
stack.push_class(activation, class)?;
11791131
}
11801132
Op::Pop => {
11811133
stack.pop(activation)?;
@@ -1228,19 +1180,25 @@ fn abstract_interpret_ops<'gc>(
12281180
stack_push_done = true;
12291181
stack.push_any(activation)?;
12301182
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) {
12331192
optimize_op_to!(Op::GetScopeObject { index: i });
12341193

12351194
stack_push_done = true;
1236-
stack.push_class_not_null(activation, class)?;
1195+
stack.push(activation, checked_scope.0)?;
12371196
break;
12381197
}
12391198
} 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.
12441202
}
12451203
}
12461204

@@ -1253,7 +1211,7 @@ fn abstract_interpret_ops<'gc>(
12531211
optimize_op_to!(Op::GetOuterScope { index });
12541212

12551213
stack_push_done = true;
1256-
stack.push_class_exact_not_null(activation, class)?;
1214+
stack.push_class_not_null(activation, class)?;
12571215
} else {
12581216
// If `get_entry_for_multiname` returned `Some(None)`, there was
12591217
// a `with` scope in the outer ScopeChain- abort optimization.
@@ -1275,7 +1233,7 @@ fn abstract_interpret_ops<'gc>(
12751233
optimize_op_to!(Op::GetScriptGlobals { script });
12761234

12771235
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())?;
12791237
}
12801238
}
12811239

@@ -1530,7 +1488,7 @@ fn abstract_interpret_ops<'gc>(
15301488
if let Some(instance_class) = slot_class.i_class() {
15311489
// ConstructProp on a c_class will construct its i_class
15321490
stack_push_done = true;
1533-
stack.push_class_exact(activation, instance_class)?;
1491+
stack.push_class(activation, instance_class)?;
15341492
}
15351493
}
15361494
}

0 commit comments

Comments
 (0)