Commit Graph

358 Commits

Author SHA1 Message Date
David Wendt 3df6c7eeef Always post-instantiate display objects when running tests. 2019-12-15 08:54:26 -08:00
David Wendt 73655c0c88 Add a separate native object type for objects tied to the stage. 2019-12-15 08:54:26 -08:00
Mike Welsh f0c6b2d8d8 core: Remove this from Object::get/set 2019-12-15 08:54:26 -08:00
Mike Welsh b59bf40c78 core: Remove this from Object::get/set 2019-12-10 01:36:02 -08:00
Mike Welsh f7822141b7 core: Rename display_node methods to display_object 2019-12-10 01:36:02 -08:00
Mike Welsh 71e4eb87d7 core: Remove as_*_mut methods on DisplayObject/Object 2019-12-10 01:36:02 -08:00
Mike Welsh d7740bc3ad core: Don't touch UpdateContext::active_clip in DisplayObjects
DisplayObject code no longer has to manage
UpdateContext::active_clip before calling out to children, because
each child still has access to its Gc pointer.
2019-12-10 01:36:02 -08:00
Mike Welsh 25b86c14ae core: Move method impls from Button to ButtonData 2019-12-10 01:36:02 -08:00
Mike Welsh 78e65a01df core: Move method impls from MovieClip to MovieClipData 2019-12-10 01:36:01 -08:00
Mike Welsh 12c1bf7cf1 core: Clean up UpdateContext creation
Added Player::mutate_with_update_context, which takes a closure
and passes it an UpdateContext.
2019-12-10 01:36:01 -08:00
Mike Welsh 30ecbd0ecc core: Use enum_trait_object for DisplayObject 2019-12-10 01:36:01 -08:00
Mike Welsh 23ca66a7e3 avm1: Use enum_trait_object for avm1::Object 2019-12-10 01:36:01 -08:00
Mike Welsh 90b6858bb2 avm1: Fix return value of `Object.addProperty` 2019-12-03 14:59:37 -08:00
Mike Welsh 28364f7d00 avm1: Fix `this` object in GetMember/SetMember 2019-12-03 14:59:01 -08:00
Mike Welsh 1a1cdfa757 desktop: Allow audio creation to fail
Switch to NullAudioBackend if CpalAudioBackend fails to initialize.
(This happens on my laptop which doesn't have an audio device!)
2019-11-30 20:08:34 -08:00
Nathan Adams eb185982cd Add more Number(x) tests, and corrected primitive_as_number to match 2019-11-29 16:07:35 -08:00
Nathan Adams 85b9ffe102 core: Merge both test macros into a generic test_method 2019-11-29 13:12:00 -08:00
Nathan Adams 1f4405189a core: Make math test_std also take in versions 2019-11-29 13:12:00 -08:00
Nathan Adams 999bb128de core: Allow global test_std to test multiple swf versions 2019-11-29 13:12:00 -08:00
Nathan Adams 4c7d37c498 core: Added `avm_debug!` macro 2019-11-29 12:59:45 -08:00
Nathan Adams d1b73582ce core: Add feature `avm_debug` that toggles tracing avm actions and stack history 2019-11-29 12:59:45 -08:00
David Wendt 9ec85c3892 Add tests for SWF6 numerical coercions. 2019-11-28 21:32:10 -05:00
David Wendt f856243247 Primitive coercions should not yield an object just because valueOf is undefined. 2019-11-28 20:53:32 -05:00
David Wendt ec3ac4e5d6 `undefined` coerces to `0.0` on SWF6 2019-11-28 20:53:32 -05:00
David Wendt 16259ad74a Calling uncallable values does not actually cause a runtime error in Flash; it just returns null.
This was discovered almost by accident: @Dinnerbone noticed that `_global == null`, and surmised that `valueOf` was the culprit. However, this doesn't really make sense: `_global` is a bare object, so it shouldn't have a `valueOf` (and in practice, it doesn't).

The ultimate cause of such an odd comparison is as such:

1. Flash coerces the `_global` object to a numerical primitive by calling `valueOf`.
2. `_global.valueOf` is undefined. Flash handles calls to any uncallable value by literally just having it return `undefined`. In other words, all values are implicitly callable as empty functions.
3. `undefined` is then compared to `null`. These two values *are* equal under abstract equality (`==`). Hence, `_global == null`.

For comparison, modern ECMAScript engines throw errors on calls to uncallable values; and won't attempt to use an invalid `valueOf` to coerce objects. So none of this applies to, say, standard JavaScript in your browser.
2019-11-28 20:53:31 -05:00
Nathan Adams 68760007fc Lessthan can return `undefined`, not just booleans 2019-11-28 20:53:30 -05:00
Nathan Adams 638231e7fb swf4 doesn't have NaN or Infinity 2019-11-28 20:53:20 -05:00
Nathan Adams 581d0940b2 NaN == NaN without coercion 2019-11-28 20:43:59 -05:00
Nathan Adams f33229a2a1 `_global` == null && `_global` == undefined 2019-11-28 20:43:58 -05:00
David Wendt 129d50bfa6 Implement ECMAScript compliant type coercions.
This includes ECMA-262 2ed `ToNumber`, `ToPrimitive` (Number), `ToString`, and abstract equality and less-than implementations. Note that `ToPrimitive` is only the "number hint" variant, and Flash specifically *never* calls `toString` like how ECMA-262 specifies.

Several builtins inherit numerical coercion - I'm not 100% sure if that's correct.

The following ActionScript opcodes now perform ECMA-262 style coercions:

`ActionAdd2` (uses `valueOf` / "ToPrimitive hint Number")
`ActionDecrement` (uses `valueOf`)
`ActionEquals2` (uses `valueOf`)
`ActionGetMember` (member names, uses `toString`)
`ActionIncrement` (uses `valueOf`)
`ActionLess2` (uses `valueOf`)
`ActionGreater` (uses `valueOf`)
`ActionSetMember` (member names, uses `toString`)
`ActionStringEquals` (uses `toString`)
`ActionStringGreater` (uses `toString`)
`ActionStringLess` (uses `toString`)
`ActionToNumber` (uses `valueOf`)
`ActionToString` (uses `toString`)
`ActionTrace` (uses `toString`)

The following functions now gained user-specified coercions via `toString`:
`_global.number` (uses `valueOf`)
`_global.is_nan` (uses `valueOf`)
Every function in `Math` (uses `valueOf`)
2019-11-28 20:23:39 -05:00
Nathan Adams 2650433271 Fixed get_keys with prototypes 2019-11-27 22:30:31 +01:00
David Wendt 46e58c3ecd Remove `ReturnValue.ignore` entirely, since you really *do* need to resolve `ReturnValue`s, even if you don't want the result. 2019-11-27 14:52:07 -05:00
David Wendt 2c87888e28 Implement prototype chain recursion limit of 255 prototypes.
In Flash, this also at least claims to halt ActionScript execution on the movie. No such implementation of AVM poisoning currently exists in Ruffle, primarily because it's unclear what gets poisoned and implementing some of these options isn't yet possible:

1. AVM (e.g. all movies) - we would need to make the AVM fail silently in this case. This is the most straightforward way to poison the movie, but I'm not sure if this is how Flash actually does it, or if it poisons...
2. Movie - the current structure of movies is incompatible with adding arbitrary data to them. We need to merge `moviefetch` in before we can attach data to loaded movies.
3. MovieClip - this would also be implementable but has problems. How do child MovieClips know that their parent has been poisoned, or vice versa? What if a movie clip is loaded from one movie and moved into another?

As a result, I have decided to hold off on implementing recursion poisoning until I know where it's supposed to go and how to implement that.
2019-11-27 08:59:16 -05:00
David Wendt 4655ebe73f Always push the constructed object on the stack. 2019-11-26 15:07:59 -05:00
David Wendt b9f02c290c Functions should be traceable. 2019-11-26 15:07:03 -05:00
David Wendt 0b1afcf8be Implement `ActionInstanceOf` (for non-interface types) 2019-11-26 14:51:06 -05:00
David Wendt 3c8d9b9c1c `new` should be called on the prototype - not the constructor function. This will allow different host object impls to subclass correctly. 2019-11-26 14:51:06 -05:00
David Wendt e8632bbcaa Implement `valueOf` for `Object` and fix the `toString` impl. 2019-11-26 14:51:06 -05:00
David Wendt 73c3b42cd4 Move `force_set` and `force_set_virtual` into the `Object` trait. They are now called `define_value` and `add_property`, respectively.
While I don't expect every host object to implement it correctly, this also gets rid of a lot of unnecessary `unwrap` calls that would allow a poorly-written Flash file to kill the interpreter.
2019-11-26 14:51:06 -05:00
David Wendt 983c0fb200 Add proto chain inspection to the object interface. 2019-11-26 14:51:06 -05:00
David Wendt 0e59e1c961 Allow host-provided constructors to override `new` and provide host objects to the AVM when a particular constructor is called. 2019-11-26 14:51:06 -05:00
David Wendt d25bdbacf8 Separate `Object` into an interface trait and a standard implementation. Host object implementations may bypass `ScriptObject` and directly interface with the AVM using this trait.
Note that host objects that do so will *not* have access to their standard representation from within member functions - you will need to extend the interface to accomodate for them. This is due to long-standing limitations with type IDs and downcasting with types that bear lifetimes - it's entirely an unsafe operation and exposing such a facility to safe Rust is unsound. However, this will at least let us separate out several things from ScriptObject that don't need to be there for the time being.
2019-11-26 14:51:05 -05:00
David Wendt 6dd40f8354 Split properties into a separate module. 2019-11-26 14:51:05 -05:00
David Wendt 813783881b Implement explicit prototypes on user-generated functions.
`Object::function` now returns a pre-allocated function object. You may supply it an explicit prototype to have it linked into the function object (which is why we have to return a cell).
2019-11-26 14:51:05 -05:00
David Wendt f347992eeb Add `as_usize` method to `Value` 2019-11-26 14:51:05 -05:00
David Wendt 207a157f20 Add missing usize conversion 2019-11-26 14:51:05 -05:00
kmeisthax fb34f73159 Manually constructing `Value` should no longer be necessary
Co-Authored-By: Nathan Adams <dinnerbone@dinnerbone.com>
2019-11-26 14:51:05 -05:00
David Wendt 1cb374da8a `ActionSetMember` accepts non-String names as parameters. 2019-11-26 14:51:04 -05:00
David Wendt fafad818d4 Implement `ActionInitObject` 2019-11-26 14:51:04 -05:00
David Wendt da315c7311 Fix docstrings on these modules 2019-11-26 14:51:04 -05:00