avm2: Implement ApplicationDomain constructor and fix parent handling
Previously, the `ApplicationDomain` constructor ignored its argument, instead of constructing a new domain with the specified domain as the parent. Additionally, we were incorrectly executing code with `Activation::from_nothing` in several places, causing `ApplicationDomain.currentDomain` to return the system domain instead of the correct parent domain. I've introduced a new method `Activation::from_domain`, which allows explicitly passing in the domain. Internally, we now store an `Option<Domain>`, and panic when calling `caller_domain` with a `None` domain. Several places in the codebase have been adjusted to pass in the correct domain.
This commit is contained in:
parent
da6384b30e
commit
1a352aa453
|
@ -180,7 +180,7 @@ impl<'gc> Avm2<'gc> {
|
||||||
|
|
||||||
pub fn load_player_globals(context: &mut UpdateContext<'_, 'gc>) -> Result<(), Error<'gc>> {
|
pub fn load_player_globals(context: &mut UpdateContext<'_, 'gc>) -> Result<(), Error<'gc>> {
|
||||||
let globals = context.avm2.globals;
|
let globals = context.avm2.globals;
|
||||||
let mut activation = Activation::from_nothing(context.reborrow());
|
let mut activation = Activation::from_domain(context.reborrow(), globals);
|
||||||
globals::load_player_globals(&mut activation, globals)
|
globals::load_player_globals(&mut activation, globals)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -400,9 +400,10 @@ impl<'gc> Avm2<'gc> {
|
||||||
callable: Object<'gc>,
|
callable: Object<'gc>,
|
||||||
reciever: Option<Object<'gc>>,
|
reciever: Option<Object<'gc>>,
|
||||||
args: &[Value<'gc>],
|
args: &[Value<'gc>],
|
||||||
|
domain: Domain<'gc>,
|
||||||
context: &mut UpdateContext<'_, 'gc>,
|
context: &mut UpdateContext<'_, 'gc>,
|
||||||
) -> Result<(), String> {
|
) -> Result<(), String> {
|
||||||
let mut evt_activation = Activation::from_nothing(context.reborrow());
|
let mut evt_activation = Activation::from_domain(context.reborrow(), domain);
|
||||||
callable
|
callable
|
||||||
.call(reciever, args, &mut evt_activation)
|
.call(reciever, args, &mut evt_activation)
|
||||||
.map_err(|e| e.detailed_message(&mut evt_activation))?;
|
.map_err(|e| e.detailed_message(&mut evt_activation))?;
|
||||||
|
|
|
@ -117,7 +117,7 @@ pub struct Activation<'a, 'gc: 'a> {
|
||||||
///
|
///
|
||||||
/// If this activation was not made for a builtin method, this will be the
|
/// If this activation was not made for a builtin method, this will be the
|
||||||
/// current domain instead.
|
/// current domain instead.
|
||||||
caller_domain: Domain<'gc>,
|
caller_domain: Option<Domain<'gc>>,
|
||||||
|
|
||||||
/// The class that yielded the currently executing method.
|
/// The class that yielded the currently executing method.
|
||||||
///
|
///
|
||||||
|
@ -176,7 +176,38 @@ impl<'a, 'gc> Activation<'a, 'gc> {
|
||||||
local_registers,
|
local_registers,
|
||||||
return_value: None,
|
return_value: None,
|
||||||
outer: ScopeChain::new(context.avm2.globals),
|
outer: ScopeChain::new(context.avm2.globals),
|
||||||
caller_domain: context.avm2.globals,
|
caller_domain: None,
|
||||||
|
subclass_object: None,
|
||||||
|
activation_class: None,
|
||||||
|
stack_depth: context.avm2.stack.len(),
|
||||||
|
scope_depth: context.avm2.scope_stack.len(),
|
||||||
|
max_stack_size: 0,
|
||||||
|
max_scope_size: 0,
|
||||||
|
context,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Like `from_nothing`, but with a specified domain.
|
||||||
|
///
|
||||||
|
/// This should be used when you actually need to run AVM2 code, but
|
||||||
|
/// don't have a particular scope to run it in. For example, this is
|
||||||
|
/// used to run frame scripts for AVM2 movies.
|
||||||
|
///
|
||||||
|
/// The 'Domain' should come from the SwfMovie associated with whatever
|
||||||
|
/// action you're performing. When running frame scripts, this is the
|
||||||
|
/// `SwfMovie` associated with the `MovieClip` being processed.
|
||||||
|
pub fn from_domain(context: UpdateContext<'a, 'gc>, domain: Domain<'gc>) -> Self {
|
||||||
|
let local_registers = RegisterSet::new(0);
|
||||||
|
|
||||||
|
Self {
|
||||||
|
this: None,
|
||||||
|
arguments: None,
|
||||||
|
is_executing: false,
|
||||||
|
actions_since_timeout_check: 0,
|
||||||
|
local_registers,
|
||||||
|
return_value: None,
|
||||||
|
outer: ScopeChain::new(context.avm2.globals),
|
||||||
|
caller_domain: Some(domain),
|
||||||
subclass_object: None,
|
subclass_object: None,
|
||||||
activation_class: None,
|
activation_class: None,
|
||||||
stack_depth: context.avm2.stack.len(),
|
stack_depth: context.avm2.stack.len(),
|
||||||
|
@ -220,7 +251,7 @@ impl<'a, 'gc> Activation<'a, 'gc> {
|
||||||
local_registers,
|
local_registers,
|
||||||
return_value: None,
|
return_value: None,
|
||||||
outer: ScopeChain::new(domain),
|
outer: ScopeChain::new(domain),
|
||||||
caller_domain: domain,
|
caller_domain: Some(domain),
|
||||||
subclass_object: None,
|
subclass_object: None,
|
||||||
activation_class: None,
|
activation_class: None,
|
||||||
stack_depth: context.avm2.stack.len(),
|
stack_depth: context.avm2.stack.len(),
|
||||||
|
@ -443,7 +474,8 @@ impl<'a, 'gc> Activation<'a, 'gc> {
|
||||||
drop(cached_cls);
|
drop(cached_cls);
|
||||||
let translation_unit = method.translation_unit();
|
let translation_unit = method.translation_unit();
|
||||||
let abc_method = method.method();
|
let abc_method = method.method();
|
||||||
let mut dummy_activation = Activation::from_nothing(context.reborrow());
|
let mut dummy_activation =
|
||||||
|
Activation::from_domain(context.reborrow(), outer.domain());
|
||||||
dummy_activation.set_outer(outer);
|
dummy_activation.set_outer(outer);
|
||||||
let activation_class = Class::for_activation(
|
let activation_class = Class::for_activation(
|
||||||
&mut dummy_activation,
|
&mut dummy_activation,
|
||||||
|
@ -472,7 +504,7 @@ impl<'a, 'gc> Activation<'a, 'gc> {
|
||||||
local_registers,
|
local_registers,
|
||||||
return_value: None,
|
return_value: None,
|
||||||
outer,
|
outer,
|
||||||
caller_domain: outer.domain(),
|
caller_domain: Some(outer.domain()),
|
||||||
subclass_object,
|
subclass_object,
|
||||||
activation_class,
|
activation_class,
|
||||||
stack_depth: context.avm2.stack.len(),
|
stack_depth: context.avm2.stack.len(),
|
||||||
|
@ -555,7 +587,7 @@ impl<'a, 'gc> Activation<'a, 'gc> {
|
||||||
local_registers,
|
local_registers,
|
||||||
return_value: None,
|
return_value: None,
|
||||||
outer,
|
outer,
|
||||||
caller_domain,
|
caller_domain: Some(caller_domain),
|
||||||
subclass_object,
|
subclass_object,
|
||||||
activation_class: None,
|
activation_class: None,
|
||||||
stack_depth: context.avm2.stack.len(),
|
stack_depth: context.avm2.stack.len(),
|
||||||
|
@ -641,7 +673,7 @@ impl<'a, 'gc> Activation<'a, 'gc> {
|
||||||
|
|
||||||
/// Returns the domain of the original AS3 caller.
|
/// Returns the domain of the original AS3 caller.
|
||||||
pub fn caller_domain(&self) -> Domain<'gc> {
|
pub fn caller_domain(&self) -> Domain<'gc> {
|
||||||
self.caller_domain
|
self.caller_domain.expect("No caller domain available - use Activation::from_domain when constructing your domain")
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the global scope of this activation.
|
/// Returns the global scope of this activation.
|
||||||
|
|
|
@ -526,14 +526,6 @@ pub fn load_player_globals<'gc>(
|
||||||
|
|
||||||
avm2_system_class!(date, activation, date::create_class(activation), script);
|
avm2_system_class!(date, activation, date::create_class(activation), script);
|
||||||
|
|
||||||
// package `flash.system`
|
|
||||||
avm2_system_class!(
|
|
||||||
application_domain,
|
|
||||||
activation,
|
|
||||||
flash::system::application_domain::create_class(activation),
|
|
||||||
script
|
|
||||||
);
|
|
||||||
|
|
||||||
// package `flash.text`
|
// package `flash.text`
|
||||||
class(
|
class(
|
||||||
flash::text::font::create_class(activation),
|
flash::text::font::create_class(activation),
|
||||||
|
@ -687,6 +679,7 @@ fn load_playerglobal<'gc>(
|
||||||
("flash.media", "SoundTransform", soundtransform),
|
("flash.media", "SoundTransform", soundtransform),
|
||||||
("flash.net", "URLVariables", urlvariables),
|
("flash.net", "URLVariables", urlvariables),
|
||||||
("flash.utils", "ByteArray", bytearray),
|
("flash.utils", "ByteArray", bytearray),
|
||||||
|
("flash.system", "ApplicationDomain", application_domain),
|
||||||
("flash.text", "StaticText", statictext),
|
("flash.text", "StaticText", statictext),
|
||||||
("flash.text", "TextFormat", textformat),
|
("flash.text", "TextFormat", textformat),
|
||||||
("flash.text", "TextField", textfield),
|
("flash.text", "TextField", textfield),
|
||||||
|
|
|
@ -1,5 +1,21 @@
|
||||||
// This is a stub - the actual class is defined in `application_domain.rs`
|
|
||||||
package flash.system {
|
package flash.system {
|
||||||
public class ApplicationDomain {
|
import flash.utils.ByteArray;
|
||||||
|
|
||||||
|
[Ruffle(InstanceAllocator)]
|
||||||
|
public final class ApplicationDomain {
|
||||||
|
public static native function get currentDomain():ApplicationDomain;
|
||||||
|
|
||||||
|
public function ApplicationDomain(parentDomain:ApplicationDomain = null) {
|
||||||
|
this.init(parentDomain)
|
||||||
|
}
|
||||||
|
|
||||||
|
private native function init(parentDomain:ApplicationDomain):void;
|
||||||
|
|
||||||
|
public native function get domainMemory():ByteArray;
|
||||||
|
public native function set domainMemory(value:ByteArray):void;
|
||||||
|
public native function get parentDomain():ApplicationDomain;
|
||||||
|
|
||||||
|
public native function getDefinition(name:String):Object;
|
||||||
|
public native function hasDefinition(name:String):Boolean;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,40 +1,40 @@
|
||||||
//! `flash.system.ApplicationDomain` class
|
//! `flash.system.ApplicationDomain` class
|
||||||
|
|
||||||
use crate::avm2::activation::Activation;
|
use crate::avm2::activation::Activation;
|
||||||
use crate::avm2::class::Class;
|
use crate::avm2::object::{DomainObject, Object, TObject};
|
||||||
use crate::avm2::method::{Method, NativeMethodImpl};
|
use crate::avm2::parameters::ParametersExt;
|
||||||
use crate::avm2::object::{appdomain_allocator, DomainObject, Object, TObject};
|
|
||||||
use crate::avm2::value::Value;
|
use crate::avm2::value::Value;
|
||||||
use crate::avm2::Error;
|
|
||||||
use crate::avm2::Multiname;
|
|
||||||
use crate::avm2::Namespace;
|
|
||||||
use crate::avm2::QName;
|
use crate::avm2::QName;
|
||||||
use gc_arena::GcCell;
|
use crate::avm2::{Domain, Error};
|
||||||
|
|
||||||
/// Implements `flash.system.ApplicationDomain`'s instance constructor.
|
pub use crate::avm2::object::application_domain_allocator;
|
||||||
pub fn instance_init<'gc>(
|
|
||||||
|
/// Implements `flash.system.ApplicationDomain`'s init method, which
|
||||||
|
/// is called from the constructor
|
||||||
|
pub fn init<'gc>(
|
||||||
activation: &mut Activation<'_, 'gc>,
|
activation: &mut Activation<'_, 'gc>,
|
||||||
this: Option<Object<'gc>>,
|
this: Option<Object<'gc>>,
|
||||||
_args: &[Value<'gc>],
|
args: &[Value<'gc>],
|
||||||
) -> Result<Value<'gc>, Error<'gc>> {
|
) -> Result<Value<'gc>, Error<'gc>> {
|
||||||
if let Some(this) = this {
|
if let Some(this) = this {
|
||||||
activation.super_init(this, &[])?;
|
activation.super_init(this, &[])?;
|
||||||
|
|
||||||
|
let parent_domain = if matches!(args[0], Value::Null) {
|
||||||
|
activation.avm2().global_domain()
|
||||||
|
} else {
|
||||||
|
args.get_object(activation, 0, "parentDomain")?
|
||||||
|
.as_application_domain()
|
||||||
|
.expect("Invalid parent domain")
|
||||||
|
};
|
||||||
|
let fresh_domain = Domain::movie_domain(activation, parent_domain);
|
||||||
|
this.init_application_domain(activation.context.gc_context, fresh_domain);
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(Value::Undefined)
|
Ok(Value::Undefined)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Implements `flash.system.ApplicationDomain`'s class constructor.
|
|
||||||
pub fn class_init<'gc>(
|
|
||||||
_activation: &mut Activation<'_, 'gc>,
|
|
||||||
_this: Option<Object<'gc>>,
|
|
||||||
_args: &[Value<'gc>],
|
|
||||||
) -> Result<Value<'gc>, Error<'gc>> {
|
|
||||||
Ok(Value::Undefined)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// `currentDomain` static property.
|
/// `currentDomain` static property.
|
||||||
pub fn current_domain<'gc>(
|
pub fn get_current_domain<'gc>(
|
||||||
activation: &mut Activation<'_, 'gc>,
|
activation: &mut Activation<'_, 'gc>,
|
||||||
_this: Option<Object<'gc>>,
|
_this: Option<Object<'gc>>,
|
||||||
_args: &[Value<'gc>],
|
_args: &[Value<'gc>],
|
||||||
|
@ -45,7 +45,7 @@ pub fn current_domain<'gc>(
|
||||||
}
|
}
|
||||||
|
|
||||||
/// `parentDomain` property
|
/// `parentDomain` property
|
||||||
pub fn parent_domain<'gc>(
|
pub fn get_parent_domain<'gc>(
|
||||||
activation: &mut Activation<'_, 'gc>,
|
activation: &mut Activation<'_, 'gc>,
|
||||||
this: Option<Object<'gc>>,
|
this: Option<Object<'gc>>,
|
||||||
_args: &[Value<'gc>],
|
_args: &[Value<'gc>],
|
||||||
|
@ -120,7 +120,7 @@ pub fn set_domain_memory<'gc>(
|
||||||
}
|
}
|
||||||
|
|
||||||
/// `domainMemory` property getter
|
/// `domainMemory` property getter
|
||||||
pub fn domain_memory<'gc>(
|
pub fn get_domain_memory<'gc>(
|
||||||
_activation: &mut Activation<'_, 'gc>,
|
_activation: &mut Activation<'_, 'gc>,
|
||||||
this: Option<Object<'gc>>,
|
this: Option<Object<'gc>>,
|
||||||
_args: &[Value<'gc>],
|
_args: &[Value<'gc>],
|
||||||
|
@ -132,56 +132,3 @@ pub fn domain_memory<'gc>(
|
||||||
|
|
||||||
Ok(Value::Undefined)
|
Ok(Value::Undefined)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Construct `ApplicationDomain`'s class.
|
|
||||||
pub fn create_class<'gc>(activation: &mut Activation<'_, 'gc>) -> GcCell<'gc, Class<'gc>> {
|
|
||||||
let mc = activation.context.gc_context;
|
|
||||||
let class = Class::new(
|
|
||||||
QName::new(Namespace::package("flash.system", mc), "ApplicationDomain"),
|
|
||||||
Some(Multiname::new(activation.avm2().public_namespace, "Object")),
|
|
||||||
Method::from_builtin(
|
|
||||||
instance_init,
|
|
||||||
"<ApplicationDomain instance initializer>",
|
|
||||||
mc,
|
|
||||||
),
|
|
||||||
Method::from_builtin(class_init, "<ApplicationDomain class initializer>", mc),
|
|
||||||
mc,
|
|
||||||
);
|
|
||||||
|
|
||||||
let mut write = class.write(mc);
|
|
||||||
write.set_instance_allocator(appdomain_allocator);
|
|
||||||
|
|
||||||
const PUBLIC_CLASS_PROPERTIES: &[(&str, Option<NativeMethodImpl>, Option<NativeMethodImpl>)] =
|
|
||||||
&[("currentDomain", Some(current_domain), None)];
|
|
||||||
write.define_builtin_class_properties(
|
|
||||||
mc,
|
|
||||||
activation.avm2().public_namespace,
|
|
||||||
PUBLIC_CLASS_PROPERTIES,
|
|
||||||
);
|
|
||||||
|
|
||||||
const PUBLIC_INSTANCE_PROPERTIES: &[(
|
|
||||||
&str,
|
|
||||||
Option<NativeMethodImpl>,
|
|
||||||
Option<NativeMethodImpl>,
|
|
||||||
)] = &[
|
|
||||||
("domainMemory", Some(domain_memory), Some(set_domain_memory)),
|
|
||||||
("parentDomain", Some(parent_domain), None),
|
|
||||||
];
|
|
||||||
write.define_builtin_instance_properties(
|
|
||||||
mc,
|
|
||||||
activation.avm2().public_namespace,
|
|
||||||
PUBLIC_INSTANCE_PROPERTIES,
|
|
||||||
);
|
|
||||||
|
|
||||||
const PUBLIC_INSTANCE_METHODS: &[(&str, NativeMethodImpl)] = &[
|
|
||||||
("getDefinition", get_definition),
|
|
||||||
("hasDefinition", has_definition),
|
|
||||||
];
|
|
||||||
write.define_builtin_instance_methods(
|
|
||||||
mc,
|
|
||||||
activation.avm2().public_namespace,
|
|
||||||
PUBLIC_INSTANCE_METHODS,
|
|
||||||
);
|
|
||||||
|
|
||||||
class
|
|
||||||
}
|
|
||||||
|
|
|
@ -264,6 +264,7 @@ include "flash/printing/PrintJobOrientation.as"
|
||||||
include "flash/profiler.as"
|
include "flash/profiler.as"
|
||||||
|
|
||||||
include "flash/security/CertificateStatus.as"
|
include "flash/security/CertificateStatus.as"
|
||||||
|
include "flash/system/ApplicationDomain.as"
|
||||||
include "flash/system/Capabilities.as"
|
include "flash/system/Capabilities.as"
|
||||||
include "flash/system/IME.as"
|
include "flash/system/IME.as"
|
||||||
include "flash/system/IMEConversionMode.as"
|
include "flash/system/IMEConversionMode.as"
|
||||||
|
|
|
@ -9,7 +9,6 @@ include "Array.as"
|
||||||
include "Boolean.as"
|
include "Boolean.as"
|
||||||
include "Date.as"
|
include "Date.as"
|
||||||
|
|
||||||
include "flash/system/ApplicationDomain.as"
|
|
||||||
include "Function.as"
|
include "Function.as"
|
||||||
include "Number.as"
|
include "Number.as"
|
||||||
include "String.as"
|
include "String.as"
|
||||||
|
|
|
@ -70,7 +70,7 @@ pub use crate::avm2::object::context3d_object::Context3DObject;
|
||||||
pub use crate::avm2::object::date_object::{date_allocator, DateObject};
|
pub use crate::avm2::object::date_object::{date_allocator, DateObject};
|
||||||
pub use crate::avm2::object::dictionary_object::{dictionary_allocator, DictionaryObject};
|
pub use crate::avm2::object::dictionary_object::{dictionary_allocator, DictionaryObject};
|
||||||
pub use crate::avm2::object::dispatch_object::DispatchObject;
|
pub use crate::avm2::object::dispatch_object::DispatchObject;
|
||||||
pub use crate::avm2::object::domain_object::{appdomain_allocator, DomainObject};
|
pub use crate::avm2::object::domain_object::{application_domain_allocator, DomainObject};
|
||||||
pub use crate::avm2::object::error_object::{error_allocator, ErrorObject};
|
pub use crate::avm2::object::error_object::{error_allocator, ErrorObject};
|
||||||
pub use crate::avm2::object::event_object::{event_allocator, EventObject};
|
pub use crate::avm2::object::event_object::{event_allocator, EventObject};
|
||||||
pub use crate::avm2::object::function_object::{function_allocator, FunctionObject};
|
pub use crate::avm2::object::function_object::{function_allocator, FunctionObject};
|
||||||
|
@ -1155,6 +1155,10 @@ pub trait TObject<'gc>: 'gc + Collect + Debug + Into<Object<'gc>> + Clone + Copy
|
||||||
fn init_display_object(&self, _context: &mut UpdateContext<'_, 'gc>, _obj: DisplayObject<'gc>) {
|
fn init_display_object(&self, _context: &mut UpdateContext<'_, 'gc>, _obj: DisplayObject<'gc>) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn init_application_domain(&self, _mc: MutationContext<'gc, '_>, _domain: Domain<'gc>) {
|
||||||
|
panic!("Tried to init an application domain on a non-ApplicationDomain object!")
|
||||||
|
}
|
||||||
|
|
||||||
/// Unwrap this object as an ApplicationDomain.
|
/// Unwrap this object as an ApplicationDomain.
|
||||||
fn as_application_domain(&self) -> Option<Domain<'gc>> {
|
fn as_application_domain(&self) -> Option<Domain<'gc>> {
|
||||||
None
|
None
|
||||||
|
|
|
@ -11,7 +11,7 @@ use gc_arena::{Collect, GcCell, MutationContext};
|
||||||
use std::cell::{Ref, RefMut};
|
use std::cell::{Ref, RefMut};
|
||||||
|
|
||||||
/// A class instance allocator that allocates AppDomain objects.
|
/// A class instance allocator that allocates AppDomain objects.
|
||||||
pub fn appdomain_allocator<'gc>(
|
pub fn application_domain_allocator<'gc>(
|
||||||
class: ClassObject<'gc>,
|
class: ClassObject<'gc>,
|
||||||
activation: &mut Activation<'_, 'gc>,
|
activation: &mut Activation<'_, 'gc>,
|
||||||
) -> Result<Object<'gc>, Error<'gc>> {
|
) -> Result<Object<'gc>, Error<'gc>> {
|
||||||
|
@ -65,8 +65,12 @@ impl<'gc> DomainObject<'gc> {
|
||||||
.into();
|
.into();
|
||||||
this.install_instance_slots(activation);
|
this.install_instance_slots(activation);
|
||||||
|
|
||||||
class.call_init(Some(this), &[], activation)?;
|
// Note - we do *not* call the normal constructor, since that
|
||||||
|
// creates a new domain using the system domain as a parent.
|
||||||
|
class
|
||||||
|
.superclass_object()
|
||||||
|
.unwrap()
|
||||||
|
.call_native_init(Some(this), &[], activation)?;
|
||||||
Ok(this)
|
Ok(this)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -88,6 +92,10 @@ impl<'gc> TObject<'gc> for DomainObject<'gc> {
|
||||||
Some(self.0.read().domain)
|
Some(self.0.read().domain)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn init_application_domain(&self, mc: MutationContext<'gc, '_>, domain: Domain<'gc>) {
|
||||||
|
self.0.write(mc).domain = domain;
|
||||||
|
}
|
||||||
|
|
||||||
fn value_of(&self, _mc: MutationContext<'gc, '_>) -> Result<Value<'gc>, Error<'gc>> {
|
fn value_of(&self, _mc: MutationContext<'gc, '_>) -> Result<Value<'gc>, Error<'gc>> {
|
||||||
let this: Object<'gc> = Object::DomainObject(*self);
|
let this: Object<'gc> = Object::DomainObject(*self);
|
||||||
|
|
||||||
|
|
|
@ -203,7 +203,7 @@ impl<'gc> TranslationUnit<'gc> {
|
||||||
|
|
||||||
drop(read);
|
drop(read);
|
||||||
|
|
||||||
let mut activation = Activation::from_nothing(uc.reborrow());
|
let mut activation = Activation::from_domain(uc.reborrow(), domain);
|
||||||
let global_class = activation.avm2().classes().global;
|
let global_class = activation.avm2().classes().global;
|
||||||
let global_obj = global_class.construct(&mut activation, &[])?;
|
let global_obj = global_class.construct(&mut activation, &[])?;
|
||||||
global_obj.fork_vtable(activation.context.gc_context);
|
global_obj.fork_vtable(activation.context.gc_context);
|
||||||
|
|
|
@ -479,13 +479,6 @@ pub enum ActionType<'gc> {
|
||||||
method: &'static str,
|
method: &'static str,
|
||||||
args: Vec<Avm1Value<'gc>>,
|
args: Vec<Avm1Value<'gc>>,
|
||||||
},
|
},
|
||||||
|
|
||||||
/// An AVM2 callable, e.g. a frame script or event handler.
|
|
||||||
Callable2 {
|
|
||||||
callable: Avm2Object<'gc>,
|
|
||||||
reciever: Option<Avm2Object<'gc>>,
|
|
||||||
args: Vec<Avm2Value<'gc>>,
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ActionType<'_> {
|
impl ActionType<'_> {
|
||||||
|
@ -533,16 +526,6 @@ impl fmt::Debug for ActionType<'_> {
|
||||||
.field("method", method)
|
.field("method", method)
|
||||||
.field("args", args)
|
.field("args", args)
|
||||||
.finish(),
|
.finish(),
|
||||||
ActionType::Callable2 {
|
|
||||||
callable,
|
|
||||||
reciever,
|
|
||||||
args,
|
|
||||||
} => f
|
|
||||||
.debug_struct("ActionType::Callable2")
|
|
||||||
.field("callable", callable)
|
|
||||||
.field("reciever", reciever)
|
|
||||||
.field("args", args)
|
|
||||||
.finish(),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2490,10 +2490,19 @@ impl<'gc> TDisplayObject<'gc> for MovieClip<'gc> {
|
||||||
.insert(MovieClipFlags::EXECUTING_AVM2_FRAME_SCRIPT);
|
.insert(MovieClipFlags::EXECUTING_AVM2_FRAME_SCRIPT);
|
||||||
|
|
||||||
drop(write);
|
drop(write);
|
||||||
|
|
||||||
|
let movie = self.movie();
|
||||||
|
let domain = context
|
||||||
|
.library
|
||||||
|
.library_for_movie(movie)
|
||||||
|
.unwrap()
|
||||||
|
.avm2_domain();
|
||||||
|
|
||||||
if let Err(e) = Avm2::run_stack_frame_for_callable(
|
if let Err(e) = Avm2::run_stack_frame_for_callable(
|
||||||
callable,
|
callable,
|
||||||
Some(avm2_object),
|
Some(avm2_object),
|
||||||
&[],
|
&[],
|
||||||
|
domain,
|
||||||
context,
|
context,
|
||||||
) {
|
) {
|
||||||
tracing::error!(
|
tracing::error!(
|
||||||
|
|
|
@ -745,7 +745,8 @@ impl<'gc> TDisplayObject<'gc> for Stage<'gc> {
|
||||||
// TODO: Replace this when we have a convenience method for constructing AVM2 native objects.
|
// TODO: Replace this when we have a convenience method for constructing AVM2 native objects.
|
||||||
// TODO: We should only do this if the movie is actually an AVM2 movie.
|
// TODO: We should only do this if the movie is actually an AVM2 movie.
|
||||||
// This is necessary for EventDispatcher super-constructor to run.
|
// This is necessary for EventDispatcher super-constructor to run.
|
||||||
let mut activation = Avm2Activation::from_nothing(context.reborrow());
|
let global_domain = context.avm2.global_domain();
|
||||||
|
let mut activation = Avm2Activation::from_domain(context.reborrow(), global_domain);
|
||||||
let avm2_stage = Avm2StageObject::for_display_object_childless(
|
let avm2_stage = Avm2StageObject::for_display_object_childless(
|
||||||
&mut activation,
|
&mut activation,
|
||||||
(*self).into(),
|
(*self).into(),
|
||||||
|
|
|
@ -243,7 +243,12 @@ impl<'gc> TDisplayObject<'gc> for Text<'gc> {
|
||||||
_run_frame: bool,
|
_run_frame: bool,
|
||||||
) {
|
) {
|
||||||
if context.is_action_script_3() {
|
if context.is_action_script_3() {
|
||||||
let mut activation = Avm2Activation::from_nothing(context.reborrow());
|
let domain = context
|
||||||
|
.library
|
||||||
|
.library_for_movie(self.movie())
|
||||||
|
.unwrap()
|
||||||
|
.avm2_domain();
|
||||||
|
let mut activation = Avm2Activation::from_domain(context.reborrow(), domain);
|
||||||
let statictext = activation.avm2().classes().statictext;
|
let statictext = activation.avm2().classes().statictext;
|
||||||
match Avm2StageObject::for_display_object_childless(
|
match Avm2StageObject::for_display_object_childless(
|
||||||
&mut activation,
|
&mut activation,
|
||||||
|
|
|
@ -279,7 +279,12 @@ impl<'gc> Callback<'gc> {
|
||||||
Value::Null
|
Value::Null
|
||||||
}
|
}
|
||||||
Callback::Avm2 { method } => {
|
Callback::Avm2 { method } => {
|
||||||
let mut activation = Avm2Activation::from_nothing(context.reborrow());
|
let domain = context
|
||||||
|
.library
|
||||||
|
.library_for_movie(context.swf.clone())
|
||||||
|
.unwrap()
|
||||||
|
.avm2_domain();
|
||||||
|
let mut activation = Avm2Activation::from_domain(context.reborrow(), domain);
|
||||||
let args: Vec<Avm2Value> = args
|
let args: Vec<Avm2Value> = args
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|v| v.into_avm2(&mut activation))
|
.map(|v| v.into_avm2(&mut activation))
|
||||||
|
|
|
@ -678,7 +678,12 @@ impl<'gc> Loader<'gc> {
|
||||||
.set_skip_next_enter_frame(true);
|
.set_skip_next_enter_frame(true);
|
||||||
|
|
||||||
if let Some(MovieLoaderEventHandler::Avm2LoaderInfo(loader_info)) = event_handler {
|
if let Some(MovieLoaderEventHandler::Avm2LoaderInfo(loader_info)) = event_handler {
|
||||||
let mut activation = Avm2Activation::from_nothing(context.reborrow());
|
let domain = context
|
||||||
|
.library
|
||||||
|
.library_for_movie(mc.movie())
|
||||||
|
.unwrap()
|
||||||
|
.avm2_domain();
|
||||||
|
let mut activation = Avm2Activation::from_domain(context.reborrow(), domain);
|
||||||
let mut loader = loader_info
|
let mut loader = loader_info
|
||||||
.get_public_property("loader", &mut activation)
|
.get_public_property("loader", &mut activation)
|
||||||
.map_err(|e| Error::Avm2Error(e.to_string()))?
|
.map_err(|e| Error::Avm2Error(e.to_string()))?
|
||||||
|
|
|
@ -358,9 +358,13 @@ impl Player {
|
||||||
.stage
|
.stage
|
||||||
.set_movie(context.gc_context, context.swf.clone());
|
.set_movie(context.gc_context, context.swf.clone());
|
||||||
|
|
||||||
let mut activation = Avm2Activation::from_nothing(context.reborrow());
|
let global_domain = context.avm2.global_domain();
|
||||||
let global_domain = activation.avm2().global_domain();
|
let mut global_activation =
|
||||||
let domain = Avm2Domain::movie_domain(&mut activation, global_domain);
|
Avm2Activation::from_domain(context.reborrow(), global_domain);
|
||||||
|
let domain = Avm2Domain::movie_domain(&mut global_activation, global_domain);
|
||||||
|
|
||||||
|
let mut activation =
|
||||||
|
Avm2Activation::from_domain(global_activation.context.reborrow(), domain);
|
||||||
|
|
||||||
activation
|
activation
|
||||||
.context
|
.context
|
||||||
|
@ -1686,18 +1690,6 @@ impl Player {
|
||||||
&args,
|
&args,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
ActionType::Callable2 {
|
|
||||||
callable,
|
|
||||||
reciever,
|
|
||||||
args,
|
|
||||||
} => {
|
|
||||||
if let Err(e) =
|
|
||||||
Avm2::run_stack_frame_for_callable(callable, reciever, &args[..], context)
|
|
||||||
{
|
|
||||||
tracing::error!("Unhandled AVM2 exception in event handler: {}", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// AVM1 bytecode may leave the stack unbalanced, so do not let garbage values accumulate
|
// AVM1 bytecode may leave the stack unbalanced, so do not let garbage values accumulate
|
||||||
|
|
Loading…
Reference in New Issue