avm2: Put some more Multinames behind a Gc

This commit is contained in:
Lord-McSweeney 2024-09-09 16:23:48 -07:00 committed by Lord-McSweeney
parent 5512bc5742
commit 4a43ec0548
13 changed files with 141 additions and 112 deletions

View File

@ -16,7 +16,7 @@ use crate::PlayerRuntime;
use fnv::FnvHashMap;
use gc_arena::lock::GcRefLock;
use gc_arena::{Collect, Mutation};
use gc_arena::{Collect, Gc, Mutation};
use std::sync::Arc;
use swf::avm2::read::Reader;
use swf::DoAbc2Flag;
@ -79,7 +79,7 @@ pub use crate::avm2::domain::{Domain, DomainPtr};
pub use crate::avm2::error::Error;
pub use crate::avm2::flv::FlvValueAvm2Ext;
pub use crate::avm2::globals::flash::ui::context_menu::make_context_menu_state;
pub use crate::avm2::multiname::Multiname;
pub use crate::avm2::multiname::{CommonMultinames, Multiname};
pub use crate::avm2::namespace::Namespace;
pub use crate::avm2::object::{
ArrayObject, BitmapDataObject, ClassObject, EventObject, Object, SoundChannelObject,
@ -153,6 +153,8 @@ pub struct Avm2<'gc> {
pub flash_text_engine_internal: Namespace<'gc>,
pub flash_net_internal: Namespace<'gc>,
pub multinames: Gc<'gc, CommonMultinames<'gc>>,
#[collect(require_static)]
native_method_table: &'static [Option<(&'static str, NativeMethodImpl)>],
@ -207,27 +209,33 @@ impl<'gc> Avm2<'gc> {
player_version: u8,
player_runtime: PlayerRuntime,
) -> Self {
let playerglobals_domain = Domain::uninitialized_domain(context.gc_context, None);
let stage_domain =
Domain::uninitialized_domain(context.gc_context, Some(playerglobals_domain));
let mc = context.gc_context;
let playerglobals_domain = Domain::uninitialized_domain(mc, None);
let stage_domain = Domain::uninitialized_domain(mc, Some(playerglobals_domain));
let public_namespaces = (0..=(ApiVersion::VM_INTERNAL as usize))
.map(|val| Namespace::package("", ApiVersion::from_usize(val).unwrap(), context))
.collect();
let public_namespace_base_version =
Namespace::package("", ApiVersion::AllVersions, context);
let multinames = CommonMultinames::new(context, public_namespace_base_version);
Self {
player_version,
player_runtime,
stack: Vec::new(),
scope_stack: Vec::new(),
call_stack: GcRefLock::new(context.gc_context, CallStack::new().into()),
call_stack: GcRefLock::new(mc, CallStack::new().into()),
playerglobals_domain,
stage_domain,
system_classes: None,
system_class_defs: None,
toplevel_global_object: None,
public_namespace_base_version: Namespace::package("", ApiVersion::AllVersions, context),
public_namespace_base_version,
public_namespaces,
public_namespace_vm_internal: Namespace::package("", ApiVersion::VM_INTERNAL, context),
internal_namespace: Namespace::internal("", context),
@ -255,6 +263,8 @@ impl<'gc> Avm2<'gc> {
flash_text_engine_internal: Namespace::internal("flash.text.engine", context),
flash_net_internal: Namespace::internal("flash.net", context),
multinames: Gc::new(mc, multinames),
native_method_table: Default::default(),
native_instance_allocator_table: Default::default(),
native_super_initializer_table: Default::default(),

View File

@ -16,7 +16,7 @@ use crate::context::UpdateContext;
use crate::string::WString;
use bitflags::bitflags;
use fnv::FnvHashMap;
use gc_arena::{Collect, GcCell, Mutation};
use gc_arena::{Collect, Gc, GcCell, Mutation};
use std::cell::Ref;
use std::collections::HashSet;
@ -524,7 +524,7 @@ impl<'gc> Class<'gc> {
// A 'callable' class doesn't have a signature - let the
// method do any needed coercions
vec![],
Multiname::any(),
Gc::new(activation.gc(), Multiname::any()),
true,
activation.context.gc_context,
);
@ -1031,7 +1031,7 @@ impl<'gc> Class<'gc> {
activation.context.gc_context,
Trait::from_const(
name,
Multiname::new(activation.avm2().public_namespace_base_version, "Function"),
activation.avm2().multinames.function,
Some(value),
),
);
@ -1049,7 +1049,7 @@ impl<'gc> Class<'gc> {
activation.context.gc_context,
Trait::from_const(
QName::new(namespace, name),
Multiname::new(activation.avm2().public_namespace_base_version, "Number"),
activation.avm2().multinames.number,
Some(value.into()),
),
);
@ -1068,7 +1068,7 @@ impl<'gc> Class<'gc> {
activation.context.gc_context,
Trait::from_const(
QName::new(namespace, name),
Multiname::new(activation.avm2().public_namespace_base_version, "uint"),
activation.avm2().multinames.uint,
Some(value.into()),
),
);
@ -1087,7 +1087,7 @@ impl<'gc> Class<'gc> {
activation.context.gc_context,
Trait::from_const(
QName::new(namespace, name),
Multiname::new(activation.avm2().public_namespace_base_version, "int"),
activation.avm2().multinames.int,
Some(value.into()),
),
);
@ -1121,7 +1121,7 @@ impl<'gc> Class<'gc> {
&'static str,
NativeMethodImpl,
Vec<ParamConfig<'gc>>,
Multiname<'gc>,
Gc<'gc, Multiname<'gc>>,
)>,
) {
for (name, value, params, return_type) in items {
@ -1198,7 +1198,7 @@ impl<'gc> Class<'gc> {
activation.context.gc_context,
Trait::from_const(
QName::new(namespace, name),
Multiname::new(activation.avm2().public_namespace_base_version, "int"),
activation.avm2().multinames.int,
Some(value.into()),
),
);

View File

@ -2,7 +2,6 @@ use crate::avm2::activation::Activation;
use crate::avm2::api_version::ApiVersion;
use crate::avm2::class::Class;
use crate::avm2::domain::Domain;
use crate::avm2::multiname::Multiname;
use crate::avm2::object::{ClassObject, ScriptObject, TObject};
use crate::avm2::scope::{Scope, ScopeChain};
use crate::avm2::script::Script;
@ -613,7 +612,7 @@ pub fn load_player_globals<'gc>(
// right now.
global_traits.push(Trait::from_const(
qname,
Multiname::new(public_ns, "Function"),
activation.avm2().multinames.function,
Some(Value::Null),
));
}

View File

@ -183,6 +183,8 @@ fn describe_internal_body<'gc>(
class_def: Class<'gc>,
flags: DescribeTypeFlags,
) -> Result<Object<'gc>, Error<'gc>> {
let mc = activation.gc();
let traits = activation
.avm2()
.classes()
@ -225,30 +227,18 @@ fn describe_internal_body<'gc>(
traits.set_public_property("methods", Value::Null, activation)?;
}
let mut bases_array = bases
.as_array_storage_mut(activation.context.gc_context)
.unwrap();
let mut interfaces_array = interfaces
.as_array_storage_mut(activation.context.gc_context)
.unwrap();
let mut variables_array = variables
.as_array_storage_mut(activation.context.gc_context)
.unwrap();
let mut accessors_array = accessors
.as_array_storage_mut(activation.context.gc_context)
.unwrap();
let mut methods_array = methods
.as_array_storage_mut(activation.context.gc_context)
.unwrap();
let mut bases_array = bases.as_array_storage_mut(mc).unwrap();
let mut interfaces_array = interfaces.as_array_storage_mut(mc).unwrap();
let mut variables_array = variables.as_array_storage_mut(mc).unwrap();
let mut accessors_array = accessors.as_array_storage_mut(mc).unwrap();
let mut methods_array = methods.as_array_storage_mut(mc).unwrap();
let superclass = class_def.super_class();
if flags.contains(DescribeTypeFlags::INCLUDE_BASES) {
let mut current_super_class = superclass;
while let Some(super_class) = current_super_class {
let super_name = super_class
.name()
.to_qualified_name(activation.context.gc_context);
let super_name = super_class.name().to_qualified_name(mc);
bases_array.push(super_name.into());
current_super_class = super_class.super_class();
}
@ -259,9 +249,7 @@ fn describe_internal_body<'gc>(
if flags.contains(DescribeTypeFlags::INCLUDE_INTERFACES) {
for interface in &*class_def.all_interfaces() {
let interface_name = interface
.name()
.to_qualified_name(activation.context.gc_context);
let interface_name = interface.name().to_qualified_name(mc);
interfaces_array.push(interface_name.into());
}
}
@ -314,9 +302,7 @@ fn describe_internal_body<'gc>(
if !flags.contains(DescribeTypeFlags::INCLUDE_VARIABLES) {
continue;
}
let prop_class_name = vtable
.slot_class_name(*slot_id)?
.to_qualified_name_or_star(activation.context.gc_context);
let prop_class_name = vtable.slot_class_name(mc, *slot_id)?;
let access = match prop {
Property::ConstSlot { .. } => "readonly",
@ -370,10 +356,7 @@ fn describe_internal_body<'gc>(
continue;
}
let return_type_name = method
.method
.return_type()
.to_qualified_name_or_star(activation.context.gc_context);
let return_type_name = method.method.return_type().to_qualified_name_or_star(mc);
let declared_by = method.class;
if flags.contains(DescribeTypeFlags::HIDE_OBJECT)
@ -382,9 +365,7 @@ fn describe_internal_body<'gc>(
continue;
}
let declared_by_name = declared_by
.dollar_removed_name(activation.context.gc_context)
.to_qualified_name(activation.context.gc_context);
let declared_by_name = declared_by.dollar_removed_name(mc).to_qualified_name(mc);
let trait_metadata = vtable.get_metadata_for_disp(disp_id);
@ -475,11 +456,8 @@ fn describe_internal_body<'gc>(
Some(ns.as_uri())
};
let accessor_type =
method_type.to_qualified_name_or_star(activation.context.gc_context);
let declared_by = defining_class
.dollar_removed_name(activation.context.gc_context)
.to_qualified_name(activation.context.gc_context);
let accessor_type = method_type.to_qualified_name_or_star(mc);
let declared_by = defining_class.dollar_removed_name(mc).to_qualified_name(mc);
let accessor_obj = activation
.avm2()

View File

@ -9,6 +9,8 @@ use crate::avm2::object::{primitive_allocator, FunctionObject, Object, TObject};
use crate::avm2::value::Value;
use crate::avm2::{AvmString, Error, Multiname, QName};
use gc_arena::Gc;
/// Implements `int`'s instance initializer.
fn instance_init<'gc>(
activation: &mut Activation<'_, 'gc>,
@ -227,10 +229,10 @@ pub fn create_class<'gc>(activation: &mut Activation<'_, 'gc>) -> Class<'gc> {
"<int instance initializer>",
vec![ParamConfig {
param_name: AvmString::new_utf8(activation.context.gc_context, "value"),
param_type_name: Multiname::any(),
param_type_name: Gc::new(mc, Multiname::any()),
default_value: Some(Value::Integer(0)),
}],
Multiname::any(),
Gc::new(mc, Multiname::any()),
true,
mc,
),

View File

@ -10,6 +10,8 @@ use crate::avm2::Error;
use crate::avm2::Multiname;
use crate::avm2::QName;
use gc_arena::Gc;
/// Implements `Object`'s instance initializer.
pub fn instance_init<'gc>(
_activation: &mut Activation<'_, 'gc>,
@ -279,30 +281,30 @@ pub fn create_i_class<'gc>(activation: &mut Activation<'_, 'gc>) -> Class<'gc> {
has_own_property,
vec![ParamConfig::optional(
"name",
Multiname::any(),
Gc::new(gc_context, Multiname::any()),
Value::Undefined,
)],
Multiname::new(activation.avm2().public_namespace_base_version, "Boolean"),
activation.avm2().multinames.boolean,
),
(
"isPrototypeOf",
is_prototype_of,
vec![ParamConfig::optional(
"theClass",
Multiname::any(),
Gc::new(gc_context, Multiname::any()),
Value::Undefined,
)],
Multiname::new(activation.avm2().public_namespace_base_version, "Boolean"),
activation.avm2().multinames.boolean,
),
(
"propertyIsEnumerable",
property_is_enumerable,
vec![ParamConfig::optional(
"name",
Multiname::any(),
Gc::new(gc_context, Multiname::any()),
Value::Undefined,
)],
Multiname::new(activation.avm2().public_namespace_base_version, "Boolean"),
activation.avm2().multinames.boolean,
),
];
object_i_class.define_builtin_instance_methods_with_sig(
@ -337,7 +339,7 @@ pub fn create_c_class<'gc>(
gc_context,
Trait::from_const(
QName::new(activation.avm2().public_namespace_base_version, "length"),
Multiname::new(activation.avm2().public_namespace_base_version, "int"),
activation.avm2().multinames.int,
Some(1.into()),
),
);

View File

@ -9,6 +9,8 @@ use crate::avm2::object::{primitive_allocator, FunctionObject, Object, TObject};
use crate::avm2::value::Value;
use crate::avm2::{AvmString, Error, Multiname, QName};
use gc_arena::Gc;
/// Implements `uint`'s instance initializer.
fn instance_init<'gc>(
activation: &mut Activation<'_, 'gc>,
@ -228,10 +230,10 @@ pub fn create_class<'gc>(activation: &mut Activation<'_, 'gc>) -> Class<'gc> {
"<uint instance initializer>",
vec![ParamConfig {
param_name: AvmString::new_utf8(activation.context.gc_context, "value"),
param_type_name: Multiname::any(),
param_type_name: Gc::new(mc, Multiname::any()),
default_value: Some(Value::Integer(0)),
}],
Multiname::any(),
Gc::new(mc, Multiname::any()),
true,
mc,
),

View File

@ -15,7 +15,6 @@ use gc_arena::lock::Lock;
use gc_arena::{Collect, Gc, GcCell, Mutation};
use std::borrow::Cow;
use std::fmt;
use std::ops::Deref;
use std::rc::Rc;
use std::sync::Arc;
use swf::avm2::types::{
@ -61,7 +60,7 @@ pub struct ParamConfig<'gc> {
pub param_name: AvmString<'gc>,
/// The name of the type of the parameter.
pub param_type_name: Multiname<'gc>,
pub param_type_name: Gc<'gc, Multiname<'gc>>,
/// The default value for this parameter.
pub default_value: Option<Value<'gc>>,
@ -80,10 +79,7 @@ impl<'gc> ParamConfig<'gc> {
} else {
AvmString::from("<Unnamed Parameter>")
};
let param_type_name = txunit
.pool_multiname_static_any(config.kind, activation.context)?
.deref()
.clone();
let param_type_name = txunit.pool_multiname_static_any(config.kind, activation.context)?;
let default_value = if let Some(dv) = &config.default_value {
Some(abc_default_value(txunit, dv, activation)?)
@ -98,7 +94,10 @@ impl<'gc> ParamConfig<'gc> {
})
}
pub fn of_type(name: impl Into<AvmString<'gc>>, param_type_name: Multiname<'gc>) -> Self {
pub fn of_type(
name: impl Into<AvmString<'gc>>,
param_type_name: Gc<'gc, Multiname<'gc>>,
) -> Self {
Self {
param_name: name.into(),
param_type_name,
@ -108,7 +107,7 @@ impl<'gc> ParamConfig<'gc> {
pub fn optional(
name: impl Into<AvmString<'gc>>,
param_type_name: Multiname<'gc>,
param_type_name: Gc<'gc, Multiname<'gc>>,
default_value: impl Into<Value<'gc>>,
) -> Self {
Self {
@ -142,7 +141,7 @@ pub struct BytecodeMethod<'gc> {
pub signature: Vec<ParamConfig<'gc>>,
/// The return type of this method.
pub return_type: Multiname<'gc>,
pub return_type: Gc<'gc, Multiname<'gc>>,
/// The associated activation class. Initialized lazily, and only
/// if the method requires it.
@ -163,9 +162,11 @@ impl<'gc> BytecodeMethod<'gc> {
is_function: bool,
activation: &mut Activation<'_, 'gc>,
) -> Result<Self, Error<'gc>> {
let mc = activation.gc();
let abc = txunit.abc();
let mut signature = Vec::new();
let mut return_type = Multiname::any();
let mut return_type = Gc::new(mc, Multiname::any());
let mut abc_method_body = None;
if abc.methods.get(abc_method.0 as usize).is_some() {
@ -174,10 +175,8 @@ impl<'gc> BytecodeMethod<'gc> {
signature.push(ParamConfig::from_abc_param(param, txunit, activation)?);
}
return_type = txunit
.pool_multiname_static_any(method.return_type, activation.context)?
.deref()
.clone();
return_type =
txunit.pool_multiname_static_any(method.return_type, activation.context)?;
if let Some(body) = method.body {
abc_method_body = Some(body.0);
@ -189,7 +188,7 @@ impl<'gc> BytecodeMethod<'gc> {
abc: txunit.abc(),
abc_method: abc_method.0,
abc_method_body,
verified_info: GcCell::new(activation.context.gc_context, None),
verified_info: GcCell::new(mc, None),
signature,
return_type,
is_function,
@ -337,7 +336,7 @@ pub struct NativeMethod<'gc> {
pub resolved_signature: GcCell<'gc, Option<Vec<ResolvedParamConfig<'gc>>>>,
/// The return type of this method.
pub return_type: Multiname<'gc>,
pub return_type: Gc<'gc, Multiname<'gc>>,
/// Whether or not this method accepts parameters beyond those
/// mentioned in the parameter list.
@ -391,7 +390,7 @@ impl<'gc> Method<'gc> {
method: NativeMethodImpl,
name: &'static str,
signature: Vec<ParamConfig<'gc>>,
return_type: Multiname<'gc>,
return_type: Gc<'gc, Multiname<'gc>>,
is_variadic: bool,
mc: &Mutation<'gc>,
) -> Self {
@ -418,7 +417,7 @@ impl<'gc> Method<'gc> {
signature: Vec::new(),
resolved_signature: GcCell::new(mc, None),
// FIXME - take in the real return type. This is needed for 'describeType'
return_type: Multiname::any(),
return_type: Gc::new(mc, Multiname::any()),
is_variadic: true,
},
))
@ -436,10 +435,10 @@ impl<'gc> Method<'gc> {
}
}
pub fn return_type(&self) -> Multiname<'gc> {
pub fn return_type(&self) -> Gc<'gc, Multiname<'gc>> {
match self {
Method::Native(nm) => nm.return_type.clone(),
Method::Bytecode(bm) => bm.return_type.clone(),
Method::Native(nm) => nm.return_type,
Method::Bytecode(bm) => bm.return_type,
}
}

View File

@ -4,7 +4,7 @@ use crate::avm2::Error;
use crate::avm2::Namespace;
use crate::avm2::QName;
use crate::avm2::{Object, Value};
use crate::context::UpdateContext;
use crate::context::{GcContext, UpdateContext};
use crate::string::{AvmString, WStr, WString};
use bitflags::bitflags;
use gc_arena::Gc;
@ -519,3 +519,40 @@ impl<'gc> From<QName<'gc>> for Multiname<'gc> {
}
}
}
#[derive(Collect)]
#[collect(no_drop)]
pub struct CommonMultinames<'gc> {
pub boolean: Gc<'gc, Multiname<'gc>>,
pub function: Gc<'gc, Multiname<'gc>>,
pub int: Gc<'gc, Multiname<'gc>>,
pub number: Gc<'gc, Multiname<'gc>>,
pub uint: Gc<'gc, Multiname<'gc>>,
}
impl<'gc> CommonMultinames<'gc> {
pub fn new(
context: &mut GcContext<'_, 'gc>,
public_namespace_base_version: Namespace<'gc>,
) -> Self {
let mut create_pub_multiname = |local_name: &'static [u8]| -> Gc<'gc, Multiname<'gc>> {
Gc::new(
context.gc_context,
Multiname::new(
public_namespace_base_version,
context
.interner
.intern_static(context.gc_context, WStr::from_units(local_name)),
),
)
};
Self {
boolean: create_pub_multiname(b"Boolean"),
function: create_pub_multiname(b"Function"),
int: create_pub_multiname(b"int"),
number: create_pub_multiname(b"Number"),
uint: create_pub_multiname(b"uint"),
}
}
}

View File

@ -30,20 +30,22 @@ pub fn function_allocator<'gc>(
) -> Result<Object<'gc>, Error<'gc>> {
let base = ScriptObjectData::new(class);
let mc = activation.gc();
let dummy = Gc::new(
activation.context.gc_context,
mc,
NativeMethod {
method: |_, _, _| Ok(Value::Undefined),
name: "<Empty Function>",
signature: vec![],
resolved_signature: GcCell::new(activation.context.gc_context, None),
return_type: Multiname::any(),
resolved_signature: GcCell::new(mc, None),
return_type: Gc::new(mc, Multiname::any()),
is_variadic: true,
},
);
Ok(FunctionObject(Gc::new(
activation.context.gc_context,
mc,
FunctionObjectData {
base,
exec: RefLock::new(BoundMethod::from_method(

View File

@ -5,6 +5,7 @@ use crate::avm2::Error;
use crate::avm2::Multiname;
use crate::avm2::TranslationUnit;
use crate::avm2::Value;
use crate::string::AvmString;
use gc_arena::{Collect, Gc, Mutation};
use super::class::Class;
@ -39,13 +40,13 @@ pub enum PropertyClass<'gc> {
/// from the `Object` class
Any,
Class(Class<'gc>),
Name(Gc<'gc, (Multiname<'gc>, Option<TranslationUnit<'gc>>)>),
Name(Gc<'gc, (Gc<'gc, Multiname<'gc>>, Option<TranslationUnit<'gc>>)>),
}
impl<'gc> PropertyClass<'gc> {
pub fn name(
mc: &Mutation<'gc>,
name: Multiname<'gc>,
name: Gc<'gc, Multiname<'gc>>,
unit: Option<TranslationUnit<'gc>>,
) -> Self {
PropertyClass::Name(Gc::new(mc, (name, unit)))
@ -127,11 +128,11 @@ impl<'gc> PropertyClass<'gc> {
}
}
pub fn get_name(&self) -> Multiname<'gc> {
pub fn get_name(&self, mc: &Mutation<'gc>) -> AvmString<'gc> {
match self {
PropertyClass::Class(class) => class.name().into(),
PropertyClass::Name(gc) => gc.0.clone(),
PropertyClass::Any => Multiname::any(),
PropertyClass::Class(class) => class.name().to_qualified_name(mc),
PropertyClass::Name(gc) => gc.0.to_qualified_name_or_star(mc),
PropertyClass::Any => AvmString::new_utf8(mc, "*"),
}
}
}

View File

@ -10,8 +10,7 @@ use crate::avm2::Error;
use crate::avm2::Multiname;
use crate::avm2::QName;
use bitflags::bitflags;
use gc_arena::Collect;
use std::ops::Deref;
use gc_arena::{Collect, Gc};
use swf::avm2::types::{
DefaultValue as AbcDefaultValue, Trait as AbcTrait, TraitKind as AbcTraitKind,
};
@ -75,7 +74,7 @@ pub enum TraitKind<'gc> {
/// to.
Slot {
slot_id: u32,
type_name: Multiname<'gc>,
type_name: Gc<'gc, Multiname<'gc>>,
default_value: Value<'gc>,
unit: Option<TranslationUnit<'gc>>,
},
@ -100,7 +99,7 @@ pub enum TraitKind<'gc> {
/// be overridden.
Const {
slot_id: u32,
type_name: Multiname<'gc>,
type_name: Gc<'gc, Multiname<'gc>>,
default_value: Value<'gc>,
unit: Option<TranslationUnit<'gc>>,
},
@ -157,7 +156,7 @@ impl<'gc> Trait<'gc> {
pub fn from_slot(
name: QName<'gc>,
type_name: Multiname<'gc>,
type_name: Gc<'gc, Multiname<'gc>>,
default_value: Option<Value<'gc>>,
) -> Self {
Trait {
@ -175,7 +174,7 @@ impl<'gc> Trait<'gc> {
pub fn from_const(
name: QName<'gc>,
type_name: Multiname<'gc>,
type_name: Gc<'gc, Multiname<'gc>>,
default_value: Option<Value<'gc>>,
) -> Self {
Trait {
@ -205,10 +204,7 @@ impl<'gc> Trait<'gc> {
type_name,
value,
} => {
let type_name = unit
.pool_multiname_static_any(*type_name, activation.context)?
.deref()
.clone();
let type_name = unit.pool_multiname_static_any(*type_name, activation.context)?;
let default_value = slot_default_value(unit, value, &type_name, activation)?;
Trait {
name,
@ -272,10 +268,7 @@ impl<'gc> Trait<'gc> {
type_name,
value,
} => {
let type_name = unit
.pool_multiname_static_any(*type_name, activation.context)?
.deref()
.clone();
let type_name = unit.pool_multiname_static_any(*type_name, activation.context)?;
let default_value = slot_default_value(unit, value, &type_name, activation)?;
Trait {
name,

View File

@ -112,13 +112,17 @@ impl<'gc> VTable<'gc> {
self.0.read().disp_metadata_table.get(disp_id).cloned()
}
pub fn slot_class_name(&self, slot_id: u32) -> Result<Multiname<'gc>, Error<'gc>> {
pub fn slot_class_name(
&self,
mc: &Mutation<'gc>,
slot_id: u32,
) -> Result<AvmString<'gc>, Error<'gc>> {
self.0
.read()
.slot_classes
.get(slot_id as usize)
.ok_or_else(|| "Invalid slot ID".into())
.map(|c| c.get_name())
.map(|c| c.get_name(mc))
}
pub fn get_trait(self, name: &Multiname<'gc>) -> Option<Property> {