-
-
Notifications
You must be signed in to change notification settings - Fork 892
AVM2 interpreter #404
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
AVM2 interpreter #404
Changes from 181 commits
Commits
Show all changes
189 commits
Select commit
Hold shift + click to select a range
a852a69
Add an extremely trivial implementation for the AVM2 interpreter state.
kmeisthax b7f257e
Add a path to get from the movie clip to the Avm2.
kmeisthax e80c887
Add a very basic object model to the AVM2 interpreter.
kmeisthax 7f60fab
Add the bare minimum necessary to get opcodes out of an ABC and into …
kmeisthax 5600ac4
Always execute any AVM2 code that may have been queued as a result of…
kmeisthax 4d000e1
Implement `pushxyz` opcodes for all value types that we currently sup…
kmeisthax d1aeae8
Add support for local registers in the interpreter.
kmeisthax 115f039
Add `call` method to the object trait. Only functions are callable in…
kmeisthax 52ac7a6
Implement call/return for bare functions
kmeisthax 43f1080
Implement namespaces as a value type
kmeisthax 6bd94d6
`from_abc_namespace` should accept a namespace index and retrieve it …
kmeisthax c65d93d
Implement multinames, sans runtime namespace support.
kmeisthax 6d8dc6e
Pull ABC constant pool methods out of Avm2 and into Value.
kmeisthax 2f3a3af
Add exact type assertion methods for strings and namespace values.
kmeisthax 1a6acb9
Implement late binding and runtime qualifications for names.
kmeisthax 3b476cb
Implement `pushnamespace` since that's a value type now
kmeisthax 376d1a8
Add scope support
kmeisthax 0ff1ba7
Multiname resolution is another object method.
kmeisthax 12223d5
Add support methods in `Scope` to support opcodes that traverse the s…
kmeisthax 3c8035f
clippy pls
kmeisthax 60c16b0
Implement `findproperty`, `findpropstrict`, and `getlex`; which are n…
kmeisthax 5e6fc79
Implement `getproperty`, `setproperty`
kmeisthax 78a1c9a
Implement `pushscope`, `popscope`, and `pushwith`.
kmeisthax d56db06
Implement `resolve_multiname`, sort of.
kmeisthax e5142e8
Replace `get_property` and `set_property` with slightly-less-stub impls.
kmeisthax 984e701
Swap out `has_property`'s stub impl.
kmeisthax 7d75255
Add global scope which is automatically included on all new activations.
kmeisthax b12c6e0
Implement closure scope stacks.
kmeisthax cf490be
Unstub `proto`.
kmeisthax eb0c9dc
Allow constructing a function around a particular class definition.
kmeisthax 12e9fbb
Impl virtual property slots
kmeisthax 502936f
Implement non-slot trait properties (Method, Getter, and Setter)
kmeisthax 560900e
ABC files are always pre-loaded.
kmeisthax 35c36a8
Always execute the last script when loading an ABC file
kmeisthax 1945f36
When running the initial script, also install it's traits onto the gl…
kmeisthax 88957b2
Add stub builtins for Object and Function. These are more-or-less ide…
kmeisthax 1ab4091
Implement slots and related opcodes.
kmeisthax ecfd5ab
Impl `construct` and `constructprop`.
kmeisthax 04879fc
Implement class traits.
kmeisthax bc0bdf8
The public namespace appears to just be an unnamed package namespace,…
kmeisthax cfe0e33
Fix invalid script index when loading an ABC file.
kmeisthax e191651
Add debug for trait installs
kmeisthax 3622941
Implement constant pool default values (index 0).
kmeisthax ebcfee4
Add specific error messages for unresolvable super classes
kmeisthax d42b16f
Add stub impl of `flash.display.MovieClip`.
kmeisthax 200c10b
Classes can fit in slots, so let's stick them in there.
kmeisthax af70024
Implement slot traits.
kmeisthax 412c3d8
Implement `Function` traits.
kmeisthax fd275bd
Implement constant slots and traits.
kmeisthax 8b56973
Remove scope methods that aren't necessary.
kmeisthax d19d9ef
Clean up unused variables
kmeisthax cbce866
Implement `deleteproperty`.
kmeisthax 279d90e
Remove `define_value` from AVM2 objects.
kmeisthax 5f98a19
Remove dead code in Activation
kmeisthax 4ab9a46
Impl `getscopeobject`
kmeisthax b2f5307
Add `flash.display.Sprite` because Flash Builder tests demand it.
kmeisthax 5b00c1f
Ensure that `this` is properly populated into local registers.
kmeisthax 9e120c2
Propagate arguments into local registers when calling AVM functions.
kmeisthax 5c0e095
`getlex` does not support runtime multinames according to spec.
kmeisthax 5042fc1
Debug all multiname resolutions
kmeisthax 0ff1c04
Impl `initproperty`
kmeisthax 1fe73b3
Impl `dup`
kmeisthax 074ba94
Impl `newfunction` and `newclass`.
kmeisthax 1d1bad1
Impl `getglobalscope`
kmeisthax 7201f6c
Impl `debug`, `debugfile` and `debugline`.
kmeisthax 843de29
Impl `newobject`
kmeisthax 38b1524
Fix the error messages for `findpropstrict` and `getlex` to be more i…
kmeisthax f6e2ca1
Clean up the current set of builtins to accurately reflect the namesp…
kmeisthax a557867
Add the entire class hierarchy of `MovieClip` and `Sprite`.
kmeisthax 7792fd5
Impl `trace`, which is a free function rather than an opcode this time.
kmeisthax bf45f7f
Fix crash when reading or writing a property that redirects to a slot.
kmeisthax dd6b0a8
Remove unused reference to slot property fields
kmeisthax a7ff2de
Don't spam the test log with `Resolving Multiname` messages for each …
kmeisthax 68cf9e8
Upon encountering an `Err`, dispose of the current AVM2 stack.
kmeisthax a0ab978
Impl `callmethod`, `callproperty`, `callproplex`, `callpropvoid`, and…
kmeisthax 7d57620
Impl `coerce_a`.
kmeisthax a2dfffc
Add our first AVM2 regression test: hello world!
kmeisthax 38868fb
Args are pushed onto the stack in normal order, so we need to pop the…
kmeisthax bedf5cb
Add a basic test for function calls.
kmeisthax 9431e02
The class function should use the *instance* initializer as it's call…
kmeisthax 0fc9b9a
`construct` and `constructprop` should take their args in reverse-ord…
kmeisthax a77f676
`construct` and `constructprop` should push the object that was just …
kmeisthax f3dee5c
Add (currently failing) test for constructors.
kmeisthax 1b67bb9
Impl `callsuper`, `callsupervoid`, and `constructsuper`.
kmeisthax 73966f1
Make sure that we actually call the super constructor, not our own co…
kmeisthax 687a82f
Constructors should also inherit closure scope.
kmeisthax fa4369d
Execute static class initializers.
kmeisthax 1c3b9c5
Implement prototype awareness for `get_property`, `has_property`, and…
kmeisthax ab5a95c
Add a test for various types of class methods.
kmeisthax 43da7ac
`resolve_multiname` should actually return it's prototype's return va…
kmeisthax e8fbac6
Refactor the base_proto system to more accurately record what prototy…
kmeisthax 785832b
Add `as3_inheritance` test, which is primarily designed to test metho…
kmeisthax 665d7a4
Implement `getsuper` and `setsuper`.
kmeisthax b8106d2
Ensure virtual setters are run when defined on a prototype.
kmeisthax 54b792e
Ensure that called setters are properly resolved so that errors in se…
kmeisthax c5e3af2
When resolving `get_property`, skip over virtual properties that do n…
kmeisthax 5abc78d
Add test of AVM2 virtual properties.
kmeisthax 6cc3f7e
Add a test for stored properties as well.
kmeisthax 6774465
Pass the ABC name and lazy init flag to the AVM2.
kmeisthax f10920a
Implement `Object.prototype.hasOwnProperty` and resolution of `Namesp…
kmeisthax 3530175
`ScriptObject` now holds a reference to a class and allows retrieving…
kmeisthax 2f95a7a
Completely overhaul the way traits are defined on objects.
kmeisthax f042e45
Add a test for interactions between prototype and class-trait propert…
kmeisthax 915b2da
Allow binding a reciever to a function, and make all method traits bi…
kmeisthax ddc9aa4
Add a test for ES4 method binding of `this`.
kmeisthax b33c246
Implement `is_property_overwritable`.
kmeisthax 9c5ea1d
Implement `jump`, `iftrue`, `iffalse`, `ifstricteq`, and `ifstrictne`.
kmeisthax 7253c09
Add tests for control flow instructions that use booleans or strict e…
kmeisthax a44e700
Sign extend negative `s24` values correctly.
kmeisthax da6a7c0
Implement `kill`, at least a little.
kmeisthax 67b7fbb
Implement `label`, which is a no-op designed specifically to silence …
kmeisthax 9496fbd
Remove `DontEnum`, `is_enumerable` and attribute mutation. They won't…
kmeisthax 1cc8954
Impl `pop`, which is the opposite of `dup`; and also the opposite of …
kmeisthax 73189b6
Properly unwind errors thrown from the AVM2 reader.
kmeisthax c014b40
Implement `hasnext`, `hasnext2`, `nextname`, `nextvalue`, and the und…
kmeisthax d29f3dc
Add `as3_object_enumeration` and `as3_class_enumeration` tests.
kmeisthax 0e89cb2
Impl `Object.isPrototypeOf` w/ test
kmeisthax 00186f7
Free functions always have a `prototype`, this is a holdover from ES3.
kmeisthax c6265bb
Allow tracing booleans.
kmeisthax 8677804
Actually enable the `isPrototypeOf` test.
kmeisthax 6e2508a
Fix `any` name resolution, at least enough for the `has_own_property`…
kmeisthax 42cb8f5
Add a test for `has_own_property` in various class instance scenarios.
kmeisthax 307a95e
`callproperty` and `callpropvoid` should *never* get callables from `…
kmeisthax a0ca589
Prevent instance traits from being accessible directly from prototypes.
kmeisthax 2afbcf4
Impl `propertyIsEnumerable`
kmeisthax dc0cb00
Add a test for `propertyIsEnumerable`.
kmeisthax f13e2ea
Implement `setPropertyIsEnumerable`
kmeisthax ba2c1f5
Add test for `setPropertyIsEnumerable`
kmeisthax f493cf9
Make `toString` and `valueOf` methods of `TObject`, called `to_string…
kmeisthax 37cdcb3
Add tests for `toString` on objects, functions, and classes.
kmeisthax 8b36751
Several built-in functions are not `public`, but instead live in the …
kmeisthax 4b66af8
ES4 classes, while superficially similar to functions, are not functi…
kmeisthax 16774aa
Add a test for legacy / ES3 inheritance.
kmeisthax 3558c3a
Add test of `Function.prototype.call`
kmeisthax cf6714d
Implement and test `toLocaleString`.
kmeisthax 3b52dfe
Since we have an `es3_inheritance` test now, rename the existing inhe…
kmeisthax b4d907b
Implement `strictequals`.
kmeisthax 03a240e
Add tests for `valueOf`.
kmeisthax ecfd16c
Add global constants `undefined`, `null`, and `NaN`.
kmeisthax 34b3bba
*Correctly* implement `ifstricteq` and `ifstrictne`.
kmeisthax 34ab8c8
`NaN` is not special-cased in AS3.
kmeisthax 6117288
Add tests for `ifstricteq`, `ifstrictne`, and `strictequals`.
kmeisthax fe283e6
Silence this warning about occupied slots being an unused variant.
kmeisthax 3362ec0
chore: Clippy conformance
kmeisthax 4cd3045
Excise `ReturnValue<'gc>` from all `TObject` methods.
kmeisthax 15a62d3
Add an internal representation of `Trait`, separate from `swf::avm2::…
kmeisthax 70e9030
Decouple the entire trait machinery from ABC-provided traits.
kmeisthax b4f944b
Wrap ABC loading inside of a `TranslationUnit`.
kmeisthax f549d01
Fix compilation bugs involved with automatic script initializer execu…
kmeisthax 60f3ae3
Remove `Avm2ScriptEntry`. It is now obsolete and unused.
kmeisthax 4467bc3
Make `TranslationUnit` a GC-mandatory type (only referred to by `GcCe…
kmeisthax eaebd3c
Make `Avm2MethodEntry` hold it's `TranslationUnit` rather than an `Ab…
kmeisthax 232c29d
Fix remaining problems with method loading using `callstatic`
kmeisthax 7684736
`table_class` should resolve `Class`es straight from the current tran…
kmeisthax 0d2235d
Resolve all remaining compilation issues with this refactor.
kmeisthax 041cb0b
Resolve multiname constant zero as an error rather than a panic.
kmeisthax 12fc13d
Clippy compliance for the last batch of commits.
kmeisthax b6e0551
Remove `Avm2ClassEntry`. It is no longer used.
kmeisthax 098b034
Refactor method-related structs into a separate method module.
kmeisthax 5b5bf07
Remove `Avm2Function` as it is no longer used.
kmeisthax 97e0056
Invert the role of `Avm2` and it's `Activation`, similar to what was …
kmeisthax 090fe56
Wrap `BytecodeMethod` (and the bytecode half of `Executable`) in a `Gc`.
kmeisthax 5d89d4e
Allow methods to not hold a body.
kmeisthax 8f2d331
Allow the construction of classes with no base class.
kmeisthax 563a515
Add a test for loading interfaces into the AVM2.
kmeisthax cce68db
Add trait methods for getting and setting the interfaces list.
kmeisthax 3fae8b3
Read the interface list when instantiating classes, resolve them, and…
kmeisthax a0cb052
Add `is_instance_of` trait method to `TObject`
kmeisthax c917b3d
Implement `istype`, `istypelate`, and `instanceof`.
kmeisthax 39a4566
Instances should be listed as their prototypes (empty as they are)
kmeisthax 64e5b46
Add tests for `instanceof` and `is` operators.
kmeisthax f0c633f
Allow borrowing string values from an ABC file instead of cloning eve…
kmeisthax ae26615
`coerce_string` may return a static string, which we shouldn't clone.
kmeisthax a406bda
Don't attempt to log debugging information if we're not in a debug bu…
kmeisthax 508fcd6
`pool_string` should return a `Ref<str>` just like `value::abc_string`.
kmeisthax 2021cec
Impl `Copy`, `Eq`, `PartialOrd`, `Ord`, and `Hash` for `AvmString`.
kmeisthax 61a3ff8
Replace `String` or `&str` references with `AvmString` everywhere in …
kmeisthax e1b9b82
Remove `abc_string` and replace it with `abc_string_copy`. All code t…
kmeisthax 70e9e7e
Add support for cached/interned pool strings in the `TranslationUnit`.
kmeisthax f4c5075
Run all string constant retrieval through the `TranslationUnit`, prev…
kmeisthax e354c53
Remove any remaining uses of `abc_ref`.
kmeisthax ccacc54
Remove dead code on all now-in-use structs and methods.
kmeisthax 37b6b89
Add a stub AVM2 string representation to allow for both VMs' strings …
kmeisthax dc962f2
Add AVM2 equivalent of `PropertyMap` for further expansion.
kmeisthax c415190
Zero-index multinames should generate a validation error in `QName::f…
kmeisthax 262bb14
Rename `a2me` to `entry` (or `method` in one case where it lets me si…
kmeisthax 575a9b0
Use FnvHashMap for the translation unit pools.
kmeisthax 44b924d
`Script` should not hold write locks when probing it's internal caches.
kmeisthax 7adabc8
Use `unwrap_or_default`
kmeisthax File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,162 @@ | ||
//! ActionScript Virtual Machine 2 (AS3) support | ||
|
||
use crate::avm2::activation::Activation; | ||
use crate::avm2::globals::SystemPrototypes; | ||
use crate::avm2::object::{Object, TObject}; | ||
use crate::avm2::scope::Scope; | ||
use crate::avm2::script::Script; | ||
use crate::avm2::script::TranslationUnit; | ||
use crate::avm2::value::Value; | ||
use crate::context::UpdateContext; | ||
use crate::tag_utils::SwfSlice; | ||
use gc_arena::{Collect, GcCell, MutationContext}; | ||
use std::rc::Rc; | ||
use swf::avm2::read::Reader; | ||
|
||
#[macro_export] | ||
macro_rules! avm_debug { | ||
($($arg:tt)*) => ( | ||
#[cfg(feature = "avm_debug")] | ||
log::debug!($($arg)*) | ||
) | ||
} | ||
|
||
mod activation; | ||
mod class; | ||
mod function; | ||
mod globals; | ||
mod method; | ||
mod names; | ||
mod object; | ||
mod property; | ||
mod return_value; | ||
mod scope; | ||
mod script; | ||
mod script_object; | ||
mod slot; | ||
mod r#trait; | ||
mod value; | ||
|
||
/// Boxed error alias. | ||
/// | ||
/// As AVM2 is a far stricter VM than AVM1, this may eventually be replaced | ||
/// with a proper Avm2Error enum. | ||
type Error = Box<dyn std::error::Error>; | ||
|
||
/// The state of an AVM2 interpreter. | ||
#[derive(Collect)] | ||
#[collect(no_drop)] | ||
pub struct Avm2<'gc> { | ||
/// Values currently present on the operand stack. | ||
stack: Vec<Value<'gc>>, | ||
|
||
/// Global scope object. | ||
globals: Object<'gc>, | ||
|
||
/// System prototypes. | ||
system_prototypes: SystemPrototypes<'gc>, | ||
} | ||
|
||
impl<'gc> Avm2<'gc> { | ||
/// Construct a new AVM interpreter. | ||
pub fn new(mc: MutationContext<'gc, '_>) -> Self { | ||
let (globals, system_prototypes) = globals::construct_global_scope(mc); | ||
|
||
Self { | ||
stack: Vec::new(), | ||
globals, | ||
system_prototypes, | ||
} | ||
} | ||
|
||
/// Return the current set of system prototypes. | ||
pub fn prototypes(&self) -> &SystemPrototypes<'gc> { | ||
&self.system_prototypes | ||
} | ||
|
||
/// Run a script's initializer method. | ||
pub fn run_script_initializer( | ||
&mut self, | ||
script: GcCell<'gc, Script<'gc>>, | ||
context: &mut UpdateContext<'_, 'gc, '_>, | ||
) -> Result<(), Error> { | ||
let mut init_activation = Activation::from_script(self, context, script, self.globals)?; | ||
|
||
init_activation.run_stack_frame_for_script(context, script) | ||
} | ||
|
||
/// Load an ABC file embedded in a `SwfSlice`. | ||
/// | ||
/// The `SwfSlice` must resolve to the contents of an ABC file. | ||
pub fn load_abc( | ||
&mut self, | ||
abc: SwfSlice, | ||
_abc_name: &str, | ||
_lazy_init: bool, | ||
context: &mut UpdateContext<'_, 'gc, '_>, | ||
) -> Result<(), Error> { | ||
let mut read = Reader::new(abc.as_ref()); | ||
|
||
let abc_file = Rc::new(read.read()?); | ||
let tunit = TranslationUnit::from_abc(abc_file.clone(), context.gc_context); | ||
|
||
for i in (0..abc_file.scripts.len()).rev() { | ||
let script = tunit.load_script(i as u32, context.gc_context)?; | ||
let mut globals = self.globals(); | ||
let scope = Scope::push_scope(None, globals, context.gc_context); | ||
let mut null_activation = Activation::from_nothing(self, context); | ||
|
||
// TODO: Lazyinit means we shouldn't do this until traits are | ||
// actually mentioned... | ||
for trait_entry in script.read().traits()?.iter() { | ||
globals.install_foreign_trait( | ||
&mut null_activation, | ||
context, | ||
trait_entry.clone(), | ||
Some(scope), | ||
globals, | ||
)?; | ||
} | ||
|
||
drop(null_activation); | ||
|
||
self.run_script_initializer(script, context)?; | ||
} | ||
|
||
Ok(()) | ||
} | ||
|
||
pub fn globals(&self) -> Object<'gc> { | ||
self.globals | ||
} | ||
|
||
/// Push a value onto the operand stack. | ||
fn push(&mut self, value: impl Into<Value<'gc>>) { | ||
let value = value.into(); | ||
avm_debug!("Stack push {}: {:?}", self.stack.len(), value); | ||
self.stack.push(value); | ||
} | ||
|
||
/// Retrieve the top-most value on the operand stack. | ||
#[allow(clippy::let_and_return)] | ||
fn pop(&mut self) -> Value<'gc> { | ||
let value = self.stack.pop().unwrap_or_else(|| { | ||
log::warn!("Avm1::pop: Stack underflow"); | ||
Value::Undefined | ||
}); | ||
|
||
avm_debug!("Stack pop {}: {:?}", self.stack.len(), value); | ||
|
||
value | ||
} | ||
|
||
fn pop_args(&mut self, arg_count: u32) -> Vec<Value<'gc>> { | ||
let mut args = Vec::with_capacity(arg_count as usize); | ||
args.resize(arg_count as usize, Value::Undefined); | ||
for arg in args.iter_mut().rev() { | ||
*arg = self.pop(); | ||
} | ||
|
||
args | ||
} | ||
} |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.