Allow methods to not hold a body.

Interface methods are specifically not allowed to be called: as a result, they don't get a method body. Existing code assumed a 1:1 relationship between methods and bodies, which causes spurious errors.
This commit is contained in:
David Wendt 2020-07-07 21:28:24 -04:00
parent 090fe56bd3
commit 5d89d4ed85
4 changed files with 36 additions and 18 deletions

View File

@ -139,7 +139,10 @@ impl<'a, 'gc: 'a> Activation<'a, 'gc> {
) -> Result<Self, Error> {
let method = script.read().init().into_bytecode()?;
let scope = Some(Scope::push_scope(None, global, context.gc_context));
let num_locals = method.body().num_locals;
let body: Result<_, Error> = method
.body()
.ok_or_else(|| "Cannot execute non-native method (for script) without body".into());
let num_locals = body?.num_locals;
let local_registers =
GcCell::allocate(context.gc_context, RegisterSet::new(num_locals + 1));
@ -171,8 +174,11 @@ impl<'a, 'gc: 'a> Activation<'a, 'gc> {
this: Option<Object<'gc>>,
arguments: &[Value<'gc>],
base_proto: Option<Object<'gc>>,
) -> Self {
let num_locals = method.body().num_locals;
) -> Result<Self, Error> {
let body: Result<_, Error> = method
.body()
.ok_or_else(|| "Cannot execute non-native method without body".into());
let num_locals = body?.num_locals;
let num_declared_arguments = method.method().params.len() as u32;
let local_registers = GcCell::allocate(
context.gc_context,
@ -191,7 +197,7 @@ impl<'a, 'gc: 'a> Activation<'a, 'gc> {
}
}
Self {
Ok(Self {
avm2,
this,
arguments: None,
@ -201,7 +207,7 @@ impl<'a, 'gc: 'a> Activation<'a, 'gc> {
local_scope: ScriptObject::bare_object(context.gc_context),
scope,
base_proto,
}
})
}
/// Execute a script initializer.
@ -380,7 +386,10 @@ impl<'a, 'gc: 'a> Activation<'a, 'gc> {
method: Gc<'gc, BytecodeMethod<'gc>>,
context: &mut UpdateContext<'_, 'gc, '_>,
) -> Result<Value<'gc>, Error> {
let mut read = Reader::new(Cursor::new(method.body().code.as_ref()));
let body: Result<_, Error> = method
.body()
.ok_or_else(|| "Cannot execute non-native method without body".into());
let mut read = Reader::new(Cursor::new(body?.code.as_ref()));
loop {
let result = self.do_next_opcode(method, context, &mut read);

View File

@ -107,7 +107,7 @@ impl<'gc> Executable<'gc> {
reciever,
arguments,
base_proto,
);
)?;
activation.run_actions(bm.method, context)
}

View File

@ -50,7 +50,7 @@ pub struct BytecodeMethod<'gc> {
pub abc_method: u32,
/// The ABC method body this function uses.
pub abc_method_body: u32,
pub abc_method_body: Option<u32>,
}
impl<'gc> BytecodeMethod<'gc> {
@ -74,14 +74,22 @@ impl<'gc> BytecodeMethod<'gc> {
txunit,
abc: CollectWrapper(txunit.abc()),
abc_method: abc_method.0,
abc_method_body: index as u32,
abc_method_body: Some(index as u32),
},
));
}
}
}
None
Some(Gc::allocate(
mc,
Self {
txunit,
abc: CollectWrapper(txunit.abc()),
abc_method: abc_method.0,
abc_method_body: None,
},
))
}
/// Get the underlying ABC file.
@ -101,13 +109,14 @@ impl<'gc> BytecodeMethod<'gc> {
}
/// Get a reference to the ABC method body entry this refers to.
pub fn body(&self) -> &AbcMethodBody {
&self
.abc
.0
.method_bodies
.get(self.abc_method_body as usize)
.unwrap()
///
/// Some methods do not have bodies; this returns `None` in that case.
pub fn body(&self) -> Option<&AbcMethodBody> {
if let Some(abc_method_body) = self.abc_method_body {
self.abc.0.method_bodies.get(abc_method_body as usize)
} else {
None
}
}
}

View File

@ -427,7 +427,7 @@ pub trait TObject<'gc>: 'gc + Collect + Debug + Into<Object<'gc>> + Clone + Copy
avm_debug!(
"Installing trait {:?} of kind {:?}",
trait_name,
trait_entry.kind
trait_entry.kind()
);
match trait_entry.kind() {