Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 5 additions & 3 deletions core/src/avm2/globals/Array.as
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,14 @@ package {
public static const RETURNINDEXEDARRAY:uint = 8;
public static const NUMERIC:uint = 16;

private static native function initCustomPrototype();

// FIXME avmplus allows for calling some of these prototype functions on any
// Array-like object (for example, `Array.prototype.sort.call(myVector)` works),
// but currently we only support calling them on real Arrays
{
initCustomPrototype();

prototype.concat = function(...rest):Array {
var a:Array = this;
return a.AS3::concat.apply(a, rest);
Expand Down Expand Up @@ -103,9 +107,7 @@ package {
var arrayLength:uint = a.length;

for (var i:uint = 0; i < arrayLength; i ++) {
if (a[i] === void 0 || a[i] === null) {
result += a[i];
} else {
if (a[i] !== void 0 && a[i] !== null) {
result += a[i].toLocaleString();
}

Expand Down
15 changes: 15 additions & 0 deletions core/src/avm2/globals/array.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,21 @@ use std::mem::swap;

pub use crate::avm2::object::array_allocator;

pub fn init_custom_prototype<'gc>(
activation: &mut Activation<'_, 'gc>,
this: Value<'gc>,
_args: &[Value<'gc>],
) -> Result<Value<'gc>, Error<'gc>> {
let this = this.as_object().unwrap();
let this = this.as_class_object().unwrap();

let prototype_array_object = ArrayObject::for_prototype(activation.context, this);

this.link_prototype(activation.context, prototype_array_object);

Ok(Value::Undefined)
}

/// Implements `Array`'s instance initializer.
pub fn array_initializer<'gc>(
activation: &mut Activation<'_, 'gc>,
Expand Down
39 changes: 35 additions & 4 deletions core/src/avm2/object/array_object.rs
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,27 @@ impl<'gc> ArrayObject<'gc> {
))
}

pub fn for_prototype(
context: &mut UpdateContext<'gc>,
array_class: ClassObject<'gc>,
) -> Object<'gc> {
let object_class = context.avm2.classes().object;
let base = ScriptObjectData::custom_new(
array_class.inner_class_definition(),
Some(object_class.prototype()),
array_class.instance_vtable(),
);

ArrayObject(Gc::new(
context.gc(),
ArrayObjectData {
base,
array: RefLock::new(ArrayStorage::new(0)),
},
))
.into()
}

pub fn as_array_index(local_name: &WStr) -> Option<usize> {
// TODO: this should use a custom implementation instead of `parse()`,
// see `script_object::maybe_int_property`
Expand All @@ -96,6 +117,18 @@ impl<'gc> ArrayObject<'gc> {
.map(|i| i as usize)
}

/// Try to access "`name`" element on this array. If it's a hole or out of
/// range, this method returns `None`.
pub fn try_get_element(self, name: AvmString<'gc>) -> Option<Value<'gc>> {
if let Some(index) = ArrayObject::as_array_index(&name) {
if let Some(result) = self.get_index_property(index) {
return Some(result);
}
}

return None;
}

pub fn set_element(self, mc: &Mutation<'gc>, index: usize, value: Value<'gc>) {
unlock!(Gc::write(mc, self.0), ArrayObjectData, array)
.borrow_mut()
Expand Down Expand Up @@ -123,10 +156,8 @@ impl<'gc> TObject<'gc> for ArrayObject<'gc> {
) -> Result<Value<'gc>, Error<'gc>> {
if name.valid_dynamic_name() {
if let Some(name) = name.local_name() {
if let Some(index) = ArrayObject::as_array_index(&name) {
if let Some(result) = self.get_index_property(index) {
return Ok(result);
}
if let Some(result) = self.try_get_element(name) {
return Ok(result);
}
}
}
Expand Down
19 changes: 16 additions & 3 deletions core/src/avm2/object/script_object.rs
Original file line number Diff line number Diff line change
Expand Up @@ -483,14 +483,27 @@ pub fn get_dynamic_property<'gc>(

// follow the prototype chain
let mut proto = prototype;
while let Some(obj) = proto {
let obj = obj.base();
while let Some(this_proto) = proto {
// First search dynamic properties
let obj = this_proto.base();
let values = obj.values();
let value = values.as_hashmap().get(&key);
if let Some(value) = value {
return Ok(Some(value.value));
}
proto = obj.proto();

// Special-case: `Array.prototype` is an instance of `Array`, so to make
// sure that property lookups work correctly it, also check dynamic
// array elements (if this prototype is an `Array`).
//
// This special-case doesn't apply to anything else (e.g. Vector elements).
if let Some(array) = this_proto.as_array_object() {
if let Some(value) = array.try_get_element(local_name) {
return Ok(Some(value));
}
}

proto = this_proto.proto();
}

Ok(None)
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,2 +1 @@
num_ticks = 1
known_failure = true
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
Array.prototype.toLocaleString.length PASSED!
(new Array()).toLocaleString() PASSED!
(new Array(2)).toLocaleString() FAILED! expected: , got: undefined,undefined
(new Array(2)).toLocaleString() PASSED!
(new Array(0,1)).toLocaleString() PASSED!
(new Array( Number.NaN, Number.POSITIVE_INFINITY, Number.NEGATIVE_INFINITY)).toLocaleString() PASSED!
(new Array(Boolean(1), Boolean(0))).toLocaleString() PASSED!
(new Array(void 0,null)).toLocaleString() FAILED! expected: , got: undefined,null
(new Array(void 0,null)).toLocaleString() PASSED!
MYARR.toLocaleString() PASSED!
MYARR2.toLocaleString() PASSED!
MYARRARR.toLocaleString() PASSED!
MYUNDEFARR.toLocaleString() FAILED! expected: got: undefined
MYNULLARR.toLocaleString() FAILED! expected: got: null
MYNULLARR2.toLocaleString() FAILED! expected: got: null
MYUNDEFARR.toLocaleString() PASSED!
MYNULLARR.toLocaleString() PASSED!
MYNULLARR2.toLocaleString() PASSED!
MyAllArray.toLocaleString() FAILED! expected: [object String],1,2,3,100000,[object Boolean],1.79769313486231e+308 got: [object String],1,2,3,100000,[object Boolean],1.7976931348623149e+308
111 changes: 0 additions & 111 deletions tests/tests/swfs/from_avmplus/regress/bug_687838/output.ruffle.txt

This file was deleted.

1 change: 0 additions & 1 deletion tests/tests/swfs/from_avmplus/regress/bug_687838/test.toml
Original file line number Diff line number Diff line change
@@ -1,2 +1 @@
num_ticks = 1
known_failure = true
Loading