Skip to content

Commit ff9b6b3

Browse files
committed
avm1: Allow non-object prototypes in Object::new
Progresses some Gnash tests
1 parent e9e45fb commit ff9b6b3

33 files changed

+105
-127
lines changed

core/src/avm1/activation.rs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1039,9 +1039,7 @@ impl<'a, 'gc> Activation<'a, 'gc> {
10391039

10401040
//TODO: What happens if we try to extend an object which has no `prototype`?
10411041
//e.g. `class Whatever extends Object.prototype` or `class Whatever extends 5`
1042-
let super_prototype = superclass
1043-
.get(istr!(self, "prototype"), self)?
1044-
.coerce_to_object(self);
1042+
let super_prototype = superclass.get(istr!(self, "prototype"), self)?;
10451043

10461044
let sub_prototype = Object::new(self.strings(), Some(super_prototype));
10471045

core/src/avm1/function.rs

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -231,7 +231,7 @@ impl<'gc> Avm1Function<'gc> {
231231
// `f[""]()` emits a CallMethod op, causing `this` to be undefined, but `super` is a function; what is it?
232232
let zuper = this.filter(|_| !suppress).map(|this| {
233233
let zuper = NativeObject::Super(SuperObject::new(this, depth));
234-
Object::new_with_native(frame.strings(), None, zuper).into()
234+
Object::new_with_native(frame.strings(), None::<Value<'_>>, zuper).into()
235235
});
236236

237237
if preload {
@@ -656,9 +656,7 @@ impl<'gc> FunctionObject<'gc> {
656656
callee: Object<'gc>,
657657
args: &[Value<'gc>],
658658
) -> Result<Value<'gc>, Error<'gc>> {
659-
let prototype = callee
660-
.get(istr!("prototype"), activation)?
661-
.coerce_to_object(activation);
659+
let prototype = callee.get(istr!("prototype"), activation)?;
662660
let this = Object::new(activation.strings(), Some(prototype));
663661

664662
Self::define_constructor_props(activation, this, callee.into());

core/src/avm1/globals.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -545,7 +545,7 @@ pub fn create_globals<'gc>(
545545
as_broadcaster::BroadcasterFunctions<'gc>,
546546
) {
547547
let context = {
548-
let object_proto = Object::new(context, None);
548+
let object_proto = Object::new_without_proto(context.gc());
549549
&mut DeclContext {
550550
object_proto,
551551
fn_proto: Object::new(context, Some(object_proto)),

core/src/avm1/globals/bitmap_filter.rs

Lines changed: 3 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ use crate::avm1::globals::glow_filter::GlowFilter;
1212
use crate::avm1::globals::gradient_filter::GradientFilter;
1313
use crate::avm1::object::NativeObject;
1414
use crate::avm1::property_decl::{DeclContext, Declaration, SystemClass};
15-
use crate::avm1::{Attribute, Object, Value};
15+
use crate::avm1::{Object, Value};
1616
use crate::context::UpdateContext;
1717
use ruffle_macros::istr;
1818
use ruffle_render::filters::Filter;
@@ -66,7 +66,7 @@ pub fn clone<'gc>(
6666
_ => return Ok(Value::Undefined),
6767
};
6868
let proto = this.get_local_stored(istr!("__proto__"), activation);
69-
Ok(create_instance(activation, native, proto).into())
69+
Ok(Object::new_with_native(activation.strings(), proto, native).into())
7070
}
7171

7272
pub fn avm1_to_filter<'gc>(
@@ -149,26 +149,5 @@ pub fn filter_to_avm1<'gc>(activation: &mut Activation<'_, 'gc>, filter: Filter)
149149
)
150150
}
151151
};
152-
153-
create_instance(activation, native, Some(proto.into())).into()
154-
}
155-
156-
pub fn create_instance<'gc>(
157-
activation: &mut Activation<'_, 'gc>,
158-
native: NativeObject<'gc>,
159-
proto: Option<Value<'gc>>,
160-
) -> Object<'gc> {
161-
let result = Object::new(activation.strings(), None);
162-
// Set `__proto__` manually since `Object::new()` doesn't support primitive prototypes.
163-
// TODO: Pass `proto` to `Object::new()` once possible.
164-
if let Some(proto) = proto {
165-
result.define_value(
166-
activation.gc(),
167-
istr!("__proto__"),
168-
proto,
169-
Attribute::DONT_ENUM | Attribute::DONT_DELETE,
170-
);
171-
}
172-
result.set_native(activation.gc(), native);
173-
result
152+
Object::new_with_native(activation.strings(), Some(proto), native).into()
174153
}

core/src/avm1/globals/function.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ fn function<'gc>(
4040
) -> Result<Value<'gc>, Error<'gc>> {
4141
Ok(args.get(0).copied().unwrap_or_else(|| {
4242
// Calling `Function()` seems to give a prototypeless bare object.
43-
Object::new(&activation.context.strings, None).into()
43+
Object::new_without_proto(activation.gc()).into()
4444
}))
4545
}
4646

core/src/avm1/globals/movie_clip_loader.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,7 @@ fn get_progress<'gc>(
147147
Value::MovieClip(_) => target.coerce_to_object(activation).as_display_object(),
148148
_ => return Ok(Value::Undefined),
149149
};
150-
let result = Object::new(&activation.context.strings, None);
150+
let result = Object::new_without_proto(activation.gc());
151151
if let Some(target) = target {
152152
result.define_value(
153153
activation.gc(),

core/src/avm1/globals/object.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ fn function<'gc>(
9898
args: &[Value<'gc>],
9999
) -> Result<Value<'gc>, Error<'gc>> {
100100
let obj = match args.get(0).unwrap_or(&Value::Undefined) {
101-
Value::Undefined | Value::Null => Object::new(&activation.context.strings, None),
101+
Value::Undefined | Value::Null => Object::new_without_proto(activation.gc()),
102102
val => val.coerce_to_object(activation),
103103
};
104104
Ok(obj.into())

core/src/avm1/globals/text_format.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -538,7 +538,7 @@ fn get_text_extent<'gc>(
538538
temp_edittext.set_new_text_format(text_format.clone());
539539
temp_edittext.set_text(&text, activation.context);
540540

541-
let result = Object::new(&activation.context.strings, None);
541+
let result = Object::new_without_proto(activation.gc());
542542
let metrics = temp_edittext
543543
.layout_metrics()
544544
.expect("All text boxes should have at least one line at all times");

core/src/avm1/globals/xml.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ impl<'gc> Xml<'gc> {
9797
root,
9898
xml_decl: Lock::new(None),
9999
doctype: Lock::new(None),
100-
id_map: Object::new(context, None),
100+
id_map: Object::new_without_proto(context.gc()),
101101
status: Cell::new(XmlStatus::NoError),
102102
},
103103
));

core/src/avm1/object/script_object.rs

Lines changed: 19 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -111,11 +111,27 @@ impl<'gc> Object<'gc> {
111111
ObjectWeak(Gc::downgrade(self.0))
112112
}
113113

114-
pub fn new(context: &StringContext<'gc>, proto: Option<Object<'gc>>) -> Self {
114+
pub fn new(context: &StringContext<'gc>, proto: Option<impl Into<Value<'gc>>>) -> Self {
115+
Self::new_impl(context, proto.map(Into::into), NativeObject::None)
116+
}
117+
118+
pub fn new_with_native(
119+
context: &StringContext<'gc>,
120+
proto: Option<impl Into<Value<'gc>>>,
121+
native: NativeObject<'gc>,
122+
) -> Self {
123+
Self::new_impl(context, proto.map(Into::into), native)
124+
}
125+
126+
fn new_impl(
127+
context: &StringContext<'gc>,
128+
proto: Option<Value<'gc>>,
129+
native: NativeObject<'gc>,
130+
) -> Self {
115131
let object = Self(Gc::new(
116132
context.gc(),
117133
RefLock::new(ObjectData {
118-
native: NativeObject::None,
134+
native,
119135
properties: PropertyMap::new(),
120136
interfaces: None,
121137
watchers: PropertyMap::new(),
@@ -125,23 +141,13 @@ impl<'gc> Object<'gc> {
125141
object.define_value(
126142
context.gc(),
127143
istr!(context, "__proto__"),
128-
proto.into(),
144+
proto,
129145
Attribute::DONT_ENUM | Attribute::DONT_DELETE,
130146
);
131147
}
132148
object
133149
}
134150

135-
pub fn new_with_native(
136-
context: &StringContext<'gc>,
137-
proto: Option<Object<'gc>>,
138-
native: NativeObject<'gc>,
139-
) -> Self {
140-
let obj = Self::new(context, proto);
141-
obj.set_native(context.gc(), native);
142-
obj
143-
}
144-
145151
// Creates a Object, without assigning any __proto__ property.
146152
pub fn new_without_proto(gc_context: &Mutation<'gc>) -> Self {
147153
Self(Gc::new(

0 commit comments

Comments
 (0)