avm2: Add an `Op` enum to AVM2; pre-pool double/uint/ints for `pushX` opcodes
This commit is contained in:
parent
65848104a6
commit
2022321a03
|
@ -50,6 +50,7 @@ mod method;
|
||||||
mod multiname;
|
mod multiname;
|
||||||
mod namespace;
|
mod namespace;
|
||||||
pub mod object;
|
pub mod object;
|
||||||
|
mod op;
|
||||||
mod parameters;
|
mod parameters;
|
||||||
pub mod property;
|
pub mod property;
|
||||||
mod property_map;
|
mod property_map;
|
||||||
|
|
|
@ -14,13 +14,14 @@ use crate::avm2::object::{
|
||||||
XmlListObject,
|
XmlListObject,
|
||||||
};
|
};
|
||||||
use crate::avm2::object::{Object, TObject};
|
use crate::avm2::object::{Object, TObject};
|
||||||
|
use crate::avm2::op::Op;
|
||||||
use crate::avm2::scope::{search_scope_stack, Scope, ScopeChain};
|
use crate::avm2::scope::{search_scope_stack, Scope, ScopeChain};
|
||||||
use crate::avm2::script::Script;
|
use crate::avm2::script::Script;
|
||||||
use crate::avm2::value::Value;
|
use crate::avm2::value::Value;
|
||||||
use crate::avm2::Multiname;
|
use crate::avm2::Multiname;
|
||||||
use crate::avm2::Namespace;
|
use crate::avm2::Namespace;
|
||||||
use crate::avm2::QName;
|
use crate::avm2::QName;
|
||||||
use crate::avm2::{value, Avm2, Error};
|
use crate::avm2::{Avm2, Error};
|
||||||
use crate::context::{GcContext, UpdateContext};
|
use crate::context::{GcContext, UpdateContext};
|
||||||
use crate::string::{AvmAtom, AvmString};
|
use crate::string::{AvmAtom, AvmString};
|
||||||
use crate::tag_utils::SwfMovie;
|
use crate::tag_utils::SwfMovie;
|
||||||
|
@ -31,7 +32,7 @@ use std::cmp::{min, Ordering};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use swf::avm2::types::{
|
use swf::avm2::types::{
|
||||||
Class as AbcClass, Exception, Index, Method as AbcMethod, MethodFlags as AbcMethodFlags,
|
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;
|
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.
|
/// Retrieve a string from the current constant pool.
|
||||||
fn pool_string<'b>(
|
fn pool_string<'b>(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
@ -939,16 +913,16 @@ impl<'a, 'gc> Activation<'a, 'gc> {
|
||||||
{
|
{
|
||||||
let result = match op {
|
let result = match op {
|
||||||
Op::PushByte { value } => self.op_push_byte(*value),
|
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::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::PushNamespace { value } => self.op_push_namespace(method, *value),
|
||||||
Op::PushNaN => self.op_push_nan(),
|
Op::PushNaN => self.op_push_nan(),
|
||||||
Op::PushNull => self.op_push_null(),
|
Op::PushNull => self.op_push_null(),
|
||||||
Op::PushShort { value } => self.op_push_short(*value),
|
Op::PushShort { value } => self.op_push_short(*value),
|
||||||
Op::PushString { value } => self.op_push_string(method, *value),
|
Op::PushString { value } => self.op_push_string(method, *value),
|
||||||
Op::PushTrue => self.op_push_true(),
|
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::PushUndefined => self.op_push_undefined(),
|
||||||
Op::Pop => self.op_pop(),
|
Op::Pop => self.op_pop(),
|
||||||
Op::Dup => self.op_dup(),
|
Op::Dup => self.op_dup(),
|
||||||
|
@ -1116,7 +1090,6 @@ impl<'a, 'gc> Activation<'a, 'gc> {
|
||||||
Op::Sxi8 => self.op_sxi8(),
|
Op::Sxi8 => self.op_sxi8(),
|
||||||
Op::Sxi16 => self.op_sxi16(),
|
Op::Sxi16 => self.op_sxi16(),
|
||||||
Op::Throw => self.op_throw(),
|
Op::Throw => self.op_throw(),
|
||||||
_ => self.unknown_op(op),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Err(error) = result {
|
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>> {
|
fn op_push_byte(&mut self, value: u8) -> Result<FrameControl<'gc>, Error<'gc>> {
|
||||||
//TODO: Adobe Animate CC appears to generate signed byte values, and
|
//TODO: Adobe Animate CC appears to generate signed byte values, and
|
||||||
//JPEXS appears to take them.
|
//JPEXS appears to take them.
|
||||||
|
@ -1138,12 +1106,8 @@ impl<'a, 'gc> Activation<'a, 'gc> {
|
||||||
Ok(FrameControl::Continue)
|
Ok(FrameControl::Continue)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn op_push_double(
|
fn op_push_double(&mut self, value: f64) -> Result<FrameControl<'gc>, Error<'gc>> {
|
||||||
&mut self,
|
self.push_stack(value);
|
||||||
method: Gc<'gc, BytecodeMethod<'gc>>,
|
|
||||||
value: Index<f64>,
|
|
||||||
) -> Result<FrameControl<'gc>, Error<'gc>> {
|
|
||||||
self.push_stack(self.pool_double(method, value)?);
|
|
||||||
Ok(FrameControl::Continue)
|
Ok(FrameControl::Continue)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1152,12 +1116,8 @@ impl<'a, 'gc> Activation<'a, 'gc> {
|
||||||
Ok(FrameControl::Continue)
|
Ok(FrameControl::Continue)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn op_push_int(
|
fn op_push_int(&mut self, value: i32) -> Result<FrameControl<'gc>, Error<'gc>> {
|
||||||
&mut self,
|
self.push_stack(value);
|
||||||
method: Gc<'gc, BytecodeMethod<'gc>>,
|
|
||||||
value: Index<i32>,
|
|
||||||
) -> Result<FrameControl<'gc>, Error<'gc>> {
|
|
||||||
self.push_stack(self.pool_int(method, value)?);
|
|
||||||
Ok(FrameControl::Continue)
|
Ok(FrameControl::Continue)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1203,12 +1163,8 @@ impl<'a, 'gc> Activation<'a, 'gc> {
|
||||||
Ok(FrameControl::Continue)
|
Ok(FrameControl::Continue)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn op_push_uint(
|
fn op_push_uint(&mut self, value: u32) -> Result<FrameControl<'gc>, Error<'gc>> {
|
||||||
&mut self,
|
self.push_stack(value);
|
||||||
method: Gc<'gc, BytecodeMethod<'gc>>,
|
|
||||||
value: Index<u32>,
|
|
||||||
) -> Result<FrameControl<'gc>, Error<'gc>> {
|
|
||||||
self.push_stack(self.pool_uint(method, value)?);
|
|
||||||
Ok(FrameControl::Continue)
|
Ok(FrameControl::Continue)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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);
|
|
@ -1,9 +1,11 @@
|
||||||
use crate::avm2::error::{make_error_1025, make_error_1054, make_error_1107, verify_error};
|
use crate::avm2::error::{make_error_1025, make_error_1054, make_error_1107, verify_error};
|
||||||
use crate::avm2::method::BytecodeMethod;
|
use crate::avm2::method::BytecodeMethod;
|
||||||
|
use crate::avm2::op::Op;
|
||||||
|
use crate::avm2::script::TranslationUnit;
|
||||||
use crate::avm2::{Activation, Error};
|
use crate::avm2::{Activation, Error};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use swf::avm2::read::Reader;
|
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;
|
use swf::error::Error as AbcReadError;
|
||||||
|
|
||||||
pub struct VerifiedMethodInfo {
|
pub struct VerifiedMethodInfo {
|
||||||
|
@ -27,6 +29,7 @@ pub fn verify_method<'gc>(
|
||||||
let body = method
|
let body = method
|
||||||
.body()
|
.body()
|
||||||
.expect("Cannot verify non-native method without body!");
|
.expect("Cannot verify non-native method without body!");
|
||||||
|
let translation_unit = method.translation_unit();
|
||||||
|
|
||||||
let param_count = method.method().params.len();
|
let param_count = method.method().params.len();
|
||||||
let locals_count = body.num_locals;
|
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.
|
// FIXME: This is wrong, verification/control flow handling should happen at the same
|
||||||
// A side effect of this is that avmplus allows for holes in bytecode.
|
// 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);
|
let mut reader = Reader::new(&body.code);
|
||||||
loop {
|
loop {
|
||||||
let op = match reader.read_op() {
|
let op = match reader.read_op() {
|
||||||
|
@ -193,24 +197,24 @@ pub fn verify_method<'gc>(
|
||||||
new_idx - i - 1
|
new_idx - i - 1
|
||||||
};
|
};
|
||||||
match op {
|
match op {
|
||||||
Op::IfEq { offset }
|
AbcOp::IfEq { offset }
|
||||||
| Op::IfFalse { offset }
|
| AbcOp::IfFalse { offset }
|
||||||
| Op::IfGe { offset }
|
| AbcOp::IfGe { offset }
|
||||||
| Op::IfGt { offset }
|
| AbcOp::IfGt { offset }
|
||||||
| Op::IfLe { offset }
|
| AbcOp::IfLe { offset }
|
||||||
| Op::IfLt { offset }
|
| AbcOp::IfLt { offset }
|
||||||
| Op::IfNe { offset }
|
| AbcOp::IfNe { offset }
|
||||||
| Op::IfNge { offset }
|
| AbcOp::IfNge { offset }
|
||||||
| Op::IfNgt { offset }
|
| AbcOp::IfNgt { offset }
|
||||||
| Op::IfNle { offset }
|
| AbcOp::IfNle { offset }
|
||||||
| Op::IfNlt { offset }
|
| AbcOp::IfNlt { offset }
|
||||||
| Op::IfStrictEq { offset }
|
| AbcOp::IfStrictEq { offset }
|
||||||
| Op::IfStrictNe { offset }
|
| AbcOp::IfStrictNe { offset }
|
||||||
| Op::IfTrue { offset }
|
| AbcOp::IfTrue { offset }
|
||||||
| Op::Jump { offset } => {
|
| AbcOp::Jump { offset } => {
|
||||||
*offset = adjusted(i, *offset, true);
|
*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);
|
lookup_switch.default_offset = adjusted(i, lookup_switch.default_offset, false);
|
||||||
for case in lookup_switch.case_offsets.iter_mut() {
|
for case in lookup_switch.case_offsets.iter_mut() {
|
||||||
*case = adjusted(i, *case, false);
|
*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 {
|
Ok(VerifiedMethodInfo {
|
||||||
parsed_code: new_code,
|
parsed_code: verified_code,
|
||||||
exceptions: new_exceptions,
|
exceptions: new_exceptions,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -258,7 +269,7 @@ fn verify_code_starting_from<'gc>(
|
||||||
idx_to_byte_offset: &[i32],
|
idx_to_byte_offset: &[i32],
|
||||||
byte_offset_to_idx: &HashMap<i32, i32>,
|
byte_offset_to_idx: &HashMap<i32, i32>,
|
||||||
verified_blocks: &mut Vec<i32>,
|
verified_blocks: &mut Vec<i32>,
|
||||||
ops: &[Op],
|
ops: &[AbcOp],
|
||||||
start_idx: i32,
|
start_idx: i32,
|
||||||
) -> Result<(), Error<'gc>> {
|
) -> Result<(), Error<'gc>> {
|
||||||
if verified_blocks.iter().any(|o| *o == start_idx) {
|
if verified_blocks.iter().any(|o| *o == start_idx) {
|
||||||
|
@ -279,21 +290,21 @@ fn verify_code_starting_from<'gc>(
|
||||||
|
|
||||||
// Special control flow ops
|
// Special control flow ops
|
||||||
match op {
|
match op {
|
||||||
Op::IfEq { offset }
|
AbcOp::IfEq { offset }
|
||||||
| Op::IfFalse { offset }
|
| AbcOp::IfFalse { offset }
|
||||||
| Op::IfGe { offset }
|
| AbcOp::IfGe { offset }
|
||||||
| Op::IfGt { offset }
|
| AbcOp::IfGt { offset }
|
||||||
| Op::IfLe { offset }
|
| AbcOp::IfLe { offset }
|
||||||
| Op::IfLt { offset }
|
| AbcOp::IfLt { offset }
|
||||||
| Op::IfNe { offset }
|
| AbcOp::IfNe { offset }
|
||||||
| Op::IfNge { offset }
|
| AbcOp::IfNge { offset }
|
||||||
| Op::IfNgt { offset }
|
| AbcOp::IfNgt { offset }
|
||||||
| Op::IfNle { offset }
|
| AbcOp::IfNle { offset }
|
||||||
| Op::IfNlt { offset }
|
| AbcOp::IfNlt { offset }
|
||||||
| Op::IfStrictEq { offset }
|
| AbcOp::IfStrictEq { offset }
|
||||||
| Op::IfStrictNe { offset }
|
| AbcOp::IfStrictNe { offset }
|
||||||
| Op::IfTrue { offset }
|
| AbcOp::IfTrue { offset }
|
||||||
| Op::Jump { offset } => {
|
| AbcOp::Jump { offset } => {
|
||||||
let op_idx = adjust_jump_offset(
|
let op_idx = adjust_jump_offset(
|
||||||
activation,
|
activation,
|
||||||
i,
|
i,
|
||||||
|
@ -315,7 +326,7 @@ fn verify_code_starting_from<'gc>(
|
||||||
position + 1,
|
position + 1,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
if matches!(op, Op::Jump { .. }) {
|
if matches!(op, AbcOp::Jump { .. }) {
|
||||||
// A Jump is terminal, the code
|
// A Jump is terminal, the code
|
||||||
// after it won't be executed
|
// after it won't be executed
|
||||||
return Ok(());
|
return Ok(());
|
||||||
|
@ -324,11 +335,11 @@ fn verify_code_starting_from<'gc>(
|
||||||
}
|
}
|
||||||
|
|
||||||
// Terminal opcodes
|
// Terminal opcodes
|
||||||
Op::Throw => return Ok(()),
|
AbcOp::Throw => return Ok(()),
|
||||||
Op::ReturnValue => return Ok(()),
|
AbcOp::ReturnValue => return Ok(()),
|
||||||
Op::ReturnVoid => return Ok(()),
|
AbcOp::ReturnVoid => return Ok(()),
|
||||||
|
|
||||||
Op::LookupSwitch(ref lookup_switch) => {
|
AbcOp::LookupSwitch(ref lookup_switch) => {
|
||||||
let default_idx = adjust_jump_offset(
|
let default_idx = adjust_jump_offset(
|
||||||
activation,
|
activation,
|
||||||
i,
|
i,
|
||||||
|
@ -376,19 +387,19 @@ fn verify_code_starting_from<'gc>(
|
||||||
// Verifications
|
// Verifications
|
||||||
|
|
||||||
// Local register verifications
|
// Local register verifications
|
||||||
Op::GetLocal { index }
|
AbcOp::GetLocal { index }
|
||||||
| Op::SetLocal { index }
|
| AbcOp::SetLocal { index }
|
||||||
| Op::Kill { index }
|
| AbcOp::Kill { index }
|
||||||
| Op::DecLocal { index }
|
| AbcOp::DecLocal { index }
|
||||||
| Op::DecLocalI { index }
|
| AbcOp::DecLocalI { index }
|
||||||
| Op::IncLocal { index }
|
| AbcOp::IncLocal { index }
|
||||||
| Op::IncLocalI { index } => {
|
| AbcOp::IncLocalI { index } => {
|
||||||
if *index >= max_locals {
|
if *index >= max_locals {
|
||||||
return Err(make_error_1025(activation, *index));
|
return Err(make_error_1025(activation, *index));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Op::HasNext2 {
|
AbcOp::HasNext2 {
|
||||||
object_register,
|
object_register,
|
||||||
index_register,
|
index_register,
|
||||||
} => {
|
} => {
|
||||||
|
@ -401,7 +412,7 @@ fn verify_code_starting_from<'gc>(
|
||||||
}
|
}
|
||||||
|
|
||||||
// Misc opcode verification
|
// Misc opcode verification
|
||||||
Op::CallMethod { index, .. } => {
|
AbcOp::CallMethod { index, .. } => {
|
||||||
return Err(Error::AvmError(if index.as_u30() == 0 {
|
return Err(Error::AvmError(if index.as_u30() == 0 {
|
||||||
verify_error(activation, "Error #1072: Disp_id 0 is illegal.", 1072)?
|
verify_error(activation, "Error #1072: Disp_id 0 is illegal.", 1072)?
|
||||||
} else {
|
} else {
|
||||||
|
@ -413,7 +424,7 @@ fn verify_code_starting_from<'gc>(
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
Op::NewActivation => {
|
AbcOp::NewActivation => {
|
||||||
if !method
|
if !method
|
||||||
.method()
|
.method()
|
||||||
.flags
|
.flags
|
||||||
|
@ -427,7 +438,7 @@ fn verify_code_starting_from<'gc>(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Op::GetLex { index } => {
|
AbcOp::GetLex { index } => {
|
||||||
let multiname = method
|
let multiname = method
|
||||||
.translation_unit()
|
.translation_unit()
|
||||||
.pool_maybe_uninitialized_multiname(*index, &mut activation.context)?;
|
.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 {
|
for i in start_idx..end_idx {
|
||||||
let op = &ops[i as usize];
|
let op = &ops[i as usize];
|
||||||
match op {
|
match op {
|
||||||
Op::PushByte { .. }
|
AbcOp::PushByte { .. }
|
||||||
| Op::PushDouble { .. }
|
| AbcOp::PushDouble { .. }
|
||||||
| Op::PushFalse
|
| AbcOp::PushFalse
|
||||||
| Op::PushInt { .. }
|
| AbcOp::PushInt { .. }
|
||||||
| Op::PushNamespace { .. }
|
| AbcOp::PushNamespace { .. }
|
||||||
| Op::PushNaN
|
| AbcOp::PushNaN
|
||||||
| Op::PushNull
|
| AbcOp::PushNull
|
||||||
| Op::PushShort { .. }
|
| AbcOp::PushShort { .. }
|
||||||
| Op::PushString { .. }
|
| AbcOp::PushString { .. }
|
||||||
| Op::PushTrue
|
| AbcOp::PushTrue
|
||||||
| Op::PushUint { .. }
|
| AbcOp::PushUint { .. }
|
||||||
| Op::PushUndefined
|
| AbcOp::PushUndefined
|
||||||
| Op::Dup
|
| AbcOp::Dup
|
||||||
| Op::Pop
|
| AbcOp::Pop
|
||||||
| Op::GetLocal { .. }
|
| AbcOp::GetLocal { .. }
|
||||||
| Op::SetLocal { .. }
|
| AbcOp::SetLocal { .. }
|
||||||
| Op::Kill { .. }
|
| AbcOp::Kill { .. }
|
||||||
| Op::Nop
|
| AbcOp::Nop
|
||||||
| Op::Not
|
| AbcOp::Not
|
||||||
| Op::PopScope
|
| AbcOp::PopScope
|
||||||
| Op::ReturnVoid => {}
|
| AbcOp::ReturnVoid => {}
|
||||||
_ => return true,
|
_ => return true,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
false
|
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,
|
||||||
|
)?));
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
|
@ -1,7 +1,5 @@
|
||||||
use bitflags::bitflags;
|
use bitflags::bitflags;
|
||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
#[cfg(target_pointer_width = "64")]
|
|
||||||
use std::mem::size_of;
|
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
pub struct AbcFile {
|
pub struct AbcFile {
|
||||||
|
@ -574,6 +572,3 @@ pub enum Op {
|
||||||
Timestamp,
|
Timestamp,
|
||||||
URShift,
|
URShift,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(target_pointer_width = "64")]
|
|
||||||
const _: () = assert!(size_of::<Op>() == 16);
|
|
||||||
|
|
Loading…
Reference in New Issue