ArrayReduce: 1,
ArrayReduceRight: 1
});
+
+ %FinishArrayPrototypeSetup($Array.prototype);
}
}
+static Object* AllocateUninitializedFixedArray(int len) {
+ Object* obj = Heap::AllocateRawFixedArray(len);
+ if (obj->IsFailure()) return obj;
+
+ reinterpret_cast<FixedArray*>(obj)->set_map(Heap::fixed_array_map());
+ FixedArray::cast(obj)->set_length(len);
+ return obj;
+}
+
+
+static Object* AllocateJSArray() {
+ JSFunction* array_function =
+ Top::context()->global_context()->array_function();
+ Object* result = Heap::AllocateJSObject(array_function);
+ if (result->IsFailure()) return result;
+ return result;
+}
+
+
+static void CopyElements(AssertNoAllocation* no_gc,
+ FixedArray* dst,
+ int dst_index,
+ FixedArray* src,
+ int src_index,
+ int len) {
+ ASSERT(dst != src); // Use MoveElements instead.
+ memcpy(dst->data_start() + dst_index,
+ src->data_start() + src_index,
+ len * kPointerSize);
+ WriteBarrierMode mode = dst->GetWriteBarrierMode(*no_gc);
+ if (mode == UPDATE_WRITE_BARRIER) {
+ Heap::RecordWrites(dst->address(), dst->OffsetOfElementAt(dst_index), len);
+ }
+}
+
+
+static void MoveElements(AssertNoAllocation* no_gc,
+ FixedArray* dst,
+ int dst_index,
+ FixedArray* src,
+ int src_index,
+ int len) {
+ memmove(dst->data_start() + dst_index,
+ src->data_start() + src_index,
+ len * kPointerSize);
+ WriteBarrierMode mode = dst->GetWriteBarrierMode(*no_gc);
+ if (mode == UPDATE_WRITE_BARRIER) {
+ Heap::RecordWrites(dst->address(), dst->OffsetOfElementAt(dst_index), len);
+ }
+}
+
+
+static void FillWithHoles(FixedArray* dst, int from, int to) {
+ MemsetPointer(dst->data_start() + from, Heap::the_hole_value(), to - from);
+}
+
+
+static bool ArrayPrototypeHasNoElements() {
+ // This method depends on non writability of Object and Array prototype
+ // fields.
+ Context* global_context = Top::context()->global_context();
+ // Array.prototype
+ JSObject* proto =
+ JSObject::cast(global_context->array_function()->prototype());
+ if (proto->elements() != Heap::empty_fixed_array()) return false;
+ // Hidden prototype
+ proto = JSObject::cast(proto->GetPrototype());
+ ASSERT(proto->elements() == Heap::empty_fixed_array());
+ // Object.prototype
+ proto = JSObject::cast(proto->GetPrototype());
+ if (proto != global_context->initial_object_prototype()) return false;
+ if (proto->elements() != Heap::empty_fixed_array()) return false;
+ ASSERT(proto->GetPrototype()->IsNull());
+ return true;
+}
+
+
+static Object* CallJsBuiltin(const char* name,
+ BuiltinArguments<NO_EXTRA_ARGUMENTS> args) {
+ HandleScope handleScope;
+
+ Handle<Object> js_builtin =
+ GetProperty(Handle<JSObject>(Top::global_context()->builtins()),
+ name);
+ ASSERT(js_builtin->IsJSFunction());
+ Handle<JSFunction> function(Handle<JSFunction>::cast(js_builtin));
+ Vector<Object**> argv(Vector<Object**>::New(args.length() - 1));
+ int n_args = args.length() - 1;
+ for (int i = 0; i < n_args; i++) {
+ argv[i] = &args[i + 1];
+ }
+ bool pending_exception = false;
+ Handle<Object> result = Execution::Call(function,
+ args.receiver(),
+ n_args,
+ argv.start(),
+ &pending_exception);
+ if (pending_exception) return Failure::Exception();
+ return *result;
+}
+
+
BUILTIN(ArrayPush) {
JSArray* array = JSArray::cast(*args.receiver());
ASSERT(array->HasFastElements());
if (new_length > elms->length()) {
// New backing storage is needed.
int capacity = new_length + (new_length >> 1) + 16;
- Object* obj = Heap::AllocateFixedArrayWithHoles(capacity);
+ Object* obj = AllocateUninitializedFixedArray(capacity);
if (obj->IsFailure()) return obj;
+ FixedArray* new_elms = FixedArray::cast(obj);
AssertNoAllocation no_gc;
- FixedArray* new_elms = FixedArray::cast(obj);
- WriteBarrierMode mode = new_elms->GetWriteBarrierMode(no_gc);
- // Fill out the new array with old elements.
- for (int i = 0; i < len; i++) new_elms->set(i, elms->get(i), mode);
+ CopyElements(&no_gc, new_elms, 0, elms, 0, len);
+ FillWithHoles(new_elms, new_length, capacity);
+
elms = new_elms;
array->set_elements(elms);
}
+ // Add the provided values.
AssertNoAllocation no_gc;
WriteBarrierMode mode = elms->GetWriteBarrierMode(no_gc);
-
- // Add the provided values.
for (int index = 0; index < to_add; index++) {
elms->set(index + len, args[index + 1], mode);
}
BUILTIN(ArrayPop) {
JSArray* array = JSArray::cast(*args.receiver());
ASSERT(array->HasFastElements());
- Object* undefined = Heap::undefined_value();
int len = Smi::cast(array->length())->value();
- if (len == 0) return undefined;
+ if (len == 0) return Heap::undefined_value();
// Get top element
FixedArray* elms = FixedArray::cast(array->elements());
}
-static Object* GetElementToMove(uint32_t index,
- FixedArray* elms,
- JSObject* prototype) {
- Object* e = elms->get(index);
- if (e->IsTheHole() && prototype->HasElement(index)) {
- e = prototype->GetElement(index);
+BUILTIN(ArrayShift) {
+ if (!ArrayPrototypeHasNoElements()) {
+ return CallJsBuiltin("ArrayShift", args);
}
- return e;
-}
-
-BUILTIN(ArrayShift) {
JSArray* array = JSArray::cast(*args.receiver());
ASSERT(array->HasFastElements());
int len = Smi::cast(array->length())->value();
if (len == 0) return Heap::undefined_value();
- // Fetch the prototype.
- JSFunction* array_function =
- Top::context()->global_context()->array_function();
- JSObject* prototype = JSObject::cast(array_function->prototype());
-
FixedArray* elms = FixedArray::cast(array->elements());
// Get first element
Object* first = elms->get(0);
if (first->IsTheHole()) {
- first = prototype->GetElement(0);
+ first = Heap::undefined_value();
}
// Shift the elements.
- for (int i = 0; i < len - 1; i++) {
- elms->set(i, GetElementToMove(i + 1, elms, prototype));
- }
+ AssertNoAllocation no_gc;
+ MoveElements(&no_gc, elms, 0, elms, 1, len - 1);
elms->set(len - 1, Heap::the_hole_value());
// Set the length.
BUILTIN(ArrayUnshift) {
+ if (!ArrayPrototypeHasNoElements()) {
+ return CallJsBuiltin("ArrayUnshift", args);
+ }
+
JSArray* array = JSArray::cast(*args.receiver());
ASSERT(array->HasFastElements());
FixedArray* elms = FixedArray::cast(array->elements());
- // Fetch the prototype.
- JSFunction* array_function =
- Top::context()->global_context()->array_function();
- JSObject* prototype = JSObject::cast(array_function->prototype());
-
if (new_length > elms->length()) {
// New backing storage is needed.
int capacity = new_length + (new_length >> 1) + 16;
- Object* obj = Heap::AllocateFixedArrayWithHoles(capacity);
+ Object* obj = AllocateUninitializedFixedArray(capacity);
if (obj->IsFailure()) return obj;
+ FixedArray* new_elms = FixedArray::cast(obj);
AssertNoAllocation no_gc;
- FixedArray* new_elms = FixedArray::cast(obj);
- WriteBarrierMode mode = new_elms->GetWriteBarrierMode(no_gc);
- // Fill out the new array with old elements.
- for (int i = 0; i < len; i++)
- new_elms->set(to_add + i,
- GetElementToMove(i, elms, prototype),
- mode);
+ CopyElements(&no_gc, new_elms, to_add, elms, 0, len);
+ FillWithHoles(new_elms, new_length, capacity);
elms = new_elms;
array->set_elements(elms);
} else {
AssertNoAllocation no_gc;
- WriteBarrierMode mode = elms->GetWriteBarrierMode(no_gc);
-
- // Move elements to the right
- for (int i = 0; i < len; i++) {
- elms->set(new_length - i - 1,
- GetElementToMove(len - i - 1, elms, prototype),
- mode);
- }
+ MoveElements(&no_gc, elms, to_add, elms, 0, len);
}
// Add the provided values.
}
-static Object* CallJsBuiltin(const char* name,
- BuiltinArguments<NO_EXTRA_ARGUMENTS> args) {
- HandleScope handleScope;
-
- Handle<Object> js_builtin =
- GetProperty(Handle<JSObject>(Top::global_context()->builtins()),
- name);
- ASSERT(js_builtin->IsJSFunction());
- Handle<JSFunction> function(Handle<JSFunction>::cast(js_builtin));
- Vector<Object**> argv(Vector<Object**>::New(args.length() - 1));
- int n_args = args.length() - 1;
- for (int i = 0; i < n_args; i++) {
- argv[i] = &args[i + 1];
+BUILTIN(ArraySlice) {
+ if (!ArrayPrototypeHasNoElements()) {
+ return CallJsBuiltin("ArraySlice", args);
}
- bool pending_exception = false;
- Handle<Object> result = Execution::Call(function,
- args.receiver(),
- n_args,
- argv.start(),
- &pending_exception);
- if (pending_exception) return Failure::Exception();
- return *result;
-}
-
-BUILTIN(ArraySlice) {
JSArray* array = JSArray::cast(*args.receiver());
ASSERT(array->HasFastElements());
result_len = 0;
}
- JSFunction* array_function =
- Top::context()->global_context()->array_function();
- Object* result = Heap::AllocateJSObject(array_function);
+ Object* result = AllocateJSArray();
if (result->IsFailure()) return result;
JSArray* result_array = JSArray::cast(result);
- result = Heap::AllocateFixedArrayWithHoles(result_len);
+ result = AllocateUninitializedFixedArray(result_len);
if (result->IsFailure()) return result;
FixedArray* result_elms = FixedArray::cast(result);
FixedArray* elms = FixedArray::cast(array->elements());
- // Fetch the prototype.
- JSObject* prototype = JSObject::cast(array_function->prototype());
-
AssertNoAllocation no_gc;
- WriteBarrierMode mode = result_elms->GetWriteBarrierMode(no_gc);
-
- // Fill newly created array.
- for (int i = 0; i < result_len; i++) {
- result_elms->set(i,
- GetElementToMove(k + i, elms, prototype),
- mode);
- }
+ CopyElements(&no_gc, result_elms, 0, elms, k, result_len);
// Set elements.
result_array->set_elements(result_elms);
BUILTIN(ArraySplice) {
+ if (!ArrayPrototypeHasNoElements()) {
+ return CallJsBuiltin("ArraySplice", args);
+ }
+
JSArray* array = JSArray::cast(*args.receiver());
ASSERT(array->HasFastElements());
}
int actualDeleteCount = Min(Max(deleteCount, 0), len - actualStart);
- JSFunction* array_function =
- Top::context()->global_context()->array_function();
-
// Allocate result array.
- Object* result = Heap::AllocateJSObject(array_function);
+ Object* result = AllocateJSArray();
if (result->IsFailure()) return result;
JSArray* result_array = JSArray::cast(result);
- result = Heap::AllocateFixedArrayWithHoles(actualDeleteCount);
+ result = AllocateUninitializedFixedArray(actualDeleteCount);
if (result->IsFailure()) return result;
FixedArray* result_elms = FixedArray::cast(result);
FixedArray* elms = FixedArray::cast(array->elements());
- // Fetch the prototype.
- JSObject* prototype = JSObject::cast(array_function->prototype());
-
AssertNoAllocation no_gc;
- WriteBarrierMode mode = result_elms->GetWriteBarrierMode(no_gc);
-
// Fill newly created array.
- for (int k = 0; k < actualDeleteCount; k++) {
- result_elms->set(k,
- GetElementToMove(actualStart + k, elms, prototype),
- mode);
- }
+ CopyElements(&no_gc, result_elms, 0, elms, actualStart, actualDeleteCount);
// Set elements.
result_array->set_elements(result_elms);
int new_length = len - actualDeleteCount + itemCount;
- mode = elms->GetWriteBarrierMode(no_gc);
if (itemCount < actualDeleteCount) {
// Shrink the array.
- for (int k = actualStart; k < (len - actualDeleteCount); k++) {
- elms->set(k + itemCount,
- GetElementToMove(k + actualDeleteCount, elms, prototype),
- mode);
- }
-
- for (int k = len; k > new_length; k--) {
- elms->set(k - 1, Heap::the_hole_value());
- }
+ MoveElements(&no_gc,
+ elms, actualStart + itemCount,
+ elms, actualStart + actualDeleteCount,
+ (len - actualDeleteCount - actualStart));
+ FillWithHoles(elms, new_length, len);
} else if (itemCount > actualDeleteCount) {
// Currently fixed arrays cannot grow too big, so
// we should never hit this case.
if (new_length > elms->length()) {
// New backing storage is needed.
int capacity = new_length + (new_length >> 1) + 16;
- Object* obj = Heap::AllocateFixedArrayWithHoles(capacity);
+ Object* obj = AllocateUninitializedFixedArray(capacity);
if (obj->IsFailure()) return obj;
-
FixedArray* new_elms = FixedArray::cast(obj);
- mode = new_elms->GetWriteBarrierMode(no_gc);
// Copy the part before actualStart as is.
- for (int k = 0; k < actualStart; k++) {
- new_elms->set(k, elms->get(k), mode);
- }
+ CopyElements(&no_gc, new_elms, 0, elms, 0, actualStart);
+ FillWithHoles(new_elms, new_length, capacity);
source_elms = elms;
elms = new_elms;
array->set_elements(elms);
}
- for (int k = len - actualDeleteCount; k > actualStart; k--) {
- elms->set(k + itemCount - 1,
- GetElementToMove(k + actualDeleteCount - 1,
- source_elms,
- prototype),
- mode);
- }
+ MoveElements(&no_gc,
+ elms, actualStart + itemCount,
+ source_elms, actualStart + actualDeleteCount,
+ (len - actualDeleteCount - actualStart));
}
+ WriteBarrierMode mode = elms->GetWriteBarrierMode(no_gc);
for (int k = actualStart; k < actualStart + itemCount; k++) {
elms->set(k, args[3 + k - actualStart], mode);
}
}
+void Heap::RecordWrites(Address address, int start, int len) {
+ if (new_space_.Contains(address)) return;
+ ASSERT(!new_space_.FromSpaceContains(address));
+ for (int offset = start;
+ offset < start + len * kPointerSize;
+ offset += kPointerSize) {
+ SLOW_ASSERT(Contains(address + offset));
+ Page::SetRSet(address, offset);
+ }
+}
+
+
OldSpace* Heap::TargetSpace(HeapObject* object) {
InstanceType type = object->map()->instance_type();
AllocationSpace space = TargetSpaceId(type);
// Write barrier support for address[offset] = o.
static inline void RecordWrite(Address address, int offset);
+ // Write barrier support for address[start : start + len[ = o.
+ static inline void RecordWrites(Address address, int start, int len);
+
// Given an address occupied by a live code object, return that object.
static Object* FindCodeObject(Address a);
}
+Object** FixedArray::data_start() {
+ return HeapObject::RawField(this, kHeaderSize);
+}
+
+
bool DescriptorArray::IsEmpty() {
ASSERT(this == Heap::empty_descriptor_array() ||
this->length() > 2);
inline void set_null(int index);
inline void set_the_hole(int index);
+ // Gives access to raw memory which stores the array's data.
+ inline Object** data_start();
+
// Copy operations.
inline Object* Copy();
Object* CopySize(int new_length);
}
+static Object* Runtime_FinishArrayPrototypeSetup(Arguments args) {
+ HandleScope scope;
+ ASSERT(args.length() == 1);
+ CONVERT_ARG_CHECKED(JSArray, prototype, 0);
+ // This is necessary to enable fast checks for absence of elements
+ // on Array.prototype and below.
+ prototype->set_elements(Heap::empty_fixed_array());
+ return Smi::FromInt(0);
+}
+
+
static Object* Runtime_MaterializeRegExpLiteral(Arguments args) {
HandleScope scope;
ASSERT(args.length() == 4);
F(GetArgumentsProperty, 1, 1) \
F(ToFastProperties, 1, 1) \
F(ToSlowProperties, 1, 1) \
+ F(FinishArrayPrototypeSetup, 1, 1) \
\
F(IsInPrototypeChain, 2, 1) \
F(SetHiddenPrototype, 2, 1) \
--- /dev/null
+// Copyright 2010 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+////////////////////////////////////////////////////////////////////////
+// Tests below verify that elements set on Array.prototype's proto propagate
+// for various Array.prototype functions (like unshift, shift, etc.)
+// If add any new tests here, consider adding them to all other files:
+// array-elements-from-array-prototype.js
+// array-elements-from-array-prototype-chain.js
+// array-elements-from-object-prototype.js
+// those ideally should be identical modulo host of elements and
+// the way elements introduced.
+//
+// Note: they are put into a separate file as we need maximally clean
+// VM setup---some optimizations might be already turned off in
+// 'dirty' VM.
+////////////////////////////////////////////////////////////////////////
+
+var at3 = '@3'
+var at7 = '@7'
+
+Array.prototype.__proto__ = {3: at3};
+Array.prototype.__proto__.__proto__ = {7: at7};
+
+var a = new Array(13)
+
+assertEquals(at3, a[3])
+assertFalse(a.hasOwnProperty(3))
+
+assertEquals(at7, a[7])
+assertFalse(a.hasOwnProperty(7))
+
+assertEquals(undefined, a.shift(), 'hole should be returned as undefined')
+// Side-effects: Array.prototype[3] percolates into a[2] and Array.prototype[7[
+// into a[6], still visible at the corresponding indices.
+
+assertEquals(at3, a[2])
+assertTrue(a.hasOwnProperty(2))
+assertEquals(at3, a[3])
+assertFalse(a.hasOwnProperty(3))
+
+assertEquals(at7, a[6])
+assertTrue(a.hasOwnProperty(6))
+assertEquals(at7, a[7])
+assertFalse(a.hasOwnProperty(7))
+
+a.unshift('foo', 'bar')
+// Side-effects: Array.prototype[3] now percolates into a[5] and Array.prototype[7]
+// into a[9].
+
+assertEquals(at3, a[3])
+assertFalse(a.hasOwnProperty(3))
+assertEquals(at3, a[4])
+assertTrue(a.hasOwnProperty(4))
+assertEquals(at3, a[5])
+assertTrue(a.hasOwnProperty(5))
+
+assertEquals(undefined, a[6])
+assertFalse(a.hasOwnProperty(6))
+
+assertEquals(at7, a[7])
+assertFalse(a.hasOwnProperty(7))
+assertEquals(at7, a[8])
+assertTrue(a.hasOwnProperty(8))
+assertEquals(at7, a[9])
+assertTrue(a.hasOwnProperty(9))
+
+var sliced = a.slice(3, 10)
+// Slice must keep intact a and reify holes at indices 0--2 and 4--6.
+
+assertEquals(at3, a[3])
+assertFalse(a.hasOwnProperty(3))
+assertEquals(at3, a[4])
+assertTrue(a.hasOwnProperty(4))
+assertEquals(at3, a[5])
+assertTrue(a.hasOwnProperty(5))
+
+assertEquals(undefined, a[6])
+assertFalse(a.hasOwnProperty(6))
+
+assertEquals(at7, a[7])
+assertFalse(a.hasOwnProperty(7))
+assertEquals(at7, a[8])
+assertTrue(a.hasOwnProperty(8))
+assertEquals(at7, a[9])
+assertTrue(a.hasOwnProperty(9))
+
+assertEquals(at3, sliced[0])
+assertTrue(sliced.hasOwnProperty(0))
+assertEquals(at3, sliced[1])
+assertTrue(sliced.hasOwnProperty(1))
+assertEquals(at3, sliced[2])
+assertTrue(sliced.hasOwnProperty(2))
+
+// Note: sliced[3] comes directly from Array.prototype[3]
+assertEquals(at3, sliced[3]);
+assertFalse(sliced.hasOwnProperty(3))
+
+assertEquals(at7, sliced[4])
+assertTrue(sliced.hasOwnProperty(4))
+assertEquals(at7, sliced[5])
+assertTrue(sliced.hasOwnProperty(5))
+assertEquals(at7, sliced[6])
+assertTrue(sliced.hasOwnProperty(6))
+
+
+// Splice is too complicated the operation, start afresh.
+
+// Shrking array.
+var a0 = [0, 1, , , 4, 5, , , , 9]
+var result = a0.splice(4, 1)
+// Side-effects: everything before 4 is kept intact:
+
+assertEquals(0, a0[0])
+assertTrue(a0.hasOwnProperty(0))
+assertEquals(1, a0[1])
+assertTrue(a0.hasOwnProperty(1))
+assertEquals(undefined, a0[2])
+assertFalse(a0.hasOwnProperty(2))
+assertEquals(at3, a0[3])
+assertFalse(a0.hasOwnProperty(3))
+
+// 4 and above shifted left by one reifying at7 into a0[6] and keeping
+// a hole at a0[7]
+
+assertEquals(5, a0[4])
+assertTrue(a0.hasOwnProperty(4))
+assertEquals(undefined, a0[5])
+assertFalse(a0.hasOwnProperty(5))
+assertEquals(at7, a0[6])
+assertTrue(a0.hasOwnProperty(6))
+assertEquals(at7, a0[7])
+assertFalse(a0.hasOwnProperty(7))
+assertEquals(9, a0[8])
+assertTrue(a0.hasOwnProperty(8))
+
+// Growing array.
+var a1 = [0, 1, , , 4, 5, , , , 9]
+var result = a1.splice(4, 0, undefined)
+// Side-effects: everything before 4 is kept intact:
+
+assertEquals(0, a1[0])
+assertTrue(a1.hasOwnProperty(0))
+assertEquals(1, a1[1])
+assertTrue(a1.hasOwnProperty(1))
+assertEquals(undefined, a1[2])
+assertFalse(a1.hasOwnProperty(2))
+assertEquals(at3, a1[3])
+assertFalse(a1.hasOwnProperty(3))
+
+// Now owned undefined resides at 4 and rest is shifted right by one
+// reifying at7 into a0[8] and keeping a hole at a0[7].
+
+assertEquals(undefined, a1[4])
+assertTrue(a1.hasOwnProperty(4))
+assertEquals(4, a1[5])
+assertTrue(a1.hasOwnProperty(5))
+assertEquals(5, a1[6])
+assertTrue(a1.hasOwnProperty(6))
+assertEquals(at7, a1[7])
+assertFalse(a1.hasOwnProperty(7))
+assertEquals(at7, a1[8])
+assertTrue(a1.hasOwnProperty(8))
+assertEquals(undefined, a1[9])
+assertFalse(a1.hasOwnProperty(9))
+assertEquals(9, a1[10])
+assertTrue(a1.hasOwnProperty(10))
--- /dev/null
+// Copyright 2010 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+////////////////////////////////////////////////////////////////////////
+// Tests below verify that elements set on Array.prototype propagate
+// for various Array.prototype functions (like unshift, shift, etc.)
+// If add any new tests here, consider adding them to all other files:
+// array-elements-from-array-prototype.js
+// array-elements-from-array-prototype-chain.js
+// array-elements-from-object-prototype.js
+// those ideally should be identical modulo host of elements and
+// the way elements introduced.
+//
+// Note: they are put into a separate file as we need maximally clean
+// VM setup---some optimizations might be already turned off in
+// 'dirty' VM.
+////////////////////////////////////////////////////////////////////////
+
+var at3 = '@3'
+var at7 = '@7'
+
+Array.prototype[3] = at3
+Array.prototype[7] = at7
+
+var a = new Array(13)
+
+assertEquals(at3, a[3])
+assertFalse(a.hasOwnProperty(3))
+
+assertEquals(at7, a[7])
+assertFalse(a.hasOwnProperty(7))
+
+assertEquals(undefined, a.shift(), 'hole should be returned as undefined')
+// Side-effects: Array.prototype[3] percolates into a[2] and Array.prototype[7[
+// into a[6], still visible at the corresponding indices.
+
+assertEquals(at3, a[2])
+assertTrue(a.hasOwnProperty(2))
+assertEquals(at3, a[3])
+assertFalse(a.hasOwnProperty(3))
+
+assertEquals(at7, a[6])
+assertTrue(a.hasOwnProperty(6))
+assertEquals(at7, a[7])
+assertFalse(a.hasOwnProperty(7))
+
+a.unshift('foo', 'bar')
+// Side-effects: Array.prototype[3] now percolates into a[5] and Array.prototype[7]
+// into a[9].
+
+assertEquals(at3, a[3])
+assertFalse(a.hasOwnProperty(3))
+assertEquals(at3, a[4])
+assertTrue(a.hasOwnProperty(4))
+assertEquals(at3, a[5])
+assertTrue(a.hasOwnProperty(5))
+
+assertEquals(undefined, a[6])
+assertFalse(a.hasOwnProperty(6))
+
+assertEquals(at7, a[7])
+assertFalse(a.hasOwnProperty(7))
+assertEquals(at7, a[8])
+assertTrue(a.hasOwnProperty(8))
+assertEquals(at7, a[9])
+assertTrue(a.hasOwnProperty(9))
+
+var sliced = a.slice(3, 10)
+// Slice must keep intact a and reify holes at indices 0--2 and 4--6.
+
+assertEquals(at3, a[3])
+assertFalse(a.hasOwnProperty(3))
+assertEquals(at3, a[4])
+assertTrue(a.hasOwnProperty(4))
+assertEquals(at3, a[5])
+assertTrue(a.hasOwnProperty(5))
+
+assertEquals(undefined, a[6])
+assertFalse(a.hasOwnProperty(6))
+
+assertEquals(at7, a[7])
+assertFalse(a.hasOwnProperty(7))
+assertEquals(at7, a[8])
+assertTrue(a.hasOwnProperty(8))
+assertEquals(at7, a[9])
+assertTrue(a.hasOwnProperty(9))
+
+assertEquals(at3, sliced[0])
+assertTrue(sliced.hasOwnProperty(0))
+assertEquals(at3, sliced[1])
+assertTrue(sliced.hasOwnProperty(1))
+assertEquals(at3, sliced[2])
+assertTrue(sliced.hasOwnProperty(2))
+
+// Note: sliced[3] comes directly from Array.prototype[3]
+assertEquals(at3, sliced[3]);
+assertFalse(sliced.hasOwnProperty(3))
+
+assertEquals(at7, sliced[4])
+assertTrue(sliced.hasOwnProperty(4))
+assertEquals(at7, sliced[5])
+assertTrue(sliced.hasOwnProperty(5))
+assertEquals(at7, sliced[6])
+assertTrue(sliced.hasOwnProperty(6))
+
+
+// Splice is too complicated the operation, start afresh.
+
+// Shrking array.
+var a0 = [0, 1, , , 4, 5, , , , 9]
+var result = a0.splice(4, 1)
+// Side-effects: everything before 4 is kept intact:
+
+assertEquals(0, a0[0])
+assertTrue(a0.hasOwnProperty(0))
+assertEquals(1, a0[1])
+assertTrue(a0.hasOwnProperty(1))
+assertEquals(undefined, a0[2])
+assertFalse(a0.hasOwnProperty(2))
+assertEquals(at3, a0[3])
+assertFalse(a0.hasOwnProperty(3))
+
+// 4 and above shifted left by one reifying at7 into a0[6] and keeping
+// a hole at a0[7]
+
+assertEquals(5, a0[4])
+assertTrue(a0.hasOwnProperty(4))
+assertEquals(undefined, a0[5])
+assertFalse(a0.hasOwnProperty(5))
+assertEquals(at7, a0[6])
+assertTrue(a0.hasOwnProperty(6))
+assertEquals(at7, a0[7])
+assertFalse(a0.hasOwnProperty(7))
+assertEquals(9, a0[8])
+assertTrue(a0.hasOwnProperty(8))
+
+// Growing array.
+var a1 = [0, 1, , , 4, 5, , , , 9]
+var result = a1.splice(4, 0, undefined)
+// Side-effects: everything before 4 is kept intact:
+
+assertEquals(0, a1[0])
+assertTrue(a1.hasOwnProperty(0))
+assertEquals(1, a1[1])
+assertTrue(a1.hasOwnProperty(1))
+assertEquals(undefined, a1[2])
+assertFalse(a1.hasOwnProperty(2))
+assertEquals(at3, a1[3])
+assertFalse(a1.hasOwnProperty(3))
+
+// Now owned undefined resides at 4 and rest is shifted right by one
+// reifying at7 into a0[8] and keeping a hole at a0[7].
+
+assertEquals(undefined, a1[4])
+assertTrue(a1.hasOwnProperty(4))
+assertEquals(4, a1[5])
+assertTrue(a1.hasOwnProperty(5))
+assertEquals(5, a1[6])
+assertTrue(a1.hasOwnProperty(6))
+assertEquals(at7, a1[7])
+assertFalse(a1.hasOwnProperty(7))
+assertEquals(at7, a1[8])
+assertTrue(a1.hasOwnProperty(8))
+assertEquals(undefined, a1[9])
+assertFalse(a1.hasOwnProperty(9))
+assertEquals(9, a1[10])
+assertTrue(a1.hasOwnProperty(10))
--- /dev/null
+// Copyright 2010 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+////////////////////////////////////////////////////////////////////////
+// Tests below verify that elements set on Object.prototype propagate
+// for various Array.prototype functions (like unshift, shift, etc.)
+// If add any new tests here, consider adding them to all other files:
+// array-elements-from-array-prototype.js
+// array-elements-from-array-prototype-chain.js
+// array-elements-from-object-prototype.js
+// those ideally should be identical modulo host of elements and
+// the way elements introduced.
+//
+// Note: they are put into a separate file as we need maximally clean
+// VM setup---some optimizations might be already turned off in
+// 'dirty' VM.
+////////////////////////////////////////////////////////////////////////
+
+var at3 = '@3'
+var at7 = '@7'
+
+Object.prototype[3] = at3
+Object.prototype[7] = at7
+
+var a = new Array(13)
+
+assertEquals(at3, a[3])
+assertFalse(a.hasOwnProperty(3))
+
+assertEquals(at7, a[7])
+assertFalse(a.hasOwnProperty(7))
+
+assertEquals(undefined, a.shift(), 'hole should be returned as undefined')
+// Side-effects: Array.prototype[3] percolates into a[2] and Array.prototype[7[
+// into a[6], still visible at the corresponding indices.
+
+assertEquals(at3, a[2])
+assertTrue(a.hasOwnProperty(2))
+assertEquals(at3, a[3])
+assertFalse(a.hasOwnProperty(3))
+
+assertEquals(at7, a[6])
+assertTrue(a.hasOwnProperty(6))
+assertEquals(at7, a[7])
+assertFalse(a.hasOwnProperty(7))
+
+a.unshift('foo', 'bar')
+// Side-effects: Array.prototype[3] now percolates into a[5] and Array.prototype[7]
+// into a[9].
+
+assertEquals(at3, a[3])
+assertFalse(a.hasOwnProperty(3))
+assertEquals(at3, a[4])
+assertTrue(a.hasOwnProperty(4))
+assertEquals(at3, a[5])
+assertTrue(a.hasOwnProperty(5))
+
+assertEquals(undefined, a[6])
+assertFalse(a.hasOwnProperty(6))
+
+assertEquals(at7, a[7])
+assertFalse(a.hasOwnProperty(7))
+assertEquals(at7, a[8])
+assertTrue(a.hasOwnProperty(8))
+assertEquals(at7, a[9])
+assertTrue(a.hasOwnProperty(9))
+
+var sliced = a.slice(3, 10)
+// Slice must keep intact a and reify holes at indices 0--2 and 4--6.
+
+assertEquals(at3, a[3])
+assertFalse(a.hasOwnProperty(3))
+assertEquals(at3, a[4])
+assertTrue(a.hasOwnProperty(4))
+assertEquals(at3, a[5])
+assertTrue(a.hasOwnProperty(5))
+
+assertEquals(undefined, a[6])
+assertFalse(a.hasOwnProperty(6))
+
+assertEquals(at7, a[7])
+assertFalse(a.hasOwnProperty(7))
+assertEquals(at7, a[8])
+assertTrue(a.hasOwnProperty(8))
+assertEquals(at7, a[9])
+assertTrue(a.hasOwnProperty(9))
+
+assertEquals(at3, sliced[0])
+assertTrue(sliced.hasOwnProperty(0))
+assertEquals(at3, sliced[1])
+assertTrue(sliced.hasOwnProperty(1))
+assertEquals(at3, sliced[2])
+assertTrue(sliced.hasOwnProperty(2))
+
+// Note: sliced[3] comes directly from Array.prototype[3]
+assertEquals(at3, sliced[3]);
+assertFalse(sliced.hasOwnProperty(3))
+
+assertEquals(at7, sliced[4])
+assertTrue(sliced.hasOwnProperty(4))
+assertEquals(at7, sliced[5])
+assertTrue(sliced.hasOwnProperty(5))
+assertEquals(at7, sliced[6])
+assertTrue(sliced.hasOwnProperty(6))
+
+
+// Splice is too complicated the operation, start afresh.
+
+// Shrking array.
+var a0 = [0, 1, , , 4, 5, , , , 9]
+var result = a0.splice(4, 1)
+// Side-effects: everything before 4 is kept intact:
+
+assertEquals(0, a0[0])
+assertTrue(a0.hasOwnProperty(0))
+assertEquals(1, a0[1])
+assertTrue(a0.hasOwnProperty(1))
+assertEquals(undefined, a0[2])
+assertFalse(a0.hasOwnProperty(2))
+assertEquals(at3, a0[3])
+assertFalse(a0.hasOwnProperty(3))
+
+// 4 and above shifted left by one reifying at7 into a0[6] and keeping
+// a hole at a0[7]
+
+assertEquals(5, a0[4])
+assertTrue(a0.hasOwnProperty(4))
+assertEquals(undefined, a0[5])
+assertFalse(a0.hasOwnProperty(5))
+assertEquals(at7, a0[6])
+assertTrue(a0.hasOwnProperty(6))
+assertEquals(at7, a0[7])
+assertFalse(a0.hasOwnProperty(7))
+assertEquals(9, a0[8])
+assertTrue(a0.hasOwnProperty(8))
+
+// Growing array.
+var a1 = [0, 1, , , 4, 5, , , , 9]
+var result = a1.splice(4, 0, undefined)
+// Side-effects: everything before 4 is kept intact:
+
+assertEquals(0, a1[0])
+assertTrue(a1.hasOwnProperty(0))
+assertEquals(1, a1[1])
+assertTrue(a1.hasOwnProperty(1))
+assertEquals(undefined, a1[2])
+assertFalse(a1.hasOwnProperty(2))
+assertEquals(at3, a1[3])
+assertFalse(a1.hasOwnProperty(3))
+
+// Now owned undefined resides at 4 and rest is shifted right by one
+// reifying at7 into a0[8] and keeping a hole at a0[7].
+
+assertEquals(undefined, a1[4])
+assertTrue(a1.hasOwnProperty(4))
+assertEquals(4, a1[5])
+assertTrue(a1.hasOwnProperty(5))
+assertEquals(5, a1[6])
+assertTrue(a1.hasOwnProperty(6))
+assertEquals(at7, a1[7])
+assertFalse(a1.hasOwnProperty(7))
+assertEquals(at7, a1[8])
+assertTrue(a1.hasOwnProperty(8))
+assertEquals(undefined, a1[9])
+assertFalse(a1.hasOwnProperty(9))
+assertEquals(9, a1[10])
+assertTrue(a1.hasOwnProperty(10))
assertEquals(bigNum + 7, array.length);
}
})();
+
+(function() {
+ for (var i = 0; i < 7; i++) {
+ var a = [7, 8, 9];
+ a.splice(0, 0, 1, 2, 3, 4, 5, 6);
+ assertEquals([1, 2, 3, 4, 5, 6, 7, 8, 9], a);
+ assertFalse(a.hasOwnProperty(10));
+ assertEquals(undefined, a[10]);
+ }
+})();
assertEquals(bigNum + 7, new Array(bigNum).unshift(1, 2, 3, 4, 5, 6, 7));
}
})();
+
+(function() {
+ for (var i = 0; i < 7; i++) {
+ var a = [6, 7, 8, 9];
+ a.unshift(1, 2, 3, 4, 5);
+ assertEquals([1, 2, 3, 4, 5, 6, 7, 8, 9], a);
+ }
+})();
"DeclareGlobals": true,
"PromoteScheduledException": true,
- "DeleteHandleScopeExtensions": true
+ "DeleteHandleScopeExtensions": true,
+
+ // That can only be invoked on Array.prototype.
+ "FinishArrayPrototypeSetup": true
};
var currentlyUncallable = {
"every", "map", "indexOf", "lastIndexOf", "reduce", "reduceRight"];
CheckJSCSemantics(Array.prototype, array, "Array prototype");
+var old_Array_prototype = Array.prototype;
+var new_Array_prototype = {};
+for (var i = 0; i < 7; i++) {
+ Array.prototype = new_Array_prototype;
+ assertEquals(old_Array_prototype, Array.prototype);
+}
+
array = [
"toString", "toDateString", "toTimeString", "toLocaleString",
"toLocaleDateString", "toLocaleTimeString", "valueOf", "getTime",
"__lookupGetter__", "__defineSetter__", "__lookupSetter__"];
CheckEcmaSemantics(Object.prototype, array, "Object prototype");
+var old_Object_prototype = Object.prototype;
+var new_Object_prototype = {};
+for (var i = 0; i < 7; i++) {
+ Object.prototype = new_Object_prototype;
+ assertEquals(old_Object_prototype, Object.prototype);
+}
+
array = [
"toString", "valueOf", "toJSON"];
CheckEcmaSemantics(Boolean.prototype, array, "Boolean prototype");