Upgrade V8 to version 4.9.385.28
https://chromium.googlesource.com/v8/v8/+/4.9.385.28
FPIIM-449
Change-Id: I4b2e74289d4bf3667f2f3dc8aa2e541f63e26eb4
diff --git a/src/elements.cc b/src/elements.cc
index 4e9a052..d4d80db 100644
--- a/src/elements.cc
+++ b/src/elements.cc
@@ -2,12 +2,13 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "src/v8.h"
+#include "src/elements.h"
#include "src/arguments.h"
#include "src/conversions.h"
-#include "src/elements.h"
-#include "src/objects.h"
+#include "src/factory.h"
+#include "src/messages.h"
+#include "src/objects-inl.h"
#include "src/utils.h"
// Each concrete ElementsAccessor can handle exactly one ElementsKind,
@@ -26,15 +27,6 @@
// - FastPackedDoubleElementsAccessor
// - FastHoleyDoubleElementsAccessor
// - TypedElementsAccessor: template, with instantiations:
-// - ExternalInt8ElementsAccessor
-// - ExternalUint8ElementsAccessor
-// - ExternalInt16ElementsAccessor
-// - ExternalUint16ElementsAccessor
-// - ExternalInt32ElementsAccessor
-// - ExternalUint32ElementsAccessor
-// - ExternalFloat32ElementsAccessor
-// - ExternalFloat64ElementsAccessor
-// - ExternalUint8ClampedElementsAccessor
// - FixedUint8ElementsAccessor
// - FixedInt8ElementsAccessor
// - FixedUint16ElementsAccessor
@@ -46,62 +38,49 @@
// - FixedUint8ClampedElementsAccessor
// - DictionaryElementsAccessor
// - SloppyArgumentsElementsAccessor
+// - FastSloppyArgumentsElementsAccessor
+// - SlowSloppyArgumentsElementsAccessor
namespace v8 {
namespace internal {
+namespace {
+
+
static const int kPackedSizeNotKnown = -1;
+enum Where { AT_START, AT_END };
+
// First argument in list is the accessor class, the second argument is the
// accessor ElementsKind, and the third is the backing store class. Use the
// fast element handler for smi-only arrays. The implementation is currently
// identical. Note that the order must match that of the ElementsKind enum for
// the |accessor_array[]| below to work.
-#define ELEMENTS_LIST(V) \
- V(FastPackedSmiElementsAccessor, FAST_SMI_ELEMENTS, FixedArray) \
- V(FastHoleySmiElementsAccessor, FAST_HOLEY_SMI_ELEMENTS, \
- FixedArray) \
- V(FastPackedObjectElementsAccessor, FAST_ELEMENTS, FixedArray) \
- V(FastHoleyObjectElementsAccessor, FAST_HOLEY_ELEMENTS, FixedArray) \
- V(FastPackedDoubleElementsAccessor, FAST_DOUBLE_ELEMENTS, \
- FixedDoubleArray) \
- V(FastHoleyDoubleElementsAccessor, FAST_HOLEY_DOUBLE_ELEMENTS, \
- FixedDoubleArray) \
- V(DictionaryElementsAccessor, DICTIONARY_ELEMENTS, \
- SeededNumberDictionary) \
- V(SloppyArgumentsElementsAccessor, SLOPPY_ARGUMENTS_ELEMENTS, \
- FixedArray) \
- V(ExternalInt8ElementsAccessor, EXTERNAL_INT8_ELEMENTS, \
- ExternalInt8Array) \
- V(ExternalUint8ElementsAccessor, \
- EXTERNAL_UINT8_ELEMENTS, ExternalUint8Array) \
- V(ExternalInt16ElementsAccessor, EXTERNAL_INT16_ELEMENTS, \
- ExternalInt16Array) \
- V(ExternalUint16ElementsAccessor, \
- EXTERNAL_UINT16_ELEMENTS, ExternalUint16Array) \
- V(ExternalInt32ElementsAccessor, EXTERNAL_INT32_ELEMENTS, \
- ExternalInt32Array) \
- V(ExternalUint32ElementsAccessor, \
- EXTERNAL_UINT32_ELEMENTS, ExternalUint32Array) \
- V(ExternalFloat32ElementsAccessor, \
- EXTERNAL_FLOAT32_ELEMENTS, ExternalFloat32Array) \
- V(ExternalFloat64ElementsAccessor, \
- EXTERNAL_FLOAT64_ELEMENTS, ExternalFloat64Array) \
- V(ExternalUint8ClampedElementsAccessor, \
- EXTERNAL_UINT8_CLAMPED_ELEMENTS, \
- ExternalUint8ClampedArray) \
- V(FixedUint8ElementsAccessor, UINT8_ELEMENTS, FixedUint8Array) \
- V(FixedInt8ElementsAccessor, INT8_ELEMENTS, FixedInt8Array) \
- V(FixedUint16ElementsAccessor, UINT16_ELEMENTS, FixedUint16Array) \
- V(FixedInt16ElementsAccessor, INT16_ELEMENTS, FixedInt16Array) \
- V(FixedUint32ElementsAccessor, UINT32_ELEMENTS, FixedUint32Array) \
- V(FixedInt32ElementsAccessor, INT32_ELEMENTS, FixedInt32Array) \
- V(FixedFloat32ElementsAccessor, FLOAT32_ELEMENTS, FixedFloat32Array) \
- V(FixedFloat64ElementsAccessor, FLOAT64_ELEMENTS, FixedFloat64Array) \
- V(FixedUint8ClampedElementsAccessor, UINT8_CLAMPED_ELEMENTS, \
+#define ELEMENTS_LIST(V) \
+ V(FastPackedSmiElementsAccessor, FAST_SMI_ELEMENTS, FixedArray) \
+ V(FastHoleySmiElementsAccessor, FAST_HOLEY_SMI_ELEMENTS, FixedArray) \
+ V(FastPackedObjectElementsAccessor, FAST_ELEMENTS, FixedArray) \
+ V(FastHoleyObjectElementsAccessor, FAST_HOLEY_ELEMENTS, FixedArray) \
+ V(FastPackedDoubleElementsAccessor, FAST_DOUBLE_ELEMENTS, FixedDoubleArray) \
+ V(FastHoleyDoubleElementsAccessor, FAST_HOLEY_DOUBLE_ELEMENTS, \
+ FixedDoubleArray) \
+ V(DictionaryElementsAccessor, DICTIONARY_ELEMENTS, SeededNumberDictionary) \
+ V(FastSloppyArgumentsElementsAccessor, FAST_SLOPPY_ARGUMENTS_ELEMENTS, \
+ FixedArray) \
+ V(SlowSloppyArgumentsElementsAccessor, SLOW_SLOPPY_ARGUMENTS_ELEMENTS, \
+ FixedArray) \
+ V(FixedUint8ElementsAccessor, UINT8_ELEMENTS, FixedUint8Array) \
+ V(FixedInt8ElementsAccessor, INT8_ELEMENTS, FixedInt8Array) \
+ V(FixedUint16ElementsAccessor, UINT16_ELEMENTS, FixedUint16Array) \
+ V(FixedInt16ElementsAccessor, INT16_ELEMENTS, FixedInt16Array) \
+ V(FixedUint32ElementsAccessor, UINT32_ELEMENTS, FixedUint32Array) \
+ V(FixedInt32ElementsAccessor, INT32_ELEMENTS, FixedInt32Array) \
+ V(FixedFloat32ElementsAccessor, FLOAT32_ELEMENTS, FixedFloat32Array) \
+ V(FixedFloat64ElementsAccessor, FLOAT64_ELEMENTS, FixedFloat64Array) \
+ V(FixedUint8ClampedElementsAccessor, UINT8_CLAMPED_ELEMENTS, \
FixedUint8ClampedArray)
@@ -120,39 +99,17 @@
#undef ELEMENTS_TRAITS
-ElementsAccessor** ElementsAccessor::elements_accessors_ = NULL;
-
-
-static bool HasKey(Handle<FixedArray> array, Handle<Object> key_handle) {
- DisallowHeapAllocation no_gc;
- Object* key = *key_handle;
- int len0 = array->length();
- for (int i = 0; i < len0; i++) {
- Object* element = array->get(i);
- if (element->IsSmi() && element == key) return true;
- if (element->IsString() &&
- key->IsString() && String::cast(element)->Equals(String::cast(key))) {
- return true;
- }
- }
- return false;
-}
-
-
MUST_USE_RESULT
-static MaybeHandle<Object> ThrowArrayLengthRangeError(Isolate* isolate) {
- THROW_NEW_ERROR(isolate, NewRangeError("invalid_array_length",
- HandleVector<Object>(NULL, 0)),
+MaybeHandle<Object> ThrowArrayLengthRangeError(Isolate* isolate) {
+ THROW_NEW_ERROR(isolate, NewRangeError(MessageTemplate::kInvalidArrayLength),
Object);
}
-static void CopyObjectToObjectElements(FixedArrayBase* from_base,
- ElementsKind from_kind,
- uint32_t from_start,
- FixedArrayBase* to_base,
- ElementsKind to_kind, uint32_t to_start,
- int raw_copy_size) {
+void CopyObjectToObjectElements(FixedArrayBase* from_base,
+ ElementsKind from_kind, uint32_t from_start,
+ FixedArrayBase* to_base, ElementsKind to_kind,
+ uint32_t to_start, int raw_copy_size) {
DCHECK(to_base->map() !=
from_base->GetIsolate()->heap()->fixed_cow_array_map());
DisallowHeapAllocation no_allocation;
@@ -179,20 +136,14 @@
FixedArray* to = FixedArray::cast(to_base);
DCHECK(IsFastSmiOrObjectElementsKind(from_kind));
DCHECK(IsFastSmiOrObjectElementsKind(to_kind));
- Address to_address = to->address() + FixedArray::kHeaderSize;
- Address from_address = from->address() + FixedArray::kHeaderSize;
- CopyWords(reinterpret_cast<Object**>(to_address) + to_start,
- reinterpret_cast<Object**>(from_address) + from_start,
- static_cast<size_t>(copy_size));
- if (IsFastObjectElementsKind(from_kind) &&
- IsFastObjectElementsKind(to_kind)) {
- Heap* heap = from->GetHeap();
- if (!heap->InNewSpace(to)) {
- heap->RecordWrites(to->address(),
- to->OffsetOfElementAt(to_start),
- copy_size);
- }
- heap->incremental_marking()->RecordWrites(to);
+
+ WriteBarrierMode write_barrier_mode =
+ (IsFastObjectElementsKind(from_kind) && IsFastObjectElementsKind(to_kind))
+ ? UPDATE_WRITE_BARRIER
+ : SKIP_WRITE_BARRIER;
+ for (int i = 0; i < copy_size; i++) {
+ Object* value = from->get(from_start + i);
+ to->set(to_start + i, value, write_barrier_mode);
}
}
@@ -203,7 +154,6 @@
DisallowHeapAllocation no_allocation;
SeededNumberDictionary* from = SeededNumberDictionary::cast(from_base);
int copy_size = raw_copy_size;
- Heap* heap = from->GetHeap();
if (raw_copy_size < 0) {
DCHECK(raw_copy_size == ElementsAccessor::kCopyToEnd ||
raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole);
@@ -226,24 +176,19 @@
if (to_start + copy_size > to_length) {
copy_size = to_length - to_start;
}
+ WriteBarrierMode write_barrier_mode = IsFastObjectElementsKind(to_kind)
+ ? UPDATE_WRITE_BARRIER
+ : SKIP_WRITE_BARRIER;
for (int i = 0; i < copy_size; i++) {
int entry = from->FindEntry(i + from_start);
if (entry != SeededNumberDictionary::kNotFound) {
Object* value = from->ValueAt(entry);
DCHECK(!value->IsTheHole());
- to->set(i + to_start, value, SKIP_WRITE_BARRIER);
+ to->set(i + to_start, value, write_barrier_mode);
} else {
to->set_the_hole(i + to_start);
}
}
- if (IsFastObjectElementsKind(to_kind)) {
- if (!heap->InNewSpace(to)) {
- heap->RecordWrites(to->address(),
- to->OffsetOfElementAt(to_start),
- copy_size);
- }
- heap->incremental_marking()->RecordWrites(to);
- }
}
@@ -253,9 +198,7 @@
static void CopyDoubleToObjectElements(FixedArrayBase* from_base,
uint32_t from_start,
FixedArrayBase* to_base,
- ElementsKind to_kind, uint32_t to_start,
- int raw_copy_size) {
- DCHECK(IsFastSmiOrObjectElementsKind(to_kind));
+ uint32_t to_start, int raw_copy_size) {
int copy_size = raw_copy_size;
if (raw_copy_size < 0) {
DisallowHeapAllocation no_allocation;
@@ -276,6 +219,7 @@
}
}
}
+
DCHECK((copy_size + static_cast<int>(to_start)) <= to_base->length() &&
(copy_size + static_cast<int>(from_start)) <= from_base->length());
if (copy_size == 0) return;
@@ -285,12 +229,15 @@
Isolate* isolate = from_base->GetIsolate();
Handle<FixedDoubleArray> from(FixedDoubleArray::cast(from_base), isolate);
Handle<FixedArray> to(FixedArray::cast(to_base), isolate);
- for (int i = 0; i < copy_size; ++i) {
+
+ // create an outer loop to not waste too much time on creating HandleScopes
+ // on the other hand we might overflow a single handle scope depending on
+ // the copy_size
+ int offset = 0;
+ while (offset < copy_size) {
HandleScope scope(isolate);
- if (IsFastSmiElementsKind(to_kind)) {
- UNIMPLEMENTED();
- } else {
- DCHECK(IsFastObjectElementsKind(to_kind));
+ offset += 100;
+ for (int i = offset - 100; i < offset && i < copy_size; ++i) {
Handle<Object> value = FixedDoubleArray::get(from, i + from_start);
to->set(i + to_start, *value, UPDATE_WRITE_BARRIER);
}
@@ -481,8 +428,8 @@
}
StackFrame* raw_frame = it.frame();
if (raw_frame->is_internal()) {
- Code* apply_builtin = isolate->builtins()->builtin(
- Builtins::kFunctionApply);
+ Code* apply_builtin =
+ isolate->builtins()->builtin(Builtins::kFunctionPrototypeApply);
if (raw_frame->unchecked_code() == apply_builtin) {
PrintF("apply from ");
it.Advance();
@@ -493,46 +440,6 @@
}
-void CheckArrayAbuse(Handle<JSObject> obj, const char* op, uint32_t key,
- bool allow_appending) {
- DisallowHeapAllocation no_allocation;
- Object* raw_length = NULL;
- const char* elements_type = "array";
- if (obj->IsJSArray()) {
- JSArray* array = JSArray::cast(*obj);
- raw_length = array->length();
- } else {
- raw_length = Smi::FromInt(obj->elements()->length());
- elements_type = "object";
- }
-
- if (raw_length->IsNumber()) {
- double n = raw_length->Number();
- if (FastI2D(FastD2UI(n)) == n) {
- int32_t int32_length = DoubleToInt32(n);
- uint32_t compare_length = static_cast<uint32_t>(int32_length);
- if (allow_appending) compare_length++;
- if (key >= compare_length) {
- PrintF("[OOB %s %s (%s length = %d, element accessed = %d) in ",
- elements_type, op, elements_type,
- static_cast<int>(int32_length),
- static_cast<int>(key));
- TraceTopFrame(obj->GetIsolate());
- PrintF("]\n");
- }
- } else {
- PrintF("[%s elements length not integer value in ", elements_type);
- TraceTopFrame(obj->GetIsolate());
- PrintF("]\n");
- }
- } else {
- PrintF("[%s elements length not a number in ", elements_type);
- TraceTopFrame(obj->GetIsolate());
- PrintF("]\n");
- }
-}
-
-
// Base class for element handler implementations. Contains the
// the common logic for objects with different ElementsKinds.
// Subclasses must specialize method for which the element
@@ -553,14 +460,14 @@
template <typename ElementsAccessorSubclass,
typename ElementsTraitsParam>
class ElementsAccessorBase : public ElementsAccessor {
- protected:
+ public:
explicit ElementsAccessorBase(const char* name)
: ElementsAccessor(name) { }
typedef ElementsTraitsParam ElementsTraits;
typedef typename ElementsTraitsParam::BackingStore BackingStore;
- ElementsKind kind() const FINAL { return ElementsTraits::Kind; }
+ static ElementsKind kind() { return ElementsTraits::Kind; }
static void ValidateContents(Handle<JSObject> holder, int length) {
}
@@ -582,119 +489,324 @@
ElementsAccessorSubclass::ValidateContents(holder, length);
}
- void Validate(Handle<JSObject> holder) FINAL {
+ void Validate(Handle<JSObject> holder) final {
DisallowHeapAllocation no_gc;
ElementsAccessorSubclass::ValidateImpl(holder);
}
- static bool HasElementImpl(Handle<Object> receiver,
- Handle<JSObject> holder,
- uint32_t key,
- Handle<FixedArrayBase> backing_store) {
- return ElementsAccessorSubclass::GetAttributesImpl(
- receiver, holder, key, backing_store) != ABSENT;
+ bool IsPacked(Handle<JSObject> holder, Handle<FixedArrayBase> backing_store,
+ uint32_t start, uint32_t end) final {
+ return ElementsAccessorSubclass::IsPackedImpl(holder, backing_store, start,
+ end);
}
- virtual bool HasElement(Handle<Object> receiver, Handle<JSObject> holder,
- uint32_t key,
- Handle<FixedArrayBase> backing_store) FINAL {
- return ElementsAccessorSubclass::HasElementImpl(
- receiver, holder, key, backing_store);
+ static bool IsPackedImpl(Handle<JSObject> holder,
+ Handle<FixedArrayBase> backing_store, uint32_t start,
+ uint32_t end) {
+ if (IsFastPackedElementsKind(kind())) return true;
+ for (uint32_t i = start; i < end; i++) {
+ if (!ElementsAccessorSubclass::HasElementImpl(holder, i, backing_store,
+ ALL_PROPERTIES)) {
+ return false;
+ }
+ }
+ return true;
}
- MUST_USE_RESULT virtual MaybeHandle<Object> Get(
- Handle<Object> receiver, Handle<JSObject> holder, uint32_t key,
- Handle<FixedArrayBase> backing_store) FINAL {
- if (!IsExternalArrayElementsKind(ElementsTraits::Kind) &&
- FLAG_trace_js_array_abuse) {
- CheckArrayAbuse(holder, "elements read", key);
+ static void TryTransitionResultArrayToPacked(Handle<JSArray> array) {
+ if (!IsHoleyElementsKind(kind())) return;
+ int length = Smi::cast(array->length())->value();
+ Handle<FixedArrayBase> backing_store(array->elements());
+ if (!ElementsAccessorSubclass::IsPackedImpl(array, backing_store, 0,
+ length)) {
+ return;
+ }
+ ElementsKind packed_kind = GetPackedElementsKind(kind());
+ Handle<Map> new_map =
+ JSObject::GetElementsTransitionMap(array, packed_kind);
+ JSObject::MigrateToMap(array, new_map);
+ if (FLAG_trace_elements_transitions) {
+ JSObject::PrintElementsTransition(stdout, array, kind(), backing_store,
+ packed_kind, backing_store);
+ }
+ }
+
+ bool HasElement(Handle<JSObject> holder, uint32_t index,
+ Handle<FixedArrayBase> backing_store,
+ PropertyFilter filter) final {
+ return ElementsAccessorSubclass::HasElementImpl(holder, index,
+ backing_store, filter);
+ }
+
+ static bool HasElementImpl(Handle<JSObject> holder, uint32_t index,
+ Handle<FixedArrayBase> backing_store,
+ PropertyFilter filter) {
+ return ElementsAccessorSubclass::GetEntryForIndexImpl(
+ *holder, *backing_store, index, filter) != kMaxUInt32;
+ }
+
+ Handle<Object> Get(Handle<FixedArrayBase> backing_store,
+ uint32_t entry) final {
+ return ElementsAccessorSubclass::GetImpl(backing_store, entry);
+ }
+
+ static Handle<Object> GetImpl(Handle<FixedArrayBase> backing_store,
+ uint32_t entry) {
+ uint32_t index = GetIndexForEntryImpl(*backing_store, entry);
+ return BackingStore::get(Handle<BackingStore>::cast(backing_store), index);
+ }
+
+ void Set(FixedArrayBase* backing_store, uint32_t entry, Object* value) final {
+ ElementsAccessorSubclass::SetImpl(backing_store, entry, value);
+ }
+
+ static inline void SetImpl(FixedArrayBase* backing_store, uint32_t entry,
+ Object* value) {
+ UNREACHABLE();
+ }
+
+
+ static inline void SetImpl(FixedArrayBase* backing_store, uint32_t entry,
+ Object* value, WriteBarrierMode mode) {
+ UNREACHABLE();
+ }
+
+ void Reconfigure(Handle<JSObject> object, Handle<FixedArrayBase> store,
+ uint32_t entry, Handle<Object> value,
+ PropertyAttributes attributes) final {
+ ElementsAccessorSubclass::ReconfigureImpl(object, store, entry, value,
+ attributes);
+ }
+
+ static void ReconfigureImpl(Handle<JSObject> object,
+ Handle<FixedArrayBase> store, uint32_t entry,
+ Handle<Object> value,
+ PropertyAttributes attributes) {
+ UNREACHABLE();
+ }
+
+ void Add(Handle<JSObject> object, uint32_t index, Handle<Object> value,
+ PropertyAttributes attributes, uint32_t new_capacity) final {
+ ElementsAccessorSubclass::AddImpl(object, index, value, attributes,
+ new_capacity);
+ }
+
+ static void AddImpl(Handle<JSObject> object, uint32_t index,
+ Handle<Object> value, PropertyAttributes attributes,
+ uint32_t new_capacity) {
+ UNREACHABLE();
+ }
+
+ uint32_t Push(Handle<JSArray> receiver, Handle<FixedArrayBase> backing_store,
+ Arguments* args, uint32_t push_size) final {
+ return ElementsAccessorSubclass::PushImpl(receiver, backing_store, args,
+ push_size);
+ }
+
+ static uint32_t PushImpl(Handle<JSArray> receiver,
+ Handle<FixedArrayBase> elms_obj, Arguments* args,
+ uint32_t push_sized) {
+ UNREACHABLE();
+ return 0;
+ }
+
+ uint32_t Unshift(Handle<JSArray> receiver,
+ Handle<FixedArrayBase> backing_store, Arguments* args,
+ uint32_t unshift_size) final {
+ return ElementsAccessorSubclass::UnshiftImpl(receiver, backing_store, args,
+ unshift_size);
+ }
+
+ static uint32_t UnshiftImpl(Handle<JSArray> receiver,
+ Handle<FixedArrayBase> elms_obj, Arguments* args,
+ uint32_t unshift_size) {
+ UNREACHABLE();
+ return 0;
+ }
+
+ Handle<JSArray> Slice(Handle<JSObject> receiver,
+ Handle<FixedArrayBase> backing_store, uint32_t start,
+ uint32_t end) final {
+ return ElementsAccessorSubclass::SliceImpl(receiver, backing_store, start,
+ end);
+ }
+
+ static Handle<JSArray> SliceImpl(Handle<JSObject> receiver,
+ Handle<FixedArrayBase> backing_store,
+ uint32_t start, uint32_t end) {
+ UNREACHABLE();
+ return Handle<JSArray>();
+ }
+
+ Handle<JSArray> Splice(Handle<JSArray> receiver,
+ Handle<FixedArrayBase> backing_store, uint32_t start,
+ uint32_t delete_count, Arguments* args,
+ uint32_t add_count) final {
+ return ElementsAccessorSubclass::SpliceImpl(receiver, backing_store, start,
+ delete_count, args, add_count);
+ }
+
+ static Handle<JSArray> SpliceImpl(Handle<JSArray> receiver,
+ Handle<FixedArrayBase> backing_store,
+ uint32_t start, uint32_t delete_count,
+ Arguments* args, uint32_t add_count) {
+ UNREACHABLE();
+ return Handle<JSArray>();
+ }
+
+ Handle<Object> Pop(Handle<JSArray> receiver,
+ Handle<FixedArrayBase> backing_store) final {
+ return ElementsAccessorSubclass::PopImpl(receiver, backing_store);
+ }
+
+ static Handle<Object> PopImpl(Handle<JSArray> receiver,
+ Handle<FixedArrayBase> backing_store) {
+ UNREACHABLE();
+ return Handle<Object>();
+ }
+
+ Handle<Object> Shift(Handle<JSArray> receiver,
+ Handle<FixedArrayBase> backing_store) final {
+ return ElementsAccessorSubclass::ShiftImpl(receiver, backing_store);
+ }
+
+ static Handle<Object> ShiftImpl(Handle<JSArray> receiver,
+ Handle<FixedArrayBase> backing_store) {
+ UNREACHABLE();
+ return Handle<Object>();
+ }
+
+ void SetLength(Handle<JSArray> array, uint32_t length) final {
+ ElementsAccessorSubclass::SetLengthImpl(array->GetIsolate(), array, length,
+ handle(array->elements()));
+ }
+
+ static void SetLengthImpl(Isolate* isolate, Handle<JSArray> array,
+ uint32_t length,
+ Handle<FixedArrayBase> backing_store) {
+ DCHECK(!array->SetLengthWouldNormalize(length));
+ DCHECK(IsFastElementsKind(array->GetElementsKind()));
+ uint32_t old_length = 0;
+ CHECK(array->length()->ToArrayIndex(&old_length));
+
+ if (old_length < length) {
+ ElementsKind kind = array->GetElementsKind();
+ if (!IsFastHoleyElementsKind(kind)) {
+ kind = GetHoleyElementsKind(kind);
+ JSObject::TransitionElementsKind(array, kind);
+ }
}
- if (IsExternalArrayElementsKind(ElementsTraits::Kind) &&
- FLAG_trace_external_array_abuse) {
- CheckArrayAbuse(holder, "external elements read", key);
- }
-
- return ElementsAccessorSubclass::GetImpl(
- receiver, holder, key, backing_store);
- }
-
- MUST_USE_RESULT static MaybeHandle<Object> GetImpl(
- Handle<Object> receiver,
- Handle<JSObject> obj,
- uint32_t key,
- Handle<FixedArrayBase> backing_store) {
- if (key < ElementsAccessorSubclass::GetCapacityImpl(backing_store)) {
- return BackingStore::get(Handle<BackingStore>::cast(backing_store), key);
+ // Check whether the backing store should be shrunk.
+ uint32_t capacity = backing_store->length();
+ old_length = Min(old_length, capacity);
+ if (length == 0) {
+ array->initialize_elements();
+ } else if (length <= capacity) {
+ if (array->HasFastSmiOrObjectElements()) {
+ backing_store = JSObject::EnsureWritableFastElements(array);
+ }
+ if (2 * length <= capacity) {
+ // If more than half the elements won't be used, trim the array.
+ isolate->heap()->RightTrimFixedArray<Heap::CONCURRENT_TO_SWEEPER>(
+ *backing_store, capacity - length);
+ } else {
+ // Otherwise, fill the unused tail with holes.
+ for (uint32_t i = length; i < old_length; i++) {
+ BackingStore::cast(*backing_store)->set_the_hole(i);
+ }
+ }
} else {
- return backing_store->GetIsolate()->factory()->the_hole_value();
+ // Check whether the backing store should be expanded.
+ capacity = Max(length, JSObject::NewElementsCapacity(capacity));
+ ElementsAccessorSubclass::GrowCapacityAndConvertImpl(array, capacity);
+ }
+
+ array->set_length(Smi::FromInt(length));
+ JSObject::ValidateElements(array);
+ }
+
+ static Handle<FixedArrayBase> ConvertElementsWithCapacity(
+ Handle<JSObject> object, Handle<FixedArrayBase> old_elements,
+ ElementsKind from_kind, uint32_t capacity) {
+ return ConvertElementsWithCapacity(
+ object, old_elements, from_kind, capacity, 0, 0,
+ ElementsAccessor::kCopyToEndAndInitializeToHole);
+ }
+
+ static Handle<FixedArrayBase> ConvertElementsWithCapacity(
+ Handle<JSObject> object, Handle<FixedArrayBase> old_elements,
+ ElementsKind from_kind, uint32_t capacity, int copy_size) {
+ return ConvertElementsWithCapacity(object, old_elements, from_kind,
+ capacity, 0, 0, copy_size);
+ }
+
+ static Handle<FixedArrayBase> ConvertElementsWithCapacity(
+ Handle<JSObject> object, Handle<FixedArrayBase> old_elements,
+ ElementsKind from_kind, uint32_t capacity, uint32_t src_index,
+ uint32_t dst_index, int copy_size) {
+ Isolate* isolate = object->GetIsolate();
+ Handle<FixedArrayBase> new_elements;
+ if (IsFastDoubleElementsKind(kind())) {
+ new_elements = isolate->factory()->NewFixedDoubleArray(capacity);
+ } else {
+ new_elements = isolate->factory()->NewUninitializedFixedArray(capacity);
+ }
+
+ int packed_size = kPackedSizeNotKnown;
+ if (IsFastPackedElementsKind(from_kind) && object->IsJSArray()) {
+ packed_size = Smi::cast(JSArray::cast(*object)->length())->value();
+ }
+
+ ElementsAccessorSubclass::CopyElementsImpl(
+ *old_elements, src_index, *new_elements, from_kind, dst_index,
+ packed_size, copy_size);
+
+ return new_elements;
+ }
+
+ static void GrowCapacityAndConvertImpl(Handle<JSObject> object,
+ uint32_t capacity) {
+ ElementsKind from_kind = object->GetElementsKind();
+ if (IsFastSmiOrObjectElementsKind(from_kind)) {
+ // Array optimizations rely on the prototype lookups of Array objects
+ // always returning undefined. If there is a store to the initial
+ // prototype object, make sure all of these optimizations are invalidated.
+ object->GetIsolate()->UpdateArrayProtectorOnSetLength(object);
+ }
+ Handle<FixedArrayBase> old_elements(object->elements());
+ // This method should only be called if there's a reason to update the
+ // elements.
+ DCHECK(IsFastDoubleElementsKind(from_kind) !=
+ IsFastDoubleElementsKind(kind()) ||
+ IsDictionaryElementsKind(from_kind) ||
+ static_cast<uint32_t>(old_elements->length()) < capacity);
+ Handle<FixedArrayBase> elements =
+ ConvertElementsWithCapacity(object, old_elements, from_kind, capacity);
+
+ ElementsKind to_kind = kind();
+ if (IsHoleyElementsKind(from_kind)) to_kind = GetHoleyElementsKind(to_kind);
+ Handle<Map> new_map = JSObject::GetElementsTransitionMap(object, to_kind);
+ JSObject::SetMapAndElements(object, new_map, elements);
+
+ // Transition through the allocation site as well if present.
+ JSObject::UpdateAllocationSite(object, to_kind);
+
+ if (FLAG_trace_elements_transitions) {
+ JSObject::PrintElementsTransition(stdout, object, from_kind, old_elements,
+ to_kind, elements);
}
}
- MUST_USE_RESULT virtual PropertyAttributes GetAttributes(
- Handle<Object> receiver, Handle<JSObject> holder, uint32_t key,
- Handle<FixedArrayBase> backing_store) FINAL {
- return ElementsAccessorSubclass::GetAttributesImpl(
- receiver, holder, key, backing_store);
+ void GrowCapacityAndConvert(Handle<JSObject> object,
+ uint32_t capacity) final {
+ ElementsAccessorSubclass::GrowCapacityAndConvertImpl(object, capacity);
}
- MUST_USE_RESULT static PropertyAttributes GetAttributesImpl(
- Handle<Object> receiver,
- Handle<JSObject> obj,
- uint32_t key,
- Handle<FixedArrayBase> backing_store) {
- if (key >= ElementsAccessorSubclass::GetCapacityImpl(backing_store)) {
- return ABSENT;
- }
- return
- Handle<BackingStore>::cast(backing_store)->is_the_hole(key)
- ? ABSENT : NONE;
+ void Delete(Handle<JSObject> obj, uint32_t entry) final {
+ ElementsAccessorSubclass::DeleteImpl(obj, entry);
}
- MUST_USE_RESULT virtual MaybeHandle<AccessorPair> GetAccessorPair(
- Handle<Object> receiver, Handle<JSObject> holder, uint32_t key,
- Handle<FixedArrayBase> backing_store) FINAL {
- return ElementsAccessorSubclass::GetAccessorPairImpl(
- receiver, holder, key, backing_store);
- }
-
- MUST_USE_RESULT static MaybeHandle<AccessorPair> GetAccessorPairImpl(
- Handle<Object> receiver,
- Handle<JSObject> obj,
- uint32_t key,
- Handle<FixedArrayBase> backing_store) {
- return MaybeHandle<AccessorPair>();
- }
-
- MUST_USE_RESULT virtual MaybeHandle<Object> SetLength(
- Handle<JSArray> array, Handle<Object> length) FINAL {
- return ElementsAccessorSubclass::SetLengthImpl(
- array, length, handle(array->elements()));
- }
-
- MUST_USE_RESULT static MaybeHandle<Object> SetLengthImpl(
- Handle<JSObject> obj,
- Handle<Object> length,
- Handle<FixedArrayBase> backing_store);
-
- virtual void SetCapacityAndLength(Handle<JSArray> array, int capacity,
- int length) FINAL {
- ElementsAccessorSubclass::
- SetFastElementsCapacityAndLength(array, capacity, length);
- }
-
- static void SetFastElementsCapacityAndLength(
- Handle<JSObject> obj,
- int capacity,
- int length) {
- UNIMPLEMENTED();
- }
-
- MUST_USE_RESULT virtual MaybeHandle<Object> Delete(
- Handle<JSObject> obj,
- uint32_t key,
- JSReceiver::DeleteMode mode) OVERRIDE = 0;
-
static void CopyElementsImpl(FixedArrayBase* from, uint32_t from_start,
FixedArrayBase* to, ElementsKind from_kind,
uint32_t to_start, int packed_size,
@@ -702,9 +814,9 @@
UNREACHABLE();
}
- virtual void CopyElements(Handle<FixedArrayBase> from, uint32_t from_start,
- ElementsKind from_kind, Handle<FixedArrayBase> to,
- uint32_t to_start, int copy_size) FINAL {
+ void CopyElements(Handle<FixedArrayBase> from, uint32_t from_start,
+ ElementsKind from_kind, Handle<FixedArrayBase> to,
+ uint32_t to_start, int copy_size) final {
DCHECK(!from.is_null());
// NOTE: the ElementsAccessorSubclass::CopyElementsImpl() methods
// violate the handlified function signature convention:
@@ -717,9 +829,9 @@
kPackedSizeNotKnown, copy_size);
}
- virtual void CopyElements(JSObject* from_holder, uint32_t from_start,
- ElementsKind from_kind, Handle<FixedArrayBase> to,
- uint32_t to_start, int copy_size) FINAL {
+ void CopyElements(JSObject* from_holder, uint32_t from_start,
+ ElementsKind from_kind, Handle<FixedArrayBase> to,
+ uint32_t to_start, int copy_size) final {
int packed_size = kPackedSizeNotKnown;
bool is_packed = IsFastPackedElementsKind(from_kind) &&
from_holder->IsJSArray();
@@ -744,104 +856,109 @@
from, from_start, *to, from_kind, to_start, packed_size, copy_size);
}
- virtual MaybeHandle<FixedArray> AddElementsToFixedArray(
- Handle<Object> receiver, Handle<JSObject> holder, Handle<FixedArray> to,
- Handle<FixedArrayBase> from, FixedArray::KeyFilter filter) FINAL {
- int len0 = to->length();
-#ifdef ENABLE_SLOW_DCHECKS
- if (FLAG_enable_slow_asserts) {
- for (int i = 0; i < len0; i++) {
- DCHECK(!to->get(i)->IsTheHole());
- }
+ static void CollectElementIndicesImpl(Handle<JSObject> object,
+ Handle<FixedArrayBase> backing_store,
+ KeyAccumulator* keys, uint32_t range,
+ PropertyFilter filter,
+ uint32_t offset) {
+ if (filter & ONLY_ALL_CAN_READ) {
+ // Non-dictionary elements can't have all-can-read accessors.
+ return;
}
-#endif
-
- // Optimize if 'other' is empty.
- // We cannot optimize if 'this' is empty, as other may have holes.
- uint32_t len1 = ElementsAccessorSubclass::GetCapacityImpl(from);
- if (len1 == 0) return to;
-
- Isolate* isolate = from->GetIsolate();
-
- // Compute how many elements are not in other.
- uint32_t extra = 0;
- for (uint32_t y = 0; y < len1; y++) {
- uint32_t key = ElementsAccessorSubclass::GetKeyForIndexImpl(from, y);
- if (ElementsAccessorSubclass::HasElementImpl(
- receiver, holder, key, from)) {
- Handle<Object> value;
- ASSIGN_RETURN_ON_EXCEPTION(
- isolate, value,
- ElementsAccessorSubclass::GetImpl(receiver, holder, key, from),
- FixedArray);
-
- DCHECK(!value->IsTheHole());
- if (filter == FixedArray::NON_SYMBOL_KEYS && value->IsSymbol()) {
- continue;
- }
- if (!HasKey(to, value)) {
- extra++;
- }
- }
+ uint32_t length = 0;
+ if (object->IsJSArray()) {
+ length = Smi::cast(JSArray::cast(*object)->length())->value();
+ } else {
+ length =
+ ElementsAccessorSubclass::GetCapacityImpl(*object, *backing_store);
}
-
- if (extra == 0) return to;
-
- // Allocate the result
- Handle<FixedArray> result = isolate->factory()->NewFixedArray(len0 + extra);
-
- // Fill in the content
- {
- DisallowHeapAllocation no_gc;
- WriteBarrierMode mode = result->GetWriteBarrierMode(no_gc);
- for (int i = 0; i < len0; i++) {
- Object* e = to->get(i);
- DCHECK(e->IsString() || e->IsNumber());
- result->set(i, e, mode);
- }
+ if (range < length) length = range;
+ for (uint32_t i = offset; i < length; i++) {
+ if (!ElementsAccessorSubclass::HasElementImpl(object, i, backing_store,
+ filter))
+ continue;
+ keys->AddKey(i);
}
- // Fill in the extra values.
- uint32_t index = 0;
- for (uint32_t y = 0; y < len1; y++) {
- uint32_t key =
- ElementsAccessorSubclass::GetKeyForIndexImpl(from, y);
- if (ElementsAccessorSubclass::HasElementImpl(
- receiver, holder, key, from)) {
- Handle<Object> value;
- ASSIGN_RETURN_ON_EXCEPTION(
- isolate, value,
- ElementsAccessorSubclass::GetImpl(receiver, holder, key, from),
- FixedArray);
- if (filter == FixedArray::NON_SYMBOL_KEYS && value->IsSymbol()) {
- continue;
- }
- if (!value->IsTheHole() && !HasKey(to, value)) {
- result->set(len0 + index, *value);
- index++;
- }
- }
- }
- DCHECK(extra == index);
- return result;
}
- protected:
- static uint32_t GetCapacityImpl(Handle<FixedArrayBase> backing_store) {
+ void CollectElementIndices(Handle<JSObject> object,
+ Handle<FixedArrayBase> backing_store,
+ KeyAccumulator* keys, uint32_t range,
+ PropertyFilter filter, uint32_t offset) final {
+ ElementsAccessorSubclass::CollectElementIndicesImpl(
+ object, backing_store, keys, range, filter, offset);
+ };
+
+ void AddElementsToKeyAccumulator(Handle<JSObject> receiver,
+ KeyAccumulator* accumulator,
+ AddKeyConversion convert) final {
+ Handle<FixedArrayBase> from(receiver->elements());
+ uint32_t add_length =
+ ElementsAccessorSubclass::GetCapacityImpl(*receiver, *from);
+ if (add_length == 0) return;
+
+ for (uint32_t i = 0; i < add_length; i++) {
+ if (!ElementsAccessorSubclass::HasEntryImpl(*from, i)) continue;
+ Handle<Object> value = ElementsAccessorSubclass::GetImpl(from, i);
+ DCHECK(!value->IsTheHole());
+ DCHECK(!value->IsAccessorPair());
+ DCHECK(!value->IsExecutableAccessorInfo());
+ accumulator->AddKey(value, convert);
+ }
+ }
+
+ static uint32_t GetCapacityImpl(JSObject* holder,
+ FixedArrayBase* backing_store) {
return backing_store->length();
}
- uint32_t GetCapacity(Handle<FixedArrayBase> backing_store) FINAL {
- return ElementsAccessorSubclass::GetCapacityImpl(backing_store);
+ uint32_t GetCapacity(JSObject* holder, FixedArrayBase* backing_store) final {
+ return ElementsAccessorSubclass::GetCapacityImpl(holder, backing_store);
}
- static uint32_t GetKeyForIndexImpl(Handle<FixedArrayBase> backing_store,
- uint32_t index) {
- return index;
+ static bool HasEntryImpl(FixedArrayBase* backing_store, uint32_t entry) {
+ return true;
}
- virtual uint32_t GetKeyForIndex(Handle<FixedArrayBase> backing_store,
- uint32_t index) FINAL {
- return ElementsAccessorSubclass::GetKeyForIndexImpl(backing_store, index);
+ static uint32_t GetIndexForEntryImpl(FixedArrayBase* backing_store,
+ uint32_t entry) {
+ return entry;
+ }
+
+ static uint32_t GetEntryForIndexImpl(JSObject* holder,
+ FixedArrayBase* backing_store,
+ uint32_t index, PropertyFilter filter) {
+ if (IsHoleyElementsKind(kind())) {
+ return index < ElementsAccessorSubclass::GetCapacityImpl(holder,
+ backing_store) &&
+ !BackingStore::cast(backing_store)->is_the_hole(index)
+ ? index
+ : kMaxUInt32;
+ } else {
+ uint32_t length =
+ holder->IsJSArray()
+ ? static_cast<uint32_t>(
+ Smi::cast(JSArray::cast(holder)->length())->value())
+ : ElementsAccessorSubclass::GetCapacityImpl(holder,
+ backing_store);
+ return index < length ? index : kMaxUInt32;
+ }
+ }
+
+ uint32_t GetEntryForIndex(JSObject* holder, FixedArrayBase* backing_store,
+ uint32_t index) final {
+ return ElementsAccessorSubclass::GetEntryForIndexImpl(
+ holder, backing_store, index, ALL_PROPERTIES);
+ }
+
+ static PropertyDetails GetDetailsImpl(FixedArrayBase* backing_store,
+ uint32_t entry) {
+ return PropertyDetails(NONE, DATA, 0, PropertyCellType::kNoCell);
+ }
+
+ PropertyDetails GetDetails(FixedArrayBase* backing_store,
+ uint32_t entry) final {
+ return ElementsAccessorSubclass::GetDetailsImpl(backing_store, entry);
}
private:
@@ -849,6 +966,202 @@
};
+class DictionaryElementsAccessor
+ : public ElementsAccessorBase<DictionaryElementsAccessor,
+ ElementsKindTraits<DICTIONARY_ELEMENTS> > {
+ public:
+ explicit DictionaryElementsAccessor(const char* name)
+ : ElementsAccessorBase<DictionaryElementsAccessor,
+ ElementsKindTraits<DICTIONARY_ELEMENTS> >(name) {}
+
+ static void SetLengthImpl(Isolate* isolate, Handle<JSArray> array,
+ uint32_t length,
+ Handle<FixedArrayBase> backing_store) {
+ Handle<SeededNumberDictionary> dict =
+ Handle<SeededNumberDictionary>::cast(backing_store);
+ int capacity = dict->Capacity();
+ uint32_t old_length = 0;
+ CHECK(array->length()->ToArrayLength(&old_length));
+ if (length < old_length) {
+ if (dict->requires_slow_elements()) {
+ // Find last non-deletable element in range of elements to be
+ // deleted and adjust range accordingly.
+ for (int entry = 0; entry < capacity; entry++) {
+ DisallowHeapAllocation no_gc;
+ Object* index = dict->KeyAt(entry);
+ if (index->IsNumber()) {
+ uint32_t number = static_cast<uint32_t>(index->Number());
+ if (length <= number && number < old_length) {
+ PropertyDetails details = dict->DetailsAt(entry);
+ if (!details.IsConfigurable()) length = number + 1;
+ }
+ }
+ }
+ }
+
+ if (length == 0) {
+ // Flush the backing store.
+ JSObject::ResetElements(array);
+ } else {
+ DisallowHeapAllocation no_gc;
+ // Remove elements that should be deleted.
+ int removed_entries = 0;
+ Handle<Object> the_hole_value = isolate->factory()->the_hole_value();
+ for (int entry = 0; entry < capacity; entry++) {
+ Object* index = dict->KeyAt(entry);
+ if (index->IsNumber()) {
+ uint32_t number = static_cast<uint32_t>(index->Number());
+ if (length <= number && number < old_length) {
+ dict->SetEntry(entry, the_hole_value, the_hole_value);
+ removed_entries++;
+ }
+ }
+ }
+
+ // Update the number of elements.
+ dict->ElementsRemoved(removed_entries);
+ }
+ }
+
+ Handle<Object> length_obj = isolate->factory()->NewNumberFromUint(length);
+ array->set_length(*length_obj);
+ }
+
+ static void CopyElementsImpl(FixedArrayBase* from, uint32_t from_start,
+ FixedArrayBase* to, ElementsKind from_kind,
+ uint32_t to_start, int packed_size,
+ int copy_size) {
+ UNREACHABLE();
+ }
+
+
+ static void DeleteImpl(Handle<JSObject> obj, uint32_t entry) {
+ // TODO(verwaest): Remove reliance on index in Shrink.
+ Handle<SeededNumberDictionary> dict(
+ SeededNumberDictionary::cast(obj->elements()));
+ uint32_t index = GetIndexForEntryImpl(*dict, entry);
+ Handle<Object> result = SeededNumberDictionary::DeleteProperty(dict, entry);
+ USE(result);
+ DCHECK(result->IsTrue());
+ Handle<FixedArray> new_elements =
+ SeededNumberDictionary::Shrink(dict, index);
+ obj->set_elements(*new_elements);
+ }
+
+ static Object* GetRaw(FixedArrayBase* store, uint32_t entry) {
+ SeededNumberDictionary* backing_store = SeededNumberDictionary::cast(store);
+ return backing_store->ValueAt(entry);
+ }
+
+ static Handle<Object> GetImpl(Handle<FixedArrayBase> store, uint32_t entry) {
+ Isolate* isolate = store->GetIsolate();
+ return handle(GetRaw(*store, entry), isolate);
+ }
+
+ static inline void SetImpl(FixedArrayBase* store, uint32_t entry,
+ Object* value) {
+ SeededNumberDictionary* dictionary = SeededNumberDictionary::cast(store);
+ dictionary->ValueAtPut(entry, value);
+ }
+
+ static void ReconfigureImpl(Handle<JSObject> object,
+ Handle<FixedArrayBase> store, uint32_t entry,
+ Handle<Object> value,
+ PropertyAttributes attributes) {
+ SeededNumberDictionary* dictionary = SeededNumberDictionary::cast(*store);
+ if (attributes != NONE) object->RequireSlowElements(dictionary);
+ dictionary->ValueAtPut(entry, *value);
+ PropertyDetails details = dictionary->DetailsAt(entry);
+ details = PropertyDetails(attributes, DATA, details.dictionary_index(),
+ PropertyCellType::kNoCell);
+ dictionary->DetailsAtPut(entry, details);
+ }
+
+ static void AddImpl(Handle<JSObject> object, uint32_t index,
+ Handle<Object> value, PropertyAttributes attributes,
+ uint32_t new_capacity) {
+ PropertyDetails details(attributes, DATA, 0, PropertyCellType::kNoCell);
+ Handle<SeededNumberDictionary> dictionary =
+ object->HasFastElements()
+ ? JSObject::NormalizeElements(object)
+ : handle(SeededNumberDictionary::cast(object->elements()));
+ Handle<SeededNumberDictionary> new_dictionary =
+ SeededNumberDictionary::AddNumberEntry(
+ dictionary, index, value, details,
+ object->map()->is_prototype_map());
+ if (attributes != NONE) object->RequireSlowElements(*new_dictionary);
+ if (dictionary.is_identical_to(new_dictionary)) return;
+ object->set_elements(*new_dictionary);
+ }
+
+ static bool HasEntryImpl(FixedArrayBase* store, uint32_t entry) {
+ DisallowHeapAllocation no_gc;
+ SeededNumberDictionary* dict = SeededNumberDictionary::cast(store);
+ Object* index = dict->KeyAt(entry);
+ return !index->IsTheHole();
+ }
+
+ static uint32_t GetIndexForEntryImpl(FixedArrayBase* store, uint32_t entry) {
+ DisallowHeapAllocation no_gc;
+ SeededNumberDictionary* dict = SeededNumberDictionary::cast(store);
+ uint32_t result = 0;
+ CHECK(dict->KeyAt(entry)->ToArrayIndex(&result));
+ return result;
+ }
+
+ static uint32_t GetEntryForIndexImpl(JSObject* holder, FixedArrayBase* store,
+ uint32_t index, PropertyFilter filter) {
+ DisallowHeapAllocation no_gc;
+ SeededNumberDictionary* dictionary = SeededNumberDictionary::cast(store);
+ int entry = dictionary->FindEntry(index);
+ if (entry == SeededNumberDictionary::kNotFound) return kMaxUInt32;
+ if (filter != ALL_PROPERTIES) {
+ PropertyDetails details = dictionary->DetailsAt(entry);
+ PropertyAttributes attr = details.attributes();
+ if ((attr & filter) != 0) return kMaxUInt32;
+ }
+ return static_cast<uint32_t>(entry);
+ }
+
+ static PropertyDetails GetDetailsImpl(FixedArrayBase* backing_store,
+ uint32_t entry) {
+ return SeededNumberDictionary::cast(backing_store)->DetailsAt(entry);
+ }
+
+ static void CollectElementIndicesImpl(Handle<JSObject> object,
+ Handle<FixedArrayBase> backing_store,
+ KeyAccumulator* keys, uint32_t range,
+ PropertyFilter filter,
+ uint32_t offset) {
+ Handle<SeededNumberDictionary> dictionary =
+ Handle<SeededNumberDictionary>::cast(backing_store);
+ int capacity = dictionary->Capacity();
+ for (int i = 0; i < capacity; i++) {
+ Object* k = dictionary->KeyAt(i);
+ if (!dictionary->IsKey(k)) continue;
+ if (k->FilterKey(filter)) continue;
+ if (dictionary->IsDeleted(i)) continue;
+ DCHECK(k->IsNumber());
+ DCHECK_LE(k->Number(), kMaxUInt32);
+ uint32_t index = static_cast<uint32_t>(k->Number());
+ if (index < offset) continue;
+ PropertyDetails details = dictionary->DetailsAt(i);
+ if (filter & ONLY_ALL_CAN_READ) {
+ if (details.kind() != kAccessor) continue;
+ Object* accessors = dictionary->ValueAt(i);
+ if (!accessors->IsAccessorInfo()) continue;
+ if (!AccessorInfo::cast(accessors)->all_can_read()) continue;
+ }
+ PropertyAttributes attr = details.attributes();
+ if ((attr & filter) != 0) continue;
+ keys->AddKey(index);
+ }
+
+ keys->SortCurrentElementsList();
+ }
+};
+
+
// Super class for all fast element arrays.
template<typename FastElementsAccessorSubclass,
typename KindTraits>
@@ -858,136 +1171,136 @@
explicit FastElementsAccessor(const char* name)
: ElementsAccessorBase<FastElementsAccessorSubclass,
KindTraits>(name) {}
- protected:
- friend class ElementsAccessorBase<FastElementsAccessorSubclass, KindTraits>;
- friend class SloppyArgumentsElementsAccessor;
typedef typename KindTraits::BackingStore BackingStore;
- // Adjusts the length of the fast backing store.
- static Handle<Object> SetLengthWithoutNormalize(
- Handle<FixedArrayBase> backing_store,
- Handle<JSArray> array,
- Handle<Object> length_object,
- uint32_t length) {
- Isolate* isolate = array->GetIsolate();
- uint32_t old_capacity = backing_store->length();
- Handle<Object> old_length(array->length(), isolate);
- bool same_or_smaller_size = old_length->IsSmi() &&
- static_cast<uint32_t>(Handle<Smi>::cast(old_length)->value()) >= length;
- ElementsKind kind = array->GetElementsKind();
-
- if (!same_or_smaller_size && IsFastElementsKind(kind) &&
- !IsFastHoleyElementsKind(kind)) {
- kind = GetHoleyElementsKind(kind);
- JSObject::TransitionElementsKind(array, kind);
+ static void DeleteAtEnd(Handle<JSObject> obj,
+ Handle<BackingStore> backing_store, uint32_t entry) {
+ uint32_t length = static_cast<uint32_t>(backing_store->length());
+ Heap* heap = obj->GetHeap();
+ for (; entry > 0; entry--) {
+ if (!backing_store->is_the_hole(entry - 1)) break;
}
-
- // Check whether the backing store should be shrunk.
- if (length <= old_capacity) {
- if (array->HasFastSmiOrObjectElements()) {
- backing_store = JSObject::EnsureWritableFastElements(array);
- }
- if (2 * length <= old_capacity) {
- // If more than half the elements won't be used, trim the array.
- if (length == 0) {
- array->initialize_elements();
- } else {
- isolate->heap()->RightTrimFixedArray<Heap::FROM_MUTATOR>(
- *backing_store, old_capacity - length);
- }
+ if (entry == 0) {
+ FixedArray* empty = heap->empty_fixed_array();
+ if (obj->HasFastArgumentsElements()) {
+ FixedArray::cast(obj->elements())->set(1, empty);
} else {
- // Otherwise, fill the unused tail with holes.
- int old_length = FastD2IChecked(array->length()->Number());
- for (int i = length; i < old_length; i++) {
- Handle<BackingStore>::cast(backing_store)->set_the_hole(i);
- }
+ obj->set_elements(empty);
}
- return length_object;
+ return;
}
- // Check whether the backing store should be expanded.
- uint32_t min = JSObject::NewElementsCapacity(old_capacity);
- uint32_t new_capacity = length > min ? length : min;
- FastElementsAccessorSubclass::SetFastElementsCapacityAndLength(
- array, new_capacity, length);
- JSObject::ValidateElements(array);
- return length_object;
+ heap->RightTrimFixedArray<Heap::CONCURRENT_TO_SWEEPER>(*backing_store,
+ length - entry);
}
- static Handle<Object> DeleteCommon(Handle<JSObject> obj,
- uint32_t key,
- JSReceiver::DeleteMode mode) {
+ static void DeleteCommon(Handle<JSObject> obj, uint32_t entry,
+ Handle<FixedArrayBase> store) {
DCHECK(obj->HasFastSmiOrObjectElements() ||
obj->HasFastDoubleElements() ||
obj->HasFastArgumentsElements());
- Isolate* isolate = obj->GetIsolate();
- Heap* heap = obj->GetHeap();
- Handle<FixedArrayBase> elements(obj->elements());
- if (*elements == heap->empty_fixed_array()) {
- return isolate->factory()->true_value();
+ Handle<BackingStore> backing_store = Handle<BackingStore>::cast(store);
+ if (!obj->IsJSArray() &&
+ entry == static_cast<uint32_t>(store->length()) - 1) {
+ DeleteAtEnd(obj, backing_store, entry);
+ return;
}
- Handle<BackingStore> backing_store = Handle<BackingStore>::cast(elements);
- bool is_sloppy_arguments_elements_map =
- backing_store->map() == heap->sloppy_arguments_elements_map();
- if (is_sloppy_arguments_elements_map) {
- backing_store = handle(
- BackingStore::cast(Handle<FixedArray>::cast(backing_store)->get(1)),
- isolate);
+
+ backing_store->set_the_hole(entry);
+
+ // TODO(verwaest): Move this out of elements.cc.
+ // If an old space backing store is larger than a certain size and
+ // has too few used values, normalize it.
+ // To avoid doing the check on every delete we require at least
+ // one adjacent hole to the value being deleted.
+ const int kMinLengthForSparsenessCheck = 64;
+ if (backing_store->length() < kMinLengthForSparsenessCheck) return;
+ if (backing_store->GetHeap()->InNewSpace(*backing_store)) return;
+ uint32_t length = 0;
+ if (obj->IsJSArray()) {
+ JSArray::cast(*obj)->length()->ToArrayLength(&length);
+ } else {
+ length = static_cast<uint32_t>(store->length());
}
- uint32_t length = static_cast<uint32_t>(
- obj->IsJSArray()
- ? Smi::cast(Handle<JSArray>::cast(obj)->length())->value()
- : backing_store->length());
- if (key < length) {
- if (!is_sloppy_arguments_elements_map) {
- ElementsKind kind = KindTraits::Kind;
- if (IsFastPackedElementsKind(kind)) {
- JSObject::TransitionElementsKind(obj, GetHoleyElementsKind(kind));
+ if ((entry > 0 && backing_store->is_the_hole(entry - 1)) ||
+ (entry + 1 < length && backing_store->is_the_hole(entry + 1))) {
+ if (!obj->IsJSArray()) {
+ uint32_t i;
+ for (i = entry + 1; i < length; i++) {
+ if (!backing_store->is_the_hole(i)) break;
}
- if (IsFastSmiOrObjectElementsKind(KindTraits::Kind)) {
- Handle<Object> writable = JSObject::EnsureWritableFastElements(obj);
- backing_store = Handle<BackingStore>::cast(writable);
+ if (i == length) {
+ DeleteAtEnd(obj, backing_store, entry);
+ return;
}
}
- backing_store->set_the_hole(key);
- // If an old space backing store is larger than a certain size and
- // has too few used values, normalize it.
- // To avoid doing the check on every delete we require at least
- // one adjacent hole to the value being deleted.
- const int kMinLengthForSparsenessCheck = 64;
- if (backing_store->length() >= kMinLengthForSparsenessCheck &&
- !heap->InNewSpace(*backing_store) &&
- ((key > 0 && backing_store->is_the_hole(key - 1)) ||
- (key + 1 < length && backing_store->is_the_hole(key + 1)))) {
- int num_used = 0;
- for (int i = 0; i < backing_store->length(); ++i) {
- if (!backing_store->is_the_hole(i)) ++num_used;
- // Bail out early if more than 1/4 is used.
- if (4 * num_used > backing_store->length()) break;
- }
- if (4 * num_used <= backing_store->length()) {
- JSObject::NormalizeElements(obj);
+ int num_used = 0;
+ for (int i = 0; i < backing_store->length(); ++i) {
+ if (!backing_store->is_the_hole(i)) {
+ ++num_used;
+ // Bail out if a number dictionary wouldn't be able to save at least
+ // 75% space.
+ if (4 * SeededNumberDictionary::ComputeCapacity(num_used) *
+ SeededNumberDictionary::kEntrySize >
+ backing_store->length()) {
+ return;
+ }
}
}
+ JSObject::NormalizeElements(obj);
}
- return isolate->factory()->true_value();
}
- virtual MaybeHandle<Object> Delete(Handle<JSObject> obj, uint32_t key,
- JSReceiver::DeleteMode mode) FINAL {
- return DeleteCommon(obj, key, mode);
+ static void ReconfigureImpl(Handle<JSObject> object,
+ Handle<FixedArrayBase> store, uint32_t entry,
+ Handle<Object> value,
+ PropertyAttributes attributes) {
+ Handle<SeededNumberDictionary> dictionary =
+ JSObject::NormalizeElements(object);
+ entry = dictionary->FindEntry(entry);
+ DictionaryElementsAccessor::ReconfigureImpl(object, dictionary, entry,
+ value, attributes);
}
- static bool HasElementImpl(
- Handle<Object> receiver,
- Handle<JSObject> holder,
- uint32_t key,
- Handle<FixedArrayBase> backing_store) {
- if (key >= static_cast<uint32_t>(backing_store->length())) {
- return false;
+ static void AddImpl(Handle<JSObject> object, uint32_t index,
+ Handle<Object> value, PropertyAttributes attributes,
+ uint32_t new_capacity) {
+ DCHECK_EQ(NONE, attributes);
+ ElementsKind from_kind = object->GetElementsKind();
+ ElementsKind to_kind = FastElementsAccessorSubclass::kind();
+ if (IsDictionaryElementsKind(from_kind) ||
+ IsFastDoubleElementsKind(from_kind) !=
+ IsFastDoubleElementsKind(to_kind) ||
+ FastElementsAccessorSubclass::GetCapacityImpl(
+ *object, object->elements()) != new_capacity) {
+ FastElementsAccessorSubclass::GrowCapacityAndConvertImpl(object,
+ new_capacity);
+ } else {
+ if (from_kind != to_kind) {
+ JSObject::TransitionElementsKind(object, to_kind);
+ }
+ if (IsFastSmiOrObjectElementsKind(from_kind)) {
+ DCHECK(IsFastSmiOrObjectElementsKind(to_kind));
+ JSObject::EnsureWritableFastElements(object);
+ }
}
- return !Handle<BackingStore>::cast(backing_store)->is_the_hole(key);
+ FastElementsAccessorSubclass::SetImpl(object->elements(), index, *value);
+ }
+
+ static void DeleteImpl(Handle<JSObject> obj, uint32_t entry) {
+ ElementsKind kind = KindTraits::Kind;
+ if (IsFastPackedElementsKind(kind)) {
+ JSObject::TransitionElementsKind(obj, GetHoleyElementsKind(kind));
+ }
+ if (IsFastSmiOrObjectElementsKind(KindTraits::Kind)) {
+ JSObject::EnsureWritableFastElements(obj);
+ }
+ DeleteCommon(obj, entry, handle(obj->elements()));
+ }
+
+ static bool HasEntryImpl(FixedArrayBase* backing_store, uint32_t entry) {
+ return !BackingStore::cast(backing_store)->is_the_hole(entry);
}
static void ValidateContents(Handle<JSObject> holder, int length) {
@@ -1002,45 +1315,237 @@
(IsFastDoubleElementsKind(KindTraits::Kind) ==
((map == isolate->heap()->fixed_array_map() && length == 0) ||
map == isolate->heap()->fixed_double_array_map())));
+ if (length == 0) return; // nothing to do!
DisallowHeapAllocation no_gc;
- for (int i = 0; i < length; i++) {
- HandleScope scope(isolate);
- Handle<BackingStore> backing_store = Handle<BackingStore>::cast(elements);
- DCHECK((!IsFastSmiElementsKind(KindTraits::Kind) ||
- BackingStore::get(backing_store, i)->IsSmi()) ||
- (IsFastHoleyElementsKind(KindTraits::Kind) ==
- backing_store->is_the_hole(i)));
+ Handle<BackingStore> backing_store = Handle<BackingStore>::cast(elements);
+ if (IsFastSmiElementsKind(KindTraits::Kind)) {
+ for (int i = 0; i < length; i++) {
+ DCHECK(BackingStore::get(backing_store, i)->IsSmi() ||
+ (IsFastHoleyElementsKind(KindTraits::Kind) &&
+ backing_store->is_the_hole(i)));
+ }
}
#endif
}
-};
-
-static inline ElementsKind ElementsKindForArray(FixedArrayBase* array) {
- switch (array->map()->instance_type()) {
- case FIXED_ARRAY_TYPE:
- if (array->IsDictionary()) {
- return DICTIONARY_ELEMENTS;
- } else {
- return FAST_HOLEY_ELEMENTS;
- }
- case FIXED_DOUBLE_ARRAY_TYPE:
- return FAST_HOLEY_DOUBLE_ELEMENTS;
-
-#define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \
- case EXTERNAL_##TYPE##_ARRAY_TYPE: \
- return EXTERNAL_##TYPE##_ELEMENTS; \
- case FIXED_##TYPE##_ARRAY_TYPE: \
- return TYPE##_ELEMENTS;
-
- TYPED_ARRAYS(TYPED_ARRAY_CASE)
-#undef TYPED_ARRAY_CASE
-
- default:
- UNREACHABLE();
+ static Handle<Object> PopImpl(Handle<JSArray> receiver,
+ Handle<FixedArrayBase> backing_store) {
+ return FastElementsAccessorSubclass::RemoveElement(receiver, backing_store,
+ AT_END);
}
- return FAST_HOLEY_ELEMENTS;
-}
+
+ static Handle<Object> ShiftImpl(Handle<JSArray> receiver,
+ Handle<FixedArrayBase> backing_store) {
+ return FastElementsAccessorSubclass::RemoveElement(receiver, backing_store,
+ AT_START);
+ }
+
+ static uint32_t PushImpl(Handle<JSArray> receiver,
+ Handle<FixedArrayBase> backing_store,
+ Arguments* args, uint32_t push_size) {
+ return FastElementsAccessorSubclass::AddArguments(receiver, backing_store,
+ args, push_size, AT_END);
+ }
+
+ static uint32_t UnshiftImpl(Handle<JSArray> receiver,
+ Handle<FixedArrayBase> backing_store,
+ Arguments* args, uint32_t unshift_size) {
+ return FastElementsAccessorSubclass::AddArguments(
+ receiver, backing_store, args, unshift_size, AT_START);
+ }
+
+ static void MoveElements(Isolate* isolate, Handle<JSArray> receiver,
+ Handle<FixedArrayBase> backing_store, int dst_index,
+ int src_index, int len, int hole_start,
+ int hole_end) {
+ UNREACHABLE();
+ }
+
+ static Handle<JSArray> SliceImpl(Handle<JSObject> receiver,
+ Handle<FixedArrayBase> backing_store,
+ uint32_t start, uint32_t end) {
+ DCHECK(start < end);
+ Isolate* isolate = receiver->GetIsolate();
+ int result_len = end - start;
+ Handle<JSArray> result_array = isolate->factory()->NewJSArray(
+ KindTraits::Kind, result_len, result_len);
+ DisallowHeapAllocation no_gc;
+ FastElementsAccessorSubclass::CopyElementsImpl(
+ *backing_store, start, result_array->elements(), KindTraits::Kind, 0,
+ kPackedSizeNotKnown, result_len);
+ FastElementsAccessorSubclass::TryTransitionResultArrayToPacked(
+ result_array);
+ return result_array;
+ }
+
+ static Handle<JSArray> SpliceImpl(Handle<JSArray> receiver,
+ Handle<FixedArrayBase> backing_store,
+ uint32_t start, uint32_t delete_count,
+ Arguments* args, uint32_t add_count) {
+ Isolate* isolate = receiver->GetIsolate();
+ Heap* heap = isolate->heap();
+ uint32_t length = Smi::cast(receiver->length())->value();
+ uint32_t new_length = length - delete_count + add_count;
+
+ if (new_length == 0) {
+ receiver->set_elements(heap->empty_fixed_array());
+ receiver->set_length(Smi::FromInt(0));
+ return isolate->factory()->NewJSArrayWithElements(
+ backing_store, KindTraits::Kind, delete_count);
+ }
+
+ // Construct the result array which holds the deleted elements.
+ Handle<JSArray> deleted_elements = isolate->factory()->NewJSArray(
+ KindTraits::Kind, delete_count, delete_count);
+ if (delete_count > 0) {
+ DisallowHeapAllocation no_gc;
+ FastElementsAccessorSubclass::CopyElementsImpl(
+ *backing_store, start, deleted_elements->elements(), KindTraits::Kind,
+ 0, kPackedSizeNotKnown, delete_count);
+ }
+
+ // Delete and move elements to make space for add_count new elements.
+ if (add_count < delete_count) {
+ FastElementsAccessorSubclass::SpliceShrinkStep(
+ isolate, receiver, backing_store, start, delete_count, add_count,
+ length, new_length);
+ } else if (add_count > delete_count) {
+ backing_store = FastElementsAccessorSubclass::SpliceGrowStep(
+ isolate, receiver, backing_store, start, delete_count, add_count,
+ length, new_length);
+ }
+
+ // Copy over the arguments.
+ FastElementsAccessorSubclass::CopyArguments(args, backing_store, add_count,
+ 3, start);
+
+ receiver->set_length(Smi::FromInt(new_length));
+ FastElementsAccessorSubclass::TryTransitionResultArrayToPacked(
+ deleted_elements);
+ return deleted_elements;
+ }
+
+ private:
+ // SpliceShrinkStep might modify the backing_store.
+ static void SpliceShrinkStep(Isolate* isolate, Handle<JSArray> receiver,
+ Handle<FixedArrayBase> backing_store,
+ uint32_t start, uint32_t delete_count,
+ uint32_t add_count, uint32_t len,
+ uint32_t new_length) {
+ const int move_left_count = len - delete_count - start;
+ const int move_left_dst_index = start + add_count;
+ FastElementsAccessorSubclass::MoveElements(
+ isolate, receiver, backing_store, move_left_dst_index,
+ start + delete_count, move_left_count, new_length, len);
+ }
+
+ // SpliceGrowStep might modify the backing_store.
+ static Handle<FixedArrayBase> SpliceGrowStep(
+ Isolate* isolate, Handle<JSArray> receiver,
+ Handle<FixedArrayBase> backing_store, uint32_t start,
+ uint32_t delete_count, uint32_t add_count, uint32_t length,
+ uint32_t new_length) {
+ // Check we do not overflow the new_length.
+ DCHECK((add_count - delete_count) <= (Smi::kMaxValue - length));
+ // Check if backing_store is big enough.
+ if (new_length <= static_cast<uint32_t>(backing_store->length())) {
+ FastElementsAccessorSubclass::MoveElements(
+ isolate, receiver, backing_store, start + add_count,
+ start + delete_count, (length - delete_count - start), 0, 0);
+ // MoveElements updates the backing_store in-place.
+ return backing_store;
+ }
+ // New backing storage is needed.
+ int capacity = JSObject::NewElementsCapacity(new_length);
+ // Partially copy all elements up to start.
+ Handle<FixedArrayBase> new_elms =
+ FastElementsAccessorSubclass::ConvertElementsWithCapacity(
+ receiver, backing_store, KindTraits::Kind, capacity, start);
+ // Copy the trailing elements after start + delete_count
+ FastElementsAccessorSubclass::CopyElementsImpl(
+ *backing_store, start + delete_count, *new_elms, KindTraits::Kind,
+ start + add_count, kPackedSizeNotKnown,
+ ElementsAccessor::kCopyToEndAndInitializeToHole);
+ receiver->set_elements(*new_elms);
+ return new_elms;
+ }
+
+ static Handle<Object> RemoveElement(Handle<JSArray> receiver,
+ Handle<FixedArrayBase> backing_store,
+ Where remove_position) {
+ Isolate* isolate = receiver->GetIsolate();
+ uint32_t length =
+ static_cast<uint32_t>(Smi::cast(receiver->length())->value());
+ DCHECK(length > 0);
+ int new_length = length - 1;
+ int remove_index = remove_position == AT_START ? 0 : new_length;
+ Handle<Object> result =
+ FastElementsAccessorSubclass::GetImpl(backing_store, remove_index);
+ if (remove_position == AT_START) {
+ FastElementsAccessorSubclass::MoveElements(
+ isolate, receiver, backing_store, 0, 1, new_length, 0, 0);
+ }
+ FastElementsAccessorSubclass::SetLengthImpl(isolate, receiver, new_length,
+ backing_store);
+
+ if (IsHoleyElementsKind(KindTraits::Kind) && result->IsTheHole()) {
+ return receiver->GetIsolate()->factory()->undefined_value();
+ }
+ return result;
+ }
+
+ static uint32_t AddArguments(Handle<JSArray> receiver,
+ Handle<FixedArrayBase> backing_store,
+ Arguments* args, uint32_t add_size,
+ Where remove_position) {
+ uint32_t length = Smi::cast(receiver->length())->value();
+ DCHECK(add_size > 0);
+ uint32_t elms_len = backing_store->length();
+ // Check we do not overflow the new_length.
+ DCHECK(add_size <= static_cast<uint32_t>(Smi::kMaxValue - length));
+ uint32_t new_length = length + add_size;
+
+ if (new_length > elms_len) {
+ // New backing storage is needed.
+ uint32_t capacity = JSObject::NewElementsCapacity(new_length);
+ // If we add arguments to the start we have to shift the existing objects.
+ int copy_dst_index = remove_position == AT_START ? add_size : 0;
+ // Copy over all objects to a new backing_store.
+ backing_store = FastElementsAccessorSubclass::ConvertElementsWithCapacity(
+ receiver, backing_store, KindTraits::Kind, capacity, 0,
+ copy_dst_index, ElementsAccessor::kCopyToEndAndInitializeToHole);
+ receiver->set_elements(*backing_store);
+ } else if (remove_position == AT_START) {
+ // If the backing store has enough capacity and we add elements to the
+ // start we have to shift the existing objects.
+ Isolate* isolate = receiver->GetIsolate();
+ FastElementsAccessorSubclass::MoveElements(
+ isolate, receiver, backing_store, add_size, 0, length, 0, 0);
+ }
+
+ int insertion_index = remove_position == AT_START ? 0 : length;
+ // Copy the arguments to the start.
+ FastElementsAccessorSubclass::CopyArguments(args, backing_store, add_size,
+ 1, insertion_index);
+ // Set the length.
+ receiver->set_length(Smi::FromInt(new_length));
+ return new_length;
+ }
+
+ static void CopyArguments(Arguments* args, Handle<FixedArrayBase> dst_store,
+ uint32_t copy_size, uint32_t src_index,
+ uint32_t dst_index) {
+ // Add the provided values.
+ DisallowHeapAllocation no_gc;
+ FixedArrayBase* raw_backing_store = *dst_store;
+ WriteBarrierMode mode = raw_backing_store->GetWriteBarrierMode(no_gc);
+ for (uint32_t i = 0; i < copy_size; i++) {
+ Object* argument = (*args)[i + src_index];
+ FastElementsAccessorSubclass::SetImpl(raw_backing_store, i + dst_index,
+ argument, mode);
+ }
+ }
+};
template<typename FastElementsAccessorSubclass,
@@ -1052,6 +1557,46 @@
: FastElementsAccessor<FastElementsAccessorSubclass,
KindTraits>(name) {}
+ static inline void SetImpl(FixedArrayBase* backing_store, uint32_t entry,
+ Object* value) {
+ FixedArray::cast(backing_store)->set(entry, value);
+ }
+
+ static inline void SetImpl(FixedArrayBase* backing_store, uint32_t entry,
+ Object* value, WriteBarrierMode mode) {
+ FixedArray::cast(backing_store)->set(entry, value, mode);
+ }
+
+ static Object* GetRaw(FixedArray* backing_store, uint32_t entry) {
+ uint32_t index = FastElementsAccessorSubclass::GetIndexForEntryImpl(
+ backing_store, entry);
+ return backing_store->get(index);
+ }
+
+ static void MoveElements(Isolate* isolate, Handle<JSArray> receiver,
+ Handle<FixedArrayBase> backing_store, int dst_index,
+ int src_index, int len, int hole_start,
+ int hole_end) {
+ Heap* heap = isolate->heap();
+ Handle<FixedArray> dst_elms = Handle<FixedArray>::cast(backing_store);
+ if (heap->CanMoveObjectStart(*dst_elms) && dst_index == 0) {
+ // Update all the copies of this backing_store handle.
+ *dst_elms.location() =
+ FixedArray::cast(heap->LeftTrimFixedArray(*dst_elms, src_index));
+ receiver->set_elements(*dst_elms);
+ // Adjust the hole offset as the array has been shrunk.
+ hole_end -= src_index;
+ DCHECK_LE(hole_start, backing_store->length());
+ DCHECK_LE(hole_end, backing_store->length());
+ } else if (len != 0) {
+ DisallowHeapAllocation no_gc;
+ heap->MoveElements(*dst_elms, dst_index, src_index, len);
+ }
+ if (hole_start != hole_end) {
+ dst_elms->FillWithHoles(hole_start, hole_end);
+ }
+ }
+
// NOTE: this method violates the handlified function signature convention:
// raw pointer parameters in the function that allocates.
// See ElementsAccessor::CopyElements() for details.
@@ -1074,46 +1619,24 @@
case FAST_DOUBLE_ELEMENTS:
case FAST_HOLEY_DOUBLE_ELEMENTS: {
AllowHeapAllocation allow_allocation;
- CopyDoubleToObjectElements(
- from, from_start, to, to_kind, to_start, copy_size);
+ DCHECK(IsFastObjectElementsKind(to_kind));
+ CopyDoubleToObjectElements(from, from_start, to, to_start, copy_size);
break;
}
case DICTIONARY_ELEMENTS:
CopyDictionaryToObjectElements(from, from_start, to, to_kind, to_start,
copy_size);
break;
- case SLOPPY_ARGUMENTS_ELEMENTS: {
- // TODO(verwaest): This is a temporary hack to support extending
- // SLOPPY_ARGUMENTS_ELEMENTS in SetFastElementsCapacityAndLength.
- // This case should be UNREACHABLE().
- FixedArray* parameter_map = FixedArray::cast(from);
- FixedArrayBase* arguments = FixedArrayBase::cast(parameter_map->get(1));
- ElementsKind from_kind = ElementsKindForArray(arguments);
- CopyElementsImpl(arguments, from_start, to, from_kind,
- to_start, packed_size, copy_size);
- break;
- }
+ case FAST_SLOPPY_ARGUMENTS_ELEMENTS:
+ case SLOW_SLOPPY_ARGUMENTS_ELEMENTS:
+ UNREACHABLE();
#define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \
- case EXTERNAL_##TYPE##_ELEMENTS: \
case TYPE##_ELEMENTS: \
UNREACHABLE();
TYPED_ARRAYS(TYPED_ARRAY_CASE)
#undef TYPED_ARRAY_CASE
}
}
-
-
- static void SetFastElementsCapacityAndLength(
- Handle<JSObject> obj,
- uint32_t capacity,
- uint32_t length) {
- JSObject::SetFastElementsCapacitySmiMode set_capacity_mode =
- obj->HasFastSmiElements()
- ? JSObject::kAllowSmiElements
- : JSObject::kDontAllowSmiElements;
- JSObject::SetFastElementsCapacityAndLength(
- obj, capacity, length, set_capacity_mode);
- }
};
@@ -1174,13 +1697,41 @@
: FastElementsAccessor<FastElementsAccessorSubclass,
KindTraits>(name) {}
- static void SetFastElementsCapacityAndLength(Handle<JSObject> obj,
- uint32_t capacity,
- uint32_t length) {
- JSObject::SetFastDoubleElementsCapacityAndLength(obj, capacity, length);
+ static inline void SetImpl(FixedArrayBase* backing_store, uint32_t entry,
+ Object* value) {
+ FixedDoubleArray::cast(backing_store)->set(entry, value->Number());
}
- protected:
+ static inline void SetImpl(FixedArrayBase* backing_store, uint32_t entry,
+ Object* value, WriteBarrierMode mode) {
+ FixedDoubleArray::cast(backing_store)->set(entry, value->Number());
+ }
+
+ static void MoveElements(Isolate* isolate, Handle<JSArray> receiver,
+ Handle<FixedArrayBase> backing_store, int dst_index,
+ int src_index, int len, int hole_start,
+ int hole_end) {
+ Heap* heap = isolate->heap();
+ Handle<FixedDoubleArray> dst_elms =
+ Handle<FixedDoubleArray>::cast(backing_store);
+ if (heap->CanMoveObjectStart(*dst_elms) && dst_index == 0) {
+ // Update all the copies of this backing_store handle.
+ *dst_elms.location() = FixedDoubleArray::cast(
+ heap->LeftTrimFixedArray(*dst_elms, src_index));
+ receiver->set_elements(*dst_elms);
+ // Adjust the hole offset as the array has been shrunk.
+ hole_end -= src_index;
+ DCHECK_LE(hole_start, backing_store->length());
+ DCHECK_LE(hole_end, backing_store->length());
+ } else if (len != 0) {
+ MemMove(dst_elms->data_start() + dst_index,
+ dst_elms->data_start() + src_index, len * kDoubleSize);
+ }
+ if (hole_start != hole_end) {
+ dst_elms->FillWithHoles(hole_start, hole_end);
+ }
+ }
+
static void CopyElementsImpl(FixedArrayBase* from, uint32_t from_start,
FixedArrayBase* to, ElementsKind from_kind,
uint32_t to_start, int packed_size,
@@ -1206,11 +1757,11 @@
CopyDictionaryToDoubleElements(from, from_start, to, to_start,
copy_size);
break;
- case SLOPPY_ARGUMENTS_ELEMENTS:
+ case FAST_SLOPPY_ARGUMENTS_ELEMENTS:
+ case SLOW_SLOPPY_ARGUMENTS_ELEMENTS:
UNREACHABLE();
#define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \
- case EXTERNAL_##TYPE##_ELEMENTS: \
case TYPE##_ELEMENTS: \
UNREACHABLE();
TYPED_ARRAYS(TYPED_ARRAY_CASE)
@@ -1225,8 +1776,6 @@
FastPackedDoubleElementsAccessor,
ElementsKindTraits<FAST_DOUBLE_ELEMENTS> > {
public:
- friend class ElementsAccessorBase<FastPackedDoubleElementsAccessor,
- ElementsKindTraits<FAST_DOUBLE_ELEMENTS> >;
explicit FastPackedDoubleElementsAccessor(const char* name)
: FastDoubleElementsAccessor<
FastPackedDoubleElementsAccessor,
@@ -1239,9 +1788,6 @@
FastHoleyDoubleElementsAccessor,
ElementsKindTraits<FAST_HOLEY_DOUBLE_ELEMENTS> > {
public:
- friend class ElementsAccessorBase<
- FastHoleyDoubleElementsAccessor,
- ElementsKindTraits<FAST_HOLEY_DOUBLE_ELEMENTS> >;
explicit FastHoleyDoubleElementsAccessor(const char* name)
: FastDoubleElementsAccessor<
FastHoleyDoubleElementsAccessor,
@@ -1259,69 +1805,64 @@
: ElementsAccessorBase<AccessorClass,
ElementsKindTraits<Kind> >(name) {}
- protected:
typedef typename ElementsKindTraits<Kind>::BackingStore BackingStore;
typedef TypedElementsAccessor<Kind> AccessorClass;
- friend class ElementsAccessorBase<AccessorClass,
- ElementsKindTraits<Kind> >;
-
- MUST_USE_RESULT static MaybeHandle<Object> GetImpl(
- Handle<Object> receiver,
- Handle<JSObject> obj,
- uint32_t key,
- Handle<FixedArrayBase> backing_store) {
- if (key < AccessorClass::GetCapacityImpl(backing_store)) {
- return BackingStore::get(Handle<BackingStore>::cast(backing_store), key);
- } else {
- return backing_store->GetIsolate()->factory()->undefined_value();
- }
+ static inline void SetImpl(FixedArrayBase* backing_store, uint32_t entry,
+ Object* value) {
+ BackingStore::cast(backing_store)->SetValue(entry, value);
}
- MUST_USE_RESULT static PropertyAttributes GetAttributesImpl(
- Handle<Object> receiver,
- Handle<JSObject> obj,
- uint32_t key,
- Handle<FixedArrayBase> backing_store) {
- return
- key < AccessorClass::GetCapacityImpl(backing_store)
- ? NONE : ABSENT;
+ static inline void SetImpl(FixedArrayBase* backing_store, uint32_t entry,
+ Object* value, WriteBarrierMode mode) {
+ BackingStore::cast(backing_store)->SetValue(entry, value);
}
- MUST_USE_RESULT static MaybeHandle<Object> SetLengthImpl(
- Handle<JSObject> obj,
- Handle<Object> length,
- Handle<FixedArrayBase> backing_store) {
+ static Handle<Object> GetImpl(Handle<FixedArrayBase> backing_store,
+ uint32_t entry) {
+ uint32_t index = GetIndexForEntryImpl(*backing_store, entry);
+ return BackingStore::get(Handle<BackingStore>::cast(backing_store), index);
+ }
+
+ static PropertyDetails GetDetailsImpl(FixedArrayBase* backing_store,
+ uint32_t entry) {
+ return PropertyDetails(DONT_DELETE, DATA, 0, PropertyCellType::kNoCell);
+ }
+
+ static void SetLengthImpl(Isolate* isolate, Handle<JSArray> array,
+ uint32_t length,
+ Handle<FixedArrayBase> backing_store) {
// External arrays do not support changing their length.
UNREACHABLE();
- return obj;
}
- MUST_USE_RESULT virtual MaybeHandle<Object> Delete(
- Handle<JSObject> obj, uint32_t key, JSReceiver::DeleteMode mode) FINAL {
- // External arrays always ignore deletes.
- return obj->GetIsolate()->factory()->true_value();
+ static void DeleteImpl(Handle<JSObject> obj, uint32_t entry) {
+ UNREACHABLE();
}
- static bool HasElementImpl(Handle<Object> receiver,
- Handle<JSObject> holder,
- uint32_t key,
- Handle<FixedArrayBase> backing_store) {
- uint32_t capacity =
- AccessorClass::GetCapacityImpl(backing_store);
- return key < capacity;
+ static uint32_t GetIndexForEntryImpl(FixedArrayBase* backing_store,
+ uint32_t entry) {
+ return entry;
+ }
+
+ static uint32_t GetEntryForIndexImpl(JSObject* holder,
+ FixedArrayBase* backing_store,
+ uint32_t index, PropertyFilter filter) {
+ return index < AccessorClass::GetCapacityImpl(holder, backing_store)
+ ? index
+ : kMaxUInt32;
+ }
+
+ static uint32_t GetCapacityImpl(JSObject* holder,
+ FixedArrayBase* backing_store) {
+ JSArrayBufferView* view = JSArrayBufferView::cast(holder);
+ if (view->WasNeutered()) return 0;
+ return backing_store->length();
}
};
-#define EXTERNAL_ELEMENTS_ACCESSOR(Type, type, TYPE, ctype, size) \
- typedef TypedElementsAccessor<EXTERNAL_##TYPE##_ELEMENTS> \
- External##Type##ElementsAccessor;
-
-TYPED_ARRAYS(EXTERNAL_ELEMENTS_ACCESSOR)
-#undef EXTERNAL_ELEMENTS_ACCESSOR
-
#define FIXED_ELEMENTS_ACCESSOR(Type, type, TYPE, ctype, size) \
typedef TypedElementsAccessor<TYPE##_ELEMENTS > \
Fixed##Type##ElementsAccessor;
@@ -1330,507 +1871,409 @@
#undef FIXED_ELEMENTS_ACCESSOR
-
-class DictionaryElementsAccessor
- : public ElementsAccessorBase<DictionaryElementsAccessor,
- ElementsKindTraits<DICTIONARY_ELEMENTS> > {
- public:
- explicit DictionaryElementsAccessor(const char* name)
- : ElementsAccessorBase<DictionaryElementsAccessor,
- ElementsKindTraits<DICTIONARY_ELEMENTS> >(name) {}
-
- // Adjusts the length of the dictionary backing store and returns the new
- // length according to ES5 section 15.4.5.2 behavior.
- static Handle<Object> SetLengthWithoutNormalize(
- Handle<FixedArrayBase> store,
- Handle<JSArray> array,
- Handle<Object> length_object,
- uint32_t length) {
- Handle<SeededNumberDictionary> dict =
- Handle<SeededNumberDictionary>::cast(store);
- Isolate* isolate = array->GetIsolate();
- int capacity = dict->Capacity();
- uint32_t new_length = length;
- uint32_t old_length = static_cast<uint32_t>(array->length()->Number());
- if (new_length < old_length) {
- // Find last non-deletable element in range of elements to be
- // deleted and adjust range accordingly.
- for (int i = 0; i < capacity; i++) {
- DisallowHeapAllocation no_gc;
- Object* key = dict->KeyAt(i);
- if (key->IsNumber()) {
- uint32_t number = static_cast<uint32_t>(key->Number());
- if (new_length <= number && number < old_length) {
- PropertyDetails details = dict->DetailsAt(i);
- if (!details.IsConfigurable()) new_length = number + 1;
- }
- }
- }
- if (new_length != length) {
- length_object = isolate->factory()->NewNumberFromUint(new_length);
- }
- }
-
- if (new_length == 0) {
- // Flush the backing store.
- JSObject::ResetElements(array);
- } else {
- DisallowHeapAllocation no_gc;
- // Remove elements that should be deleted.
- int removed_entries = 0;
- Handle<Object> the_hole_value = isolate->factory()->the_hole_value();
- for (int i = 0; i < capacity; i++) {
- Object* key = dict->KeyAt(i);
- if (key->IsNumber()) {
- uint32_t number = static_cast<uint32_t>(key->Number());
- if (new_length <= number && number < old_length) {
- dict->SetEntry(i, the_hole_value, the_hole_value);
- removed_entries++;
- }
- }
- }
-
- // Update the number of elements.
- dict->ElementsRemoved(removed_entries);
- }
- return length_object;
- }
-
- MUST_USE_RESULT static MaybeHandle<Object> DeleteCommon(
- Handle<JSObject> obj,
- uint32_t key,
- JSReceiver::DeleteMode mode) {
- Isolate* isolate = obj->GetIsolate();
- Handle<FixedArray> backing_store(FixedArray::cast(obj->elements()),
- isolate);
- bool is_arguments =
- (obj->GetElementsKind() == SLOPPY_ARGUMENTS_ELEMENTS);
- if (is_arguments) {
- backing_store = handle(FixedArray::cast(backing_store->get(1)), isolate);
- }
- Handle<SeededNumberDictionary> dictionary =
- Handle<SeededNumberDictionary>::cast(backing_store);
- int entry = dictionary->FindEntry(key);
- if (entry != SeededNumberDictionary::kNotFound) {
- Handle<Object> result =
- SeededNumberDictionary::DeleteProperty(dictionary, entry, mode);
- if (*result == *isolate->factory()->false_value()) {
- if (mode == JSObject::STRICT_DELETION) {
- // Deleting a non-configurable property in strict mode.
- Handle<Object> name = isolate->factory()->NewNumberFromUint(key);
- Handle<Object> args[2] = { name, obj };
- THROW_NEW_ERROR(isolate, NewTypeError("strict_delete_property",
- HandleVector(args, 2)),
- Object);
- }
- return isolate->factory()->false_value();
- }
- Handle<FixedArray> new_elements =
- SeededNumberDictionary::Shrink(dictionary, key);
-
- if (is_arguments) {
- FixedArray::cast(obj->elements())->set(1, *new_elements);
- } else {
- obj->set_elements(*new_elements);
- }
- }
- return isolate->factory()->true_value();
- }
-
- static void CopyElementsImpl(FixedArrayBase* from, uint32_t from_start,
- FixedArrayBase* to, ElementsKind from_kind,
- uint32_t to_start, int packed_size,
- int copy_size) {
- UNREACHABLE();
- }
-
-
- protected:
- friend class ElementsAccessorBase<DictionaryElementsAccessor,
- ElementsKindTraits<DICTIONARY_ELEMENTS> >;
-
- MUST_USE_RESULT virtual MaybeHandle<Object> Delete(
- Handle<JSObject> obj, uint32_t key, JSReceiver::DeleteMode mode) FINAL {
- return DeleteCommon(obj, key, mode);
- }
-
- MUST_USE_RESULT static MaybeHandle<Object> GetImpl(
- Handle<Object> receiver,
- Handle<JSObject> obj,
- uint32_t key,
- Handle<FixedArrayBase> store) {
- Handle<SeededNumberDictionary> backing_store =
- Handle<SeededNumberDictionary>::cast(store);
- Isolate* isolate = backing_store->GetIsolate();
- int entry = backing_store->FindEntry(key);
- if (entry != SeededNumberDictionary::kNotFound) {
- Handle<Object> element(backing_store->ValueAt(entry), isolate);
- PropertyDetails details = backing_store->DetailsAt(entry);
- if (details.type() == CALLBACKS) {
- return JSObject::GetElementWithCallback(
- obj, receiver, element, key, obj);
- } else {
- return element;
- }
- }
- return isolate->factory()->the_hole_value();
- }
-
- MUST_USE_RESULT static PropertyAttributes GetAttributesImpl(
- Handle<Object> receiver,
- Handle<JSObject> obj,
- uint32_t key,
- Handle<FixedArrayBase> backing_store) {
- Handle<SeededNumberDictionary> dictionary =
- Handle<SeededNumberDictionary>::cast(backing_store);
- int entry = dictionary->FindEntry(key);
- if (entry != SeededNumberDictionary::kNotFound) {
- return dictionary->DetailsAt(entry).attributes();
- }
- return ABSENT;
- }
-
- MUST_USE_RESULT static MaybeHandle<AccessorPair> GetAccessorPairImpl(
- Handle<Object> receiver,
- Handle<JSObject> obj,
- uint32_t key,
- Handle<FixedArrayBase> store) {
- Handle<SeededNumberDictionary> backing_store =
- Handle<SeededNumberDictionary>::cast(store);
- int entry = backing_store->FindEntry(key);
- if (entry != SeededNumberDictionary::kNotFound &&
- backing_store->DetailsAt(entry).type() == CALLBACKS &&
- backing_store->ValueAt(entry)->IsAccessorPair()) {
- return handle(AccessorPair::cast(backing_store->ValueAt(entry)));
- }
- return MaybeHandle<AccessorPair>();
- }
-
- static bool HasElementImpl(Handle<Object> receiver,
- Handle<JSObject> holder,
- uint32_t key,
- Handle<FixedArrayBase> store) {
- Handle<SeededNumberDictionary> backing_store =
- Handle<SeededNumberDictionary>::cast(store);
- return backing_store->FindEntry(key) != SeededNumberDictionary::kNotFound;
- }
-
- static uint32_t GetKeyForIndexImpl(Handle<FixedArrayBase> store,
- uint32_t index) {
- DisallowHeapAllocation no_gc;
- Handle<SeededNumberDictionary> dict =
- Handle<SeededNumberDictionary>::cast(store);
- Object* key = dict->KeyAt(index);
- return Smi::cast(key)->value();
- }
-};
-
-
-class SloppyArgumentsElementsAccessor : public ElementsAccessorBase<
- SloppyArgumentsElementsAccessor,
- ElementsKindTraits<SLOPPY_ARGUMENTS_ELEMENTS> > {
+template <typename SloppyArgumentsElementsAccessorSubclass,
+ typename ArgumentsAccessor, typename KindTraits>
+class SloppyArgumentsElementsAccessor
+ : public ElementsAccessorBase<SloppyArgumentsElementsAccessorSubclass,
+ KindTraits> {
public:
explicit SloppyArgumentsElementsAccessor(const char* name)
- : ElementsAccessorBase<
- SloppyArgumentsElementsAccessor,
- ElementsKindTraits<SLOPPY_ARGUMENTS_ELEMENTS> >(name) {}
- protected:
- friend class ElementsAccessorBase<
- SloppyArgumentsElementsAccessor,
- ElementsKindTraits<SLOPPY_ARGUMENTS_ELEMENTS> >;
+ : ElementsAccessorBase<SloppyArgumentsElementsAccessorSubclass,
+ KindTraits>(name) {
+ USE(KindTraits::Kind);
+ }
- MUST_USE_RESULT static MaybeHandle<Object> GetImpl(
- Handle<Object> receiver,
- Handle<JSObject> obj,
- uint32_t key,
- Handle<FixedArrayBase> parameters) {
- Isolate* isolate = obj->GetIsolate();
+ static Handle<Object> GetImpl(Handle<FixedArrayBase> parameters,
+ uint32_t entry) {
+ Isolate* isolate = parameters->GetIsolate();
Handle<FixedArray> parameter_map = Handle<FixedArray>::cast(parameters);
- Handle<Object> probe = GetParameterMapArg(obj, parameter_map, key);
- if (!probe->IsTheHole()) {
+ uint32_t length = parameter_map->length() - 2;
+ if (entry < length) {
DisallowHeapAllocation no_gc;
+ Object* probe = parameter_map->get(entry + 2);
Context* context = Context::cast(parameter_map->get(0));
- int context_index = Handle<Smi>::cast(probe)->value();
- DCHECK(!context->get(context_index)->IsTheHole());
- return handle(context->get(context_index), isolate);
+ int context_entry = Smi::cast(probe)->value();
+ DCHECK(!context->get(context_entry)->IsTheHole());
+ return handle(context->get(context_entry), isolate);
} else {
// Object is not mapped, defer to the arguments.
Handle<FixedArray> arguments(FixedArray::cast(parameter_map->get(1)),
isolate);
- Handle<Object> result;
- ASSIGN_RETURN_ON_EXCEPTION(
- isolate, result,
- ElementsAccessor::ForArray(arguments)->Get(
- receiver, obj, key, arguments),
- Object);
+ Handle<Object> result =
+ ArgumentsAccessor::GetImpl(arguments, entry - length);
// Elements of the arguments object in slow mode might be slow aliases.
if (result->IsAliasedArgumentsEntry()) {
DisallowHeapAllocation no_gc;
- AliasedArgumentsEntry* entry = AliasedArgumentsEntry::cast(*result);
+ AliasedArgumentsEntry* alias = AliasedArgumentsEntry::cast(*result);
Context* context = Context::cast(parameter_map->get(0));
- int context_index = entry->aliased_context_slot();
- DCHECK(!context->get(context_index)->IsTheHole());
- return handle(context->get(context_index), isolate);
+ int context_entry = alias->aliased_context_slot();
+ DCHECK(!context->get(context_entry)->IsTheHole());
+ return handle(context->get(context_entry), isolate);
+ }
+ return result;
+ }
+ }
+
+ static void GrowCapacityAndConvertImpl(Handle<JSObject> object,
+ uint32_t capacity) {
+ UNREACHABLE();
+ }
+
+ static inline void SetImpl(FixedArrayBase* store, uint32_t entry,
+ Object* value) {
+ FixedArray* parameter_map = FixedArray::cast(store);
+ uint32_t length = parameter_map->length() - 2;
+ if (entry < length) {
+ Object* probe = parameter_map->get(entry + 2);
+ Context* context = Context::cast(parameter_map->get(0));
+ int context_entry = Smi::cast(probe)->value();
+ DCHECK(!context->get(context_entry)->IsTheHole());
+ context->set(context_entry, value);
+ } else {
+ FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
+ Object* current = ArgumentsAccessor::GetRaw(arguments, entry - length);
+ if (current->IsAliasedArgumentsEntry()) {
+ AliasedArgumentsEntry* alias = AliasedArgumentsEntry::cast(current);
+ Context* context = Context::cast(parameter_map->get(0));
+ int context_entry = alias->aliased_context_slot();
+ DCHECK(!context->get(context_entry)->IsTheHole());
+ context->set(context_entry, value);
} else {
- return result;
+ ArgumentsAccessor::SetImpl(arguments, entry - length, value);
}
}
}
- MUST_USE_RESULT static PropertyAttributes GetAttributesImpl(
- Handle<Object> receiver,
- Handle<JSObject> obj,
- uint32_t key,
- Handle<FixedArrayBase> backing_store) {
- Handle<FixedArray> parameter_map = Handle<FixedArray>::cast(backing_store);
- Handle<Object> probe = GetParameterMapArg(obj, parameter_map, key);
- if (!probe->IsTheHole()) {
- return NONE;
- } else {
- // If not aliased, check the arguments.
- Handle<FixedArray> arguments(FixedArray::cast(parameter_map->get(1)));
- return ElementsAccessor::ForArray(arguments)->GetAttributes(
- receiver, obj, key, arguments);
+ static void SetLengthImpl(Isolate* isolate, Handle<JSArray> array,
+ uint32_t length,
+ Handle<FixedArrayBase> parameter_map) {
+ // Sloppy arguments objects are not arrays.
+ UNREACHABLE();
+ }
+
+ static uint32_t GetCapacityImpl(JSObject* holder,
+ FixedArrayBase* backing_store) {
+ FixedArray* parameter_map = FixedArray::cast(backing_store);
+ FixedArrayBase* arguments = FixedArrayBase::cast(parameter_map->get(1));
+ return parameter_map->length() - 2 +
+ ArgumentsAccessor::GetCapacityImpl(holder, arguments);
+ }
+
+ static bool HasEntryImpl(FixedArrayBase* parameters, uint32_t entry) {
+ FixedArray* parameter_map = FixedArray::cast(parameters);
+ uint32_t length = parameter_map->length() - 2;
+ if (entry < length) {
+ return !GetParameterMapArg(parameter_map, entry)->IsTheHole();
}
+
+ FixedArrayBase* arguments = FixedArrayBase::cast(parameter_map->get(1));
+ return ArgumentsAccessor::HasEntryImpl(arguments, entry - length);
}
- MUST_USE_RESULT static MaybeHandle<AccessorPair> GetAccessorPairImpl(
- Handle<Object> receiver,
- Handle<JSObject> obj,
- uint32_t key,
- Handle<FixedArrayBase> parameters) {
- Handle<FixedArray> parameter_map = Handle<FixedArray>::cast(parameters);
- Handle<Object> probe = GetParameterMapArg(obj, parameter_map, key);
- if (!probe->IsTheHole()) {
- return MaybeHandle<AccessorPair>();
- } else {
- // If not aliased, check the arguments.
- Handle<FixedArray> arguments(FixedArray::cast(parameter_map->get(1)));
- return ElementsAccessor::ForArray(arguments)->GetAccessorPair(
- receiver, obj, key, arguments);
+ static uint32_t GetIndexForEntryImpl(FixedArrayBase* parameters,
+ uint32_t entry) {
+ FixedArray* parameter_map = FixedArray::cast(parameters);
+ uint32_t length = parameter_map->length() - 2;
+ if (entry < length) return entry;
+
+ FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
+ return ArgumentsAccessor::GetIndexForEntryImpl(arguments, entry - length);
+ }
+
+ static uint32_t GetEntryForIndexImpl(JSObject* holder,
+ FixedArrayBase* parameters,
+ uint32_t index, PropertyFilter filter) {
+ FixedArray* parameter_map = FixedArray::cast(parameters);
+ Object* probe = GetParameterMapArg(parameter_map, index);
+ if (!probe->IsTheHole()) return index;
+
+ FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
+ uint32_t entry = ArgumentsAccessor::GetEntryForIndexImpl(holder, arguments,
+ index, filter);
+ if (entry == kMaxUInt32) return entry;
+ return (parameter_map->length() - 2) + entry;
+ }
+
+ static PropertyDetails GetDetailsImpl(FixedArrayBase* parameters,
+ uint32_t entry) {
+ FixedArray* parameter_map = FixedArray::cast(parameters);
+ uint32_t length = parameter_map->length() - 2;
+ if (entry < length) {
+ return PropertyDetails(NONE, DATA, 0, PropertyCellType::kNoCell);
}
+ FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
+ return ArgumentsAccessor::GetDetailsImpl(arguments, entry - length);
}
- MUST_USE_RESULT static MaybeHandle<Object> SetLengthImpl(
- Handle<JSObject> obj,
- Handle<Object> length,
- Handle<FixedArrayBase> parameter_map) {
- // TODO(mstarzinger): This was never implemented but will be used once we
- // correctly implement [[DefineOwnProperty]] on arrays.
- UNIMPLEMENTED();
- return obj;
+ static Object* GetParameterMapArg(FixedArray* parameter_map, uint32_t index) {
+ uint32_t length = parameter_map->length() - 2;
+ return index < length
+ ? parameter_map->get(index + 2)
+ : Object::cast(parameter_map->GetHeap()->the_hole_value());
}
- MUST_USE_RESULT virtual MaybeHandle<Object> Delete(
- Handle<JSObject> obj, uint32_t key, JSReceiver::DeleteMode mode) FINAL {
- Isolate* isolate = obj->GetIsolate();
- Handle<FixedArray> parameter_map(FixedArray::cast(obj->elements()));
- Handle<Object> probe = GetParameterMapArg(obj, parameter_map, key);
- if (!probe->IsTheHole()) {
+ static void DeleteImpl(Handle<JSObject> obj, uint32_t entry) {
+ FixedArray* parameter_map = FixedArray::cast(obj->elements());
+ uint32_t length = static_cast<uint32_t>(parameter_map->length()) - 2;
+ if (entry < length) {
// TODO(kmillikin): We could check if this was the last aliased
// parameter, and revert to normal elements in that case. That
// would enable GC of the context.
- parameter_map->set_the_hole(key + 2);
+ parameter_map->set_the_hole(entry + 2);
} else {
- Handle<FixedArray> arguments(FixedArray::cast(parameter_map->get(1)));
- if (arguments->IsDictionary()) {
- return DictionaryElementsAccessor::DeleteCommon(obj, key, mode);
- } else {
- // It's difficult to access the version of DeleteCommon that is declared
- // in the templatized super class, call the concrete implementation in
- // the class for the most generalized ElementsKind subclass.
- return FastHoleyObjectElementsAccessor::DeleteCommon(obj, key, mode);
- }
+ SloppyArgumentsElementsAccessorSubclass::DeleteFromArguments(
+ obj, entry - length);
}
- return isolate->factory()->true_value();
+ }
+};
+
+
+class SlowSloppyArgumentsElementsAccessor
+ : public SloppyArgumentsElementsAccessor<
+ SlowSloppyArgumentsElementsAccessor, DictionaryElementsAccessor,
+ ElementsKindTraits<SLOW_SLOPPY_ARGUMENTS_ELEMENTS> > {
+ public:
+ explicit SlowSloppyArgumentsElementsAccessor(const char* name)
+ : SloppyArgumentsElementsAccessor<
+ SlowSloppyArgumentsElementsAccessor, DictionaryElementsAccessor,
+ ElementsKindTraits<SLOW_SLOPPY_ARGUMENTS_ELEMENTS> >(name) {}
+
+ static void DeleteFromArguments(Handle<JSObject> obj, uint32_t entry) {
+ Handle<FixedArray> parameter_map(FixedArray::cast(obj->elements()));
+ Handle<SeededNumberDictionary> dict(
+ SeededNumberDictionary::cast(parameter_map->get(1)));
+ // TODO(verwaest): Remove reliance on index in Shrink.
+ uint32_t index = GetIndexForEntryImpl(*dict, entry);
+ Handle<Object> result = SeededNumberDictionary::DeleteProperty(dict, entry);
+ USE(result);
+ DCHECK(result->IsTrue());
+ Handle<FixedArray> new_elements =
+ SeededNumberDictionary::Shrink(dict, index);
+ parameter_map->set(1, *new_elements);
+ }
+
+ static void AddImpl(Handle<JSObject> object, uint32_t index,
+ Handle<Object> value, PropertyAttributes attributes,
+ uint32_t new_capacity) {
+ Handle<FixedArray> parameter_map(FixedArray::cast(object->elements()));
+ Handle<FixedArrayBase> old_elements(
+ FixedArrayBase::cast(parameter_map->get(1)));
+ Handle<SeededNumberDictionary> dictionary =
+ old_elements->IsSeededNumberDictionary()
+ ? Handle<SeededNumberDictionary>::cast(old_elements)
+ : JSObject::NormalizeElements(object);
+ PropertyDetails details(attributes, DATA, 0, PropertyCellType::kNoCell);
+ Handle<SeededNumberDictionary> new_dictionary =
+ SeededNumberDictionary::AddNumberEntry(
+ dictionary, index, value, details,
+ object->map()->is_prototype_map());
+ if (attributes != NONE) object->RequireSlowElements(*new_dictionary);
+ if (*dictionary != *new_dictionary) {
+ FixedArray::cast(object->elements())->set(1, *new_dictionary);
+ }
+ }
+
+ static void ReconfigureImpl(Handle<JSObject> object,
+ Handle<FixedArrayBase> store, uint32_t entry,
+ Handle<Object> value,
+ PropertyAttributes attributes) {
+ Handle<FixedArray> parameter_map = Handle<FixedArray>::cast(store);
+ uint32_t length = parameter_map->length() - 2;
+ if (entry < length) {
+ Object* probe = parameter_map->get(entry + 2);
+ DCHECK(!probe->IsTheHole());
+ Context* context = Context::cast(parameter_map->get(0));
+ int context_entry = Smi::cast(probe)->value();
+ DCHECK(!context->get(context_entry)->IsTheHole());
+ context->set(context_entry, *value);
+
+ // Redefining attributes of an aliased element destroys fast aliasing.
+ parameter_map->set_the_hole(entry + 2);
+ // For elements that are still writable we re-establish slow aliasing.
+ if ((attributes & READ_ONLY) == 0) {
+ Isolate* isolate = store->GetIsolate();
+ value = isolate->factory()->NewAliasedArgumentsEntry(context_entry);
+ }
+
+ PropertyDetails details(attributes, DATA, 0, PropertyCellType::kNoCell);
+ Handle<SeededNumberDictionary> arguments(
+ SeededNumberDictionary::cast(parameter_map->get(1)));
+ arguments = SeededNumberDictionary::AddNumberEntry(
+ arguments, entry, value, details, object->map()->is_prototype_map());
+ // If the attributes were NONE, we would have called set rather than
+ // reconfigure.
+ DCHECK_NE(NONE, attributes);
+ object->RequireSlowElements(*arguments);
+ parameter_map->set(1, *arguments);
+ } else {
+ Handle<FixedArrayBase> arguments(
+ FixedArrayBase::cast(parameter_map->get(1)));
+ DictionaryElementsAccessor::ReconfigureImpl(
+ object, arguments, entry - length, value, attributes);
+ }
+ }
+};
+
+
+class FastSloppyArgumentsElementsAccessor
+ : public SloppyArgumentsElementsAccessor<
+ FastSloppyArgumentsElementsAccessor, FastHoleyObjectElementsAccessor,
+ ElementsKindTraits<FAST_SLOPPY_ARGUMENTS_ELEMENTS> > {
+ public:
+ explicit FastSloppyArgumentsElementsAccessor(const char* name)
+ : SloppyArgumentsElementsAccessor<
+ FastSloppyArgumentsElementsAccessor,
+ FastHoleyObjectElementsAccessor,
+ ElementsKindTraits<FAST_SLOPPY_ARGUMENTS_ELEMENTS> >(name) {}
+
+ static void DeleteFromArguments(Handle<JSObject> obj, uint32_t entry) {
+ FixedArray* parameter_map = FixedArray::cast(obj->elements());
+ Handle<FixedArray> arguments(FixedArray::cast(parameter_map->get(1)));
+ FastHoleyObjectElementsAccessor::DeleteCommon(obj, entry, arguments);
+ }
+
+ static void AddImpl(Handle<JSObject> object, uint32_t index,
+ Handle<Object> value, PropertyAttributes attributes,
+ uint32_t new_capacity) {
+ DCHECK_EQ(NONE, attributes);
+ Handle<FixedArray> parameter_map(FixedArray::cast(object->elements()));
+ Handle<FixedArrayBase> old_elements(
+ FixedArrayBase::cast(parameter_map->get(1)));
+ if (old_elements->IsSeededNumberDictionary() ||
+ static_cast<uint32_t>(old_elements->length()) < new_capacity) {
+ GrowCapacityAndConvertImpl(object, new_capacity);
+ }
+ FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
+ // For fast holey objects, the entry equals the index. The code above made
+ // sure that there's enough space to store the value. We cannot convert
+ // index to entry explicitly since the slot still contains the hole, so the
+ // current EntryForIndex would indicate that it is "absent" by returning
+ // kMaxUInt32.
+ FastHoleyObjectElementsAccessor::SetImpl(arguments, index, *value);
+ }
+
+ static void ReconfigureImpl(Handle<JSObject> object,
+ Handle<FixedArrayBase> store, uint32_t entry,
+ Handle<Object> value,
+ PropertyAttributes attributes) {
+ Handle<SeededNumberDictionary> dictionary =
+ JSObject::NormalizeElements(object);
+ FixedArray::cast(*store)->set(1, *dictionary);
+ uint32_t length = static_cast<uint32_t>(store->length()) - 2;
+ if (entry >= length) {
+ entry = dictionary->FindEntry(entry - length) + length;
+ }
+ SlowSloppyArgumentsElementsAccessor::ReconfigureImpl(object, store, entry,
+ value, attributes);
}
static void CopyElementsImpl(FixedArrayBase* from, uint32_t from_start,
FixedArrayBase* to, ElementsKind from_kind,
uint32_t to_start, int packed_size,
int copy_size) {
- UNREACHABLE();
- }
-
- static uint32_t GetCapacityImpl(Handle<FixedArrayBase> backing_store) {
- Handle<FixedArray> parameter_map = Handle<FixedArray>::cast(backing_store);
- Handle<FixedArrayBase> arguments(
- FixedArrayBase::cast(parameter_map->get(1)));
- return Max(static_cast<uint32_t>(parameter_map->length() - 2),
- ForArray(arguments)->GetCapacity(arguments));
- }
-
- static uint32_t GetKeyForIndexImpl(Handle<FixedArrayBase> dict,
- uint32_t index) {
- return index;
- }
-
- static bool HasElementImpl(Handle<Object> receiver,
- Handle<JSObject> holder,
- uint32_t key,
- Handle<FixedArrayBase> parameters) {
- Handle<FixedArray> parameter_map = Handle<FixedArray>::cast(parameters);
- Handle<Object> probe = GetParameterMapArg(holder, parameter_map, key);
- if (!probe->IsTheHole()) {
- return true;
+ DCHECK(!to->IsDictionary());
+ if (from_kind == SLOW_SLOPPY_ARGUMENTS_ELEMENTS) {
+ CopyDictionaryToObjectElements(from, from_start, to, FAST_HOLEY_ELEMENTS,
+ to_start, copy_size);
} else {
- Isolate* isolate = holder->GetIsolate();
- Handle<FixedArrayBase> arguments(FixedArrayBase::cast(
- Handle<FixedArray>::cast(parameter_map)->get(1)), isolate);
- ElementsAccessor* accessor = ElementsAccessor::ForArray(arguments);
- Handle<Object> value;
- ASSIGN_RETURN_ON_EXCEPTION_VALUE(
- isolate, value,
- accessor->Get(receiver, holder, key, arguments),
- false);
- return !value->IsTheHole();
+ DCHECK_EQ(FAST_SLOPPY_ARGUMENTS_ELEMENTS, from_kind);
+ CopyObjectToObjectElements(from, FAST_HOLEY_ELEMENTS, from_start, to,
+ FAST_HOLEY_ELEMENTS, to_start, copy_size);
}
}
- private:
- static Handle<Object> GetParameterMapArg(Handle<JSObject> holder,
- Handle<FixedArray> parameter_map,
- uint32_t key) {
- Isolate* isolate = holder->GetIsolate();
- uint32_t length = holder->IsJSArray()
- ? Smi::cast(Handle<JSArray>::cast(holder)->length())->value()
- : parameter_map->length();
- return key < (length - 2)
- ? handle(parameter_map->get(key + 2), isolate)
- : Handle<Object>::cast(isolate->factory()->the_hole_value());
+ static void GrowCapacityAndConvertImpl(Handle<JSObject> object,
+ uint32_t capacity) {
+ Handle<FixedArray> parameter_map(FixedArray::cast(object->elements()));
+ Handle<FixedArray> old_elements(FixedArray::cast(parameter_map->get(1)));
+ ElementsKind from_kind = object->GetElementsKind();
+ // This method should only be called if there's a reason to update the
+ // elements.
+ DCHECK(from_kind == SLOW_SLOPPY_ARGUMENTS_ELEMENTS ||
+ static_cast<uint32_t>(old_elements->length()) < capacity);
+ Handle<FixedArrayBase> elements =
+ ConvertElementsWithCapacity(object, old_elements, from_kind, capacity);
+ Handle<Map> new_map = JSObject::GetElementsTransitionMap(
+ object, FAST_SLOPPY_ARGUMENTS_ELEMENTS);
+ JSObject::MigrateToMap(object, new_map);
+ parameter_map->set(1, *elements);
+ JSObject::ValidateElements(object);
}
};
-ElementsAccessor* ElementsAccessor::ForArray(Handle<FixedArrayBase> array) {
- return elements_accessors_[ElementsKindForArray(*array)];
-}
+} // namespace
-void ElementsAccessor::InitializeOncePerProcess() {
- static ElementsAccessor* accessor_array[] = {
-#define ACCESSOR_ARRAY(Class, Kind, Store) new Class(#Kind),
- ELEMENTS_LIST(ACCESSOR_ARRAY)
-#undef ACCESSOR_ARRAY
- };
+void CheckArrayAbuse(Handle<JSObject> obj, const char* op, uint32_t index,
+ bool allow_appending) {
+ DisallowHeapAllocation no_allocation;
+ Object* raw_length = NULL;
+ const char* elements_type = "array";
+ if (obj->IsJSArray()) {
+ JSArray* array = JSArray::cast(*obj);
+ raw_length = array->length();
+ } else {
+ raw_length = Smi::FromInt(obj->elements()->length());
+ elements_type = "object";
+ }
- STATIC_ASSERT((sizeof(accessor_array) / sizeof(*accessor_array)) ==
- kElementsKindCount);
-
- elements_accessors_ = accessor_array;
-}
-
-
-void ElementsAccessor::TearDown() {
- if (elements_accessors_ == NULL) return;
-#define ACCESSOR_DELETE(Class, Kind, Store) delete elements_accessors_[Kind];
- ELEMENTS_LIST(ACCESSOR_DELETE)
-#undef ACCESSOR_DELETE
- elements_accessors_ = NULL;
-}
-
-
-template <typename ElementsAccessorSubclass, typename ElementsKindTraits>
-MUST_USE_RESULT
-MaybeHandle<Object> ElementsAccessorBase<ElementsAccessorSubclass,
- ElementsKindTraits>::
- SetLengthImpl(Handle<JSObject> obj,
- Handle<Object> length,
- Handle<FixedArrayBase> backing_store) {
- Isolate* isolate = obj->GetIsolate();
- Handle<JSArray> array = Handle<JSArray>::cast(obj);
-
- // Fast case: The new length fits into a Smi.
- Handle<Object> smi_length;
-
- if (Object::ToSmi(isolate, length).ToHandle(&smi_length) &&
- smi_length->IsSmi()) {
- const int value = Handle<Smi>::cast(smi_length)->value();
- if (value >= 0) {
- Handle<Object> new_length = ElementsAccessorSubclass::
- SetLengthWithoutNormalize(backing_store, array, smi_length, value);
- DCHECK(!new_length.is_null());
-
- // even though the proposed length was a smi, new_length could
- // still be a heap number because SetLengthWithoutNormalize doesn't
- // allow the array length property to drop below the index of
- // non-deletable elements.
- DCHECK(new_length->IsSmi() || new_length->IsHeapNumber() ||
- new_length->IsUndefined());
- if (new_length->IsSmi()) {
- array->set_length(*Handle<Smi>::cast(new_length));
- return array;
- } else if (new_length->IsHeapNumber()) {
- array->set_length(*new_length);
- return array;
+ if (raw_length->IsNumber()) {
+ double n = raw_length->Number();
+ if (FastI2D(FastD2UI(n)) == n) {
+ int32_t int32_length = DoubleToInt32(n);
+ uint32_t compare_length = static_cast<uint32_t>(int32_length);
+ if (allow_appending) compare_length++;
+ if (index >= compare_length) {
+ PrintF("[OOB %s %s (%s length = %d, element accessed = %d) in ",
+ elements_type, op, elements_type, static_cast<int>(int32_length),
+ static_cast<int>(index));
+ TraceTopFrame(obj->GetIsolate());
+ PrintF("]\n");
}
} else {
- return ThrowArrayLengthRangeError(isolate);
+ PrintF("[%s elements length not integer value in ", elements_type);
+ TraceTopFrame(obj->GetIsolate());
+ PrintF("]\n");
}
+ } else {
+ PrintF("[%s elements length not a number in ", elements_type);
+ TraceTopFrame(obj->GetIsolate());
+ PrintF("]\n");
}
-
- // Slow case: The new length does not fit into a Smi or conversion
- // to slow elements is needed for other reasons.
- if (length->IsNumber()) {
- uint32_t value;
- if (length->ToArrayIndex(&value)) {
- Handle<SeededNumberDictionary> dictionary =
- JSObject::NormalizeElements(array);
- DCHECK(!dictionary.is_null());
-
- Handle<Object> new_length = DictionaryElementsAccessor::
- SetLengthWithoutNormalize(dictionary, array, length, value);
- DCHECK(!new_length.is_null());
-
- DCHECK(new_length->IsNumber());
- array->set_length(*new_length);
- return array;
- } else {
- return ThrowArrayLengthRangeError(isolate);
- }
- }
-
- // Fall-back case: The new length is not a number so make the array
- // size one and set only element to length.
- Handle<FixedArray> new_backing_store = isolate->factory()->NewFixedArray(1);
- new_backing_store->set(0, *length);
- JSArray::SetContent(array, new_backing_store);
- return array;
}
MaybeHandle<Object> ArrayConstructInitializeElements(Handle<JSArray> array,
Arguments* args) {
- // Optimize the case where there is one argument and the argument is a
- // small smi.
- if (args->length() == 1) {
- Handle<Object> obj = args->at<Object>(0);
- if (obj->IsSmi()) {
- int len = Handle<Smi>::cast(obj)->value();
- if (len > 0 && len < JSObject::kInitialMaxFastElementArray) {
- ElementsKind elements_kind = array->GetElementsKind();
- JSArray::Initialize(array, len, len);
+ if (args->length() == 0) {
+ // Optimize the case where there are no parameters passed.
+ JSArray::Initialize(array, JSArray::kPreallocatedArrayElements);
+ return array;
- if (!IsFastHoleyElementsKind(elements_kind)) {
- elements_kind = GetHoleyElementsKind(elements_kind);
- JSObject::TransitionElementsKind(array, elements_kind);
- }
- return array;
- } else if (len == 0) {
- JSArray::Initialize(array, JSArray::kPreallocatedArrayElements);
- return array;
- }
+ } else if (args->length() == 1 && args->at<Object>(0)->IsNumber()) {
+ uint32_t length;
+ if (!args->at<Object>(0)->ToArrayLength(&length)) {
+ return ThrowArrayLengthRangeError(array->GetIsolate());
}
- // Take the argument as the length.
- JSArray::Initialize(array, 0);
+ // Optimize the case where there is one argument and the argument is a small
+ // smi.
+ if (length > 0 && length < JSArray::kInitialMaxFastElementArray) {
+ ElementsKind elements_kind = array->GetElementsKind();
+ JSArray::Initialize(array, length, length);
- return JSArray::SetElementsLength(array, obj);
- }
-
- // Optimize the case where there are no parameters passed.
- if (args->length() == 0) {
- JSArray::Initialize(array, JSArray::kPreallocatedArrayElements);
+ if (!IsFastHoleyElementsKind(elements_kind)) {
+ elements_kind = GetHoleyElementsKind(elements_kind);
+ JSObject::TransitionElementsKind(array, elements_kind);
+ }
+ } else if (length == 0) {
+ JSArray::Initialize(array, JSArray::kPreallocatedArrayElements);
+ } else {
+ // Take the argument as the length.
+ JSArray::Initialize(array, 0);
+ JSArray::SetLength(array, length);
+ }
return array;
}
@@ -1857,8 +2300,8 @@
case FAST_HOLEY_SMI_ELEMENTS:
case FAST_SMI_ELEMENTS: {
Handle<FixedArray> smi_elms = Handle<FixedArray>::cast(elms);
- for (int index = 0; index < number_of_elements; index++) {
- smi_elms->set(index, (*args)[index], SKIP_WRITE_BARRIER);
+ for (int entry = 0; entry < number_of_elements; entry++) {
+ smi_elms->set(entry, (*args)[entry], SKIP_WRITE_BARRIER);
}
break;
}
@@ -1867,8 +2310,8 @@
DisallowHeapAllocation no_gc;
WriteBarrierMode mode = elms->GetWriteBarrierMode(no_gc);
Handle<FixedArray> object_elms = Handle<FixedArray>::cast(elms);
- for (int index = 0; index < number_of_elements; index++) {
- object_elms->set(index, (*args)[index], mode);
+ for (int entry = 0; entry < number_of_elements; entry++) {
+ object_elms->set(entry, (*args)[entry], mode);
}
break;
}
@@ -1876,8 +2319,8 @@
case FAST_DOUBLE_ELEMENTS: {
Handle<FixedDoubleArray> double_elms =
Handle<FixedDoubleArray>::cast(elms);
- for (int index = 0; index < number_of_elements; index++) {
- double_elms->set(index, (*args)[index]->Number());
+ for (int entry = 0; entry < number_of_elements; entry++) {
+ double_elms->set(entry, (*args)[entry]->Number());
}
break;
}
@@ -1891,4 +2334,91 @@
return array;
}
-} } // namespace v8::internal
+
+void ElementsAccessor::InitializeOncePerProcess() {
+ static ElementsAccessor* accessor_array[] = {
+#define ACCESSOR_ARRAY(Class, Kind, Store) new Class(#Kind),
+ ELEMENTS_LIST(ACCESSOR_ARRAY)
+#undef ACCESSOR_ARRAY
+ };
+
+ STATIC_ASSERT((sizeof(accessor_array) / sizeof(*accessor_array)) ==
+ kElementsKindCount);
+
+ elements_accessors_ = accessor_array;
+}
+
+
+void ElementsAccessor::TearDown() {
+ if (elements_accessors_ == NULL) return;
+#define ACCESSOR_DELETE(Class, Kind, Store) delete elements_accessors_[Kind];
+ ELEMENTS_LIST(ACCESSOR_DELETE)
+#undef ACCESSOR_DELETE
+ elements_accessors_ = NULL;
+}
+
+
+Handle<JSArray> ElementsAccessor::Concat(Isolate* isolate, Arguments* args,
+ uint32_t concat_size) {
+ int result_len = 0;
+ ElementsKind elements_kind = GetInitialFastElementsKind();
+ bool has_double = false;
+ {
+ DisallowHeapAllocation no_gc;
+ // Iterate through all the arguments performing checks
+ // and calculating total length.
+ bool is_holey = false;
+ for (uint32_t i = 0; i < concat_size; i++) {
+ Object* arg = (*args)[i];
+ int len = Smi::cast(JSArray::cast(arg)->length())->value();
+
+ // We shouldn't overflow when adding another len.
+ const int kHalfOfMaxInt = 1 << (kBitsPerInt - 2);
+ STATIC_ASSERT(FixedArray::kMaxLength < kHalfOfMaxInt);
+ USE(kHalfOfMaxInt);
+ result_len += len;
+ DCHECK(0 <= result_len);
+ DCHECK(result_len <= FixedDoubleArray::kMaxLength);
+
+ ElementsKind arg_kind = JSArray::cast(arg)->map()->elements_kind();
+ has_double = has_double || IsFastDoubleElementsKind(arg_kind);
+ is_holey = is_holey || IsFastHoleyElementsKind(arg_kind);
+ elements_kind = GetMoreGeneralElementsKind(elements_kind, arg_kind);
+ }
+ if (is_holey) {
+ elements_kind = GetHoleyElementsKind(elements_kind);
+ }
+ }
+
+ // If a double array is concatted into a fast elements array, the fast
+ // elements array needs to be initialized to contain proper holes, since
+ // boxing doubles may cause incremental marking.
+ ArrayStorageAllocationMode mode =
+ has_double && IsFastObjectElementsKind(elements_kind)
+ ? INITIALIZE_ARRAY_ELEMENTS_WITH_HOLE
+ : DONT_INITIALIZE_ARRAY_ELEMENTS;
+ Handle<JSArray> result_array = isolate->factory()->NewJSArray(
+ elements_kind, result_len, result_len, Strength::WEAK, mode);
+ if (result_len == 0) return result_array;
+ int j = 0;
+ Handle<FixedArrayBase> storage(result_array->elements(), isolate);
+ ElementsAccessor* accessor = ElementsAccessor::ForKind(elements_kind);
+ for (uint32_t i = 0; i < concat_size; i++) {
+ // It is crucial to keep |array| in a raw pointer form to avoid
+ // performance degradation.
+ JSArray* array = JSArray::cast((*args)[i]);
+ int len = Smi::cast(array->length())->value();
+ if (len > 0) {
+ ElementsKind from_kind = array->GetElementsKind();
+ accessor->CopyElements(array, 0, from_kind, storage, j, len);
+ j += len;
+ }
+ }
+
+ DCHECK(j == result_len);
+ return result_array;
+}
+
+ElementsAccessor** ElementsAccessor::elements_accessors_ = NULL;
+} // namespace internal
+} // namespace v8