avm2: Add optimizations for `Coerce` and `AsType` after `PushNull`, fix `optimize` panicking when out-of-bounds local registers are mentioned
This commit is contained in:
parent
3f76b248e9
commit
30f99bcd19
|
@ -4,6 +4,7 @@ use crate::avm2::op::Op;
|
||||||
use crate::avm2::property::Property;
|
use crate::avm2::property::Property;
|
||||||
use crate::avm2::script::TranslationUnit;
|
use crate::avm2::script::TranslationUnit;
|
||||||
use crate::avm2::{Activation, Error};
|
use crate::avm2::{Activation, Error};
|
||||||
|
use gc_arena::GcCell;
|
||||||
use std::collections::{HashMap, HashSet};
|
use std::collections::{HashMap, HashSet};
|
||||||
use swf::avm2::read::Reader;
|
use swf::avm2::read::Reader;
|
||||||
use swf::avm2::types::{Index, MethodFlags as AbcMethodFlags, Multiname, Op as AbcOp};
|
use swf::avm2::types::{Index, MethodFlags as AbcMethodFlags, Multiname, Op as AbcOp};
|
||||||
|
@ -473,6 +474,33 @@ fn verify_code_starting_from<'gc>(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
AbcOp::AsType {
|
||||||
|
type_name: name_index,
|
||||||
|
}
|
||||||
|
| AbcOp::Coerce { index: name_index } => {
|
||||||
|
let multiname = method
|
||||||
|
.translation_unit()
|
||||||
|
.pool_maybe_uninitialized_multiname(*name_index, &mut activation.context)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
activation
|
||||||
|
.domain()
|
||||||
|
.get_class(&multiname, activation.context.gc_context)
|
||||||
|
.ok_or_else(|| {
|
||||||
|
Error::AvmError(
|
||||||
|
verify_error(
|
||||||
|
activation,
|
||||||
|
&format!(
|
||||||
|
"Error #1014: Class {} could not be found.",
|
||||||
|
multiname.to_qualified_name(activation.context.gc_context)
|
||||||
|
),
|
||||||
|
1014,
|
||||||
|
)
|
||||||
|
.expect("Error should construct"),
|
||||||
|
)
|
||||||
|
})?;
|
||||||
|
}
|
||||||
|
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -523,7 +551,7 @@ fn optimize<'gc>(
|
||||||
| Op::IncLocalI { index }
|
| Op::IncLocalI { index }
|
||||||
| Op::DecLocal { index }
|
| Op::DecLocal { index }
|
||||||
| Op::DecLocalI { index } => {
|
| Op::DecLocalI { index } => {
|
||||||
if local_types[*index as usize].is_some() {
|
if (*index as usize) < local_types.len() {
|
||||||
local_types[*index as usize] = None;
|
local_types[*index as usize] = None;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -531,10 +559,10 @@ fn optimize<'gc>(
|
||||||
object_register,
|
object_register,
|
||||||
index_register,
|
index_register,
|
||||||
} => {
|
} => {
|
||||||
if local_types[*object_register as usize].is_some() {
|
if (*object_register as usize) < local_types.len() {
|
||||||
local_types[*object_register as usize] = None;
|
local_types[*object_register as usize] = None;
|
||||||
}
|
}
|
||||||
if local_types[*index_register as usize].is_some() {
|
if (*index_register as usize) < local_types.len() {
|
||||||
local_types[*index_register as usize] = None;
|
local_types[*index_register as usize] = None;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -632,6 +660,80 @@ fn optimize<'gc>(
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
},
|
},
|
||||||
|
Op::AsType {
|
||||||
|
type_name: name_index,
|
||||||
|
} => {
|
||||||
|
let multiname = method
|
||||||
|
.translation_unit()
|
||||||
|
.pool_maybe_uninitialized_multiname(
|
||||||
|
*name_index,
|
||||||
|
&mut activation.context,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let resolved_type = activation
|
||||||
|
.domain()
|
||||||
|
.get_class(&multiname, activation.context.gc_context);
|
||||||
|
|
||||||
|
if resolved_type.is_some() {
|
||||||
|
match previous_op_some {
|
||||||
|
Op::PushNull => {
|
||||||
|
previous_op = Some(op.clone());
|
||||||
|
*op = Op::Nop;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Op::Coerce { index: name_index } => {
|
||||||
|
let multiname = method
|
||||||
|
.translation_unit()
|
||||||
|
.pool_maybe_uninitialized_multiname(
|
||||||
|
*name_index,
|
||||||
|
&mut activation.context,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let resolved_type = activation
|
||||||
|
.domain()
|
||||||
|
.get_class(&multiname, activation.context.gc_context);
|
||||||
|
|
||||||
|
if let Some(class) = resolved_type {
|
||||||
|
match previous_op_some {
|
||||||
|
Op::PushNull => {
|
||||||
|
if !GcCell::ptr_eq(
|
||||||
|
class,
|
||||||
|
activation.avm2().classes().int.inner_class_definition(),
|
||||||
|
) && !GcCell::ptr_eq(
|
||||||
|
class,
|
||||||
|
activation.avm2().classes().uint.inner_class_definition(),
|
||||||
|
) && !GcCell::ptr_eq(
|
||||||
|
class,
|
||||||
|
activation.avm2().classes().number.inner_class_definition(),
|
||||||
|
) && !GcCell::ptr_eq(
|
||||||
|
class,
|
||||||
|
activation
|
||||||
|
.avm2()
|
||||||
|
.classes()
|
||||||
|
.boolean
|
||||||
|
.inner_class_definition(),
|
||||||
|
) && !GcCell::ptr_eq(
|
||||||
|
class,
|
||||||
|
activation.avm2().classes().void.inner_class_definition(),
|
||||||
|
) && !GcCell::ptr_eq(
|
||||||
|
class,
|
||||||
|
activation.avm2().classes().string.inner_class_definition(),
|
||||||
|
) {
|
||||||
|
previous_op = Some(op.clone());
|
||||||
|
*op = Op::Nop;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue