Remove the two-step initialization process and construct an ES4 class for `Object`, `Function`, and `Class`.

This has some particularly annoying consequences for initialization order: notably, we can't actually create any ES4 classes using the standard machinery until after the three objects I just mentioned get created. Ergo, we have to create them through lower-level means, handing prototypes around, and then initialize AVM2's system prototypes list for it.

When we start adding more system prototypes, we'll also have to fill the extras with blank objects and then slot them in as we create them.
This commit is contained in:
David Wendt 2020-08-04 23:00:17 -04:00
parent 16d8c85d20
commit 11ddccfa6a
11 changed files with 431 additions and 243 deletions

View File

@ -2,11 +2,10 @@
use crate::avm2::activation::Activation;
use crate::avm2::globals::SystemPrototypes;
use crate::avm2::object::{Object, TObject};
use crate::avm2::object::{Object, ScriptObject, TObject};
use crate::avm2::scope::Scope;
use crate::avm2::script::Script;
use crate::avm2::script::TranslationUnit;
use crate::avm2::script_object::ScriptObject;
use crate::avm2::value::Value;
use crate::context::UpdateContext;
use crate::tag_utils::SwfSlice;

View File

@ -51,6 +51,34 @@ pub struct SystemPrototypes<'gc> {
pub namespace: Object<'gc>,
}
impl<'gc> SystemPrototypes<'gc> {
/// Construct a minimal set of system prototypes necessary for
/// bootstrapping player globals.
///
/// All other system prototypes aside from the three given here will be set
/// to the empty object also handed to this function. It is the caller's
/// responsibility to instantiate each class and replace the empty object
/// with that.
fn new(
object: Object<'gc>,
function: Object<'gc>,
class: Object<'gc>,
empty: Object<'gc>,
) -> Self {
SystemPrototypes {
object,
function,
class,
string: empty,
boolean: empty,
number: empty,
int: empty,
uint: empty,
namespace: empty,
}
}
}
/// Add a free-function builtin to the global scope.
fn function<'gc>(
mc: MutationContext<'gc, '_>,
@ -69,39 +97,47 @@ fn function<'gc>(
.unwrap()
}
/// Add an ES3-style builtin to the global scope.
fn oldstyle_class<'gc>(
/// Add a class builtin with prototype methods to the global scope.
///
/// Since the function has to return a normal prototype object in this case, we
/// have to construct a constructor to go along with it, as if we had called
/// `install_foreign_trait` with such a class.
fn dynamic_class<'gc>(
mc: MutationContext<'gc, '_>,
mut global_scope: Object<'gc>,
package: impl Into<AvmString<'gc>>,
name: impl Into<AvmString<'gc>>,
constr: NativeMethod<'gc>,
proto: Object<'gc>,
fn_proto: Object<'gc>,
constr: Object<'gc>,
) {
global_scope
.install_dynamic_property(
mc,
QName::new(Namespace::package(package), name),
FunctionObject::from_builtin_constr(mc, constr, proto, fn_proto)
.unwrap()
.into(),
)
.unwrap();
let name = constr
.as_class()
.expect("constrs have classes in them")
.read()
.name()
.clone();
global_scope.install_const(mc, name, 0, constr.into());
}
/// Add a class builtin to the global scope.
///
/// This function returns a prototype which may be stored in `SystemPrototypes`.
fn class<'gc>(
activation: &mut Activation<'_, 'gc, '_>,
mut global: Object<'gc>,
class_def: GcCell<'gc, Class<'gc>>,
) -> Result<(), Error> {
) -> Result<Object<'gc>, Error> {
let class_trait = Trait::from_class(class_def);
let global_scope = Scope::push_scope(global.get_scope(), global, activation.context.gc_context);
let mut constr = global
.install_foreign_trait(activation, class_trait, Some(global_scope), global)?
.coerce_to_object(activation)?;
global.install_foreign_trait(activation, class_trait, Some(global_scope), global)?;
Ok(())
constr
.get_property(
constr,
&QName::new(Namespace::public_namespace(), "prototype"),
activation,
)?
.coerce_to_object(activation)
}
/// Add a builtin constant to the global scope.
@ -115,131 +151,99 @@ fn constant<'gc>(
global_scope.install_const(mc, QName::new(Namespace::package(package), name), 0, value)
}
/// Construct a new global scope.
///
/// This function returns both the global scope object, as well as all builtin
/// prototypes that other parts of the VM will need to use.
///
/// Due to a limitation of our type system and our garbage collector, the
/// player needs a valid `Avm2` but cannot provide us an `UpdateContext` yet.
/// As a result, global scope initialization is split into an "oldstyle phase"
/// and a "player-globals phase". This is the former phase, where we initialize
/// as much as we can without an `UpdateContext`. Note that not all
/// `SystemPrototypes` will be necessarily valid at this point in time, and
/// using them right away will result in objects of the wrong type.
pub fn construct_global_scope<'gc>(
mc: MutationContext<'gc, '_>,
) -> (Object<'gc>, SystemPrototypes<'gc>) {
let gs = ScriptObject::bare_object(mc);
// public / root package
let object_proto = ScriptObject::bare_object(mc);
let fn_proto = function::create_proto(mc, object_proto);
let class_proto = class::create_proto(mc, object_proto, fn_proto);
let string_proto = string::create_proto(mc, object_proto, fn_proto);
let boolean_proto = boolean::create_proto(mc, object_proto, fn_proto);
let number_proto = number::create_proto(mc, object_proto, fn_proto);
let int_proto = int::create_proto(mc, object_proto, fn_proto);
let uint_proto = uint::create_proto(mc, object_proto, fn_proto);
let namespace_proto = namespace::create_proto(mc, object_proto, fn_proto);
object::fill_proto(mc, object_proto, fn_proto);
oldstyle_class(
mc,
gs,
"",
"Object",
object::constructor,
object_proto,
fn_proto,
);
oldstyle_class(
mc,
gs,
"",
"Function",
function::constructor,
fn_proto,
fn_proto,
);
oldstyle_class(
mc,
gs,
"",
"Class",
class::constructor,
class_proto,
fn_proto,
);
oldstyle_class(
mc,
gs,
"",
"String",
string::constructor,
string_proto,
fn_proto,
);
oldstyle_class(
mc,
gs,
"",
"Boolean",
boolean::constructor,
boolean_proto,
fn_proto,
);
oldstyle_class(
mc,
gs,
"",
"Number",
number::constructor,
number_proto,
fn_proto,
);
oldstyle_class(mc, gs, "", "int", int::constructor, int_proto, fn_proto);
oldstyle_class(mc, gs, "", "uint", uint::constructor, uint_proto, fn_proto);
oldstyle_class(
mc,
gs,
"",
"Namespace",
namespace::constructor,
namespace_proto,
fn_proto,
);
function(mc, gs, "", "trace", trace, fn_proto);
constant(mc, gs, "", "undefined", Value::Undefined);
constant(mc, gs, "", "null", Value::Null);
constant(mc, gs, "", "NaN", NAN.into());
constant(mc, gs, "", "Infinity", f64::INFINITY.into());
let system_prototypes = SystemPrototypes {
object: object_proto,
function: fn_proto,
class: class_proto,
string: string_proto,
boolean: boolean_proto,
number: number_proto,
int: int_proto,
uint: uint_proto,
namespace: namespace_proto,
};
(gs, system_prototypes)
}
/// Initialize all remaining builtin classes.
///
/// Due to a limitation of our type system and our garbage collector, the
/// player needs a valid `Avm2` but cannot provide us an `UpdateContext` yet.
/// As a result, global scope initialization is split into an "oldstyle phase"
/// and a "player-globals phase". This is the latter phase.
/// This should be called only once, to construct the global scope of the
/// player. It will return a list of prototypes it has created, which should be
/// stored on the AVM.
pub fn load_player_globals<'gc>(activation: &mut Activation<'_, 'gc, '_>) -> Result<(), Error> {
let gs = activation.avm2().globals();
// public / root package
let object_proto = object::create_proto(activation);
let (function_constr, fn_proto) = function::create_class(activation, object_proto);
let (class_constr, class_proto) = class::create_class(activation, object_proto, fn_proto);
let object_constr = object::fill_proto(activation.context.gc_context, object_proto, fn_proto);
dynamic_class(activation.context.gc_context, gs, object_constr);
dynamic_class(activation.context.gc_context, gs, function_constr);
dynamic_class(activation.context.gc_context, gs, class_constr);
// At this point, we need at least a partial set of system prototypes in
// order to continue initializing the player. The rest of the prototypes
// are set to a bare object until we have a chance to initialize them.
activation.context.avm2.system_prototypes = Some(SystemPrototypes::new(
object_proto,
fn_proto,
class_proto,
ScriptObject::bare_object(activation.context.gc_context),
));
// Even sillier: for the sake of clarity and the borrow checker we need to
// clone the prototypes list and modify it outside of the activation. This
// also has the side effect that none of these classes can get at each
// other from the activation they're handed.
let mut sp = activation.context.avm2.system_prototypes.clone().unwrap();
sp.string = class(
activation,
gs,
string::create_class(activation.context.gc_context),
)?;
sp.boolean = class(
activation,
gs,
boolean::create_class(activation.context.gc_context),
)?;
sp.number = class(
activation,
gs,
number::create_class(activation.context.gc_context),
)?;
sp.int = class(
activation,
gs,
int::create_class(activation.context.gc_context),
)?;
sp.uint = class(
activation,
gs,
uint::create_class(activation.context.gc_context),
)?;
sp.namespace = class(
activation,
gs,
namespace::create_class(activation.context.gc_context),
)?;
activation.context.avm2.system_prototypes = Some(sp);
function(
activation.context.gc_context,
gs,
"",
"trace",
trace,
fn_proto,
);
constant(
activation.context.gc_context,
gs,
"",
"undefined",
Value::Undefined,
);
constant(activation.context.gc_context, gs, "", "null", Value::Null);
constant(activation.context.gc_context, gs, "", "NaN", NAN.into());
constant(
activation.context.gc_context,
gs,
"",
"Infinity",
f64::INFINITY.into(),
);
// package `flash.events`
class(
activation,

View File

@ -1,13 +1,16 @@
//! `Boolean` impl
use crate::avm2::activation::Activation;
use crate::avm2::object::{Object, ScriptObject};
use crate::avm2::class::Class;
use crate::avm2::method::Method;
use crate::avm2::names::{Namespace, QName};
use crate::avm2::object::Object;
use crate::avm2::value::Value;
use crate::avm2::Error;
use gc_arena::MutationContext;
use gc_arena::{GcCell, MutationContext};
/// Implements `Boolean`
pub fn constructor<'gc>(
/// Implements `Boolean`'s instance initializer.
pub fn instance_init<'gc>(
_activation: &mut Activation<'_, 'gc, '_>,
_this: Option<Object<'gc>>,
_args: &[Value<'gc>],
@ -15,11 +18,22 @@ pub fn constructor<'gc>(
Err("Boolean constructor is a stub.".into())
}
/// Construct `Boolean.prototype`.
pub fn create_proto<'gc>(
mc: MutationContext<'gc, '_>,
super_proto: Object<'gc>,
_fn_proto: Object<'gc>,
) -> Object<'gc> {
ScriptObject::object(mc, super_proto)
/// Implements `Boolean`'s class initializer.
pub fn class_init<'gc>(
_activation: &mut Activation<'_, 'gc, '_>,
_this: Option<Object<'gc>>,
_args: &[Value<'gc>],
) -> Result<Value<'gc>, Error> {
Ok(Value::Undefined)
}
/// Construct `Boolean`'s class.
pub fn create_class<'gc>(mc: MutationContext<'gc, '_>) -> GcCell<'gc, Class<'gc>> {
Class::new(
QName::new(Namespace::package(""), "Boolean"),
Some(QName::new(Namespace::public_namespace(), "Object").into()),
Method::from_builtin(instance_init),
Method::from_builtin(class_init),
mc,
)
}

View File

@ -1,16 +1,19 @@
//! `Class` builtin/prototype
use crate::avm2::activation::Activation;
use crate::avm2::object::{Object, ScriptObject};
use crate::avm2::class::Class;
use crate::avm2::method::Method;
use crate::avm2::names::{Namespace, QName};
use crate::avm2::object::{FunctionObject, Object, ScriptObject, TObject};
use crate::avm2::scope::Scope;
use crate::avm2::value::Value;
use crate::avm2::Error;
use gc_arena::MutationContext;
/// Implements `Class`
/// Implements `Class`'s instance initializer.
///
/// Notably, you cannot construct new classes this way, so this returns an
/// error.
pub fn constructor<'gc>(
pub fn instance_init<'gc>(
_activation: &mut Activation<'_, 'gc, '_>,
_this: Option<Object<'gc>>,
_args: &[Value<'gc>],
@ -18,11 +21,45 @@ pub fn constructor<'gc>(
Err("Classes cannot be constructed.".into())
}
/// Construct `Class.prototype`.
pub fn create_proto<'gc>(
mc: MutationContext<'gc, '_>,
super_proto: Object<'gc>,
_fn_proto: Object<'gc>,
) -> Object<'gc> {
ScriptObject::object(mc, super_proto)
/// Implement's `Class`'s class initializer.
pub fn class_init<'gc>(
_activation: &mut Activation<'_, 'gc, '_>,
_this: Option<Object<'gc>>,
_args: &[Value<'gc>],
) -> Result<Value<'gc>, Error> {
Err("Classes cannot be constructed.".into())
}
/// Construct `Class` and `Class.prototype`, respectively.
pub fn create_class<'gc>(
activation: &mut Activation<'_, 'gc, '_>,
super_proto: Object<'gc>,
fn_proto: Object<'gc>,
) -> (Object<'gc>, Object<'gc>) {
let class_class = Class::new(
QName::new(Namespace::public_namespace(), "Class"),
Some(QName::new(Namespace::public_namespace(), "Object").into()),
Method::from_builtin(instance_init),
Method::from_builtin(class_init),
activation.context.gc_context,
);
let globals = activation.avm2().globals();
let scope = Scope::push_scope(globals.get_scope(), globals, activation.context.gc_context);
let proto = ScriptObject::prototype(
activation.context.gc_context,
super_proto,
class_class,
Some(scope),
);
let constr = FunctionObject::from_builtin_constr(
activation.context.gc_context,
instance_init,
proto,
fn_proto,
)
.unwrap();
(constr, proto)
}

View File

@ -1,14 +1,25 @@
//! Function builtin and prototype
use crate::avm2::activation::Activation;
use crate::avm2::class::Class;
use crate::avm2::method::Method;
use crate::avm2::names::{Namespace, QName};
use crate::avm2::object::{FunctionObject, Object, ScriptObject, TObject};
use crate::avm2::scope::Scope;
use crate::avm2::value::Value;
use crate::avm2::Error;
use gc_arena::MutationContext;
/// Implements `Function`
pub fn constructor<'gc>(
/// Implements `Function`'s instance initializer.
pub fn instance_init<'gc>(
_activation: &mut Activation<'_, 'gc, '_>,
_this: Option<Object<'gc>>,
_args: &[Value<'gc>],
) -> Result<Value<'gc>, Error> {
Ok(Value::Undefined)
}
/// Implements `Function`'s class initializer.
pub fn class_init<'gc>(
_activation: &mut Activation<'_, 'gc, '_>,
_this: Option<Object<'gc>>,
_args: &[Value<'gc>],
@ -38,22 +49,42 @@ fn call<'gc>(
}
}
/// Partially construct `Function.prototype`.
///
/// `__proto__` and other cross-linked properties of this object will *not*
/// be defined here. The caller of this function is responsible for linking
/// them in order to obtain a valid ECMAScript `Function` prototype. The
/// returned object is also a bare object, which will need to be linked into
/// the prototype of `Object`.
pub fn create_proto<'gc>(gc_context: MutationContext<'gc, '_>, proto: Object<'gc>) -> Object<'gc> {
let mut function_proto = ScriptObject::object(gc_context, proto);
function_proto.install_method(
gc_context,
QName::new(Namespace::as3_namespace(), "call"),
0,
FunctionObject::from_builtin(gc_context, call, function_proto),
/// Construct `Function` and `Function.prototype`, respectively.
pub fn create_class<'gc>(
activation: &mut Activation<'_, 'gc, '_>,
proto: Object<'gc>,
) -> (Object<'gc>, Object<'gc>) {
let function_class = Class::new(
QName::new(Namespace::public_namespace(), "Function"),
Some(QName::new(Namespace::public_namespace(), "Object").into()),
Method::from_builtin(instance_init),
Method::from_builtin(class_init),
activation.context.gc_context,
);
function_proto
let globals = activation.avm2().globals();
let scope = Scope::push_scope(globals.get_scope(), globals, activation.context.gc_context);
let mut function_proto = ScriptObject::prototype(
activation.context.gc_context,
proto,
function_class,
Some(scope),
);
function_proto.install_method(
activation.context.gc_context,
QName::new(Namespace::as3_namespace(), "call"),
0,
FunctionObject::from_builtin(activation.context.gc_context, call, function_proto),
);
let constr = FunctionObject::from_builtin_constr(
activation.context.gc_context,
instance_init,
proto,
function_proto,
)
.unwrap();
(constr, function_proto)
}

View File

@ -1,13 +1,16 @@
//! `int` impl
use crate::avm2::activation::Activation;
use crate::avm2::object::{Object, ScriptObject};
use crate::avm2::class::Class;
use crate::avm2::method::Method;
use crate::avm2::names::{Namespace, QName};
use crate::avm2::object::Object;
use crate::avm2::value::Value;
use crate::avm2::Error;
use gc_arena::MutationContext;
use gc_arena::{GcCell, MutationContext};
/// Implements `int`
pub fn constructor<'gc>(
/// Implements `int`'s instance initializer.
pub fn instance_init<'gc>(
_activation: &mut Activation<'_, 'gc, '_>,
_this: Option<Object<'gc>>,
_args: &[Value<'gc>],
@ -15,11 +18,22 @@ pub fn constructor<'gc>(
Err("int constructor is a stub.".into())
}
/// Construct `int.prototype`.
pub fn create_proto<'gc>(
mc: MutationContext<'gc, '_>,
super_proto: Object<'gc>,
_fn_proto: Object<'gc>,
) -> Object<'gc> {
ScriptObject::object(mc, super_proto)
/// Implements `int`'s class initializer.
pub fn class_init<'gc>(
_activation: &mut Activation<'_, 'gc, '_>,
_this: Option<Object<'gc>>,
_args: &[Value<'gc>],
) -> Result<Value<'gc>, Error> {
Ok(Value::Undefined)
}
/// Construct `int`'s class.
pub fn create_class<'gc>(mc: MutationContext<'gc, '_>) -> GcCell<'gc, Class<'gc>> {
Class::new(
QName::new(Namespace::package(""), "int"),
Some(QName::new(Namespace::public_namespace(), "Object").into()),
Method::from_builtin(instance_init),
Method::from_builtin(class_init),
mc,
)
}

View File

@ -1,13 +1,16 @@
//! `Namespace` impl
use crate::avm2::activation::Activation;
use crate::avm2::object::{Object, ScriptObject};
use crate::avm2::class::Class;
use crate::avm2::method::Method;
use crate::avm2::names::{Namespace, QName};
use crate::avm2::object::Object;
use crate::avm2::value::Value;
use crate::avm2::Error;
use gc_arena::MutationContext;
use gc_arena::{GcCell, MutationContext};
/// Implements `Namespace`
pub fn constructor<'gc>(
/// Implements `Namespace`'s instance initializer.
pub fn instance_init<'gc>(
_activation: &mut Activation<'_, 'gc, '_>,
_this: Option<Object<'gc>>,
_args: &[Value<'gc>],
@ -15,11 +18,22 @@ pub fn constructor<'gc>(
Err("Namespace constructor is a stub.".into())
}
/// Construct `Namespace.prototype`.
pub fn create_proto<'gc>(
mc: MutationContext<'gc, '_>,
super_proto: Object<'gc>,
_fn_proto: Object<'gc>,
) -> Object<'gc> {
ScriptObject::object(mc, super_proto)
/// Implements `Namespace`'s class initializer.
pub fn class_init<'gc>(
_activation: &mut Activation<'_, 'gc, '_>,
_this: Option<Object<'gc>>,
_args: &[Value<'gc>],
) -> Result<Value<'gc>, Error> {
Ok(Value::Undefined)
}
/// Construct `Namespace`'s class.
pub fn create_class<'gc>(mc: MutationContext<'gc, '_>) -> GcCell<'gc, Class<'gc>> {
Class::new(
QName::new(Namespace::package(""), "Namespace"),
Some(QName::new(Namespace::public_namespace(), "Object").into()),
Method::from_builtin(instance_init),
Method::from_builtin(class_init),
mc,
)
}

View File

@ -1,13 +1,16 @@
//! `Number` impl
use crate::avm2::activation::Activation;
use crate::avm2::object::{Object, ScriptObject};
use crate::avm2::class::Class;
use crate::avm2::method::Method;
use crate::avm2::names::{Namespace, QName};
use crate::avm2::object::Object;
use crate::avm2::value::Value;
use crate::avm2::Error;
use gc_arena::MutationContext;
use gc_arena::{GcCell, MutationContext};
/// Implements `Number`
pub fn constructor<'gc>(
/// Implements `Number`'s instance initializer.
pub fn instance_init<'gc>(
_activation: &mut Activation<'_, 'gc, '_>,
_this: Option<Object<'gc>>,
_args: &[Value<'gc>],
@ -15,11 +18,22 @@ pub fn constructor<'gc>(
Err("Number constructor is a stub.".into())
}
/// Construct `Number.prototype`.
pub fn create_proto<'gc>(
mc: MutationContext<'gc, '_>,
super_proto: Object<'gc>,
_fn_proto: Object<'gc>,
) -> Object<'gc> {
ScriptObject::object(mc, super_proto)
/// Implements `Number`'s class initializer.
pub fn class_init<'gc>(
_activation: &mut Activation<'_, 'gc, '_>,
_this: Option<Object<'gc>>,
_args: &[Value<'gc>],
) -> Result<Value<'gc>, Error> {
Ok(Value::Undefined)
}
/// Construct `Number`'s class.
pub fn create_class<'gc>(mc: MutationContext<'gc, '_>) -> GcCell<'gc, Class<'gc>> {
Class::new(
QName::new(Namespace::package(""), "Number"),
Some(QName::new(Namespace::public_namespace(), "Object").into()),
Method::from_builtin(instance_init),
Method::from_builtin(class_init),
mc,
)
}

View File

@ -1,14 +1,26 @@
//! Object builtin and prototype
use crate::avm2::activation::Activation;
use crate::avm2::class::Class;
use crate::avm2::method::Method;
use crate::avm2::names::{Namespace, QName};
use crate::avm2::object::{FunctionObject, Object, TObject};
use crate::avm2::object::{FunctionObject, Object, ScriptObject, TObject};
use crate::avm2::scope::Scope;
use crate::avm2::value::Value;
use crate::avm2::Error;
use gc_arena::MutationContext;
/// Implements `Object`
pub fn constructor<'gc>(
/// Implements `Object`'s instance initializer.
pub fn instance_init<'gc>(
_activation: &mut Activation<'_, 'gc, '_>,
_this: Option<Object<'gc>>,
_args: &[Value<'gc>],
) -> Result<Value<'gc>, Error> {
Ok(Value::Undefined)
}
/// Implements `Object`'s class initializer
pub fn class_init<'gc>(
_activation: &mut Activation<'_, 'gc, '_>,
_this: Option<Object<'gc>>,
_args: &[Value<'gc>],
@ -140,7 +152,26 @@ pub fn set_property_is_enumerable<'gc>(
Ok(Value::Undefined)
}
/// Partially construct `Object.prototype`.
/// Create object prototype.
///
/// This function creates a suitable class and object prototype attached to it,
/// but does not actually fill it with methods. That requires a valid function
/// prototype, and is thus done by `fill_proto` below.
pub fn create_proto<'gc>(activation: &mut Activation<'_, 'gc, '_>) -> Object<'gc> {
let object_class = Class::new(
QName::new(Namespace::public_namespace(), "Object"),
None,
Method::from_builtin(instance_init),
Method::from_builtin(class_init),
activation.context.gc_context,
);
let globals = activation.avm2().globals();
let scope = Scope::push_scope(globals.get_scope(), globals, activation.context.gc_context);
ScriptObject::bare_prototype(activation.context.gc_context, object_class, Some(scope))
}
/// Finish constructing `Object.prototype`, and also construct `Object`.
///
/// `__proto__` and other cross-linked properties of this object will *not*
/// be defined here. The caller of this function is responsible for linking
@ -153,7 +184,7 @@ pub fn fill_proto<'gc>(
gc_context: MutationContext<'gc, '_>,
mut object_proto: Object<'gc>,
fn_proto: Object<'gc>,
) {
) -> Object<'gc> {
object_proto.install_method(
gc_context,
QName::new(Namespace::public_namespace(), "toString"),
@ -196,4 +227,6 @@ pub fn fill_proto<'gc>(
0,
FunctionObject::from_builtin(gc_context, set_property_is_enumerable, fn_proto),
);
FunctionObject::from_builtin_constr(gc_context, instance_init, object_proto, fn_proto).unwrap()
}

View File

@ -1,13 +1,16 @@
//! `String` impl
use crate::avm2::activation::Activation;
use crate::avm2::object::{Object, ScriptObject};
use crate::avm2::class::Class;
use crate::avm2::method::Method;
use crate::avm2::names::{Namespace, QName};
use crate::avm2::object::Object;
use crate::avm2::value::Value;
use crate::avm2::Error;
use gc_arena::MutationContext;
use gc_arena::{GcCell, MutationContext};
/// Implements `String`
pub fn constructor<'gc>(
/// Implements `String`'s instance initializer.
pub fn instance_init<'gc>(
_activation: &mut Activation<'_, 'gc, '_>,
_this: Option<Object<'gc>>,
_args: &[Value<'gc>],
@ -15,11 +18,22 @@ pub fn constructor<'gc>(
Err("String constructor is a stub.".into())
}
/// Construct `String.prototype`.
pub fn create_proto<'gc>(
mc: MutationContext<'gc, '_>,
super_proto: Object<'gc>,
_fn_proto: Object<'gc>,
) -> Object<'gc> {
ScriptObject::object(mc, super_proto)
/// Implements `String`'s class initializer.
pub fn class_init<'gc>(
_activation: &mut Activation<'_, 'gc, '_>,
_this: Option<Object<'gc>>,
_args: &[Value<'gc>],
) -> Result<Value<'gc>, Error> {
Ok(Value::Undefined)
}
/// Construct `String`'s class.
pub fn create_class<'gc>(mc: MutationContext<'gc, '_>) -> GcCell<'gc, Class<'gc>> {
Class::new(
QName::new(Namespace::package(""), "String"),
Some(QName::new(Namespace::public_namespace(), "Object").into()),
Method::from_builtin(instance_init),
Method::from_builtin(class_init),
mc,
)
}

View File

@ -1,13 +1,16 @@
//! `uint` impl
use crate::avm2::activation::Activation;
use crate::avm2::object::{Object, ScriptObject};
use crate::avm2::class::Class;
use crate::avm2::method::Method;
use crate::avm2::names::{Namespace, QName};
use crate::avm2::object::Object;
use crate::avm2::value::Value;
use crate::avm2::Error;
use gc_arena::MutationContext;
use gc_arena::{GcCell, MutationContext};
/// Implements `uint`
pub fn constructor<'gc>(
/// Implements `uint`'s instance initializer.
pub fn instance_init<'gc>(
_activation: &mut Activation<'_, 'gc, '_>,
_this: Option<Object<'gc>>,
_args: &[Value<'gc>],
@ -15,11 +18,22 @@ pub fn constructor<'gc>(
Err("uint constructor is a stub.".into())
}
/// Construct `uint.prototype`.
pub fn create_proto<'gc>(
mc: MutationContext<'gc, '_>,
super_proto: Object<'gc>,
_fn_proto: Object<'gc>,
) -> Object<'gc> {
ScriptObject::object(mc, super_proto)
/// Implements `uint`'s class initializer.
pub fn class_init<'gc>(
_activation: &mut Activation<'_, 'gc, '_>,
_this: Option<Object<'gc>>,
_args: &[Value<'gc>],
) -> Result<Value<'gc>, Error> {
Ok(Value::Undefined)
}
/// Construct `uint`'s class.
pub fn create_class<'gc>(mc: MutationContext<'gc, '_>) -> GcCell<'gc, Class<'gc>> {
Class::new(
QName::new(Namespace::package(""), "uint"),
Some(QName::new(Namespace::public_namespace(), "Object").into()),
Method::from_builtin(instance_init),
Method::from_builtin(class_init),
mc,
)
}