avm2: Add an `Op` enum to AVM2; pre-pool double/uint/ints for `pushX` opcodes

This commit is contained in:
Lord-McSweeney 2024-01-05 13:51:33 -08:00 committed by Lord-McSweeney
parent 65848104a6
commit 2022321a03
5 changed files with 705 additions and 135 deletions

View File

@ -50,6 +50,7 @@ mod method;
mod multiname;
mod namespace;
pub mod object;
mod op;
mod parameters;
pub mod property;
mod property_map;

View File

@ -14,13 +14,14 @@ use crate::avm2::object::{
XmlListObject,
};
use crate::avm2::object::{Object, TObject};
use crate::avm2::op::Op;
use crate::avm2::scope::{search_scope_stack, Scope, ScopeChain};
use crate::avm2::script::Script;
use crate::avm2::value::Value;
use crate::avm2::Multiname;
use crate::avm2::Namespace;
use crate::avm2::QName;
use crate::avm2::{value, Avm2, Error};
use crate::avm2::{Avm2, Error};
use crate::context::{GcContext, UpdateContext};
use crate::string::{AvmAtom, AvmString};
use crate::tag_utils::SwfMovie;
@ -31,7 +32,7 @@ use std::cmp::{min, Ordering};
use std::sync::Arc;
use swf::avm2::types::{
Class as AbcClass, Exception, Index, Method as AbcMethod, MethodFlags as AbcMethodFlags,
Multiname as AbcMultiname, Namespace as AbcNamespace, Op,
Multiname as AbcMultiname, Namespace as AbcNamespace,
};
use super::error::make_mismatch_error;
@ -710,33 +711,6 @@ impl<'a, 'gc> Activation<'a, 'gc> {
})
}
/// Retrieve a int from the current constant pool.
fn pool_int(
&self,
method: Gc<'gc, BytecodeMethod<'gc>>,
index: Index<i32>,
) -> Result<i32, Error<'gc>> {
value::abc_int(method.translation_unit(), index)
}
/// Retrieve a int from the current constant pool.
fn pool_uint(
&self,
method: Gc<'gc, BytecodeMethod<'gc>>,
index: Index<u32>,
) -> Result<u32, Error<'gc>> {
value::abc_uint(method.translation_unit(), index)
}
/// Retrieve a double from the current constant pool.
fn pool_double(
&self,
method: Gc<'gc, BytecodeMethod<'gc>>,
index: Index<f64>,
) -> Result<f64, Error<'gc>> {
value::abc_double(method.translation_unit(), index)
}
/// Retrieve a string from the current constant pool.
fn pool_string<'b>(
&mut self,
@ -939,16 +913,16 @@ impl<'a, 'gc> Activation<'a, 'gc> {
{
let result = match op {
Op::PushByte { value } => self.op_push_byte(*value),
Op::PushDouble { value } => self.op_push_double(method, *value),
Op::PushDouble { value } => self.op_push_double(*value),
Op::PushFalse => self.op_push_false(),
Op::PushInt { value } => self.op_push_int(method, *value),
Op::PushInt { value } => self.op_push_int(*value),
Op::PushNamespace { value } => self.op_push_namespace(method, *value),
Op::PushNaN => self.op_push_nan(),
Op::PushNull => self.op_push_null(),
Op::PushShort { value } => self.op_push_short(*value),
Op::PushString { value } => self.op_push_string(method, *value),
Op::PushTrue => self.op_push_true(),
Op::PushUint { value } => self.op_push_uint(method, *value),
Op::PushUint { value } => self.op_push_uint(*value),
Op::PushUndefined => self.op_push_undefined(),
Op::Pop => self.op_pop(),
Op::Dup => self.op_dup(),
@ -1116,7 +1090,6 @@ impl<'a, 'gc> Activation<'a, 'gc> {
Op::Sxi8 => self.op_sxi8(),
Op::Sxi16 => self.op_sxi16(),
Op::Throw => self.op_throw(),
_ => self.unknown_op(op),
};
if let Err(error) = result {
@ -1126,11 +1099,6 @@ impl<'a, 'gc> Activation<'a, 'gc> {
}
}
fn unknown_op(&mut self, op: &swf::avm2::types::Op) -> Result<FrameControl<'gc>, Error<'gc>> {
tracing::error!("Unknown AVM2 opcode: {:?}", op);
Err("Unknown op".into())
}
fn op_push_byte(&mut self, value: u8) -> Result<FrameControl<'gc>, Error<'gc>> {
//TODO: Adobe Animate CC appears to generate signed byte values, and
//JPEXS appears to take them.
@ -1138,12 +1106,8 @@ impl<'a, 'gc> Activation<'a, 'gc> {
Ok(FrameControl::Continue)
}
fn op_push_double(
&mut self,
method: Gc<'gc, BytecodeMethod<'gc>>,
value: Index<f64>,
) -> Result<FrameControl<'gc>, Error<'gc>> {
self.push_stack(self.pool_double(method, value)?);
fn op_push_double(&mut self, value: f64) -> Result<FrameControl<'gc>, Error<'gc>> {
self.push_stack(value);
Ok(FrameControl::Continue)
}
@ -1152,12 +1116,8 @@ impl<'a, 'gc> Activation<'a, 'gc> {
Ok(FrameControl::Continue)
}
fn op_push_int(
&mut self,
method: Gc<'gc, BytecodeMethod<'gc>>,
value: Index<i32>,
) -> Result<FrameControl<'gc>, Error<'gc>> {
self.push_stack(self.pool_int(method, value)?);
fn op_push_int(&mut self, value: i32) -> Result<FrameControl<'gc>, Error<'gc>> {
self.push_stack(value);
Ok(FrameControl::Continue)
}
@ -1203,12 +1163,8 @@ impl<'a, 'gc> Activation<'a, 'gc> {
Ok(FrameControl::Continue)
}
fn op_push_uint(
&mut self,
method: Gc<'gc, BytecodeMethod<'gc>>,
value: Index<u32>,
) -> Result<FrameControl<'gc>, Error<'gc>> {
self.push_stack(self.pool_uint(method, value)?);
fn op_push_uint(&mut self, value: u32) -> Result<FrameControl<'gc>, Error<'gc>> {
self.push_stack(value);
Ok(FrameControl::Continue)
}

318
core/src/avm2/op.rs Normal file
View File

@ -0,0 +1,318 @@
use swf::avm2::types::{Class, Exception, Index, LookupSwitch, Method, Multiname, Namespace};
#[derive(Clone, Debug, PartialEq)]
pub enum Op {
Add,
AddI,
ApplyType {
num_types: u32,
},
AsType {
type_name: Index<Multiname>,
},
AsTypeLate,
BitAnd,
BitNot,
BitOr,
BitXor,
Bkpt,
BkptLine {
line_num: u32,
},
Call {
num_args: u32,
},
CallMethod {
index: Index<Method>,
num_args: u32,
},
CallProperty {
index: Index<Multiname>,
num_args: u32,
},
CallPropLex {
index: Index<Multiname>,
num_args: u32,
},
CallPropVoid {
index: Index<Multiname>,
num_args: u32,
},
CallStatic {
index: Index<Method>,
num_args: u32,
},
CallSuper {
index: Index<Multiname>,
num_args: u32,
},
CallSuperVoid {
index: Index<Multiname>,
num_args: u32,
},
CheckFilter,
Coerce {
index: Index<Multiname>,
},
CoerceA,
CoerceB,
CoerceD,
CoerceI,
CoerceO,
CoerceS,
CoerceU,
Construct {
num_args: u32,
},
ConstructProp {
index: Index<Multiname>,
num_args: u32,
},
ConstructSuper {
num_args: u32,
},
ConvertB,
ConvertD,
ConvertI,
ConvertO,
ConvertS,
ConvertU,
Debug {
is_local_register: bool,
register_name: Index<String>,
register: u8,
},
DebugFile {
file_name: Index<String>,
},
DebugLine {
line_num: u32,
},
DecLocal {
index: u32,
},
DecLocalI {
index: u32,
},
Decrement,
DecrementI,
DeleteProperty {
index: Index<Multiname>,
},
Divide,
Dup,
Equals,
EscXAttr,
EscXElem,
FindDef {
index: Index<Multiname>,
},
FindProperty {
index: Index<Multiname>,
},
FindPropStrict {
index: Index<Multiname>,
},
GetDescendants {
index: Index<Multiname>,
},
GetGlobalScope,
GetGlobalSlot {
index: u32,
},
GetLex {
index: Index<Multiname>,
},
GetLocal {
index: u32,
},
GetOuterScope {
index: u32,
},
GetProperty {
index: Index<Multiname>,
},
GetScopeObject {
index: u8,
},
GetSlot {
index: u32,
},
GetSuper {
index: Index<Multiname>,
},
GreaterEquals,
GreaterThan,
HasNext,
HasNext2 {
object_register: u32,
index_register: u32,
},
IfEq {
offset: i32,
},
IfFalse {
offset: i32,
},
IfGe {
offset: i32,
},
IfGt {
offset: i32,
},
IfLe {
offset: i32,
},
IfLt {
offset: i32,
},
IfNe {
offset: i32,
},
IfNge {
offset: i32,
},
IfNgt {
offset: i32,
},
IfNle {
offset: i32,
},
IfNlt {
offset: i32,
},
IfStrictEq {
offset: i32,
},
IfStrictNe {
offset: i32,
},
IfTrue {
offset: i32,
},
In,
IncLocal {
index: u32,
},
IncLocalI {
index: u32,
},
Increment,
IncrementI,
InitProperty {
index: Index<Multiname>,
},
InstanceOf,
IsType {
index: Index<Multiname>,
},
IsTypeLate,
Jump {
offset: i32,
},
Kill {
index: u32,
},
Label,
LessEquals,
LessThan,
Lf32,
Lf64,
Li16,
Li32,
Li8,
LookupSwitch(Box<LookupSwitch>),
LShift,
Modulo,
Multiply,
MultiplyI,
Negate,
NegateI,
NewActivation,
NewArray {
num_args: u32,
},
NewCatch {
index: Index<Exception>,
},
NewClass {
index: Index<Class>,
},
NewFunction {
index: Index<Method>,
},
NewObject {
num_args: u32,
},
NextName,
NextValue,
Nop,
Not,
Pop,
PopScope,
PushByte {
value: u8,
},
PushDouble {
value: f64,
},
PushFalse,
PushInt {
value: i32,
},
PushNamespace {
value: Index<Namespace>,
},
PushNaN,
PushNull,
PushScope,
PushShort {
value: i16,
},
PushString {
value: Index<String>,
},
PushTrue,
PushUint {
value: u32,
},
PushUndefined,
PushWith,
ReturnValue,
ReturnVoid,
RShift,
SetGlobalSlot {
index: u32,
},
SetLocal {
index: u32,
},
SetProperty {
index: Index<Multiname>,
},
SetSlot {
index: u32,
},
SetSuper {
index: Index<Multiname>,
},
Sf32,
Sf64,
Si16,
Si32,
Si8,
StrictEquals,
Subtract,
SubtractI,
Swap,
Sxi1,
Sxi16,
Sxi8,
Throw,
TypeOf,
Timestamp,
URShift,
}
#[cfg(target_pointer_width = "64")]
const _: () = assert!(std::mem::size_of::<Op>() == 16);

View File

@ -1,9 +1,11 @@
use crate::avm2::error::{make_error_1025, make_error_1054, make_error_1107, verify_error};
use crate::avm2::method::BytecodeMethod;
use crate::avm2::op::Op;
use crate::avm2::script::TranslationUnit;
use crate::avm2::{Activation, Error};
use std::collections::HashMap;
use swf::avm2::read::Reader;
use swf::avm2::types::{Index, MethodFlags as AbcMethodFlags, Multiname, Op};
use swf::avm2::types::{Index, MethodFlags as AbcMethodFlags, Multiname, Op as AbcOp};
use swf::error::Error as AbcReadError;
pub struct VerifiedMethodInfo {
@ -27,6 +29,7 @@ pub fn verify_method<'gc>(
let body = method
.body()
.expect("Cannot verify non-native method without body!");
let translation_unit = method.translation_unit();
let param_count = method.method().params.len();
let locals_count = body.num_locals;
@ -53,8 +56,9 @@ pub fn verify_method<'gc>(
)?));
}
// FIXME: This is wrong, verification should happen at the same time as reading.
// A side effect of this is that avmplus allows for holes in bytecode.
// FIXME: This is wrong, verification/control flow handling should happen at the same
// time as reading. A side effect of this is that avmplus allows for holes in bytecode,
// while this implementation throws errors #1011 or #1021 in those cases.
let mut reader = Reader::new(&body.code);
loop {
let op = match reader.read_op() {
@ -193,24 +197,24 @@ pub fn verify_method<'gc>(
new_idx - i - 1
};
match op {
Op::IfEq { offset }
| Op::IfFalse { offset }
| Op::IfGe { offset }
| Op::IfGt { offset }
| Op::IfLe { offset }
| Op::IfLt { offset }
| Op::IfNe { offset }
| Op::IfNge { offset }
| Op::IfNgt { offset }
| Op::IfNle { offset }
| Op::IfNlt { offset }
| Op::IfStrictEq { offset }
| Op::IfStrictNe { offset }
| Op::IfTrue { offset }
| Op::Jump { offset } => {
AbcOp::IfEq { offset }
| AbcOp::IfFalse { offset }
| AbcOp::IfGe { offset }
| AbcOp::IfGt { offset }
| AbcOp::IfLe { offset }
| AbcOp::IfLt { offset }
| AbcOp::IfNe { offset }
| AbcOp::IfNge { offset }
| AbcOp::IfNgt { offset }
| AbcOp::IfNle { offset }
| AbcOp::IfNlt { offset }
| AbcOp::IfStrictEq { offset }
| AbcOp::IfStrictNe { offset }
| AbcOp::IfTrue { offset }
| AbcOp::Jump { offset } => {
*offset = adjusted(i, *offset, true);
}
Op::LookupSwitch(ref mut lookup_switch) => {
AbcOp::LookupSwitch(ref mut lookup_switch) => {
lookup_switch.default_offset = adjusted(i, lookup_switch.default_offset, false);
for case in lookup_switch.case_offsets.iter_mut() {
*case = adjusted(i, *case, false);
@ -220,8 +224,15 @@ pub fn verify_method<'gc>(
}
}
let mut verified_code = Vec::new();
for abc_op in new_code {
let resolved_op = resolve_op(activation, translation_unit, abc_op)?;
verified_code.push(resolved_op);
}
Ok(VerifiedMethodInfo {
parsed_code: new_code,
parsed_code: verified_code,
exceptions: new_exceptions,
})
}
@ -258,7 +269,7 @@ fn verify_code_starting_from<'gc>(
idx_to_byte_offset: &[i32],
byte_offset_to_idx: &HashMap<i32, i32>,
verified_blocks: &mut Vec<i32>,
ops: &[Op],
ops: &[AbcOp],
start_idx: i32,
) -> Result<(), Error<'gc>> {
if verified_blocks.iter().any(|o| *o == start_idx) {
@ -279,21 +290,21 @@ fn verify_code_starting_from<'gc>(
// Special control flow ops
match op {
Op::IfEq { offset }
| Op::IfFalse { offset }
| Op::IfGe { offset }
| Op::IfGt { offset }
| Op::IfLe { offset }
| Op::IfLt { offset }
| Op::IfNe { offset }
| Op::IfNge { offset }
| Op::IfNgt { offset }
| Op::IfNle { offset }
| Op::IfNlt { offset }
| Op::IfStrictEq { offset }
| Op::IfStrictNe { offset }
| Op::IfTrue { offset }
| Op::Jump { offset } => {
AbcOp::IfEq { offset }
| AbcOp::IfFalse { offset }
| AbcOp::IfGe { offset }
| AbcOp::IfGt { offset }
| AbcOp::IfLe { offset }
| AbcOp::IfLt { offset }
| AbcOp::IfNe { offset }
| AbcOp::IfNge { offset }
| AbcOp::IfNgt { offset }
| AbcOp::IfNle { offset }
| AbcOp::IfNlt { offset }
| AbcOp::IfStrictEq { offset }
| AbcOp::IfStrictNe { offset }
| AbcOp::IfTrue { offset }
| AbcOp::Jump { offset } => {
let op_idx = adjust_jump_offset(
activation,
i,
@ -315,7 +326,7 @@ fn verify_code_starting_from<'gc>(
position + 1,
)?;
if matches!(op, Op::Jump { .. }) {
if matches!(op, AbcOp::Jump { .. }) {
// A Jump is terminal, the code
// after it won't be executed
return Ok(());
@ -324,11 +335,11 @@ fn verify_code_starting_from<'gc>(
}
// Terminal opcodes
Op::Throw => return Ok(()),
Op::ReturnValue => return Ok(()),
Op::ReturnVoid => return Ok(()),
AbcOp::Throw => return Ok(()),
AbcOp::ReturnValue => return Ok(()),
AbcOp::ReturnVoid => return Ok(()),
Op::LookupSwitch(ref lookup_switch) => {
AbcOp::LookupSwitch(ref lookup_switch) => {
let default_idx = adjust_jump_offset(
activation,
i,
@ -376,19 +387,19 @@ fn verify_code_starting_from<'gc>(
// Verifications
// Local register verifications
Op::GetLocal { index }
| Op::SetLocal { index }
| Op::Kill { index }
| Op::DecLocal { index }
| Op::DecLocalI { index }
| Op::IncLocal { index }
| Op::IncLocalI { index } => {
AbcOp::GetLocal { index }
| AbcOp::SetLocal { index }
| AbcOp::Kill { index }
| AbcOp::DecLocal { index }
| AbcOp::DecLocalI { index }
| AbcOp::IncLocal { index }
| AbcOp::IncLocalI { index } => {
if *index >= max_locals {
return Err(make_error_1025(activation, *index));
}
}
Op::HasNext2 {
AbcOp::HasNext2 {
object_register,
index_register,
} => {
@ -401,7 +412,7 @@ fn verify_code_starting_from<'gc>(
}
// Misc opcode verification
Op::CallMethod { index, .. } => {
AbcOp::CallMethod { index, .. } => {
return Err(Error::AvmError(if index.as_u30() == 0 {
verify_error(activation, "Error #1072: Disp_id 0 is illegal.", 1072)?
} else {
@ -413,7 +424,7 @@ fn verify_code_starting_from<'gc>(
}));
}
Op::NewActivation => {
AbcOp::NewActivation => {
if !method
.method()
.flags
@ -427,7 +438,7 @@ fn verify_code_starting_from<'gc>(
}
}
Op::GetLex { index } => {
AbcOp::GetLex { index } => {
let multiname = method
.translation_unit()
.pool_maybe_uninitialized_multiname(*index, &mut activation.context)?;
@ -454,34 +465,323 @@ fn verify_code_starting_from<'gc>(
)?))
}
fn ops_can_throw_error(ops: &[Op], start_idx: u32, end_idx: u32) -> bool {
fn ops_can_throw_error(ops: &[AbcOp], start_idx: u32, end_idx: u32) -> bool {
for i in start_idx..end_idx {
let op = &ops[i as usize];
match op {
Op::PushByte { .. }
| Op::PushDouble { .. }
| Op::PushFalse
| Op::PushInt { .. }
| Op::PushNamespace { .. }
| Op::PushNaN
| Op::PushNull
| Op::PushShort { .. }
| Op::PushString { .. }
| Op::PushTrue
| Op::PushUint { .. }
| Op::PushUndefined
| Op::Dup
| Op::Pop
| Op::GetLocal { .. }
| Op::SetLocal { .. }
| Op::Kill { .. }
| Op::Nop
| Op::Not
| Op::PopScope
| Op::ReturnVoid => {}
AbcOp::PushByte { .. }
| AbcOp::PushDouble { .. }
| AbcOp::PushFalse
| AbcOp::PushInt { .. }
| AbcOp::PushNamespace { .. }
| AbcOp::PushNaN
| AbcOp::PushNull
| AbcOp::PushShort { .. }
| AbcOp::PushString { .. }
| AbcOp::PushTrue
| AbcOp::PushUint { .. }
| AbcOp::PushUndefined
| AbcOp::Dup
| AbcOp::Pop
| AbcOp::GetLocal { .. }
| AbcOp::SetLocal { .. }
| AbcOp::Kill { .. }
| AbcOp::Nop
| AbcOp::Not
| AbcOp::PopScope
| AbcOp::ReturnVoid => {}
_ => return true,
}
}
false
}
fn pool_int<'gc>(
activation: &mut Activation<'_, 'gc>,
translation_unit: TranslationUnit<'gc>,
index: Index<i32>,
) -> Result<i32, Error<'gc>> {
if index.0 == 0 {
return Ok(0);
}
translation_unit
.abc()
.constant_pool
.ints
.get(index.0 as usize - 1)
.cloned()
.ok_or_else(|| {
Error::AvmError(
verify_error(
activation,
&format!("Error #1032: Cpool index {} is out of range.", index.0),
1032,
)
.expect("Error should construct"),
)
})
}
fn pool_uint<'gc>(
activation: &mut Activation<'_, 'gc>,
translation_unit: TranslationUnit<'gc>,
index: Index<u32>,
) -> Result<u32, Error<'gc>> {
if index.0 == 0 {
return Ok(0);
}
translation_unit
.abc()
.constant_pool
.uints
.get(index.0 as usize - 1)
.cloned()
.ok_or_else(|| {
Error::AvmError(
verify_error(
activation,
&format!("Error #1032: Cpool index {} is out of range.", index.0),
1032,
)
.expect("Error should construct"),
)
})
}
fn pool_double<'gc>(
activation: &mut Activation<'_, 'gc>,
translation_unit: TranslationUnit<'gc>,
index: Index<f64>,
) -> Result<f64, Error<'gc>> {
if index.0 == 0 {
return Err(Error::AvmError(
verify_error(
activation,
"Error #1032: Cpool index 0 is out of range.",
1032,
)
.expect("Error should construct"),
));
}
translation_unit
.abc()
.constant_pool
.doubles
.get(index.0 as usize - 1)
.cloned()
.ok_or_else(|| {
Error::AvmError(
verify_error(
activation,
&format!("Error #1032: Cpool index {} is out of range.", index.0),
1032,
)
.expect("Error should construct"),
)
})
}
fn resolve_op<'gc>(
activation: &mut Activation<'_, 'gc>,
translation_unit: TranslationUnit<'gc>,
op: AbcOp,
) -> Result<Op, Error<'gc>> {
Ok(match op {
AbcOp::PushByte { value } => Op::PushByte { value },
AbcOp::PushDouble { value } => {
let value = pool_double(activation, translation_unit, value)?;
Op::PushDouble { value }
}
AbcOp::PushFalse => Op::PushFalse,
AbcOp::PushInt { value } => {
let value = pool_int(activation, translation_unit, value)?;
Op::PushInt { value }
}
AbcOp::PushNamespace { value } => Op::PushNamespace { value },
AbcOp::PushNaN => Op::PushNaN,
AbcOp::PushNull => Op::PushNull,
AbcOp::PushShort { value } => Op::PushShort { value },
AbcOp::PushString { value } => Op::PushString { value },
AbcOp::PushTrue => Op::PushTrue,
AbcOp::PushUint { value } => {
let value = pool_uint(activation, translation_unit, value)?;
Op::PushUint { value }
}
AbcOp::PushUndefined => Op::PushUndefined,
AbcOp::Pop => Op::Pop,
AbcOp::Dup => Op::Dup,
AbcOp::GetLocal { index } => Op::GetLocal { index },
AbcOp::SetLocal { index } => Op::SetLocal { index },
AbcOp::Kill { index } => Op::Kill { index },
AbcOp::Call { num_args } => Op::Call { num_args },
AbcOp::CallMethod { index, num_args } => Op::CallMethod { index, num_args },
AbcOp::CallProperty { index, num_args } => Op::CallProperty { index, num_args },
AbcOp::CallPropLex { index, num_args } => Op::CallPropLex { index, num_args },
AbcOp::CallPropVoid { index, num_args } => Op::CallPropVoid { index, num_args },
AbcOp::CallStatic { index, num_args } => Op::CallStatic { index, num_args },
AbcOp::CallSuper { index, num_args } => Op::CallSuper { index, num_args },
AbcOp::CallSuperVoid { index, num_args } => Op::CallSuperVoid { index, num_args },
AbcOp::ReturnValue => Op::ReturnValue,
AbcOp::ReturnVoid => Op::ReturnVoid,
AbcOp::GetProperty { index } => Op::GetProperty { index },
AbcOp::SetProperty { index } => Op::SetProperty { index },
AbcOp::InitProperty { index } => Op::InitProperty { index },
AbcOp::DeleteProperty { index } => Op::DeleteProperty { index },
AbcOp::GetSuper { index } => Op::GetSuper { index },
AbcOp::SetSuper { index } => Op::SetSuper { index },
AbcOp::In => Op::In,
AbcOp::PushScope => Op::PushScope,
AbcOp::NewCatch { index } => Op::NewCatch { index },
AbcOp::PushWith => Op::PushWith,
AbcOp::PopScope => Op::PopScope,
AbcOp::GetOuterScope { index } => Op::GetOuterScope { index },
AbcOp::GetScopeObject { index } => Op::GetScopeObject { index },
AbcOp::GetGlobalScope => Op::GetGlobalScope,
AbcOp::FindDef { index } => Op::FindDef { index },
AbcOp::FindProperty { index } => Op::FindProperty { index },
AbcOp::FindPropStrict { index } => Op::FindPropStrict { index },
AbcOp::GetLex { index } => Op::GetLex { index },
AbcOp::GetDescendants { index } => Op::GetDescendants { index },
AbcOp::GetSlot { index } => Op::GetSlot { index },
AbcOp::SetSlot { index } => Op::SetSlot { index },
AbcOp::GetGlobalSlot { index } => Op::GetGlobalSlot { index },
AbcOp::SetGlobalSlot { index } => Op::SetGlobalSlot { index },
AbcOp::Construct { num_args } => Op::Construct { num_args },
AbcOp::ConstructProp { index, num_args } => Op::ConstructProp { index, num_args },
AbcOp::ConstructSuper { num_args } => Op::ConstructSuper { num_args },
AbcOp::NewActivation => Op::NewActivation,
AbcOp::NewObject { num_args } => Op::NewObject { num_args },
AbcOp::NewFunction { index } => Op::NewFunction { index },
AbcOp::NewClass { index } => Op::NewClass { index },
AbcOp::ApplyType { num_types } => Op::ApplyType { num_types },
AbcOp::NewArray { num_args } => Op::NewArray { num_args },
AbcOp::CoerceA => Op::CoerceA,
AbcOp::CoerceB => Op::CoerceB,
AbcOp::CoerceD => Op::CoerceD,
AbcOp::CoerceI => Op::CoerceI,
AbcOp::CoerceO => Op::CoerceO,
AbcOp::CoerceS => Op::CoerceS,
AbcOp::CoerceU => Op::CoerceU,
AbcOp::ConvertB => Op::ConvertB,
AbcOp::ConvertI => Op::ConvertI,
AbcOp::ConvertD => Op::ConvertD,
AbcOp::ConvertO => Op::ConvertO,
AbcOp::ConvertU => Op::ConvertU,
AbcOp::ConvertS => Op::ConvertS,
AbcOp::Add => Op::Add,
AbcOp::AddI => Op::AddI,
AbcOp::BitAnd => Op::BitAnd,
AbcOp::BitNot => Op::BitNot,
AbcOp::BitOr => Op::BitOr,
AbcOp::BitXor => Op::BitXor,
AbcOp::DecLocal { index } => Op::DecLocal { index },
AbcOp::DecLocalI { index } => Op::DecLocalI { index },
AbcOp::Decrement => Op::Decrement,
AbcOp::DecrementI => Op::DecrementI,
AbcOp::Divide => Op::Divide,
AbcOp::IncLocal { index } => Op::IncLocal { index },
AbcOp::IncLocalI { index } => Op::IncLocalI { index },
AbcOp::Increment => Op::Increment,
AbcOp::IncrementI => Op::IncrementI,
AbcOp::LShift => Op::LShift,
AbcOp::Modulo => Op::Modulo,
AbcOp::Multiply => Op::Multiply,
AbcOp::MultiplyI => Op::MultiplyI,
AbcOp::Negate => Op::Negate,
AbcOp::NegateI => Op::NegateI,
AbcOp::RShift => Op::RShift,
AbcOp::Subtract => Op::Subtract,
AbcOp::SubtractI => Op::SubtractI,
AbcOp::Swap => Op::Swap,
AbcOp::URShift => Op::URShift,
AbcOp::Jump { offset } => Op::Jump { offset },
AbcOp::IfTrue { offset } => Op::IfTrue { offset },
AbcOp::IfFalse { offset } => Op::IfFalse { offset },
AbcOp::IfStrictEq { offset } => Op::IfStrictEq { offset },
AbcOp::IfStrictNe { offset } => Op::IfStrictNe { offset },
AbcOp::IfEq { offset } => Op::IfEq { offset },
AbcOp::IfNe { offset } => Op::IfNe { offset },
AbcOp::IfGe { offset } => Op::IfGe { offset },
AbcOp::IfGt { offset } => Op::IfGt { offset },
AbcOp::IfLe { offset } => Op::IfLe { offset },
AbcOp::IfLt { offset } => Op::IfLt { offset },
AbcOp::IfNge { offset } => Op::IfNge { offset },
AbcOp::IfNgt { offset } => Op::IfNgt { offset },
AbcOp::IfNle { offset } => Op::IfNle { offset },
AbcOp::IfNlt { offset } => Op::IfNlt { offset },
AbcOp::StrictEquals => Op::StrictEquals,
AbcOp::Equals => Op::Equals,
AbcOp::GreaterEquals => Op::GreaterEquals,
AbcOp::GreaterThan => Op::GreaterThan,
AbcOp::LessEquals => Op::LessEquals,
AbcOp::LessThan => Op::LessThan,
AbcOp::Nop => Op::Nop,
AbcOp::Not => Op::Not,
AbcOp::HasNext => Op::HasNext,
AbcOp::HasNext2 {
object_register,
index_register,
} => Op::HasNext2 {
object_register,
index_register,
},
AbcOp::NextName => Op::NextName,
AbcOp::NextValue => Op::NextValue,
AbcOp::IsType { index } => Op::IsType { index },
AbcOp::IsTypeLate => Op::IsTypeLate,
AbcOp::AsType { type_name } => Op::AsType { type_name },
AbcOp::AsTypeLate => Op::AsTypeLate,
AbcOp::InstanceOf => Op::InstanceOf,
AbcOp::Label => Op::Label,
AbcOp::Debug {
is_local_register,
register_name,
register,
} => Op::Debug {
is_local_register,
register_name,
register,
},
AbcOp::DebugFile { file_name } => Op::DebugFile { file_name },
AbcOp::DebugLine { line_num } => Op::DebugLine { line_num },
AbcOp::Bkpt => Op::Bkpt,
AbcOp::BkptLine { line_num } => Op::BkptLine { line_num },
AbcOp::Timestamp => Op::Timestamp,
AbcOp::TypeOf => Op::TypeOf,
AbcOp::EscXAttr => Op::EscXAttr,
AbcOp::EscXElem => Op::EscXElem,
AbcOp::LookupSwitch(lookup_switch) => Op::LookupSwitch(lookup_switch),
AbcOp::Coerce { index } => Op::Coerce { index },
AbcOp::CheckFilter => Op::CheckFilter,
AbcOp::Si8 => Op::Si8,
AbcOp::Si16 => Op::Si16,
AbcOp::Si32 => Op::Si32,
AbcOp::Sf32 => Op::Sf32,
AbcOp::Sf64 => Op::Sf64,
AbcOp::Li8 => Op::Li8,
AbcOp::Li16 => Op::Li16,
AbcOp::Li32 => Op::Li32,
AbcOp::Lf32 => Op::Lf32,
AbcOp::Lf64 => Op::Lf64,
AbcOp::Sxi1 => Op::Sxi1,
AbcOp::Sxi8 => Op::Sxi8,
AbcOp::Sxi16 => Op::Sxi16,
AbcOp::Throw => Op::Throw,
_ => {
tracing::error!("Unimplemented AVM2 op {:?} found during verification", op);
return Err(Error::AvmError(verify_error(
activation,
"Error #1011: Method contained illegal opcode.",
1011,
)?));
}
})
}

View File

@ -1,7 +1,5 @@
use bitflags::bitflags;
use std::marker::PhantomData;
#[cfg(target_pointer_width = "64")]
use std::mem::size_of;
#[derive(Clone, Debug, PartialEq)]
pub struct AbcFile {
@ -574,6 +572,3 @@ pub enum Op {
Timestamp,
URShift,
}
#[cfg(target_pointer_width = "64")]
const _: () = assert!(size_of::<Op>() == 16);