|
@ -29,6 +29,7 @@ |
|
|
|
|
|
|
|
|
#include "objects.h" |
|
|
#include "objects.h" |
|
|
#include "elements.h" |
|
|
#include "elements.h" |
|
|
|
|
|
#include "utils.h" |
|
|
|
|
|
|
|
|
namespace v8 { |
|
|
namespace v8 { |
|
|
namespace internal { |
|
|
namespace internal { |
|
@ -70,24 +71,34 @@ bool HasKey(FixedArray* array, Object* key) { |
|
|
// specialization of SomeElementsAccessor methods).
|
|
|
// specialization of SomeElementsAccessor methods).
|
|
|
template <typename ElementsAccessorSubclass, typename BackingStoreClass> |
|
|
template <typename ElementsAccessorSubclass, typename BackingStoreClass> |
|
|
class ElementsAccessorBase : public ElementsAccessor { |
|
|
class ElementsAccessorBase : public ElementsAccessor { |
|
|
public: |
|
|
protected: |
|
|
ElementsAccessorBase() { } |
|
|
ElementsAccessorBase() { } |
|
|
virtual MaybeObject* GetWithReceiver(JSObject* obj, |
|
|
virtual MaybeObject* Get(FixedArrayBase* backing_store, |
|
|
Object* receiver, |
|
|
uint32_t key, |
|
|
uint32_t index) { |
|
|
JSObject* obj, |
|
|
BackingStoreClass* backing_store = BackingStoreClass::cast(obj->elements()); |
|
|
Object* receiver) { |
|
|
if (index < ElementsAccessorSubclass::GetLength(backing_store)) { |
|
|
return ElementsAccessorSubclass::Get( |
|
|
return backing_store->get(index); |
|
|
BackingStoreClass::cast(backing_store), key, obj, receiver); |
|
|
} |
|
|
} |
|
|
return obj->GetHeap()->the_hole_value(); |
|
|
|
|
|
|
|
|
static MaybeObject* Get(BackingStoreClass* backing_store, |
|
|
|
|
|
uint32_t key, |
|
|
|
|
|
JSObject* obj, |
|
|
|
|
|
Object* receiver) { |
|
|
|
|
|
if (key < ElementsAccessorSubclass::GetCapacity(backing_store)) { |
|
|
|
|
|
return backing_store->get(key); |
|
|
|
|
|
} |
|
|
|
|
|
return backing_store->GetHeap()->the_hole_value(); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
virtual MaybeObject* Delete(JSObject* obj, |
|
|
virtual MaybeObject* Delete(JSObject* obj, |
|
|
uint32_t index, |
|
|
uint32_t key, |
|
|
JSReceiver::DeleteMode mode) = 0; |
|
|
JSReceiver::DeleteMode mode) = 0; |
|
|
|
|
|
|
|
|
virtual MaybeObject* AddElementsToFixedArray(FixedArrayBase* from, |
|
|
virtual MaybeObject* AddElementsToFixedArray(FixedArrayBase* from, |
|
|
FixedArray* to) { |
|
|
FixedArray* to, |
|
|
|
|
|
JSObject* holder, |
|
|
|
|
|
Object* receiver) { |
|
|
int len0 = to->length(); |
|
|
int len0 = to->length(); |
|
|
#ifdef DEBUG |
|
|
#ifdef DEBUG |
|
|
if (FLAG_enable_slow_asserts) { |
|
|
if (FLAG_enable_slow_asserts) { |
|
@ -97,7 +108,7 @@ class ElementsAccessorBase : public ElementsAccessor { |
|
|
} |
|
|
} |
|
|
#endif |
|
|
#endif |
|
|
BackingStoreClass* backing_store = BackingStoreClass::cast(from); |
|
|
BackingStoreClass* backing_store = BackingStoreClass::cast(from); |
|
|
int len1 = ElementsAccessorSubclass::GetCapacity(backing_store); |
|
|
uint32_t len1 = ElementsAccessorSubclass::GetCapacity(backing_store); |
|
|
|
|
|
|
|
|
// Optimize if 'other' is empty.
|
|
|
// Optimize if 'other' is empty.
|
|
|
// We cannot optimize if 'this' is empty, as other may have holes.
|
|
|
// We cannot optimize if 'this' is empty, as other may have holes.
|
|
@ -105,12 +116,22 @@ class ElementsAccessorBase : public ElementsAccessor { |
|
|
|
|
|
|
|
|
// Compute how many elements are not in other.
|
|
|
// Compute how many elements are not in other.
|
|
|
int extra = 0; |
|
|
int extra = 0; |
|
|
for (int y = 0; y < len1; y++) { |
|
|
for (uint32_t y = 0; y < len1; y++) { |
|
|
Object* value; |
|
|
if (ElementsAccessorSubclass::HasElementAtIndex(backing_store, |
|
|
|
|
|
y, |
|
|
|
|
|
holder, |
|
|
|
|
|
receiver)) { |
|
|
|
|
|
uint32_t key = |
|
|
|
|
|
ElementsAccessorSubclass::GetKeyForIndex(backing_store, y); |
|
|
MaybeObject* maybe_value = |
|
|
MaybeObject* maybe_value = |
|
|
ElementsAccessorSubclass::GetElementAtCapacityIndex(backing_store, y); |
|
|
ElementsAccessorSubclass::Get(backing_store, key, holder, receiver); |
|
|
|
|
|
Object* value; |
|
|
if (!maybe_value->ToObject(&value)) return maybe_value; |
|
|
if (!maybe_value->ToObject(&value)) return maybe_value; |
|
|
if (!value->IsTheHole() && !HasKey(to, value)) extra++; |
|
|
ASSERT(!value->IsTheHole()); |
|
|
|
|
|
if (!HasKey(to, value)) { |
|
|
|
|
|
extra++; |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
if (extra == 0) return to; |
|
|
if (extra == 0) return to; |
|
@ -133,9 +154,15 @@ class ElementsAccessorBase : public ElementsAccessor { |
|
|
} |
|
|
} |
|
|
// Fill in the extra values.
|
|
|
// Fill in the extra values.
|
|
|
int index = 0; |
|
|
int index = 0; |
|
|
for (int y = 0; y < len1; y++) { |
|
|
for (uint32_t y = 0; y < len1; y++) { |
|
|
|
|
|
if (ElementsAccessorSubclass::HasElementAtIndex(backing_store, |
|
|
|
|
|
y, |
|
|
|
|
|
holder, |
|
|
|
|
|
receiver)) { |
|
|
|
|
|
uint32_t key = |
|
|
|
|
|
ElementsAccessorSubclass::GetKeyForIndex(backing_store, y); |
|
|
MaybeObject* maybe_value = |
|
|
MaybeObject* maybe_value = |
|
|
ElementsAccessorSubclass::GetElementAtCapacityIndex(backing_store, y); |
|
|
ElementsAccessorSubclass::Get(backing_store, key, holder, receiver); |
|
|
Object* value; |
|
|
Object* value; |
|
|
if (!maybe_value->ToObject(&value)) return maybe_value; |
|
|
if (!maybe_value->ToObject(&value)) return maybe_value; |
|
|
if (!value->IsTheHole() && !HasKey(to, value)) { |
|
|
if (!value->IsTheHole() && !HasKey(to, value)) { |
|
@ -143,22 +170,51 @@ class ElementsAccessorBase : public ElementsAccessor { |
|
|
index++; |
|
|
index++; |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
} |
|
|
ASSERT(extra == index); |
|
|
ASSERT(extra == index); |
|
|
return result; |
|
|
return result; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
static uint32_t GetLength(BackingStoreClass* backing_store) { |
|
|
protected: |
|
|
|
|
|
static uint32_t GetCapacity(BackingStoreClass* backing_store) { |
|
|
return backing_store->length(); |
|
|
return backing_store->length(); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
static uint32_t GetCapacity(BackingStoreClass* backing_store) { |
|
|
virtual uint32_t GetCapacity(FixedArrayBase* backing_store) { |
|
|
return GetLength(backing_store); |
|
|
return ElementsAccessorSubclass::GetCapacity( |
|
|
|
|
|
BackingStoreClass::cast(backing_store)); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static bool HasElementAtIndex(BackingStoreClass* backing_store, |
|
|
|
|
|
uint32_t index, |
|
|
|
|
|
JSObject* holder, |
|
|
|
|
|
Object* receiver) { |
|
|
|
|
|
uint32_t key = |
|
|
|
|
|
ElementsAccessorSubclass::GetKeyForIndex(backing_store, index); |
|
|
|
|
|
MaybeObject* element = ElementsAccessorSubclass::Get(backing_store, |
|
|
|
|
|
key, |
|
|
|
|
|
holder, |
|
|
|
|
|
receiver); |
|
|
|
|
|
return !element->IsTheHole(); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
virtual bool HasElementAtIndex(FixedArrayBase* backing_store, |
|
|
|
|
|
uint32_t index, |
|
|
|
|
|
JSObject* holder, |
|
|
|
|
|
Object* receiver) { |
|
|
|
|
|
return ElementsAccessorSubclass::HasElementAtIndex( |
|
|
|
|
|
BackingStoreClass::cast(backing_store), index, holder, receiver); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
static MaybeObject* GetElementAtCapacityIndex( |
|
|
static uint32_t GetKeyForIndex(BackingStoreClass* backing_store, |
|
|
BackingStoreClass* backing_store, |
|
|
uint32_t index) { |
|
|
int index) { |
|
|
return index; |
|
|
return backing_store->get(index); |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
virtual uint32_t GetKeyForIndex(FixedArrayBase* backing_store, |
|
|
|
|
|
uint32_t index) { |
|
|
|
|
|
return ElementsAccessorSubclass::GetKeyForIndex( |
|
|
|
|
|
BackingStoreClass::cast(backing_store), index); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
private: |
|
|
private: |
|
@ -170,7 +226,7 @@ class FastElementsAccessor |
|
|
: public ElementsAccessorBase<FastElementsAccessor, FixedArray> { |
|
|
: public ElementsAccessorBase<FastElementsAccessor, FixedArray> { |
|
|
public: |
|
|
public: |
|
|
static MaybeObject* DeleteCommon(JSObject* obj, |
|
|
static MaybeObject* DeleteCommon(JSObject* obj, |
|
|
uint32_t index) { |
|
|
uint32_t key) { |
|
|
ASSERT(obj->HasFastElements() || obj->HasFastArgumentsElements()); |
|
|
ASSERT(obj->HasFastElements() || obj->HasFastArgumentsElements()); |
|
|
Heap* heap = obj->GetHeap(); |
|
|
Heap* heap = obj->GetHeap(); |
|
|
FixedArray* backing_store = FixedArray::cast(obj->elements()); |
|
|
FixedArray* backing_store = FixedArray::cast(obj->elements()); |
|
@ -186,8 +242,8 @@ class FastElementsAccessor |
|
|
obj->IsJSArray() |
|
|
obj->IsJSArray() |
|
|
? Smi::cast(JSArray::cast(obj)->length())->value() |
|
|
? Smi::cast(JSArray::cast(obj)->length())->value() |
|
|
: backing_store->length()); |
|
|
: backing_store->length()); |
|
|
if (index < length) { |
|
|
if (key < length) { |
|
|
backing_store->set_the_hole(index); |
|
|
backing_store->set_the_hole(key); |
|
|
// If an old space backing store is larger than a certain size and
|
|
|
// If an old space backing store is larger than a certain size and
|
|
|
// has too few used values, normalize it.
|
|
|
// has too few used values, normalize it.
|
|
|
// To avoid doing the check on every delete we require at least
|
|
|
// To avoid doing the check on every delete we require at least
|
|
@ -196,8 +252,8 @@ class FastElementsAccessor |
|
|
const int kMinLengthForSparsenessCheck = 64; |
|
|
const int kMinLengthForSparsenessCheck = 64; |
|
|
if (backing_store->length() >= kMinLengthForSparsenessCheck && |
|
|
if (backing_store->length() >= kMinLengthForSparsenessCheck && |
|
|
!heap->InNewSpace(backing_store) && |
|
|
!heap->InNewSpace(backing_store) && |
|
|
((index > 0 && backing_store->get(index - 1) == hole) || |
|
|
((key > 0 && backing_store->get(key - 1) == hole) || |
|
|
(index + 1 < length && backing_store->get(index + 1) == hole))) { |
|
|
(key + 1 < length && backing_store->get(key + 1) == hole))) { |
|
|
int num_used = 0; |
|
|
int num_used = 0; |
|
|
for (int i = 0; i < backing_store->length(); ++i) { |
|
|
for (int i = 0; i < backing_store->length(); ++i) { |
|
|
if (backing_store->get(i) != hole) ++num_used; |
|
|
if (backing_store->get(i) != hole) ++num_used; |
|
@ -213,10 +269,11 @@ class FastElementsAccessor |
|
|
return heap->true_value(); |
|
|
return heap->true_value(); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
protected: |
|
|
virtual MaybeObject* Delete(JSObject* obj, |
|
|
virtual MaybeObject* Delete(JSObject* obj, |
|
|
uint32_t index, |
|
|
uint32_t key, |
|
|
JSReceiver::DeleteMode mode) { |
|
|
JSReceiver::DeleteMode mode) { |
|
|
return DeleteCommon(obj, index); |
|
|
return DeleteCommon(obj, key); |
|
|
} |
|
|
} |
|
|
}; |
|
|
}; |
|
|
|
|
|
|
|
@ -224,17 +281,28 @@ class FastElementsAccessor |
|
|
class FastDoubleElementsAccessor |
|
|
class FastDoubleElementsAccessor |
|
|
: public ElementsAccessorBase<FastDoubleElementsAccessor, |
|
|
: public ElementsAccessorBase<FastDoubleElementsAccessor, |
|
|
FixedDoubleArray> { |
|
|
FixedDoubleArray> { |
|
|
|
|
|
protected: |
|
|
|
|
|
friend class ElementsAccessorBase<FastDoubleElementsAccessor, |
|
|
|
|
|
FixedDoubleArray>; |
|
|
|
|
|
|
|
|
virtual MaybeObject* Delete(JSObject* obj, |
|
|
virtual MaybeObject* Delete(JSObject* obj, |
|
|
uint32_t index, |
|
|
uint32_t key, |
|
|
JSReceiver::DeleteMode mode) { |
|
|
JSReceiver::DeleteMode mode) { |
|
|
int length = obj->IsJSArray() |
|
|
int length = obj->IsJSArray() |
|
|
? Smi::cast(JSArray::cast(obj)->length())->value() |
|
|
? Smi::cast(JSArray::cast(obj)->length())->value() |
|
|
: FixedDoubleArray::cast(obj->elements())->length(); |
|
|
: FixedDoubleArray::cast(obj->elements())->length(); |
|
|
if (index < static_cast<uint32_t>(length)) { |
|
|
if (key < static_cast<uint32_t>(length)) { |
|
|
FixedDoubleArray::cast(obj->elements())->set_the_hole(index); |
|
|
FixedDoubleArray::cast(obj->elements())->set_the_hole(key); |
|
|
} |
|
|
} |
|
|
return obj->GetHeap()->true_value(); |
|
|
return obj->GetHeap()->true_value(); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static bool HasElementAtIndex(FixedDoubleArray* backing_store, |
|
|
|
|
|
uint32_t index, |
|
|
|
|
|
JSObject* holder, |
|
|
|
|
|
Object* receiver) { |
|
|
|
|
|
return !backing_store->is_the_hole(index); |
|
|
|
|
|
} |
|
|
}; |
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
@ -244,20 +312,23 @@ template<typename ExternalElementsAccessorSubclass, |
|
|
class ExternalElementsAccessor |
|
|
class ExternalElementsAccessor |
|
|
: public ElementsAccessorBase<ExternalElementsAccessorSubclass, |
|
|
: public ElementsAccessorBase<ExternalElementsAccessorSubclass, |
|
|
ExternalArray> { |
|
|
ExternalArray> { |
|
|
public: |
|
|
protected: |
|
|
virtual MaybeObject* GetWithReceiver(JSObject* obj, |
|
|
friend class ElementsAccessorBase<ExternalElementsAccessorSubclass, |
|
|
Object* receiver, |
|
|
ExternalArray>; |
|
|
uint32_t index) { |
|
|
|
|
|
ExternalArray* backing_store = ExternalArray::cast(obj->elements()); |
|
|
static MaybeObject* Get(ExternalArray* backing_store, |
|
|
if (index < ExternalElementsAccessorSubclass::GetLength(backing_store)) { |
|
|
uint32_t key, |
|
|
return backing_store->get(index); |
|
|
JSObject* obj, |
|
|
|
|
|
Object* receiver) { |
|
|
|
|
|
if (key < ExternalElementsAccessorSubclass::GetCapacity(backing_store)) { |
|
|
|
|
|
return backing_store->get(key); |
|
|
} else { |
|
|
} else { |
|
|
return obj->GetHeap()->undefined_value(); |
|
|
return backing_store->GetHeap()->undefined_value(); |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
virtual MaybeObject* Delete(JSObject* obj, |
|
|
virtual MaybeObject* Delete(JSObject* obj, |
|
|
uint32_t index, |
|
|
uint32_t key, |
|
|
JSReceiver::DeleteMode mode) { |
|
|
JSReceiver::DeleteMode mode) { |
|
|
// External arrays always ignore deletes.
|
|
|
// External arrays always ignore deletes.
|
|
|
return obj->GetHeap()->true_value(); |
|
|
return obj->GetHeap()->true_value(); |
|
@ -323,30 +394,8 @@ class DictionaryElementsAccessor |
|
|
: public ElementsAccessorBase<DictionaryElementsAccessor, |
|
|
: public ElementsAccessorBase<DictionaryElementsAccessor, |
|
|
NumberDictionary> { |
|
|
NumberDictionary> { |
|
|
public: |
|
|
public: |
|
|
static MaybeObject* GetNumberDictionaryElement( |
|
|
|
|
|
JSObject* obj, |
|
|
|
|
|
Object* receiver, |
|
|
|
|
|
NumberDictionary* backing_store, |
|
|
|
|
|
uint32_t index) { |
|
|
|
|
|
int entry = backing_store->FindEntry(index); |
|
|
|
|
|
if (entry != NumberDictionary::kNotFound) { |
|
|
|
|
|
Object* element = backing_store->ValueAt(entry); |
|
|
|
|
|
PropertyDetails details = backing_store->DetailsAt(entry); |
|
|
|
|
|
if (details.type() == CALLBACKS) { |
|
|
|
|
|
return obj->GetElementWithCallback(receiver, |
|
|
|
|
|
element, |
|
|
|
|
|
index, |
|
|
|
|
|
obj); |
|
|
|
|
|
} else { |
|
|
|
|
|
return element; |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
return obj->GetHeap()->the_hole_value(); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static MaybeObject* DeleteCommon(JSObject* obj, |
|
|
static MaybeObject* DeleteCommon(JSObject* obj, |
|
|
uint32_t index, |
|
|
uint32_t key, |
|
|
JSReceiver::DeleteMode mode) { |
|
|
JSReceiver::DeleteMode mode) { |
|
|
Isolate* isolate = obj->GetIsolate(); |
|
|
Isolate* isolate = obj->GetIsolate(); |
|
|
Heap* heap = isolate->heap(); |
|
|
Heap* heap = isolate->heap(); |
|
@ -357,11 +406,11 @@ class DictionaryElementsAccessor |
|
|
backing_store = FixedArray::cast(backing_store->get(1)); |
|
|
backing_store = FixedArray::cast(backing_store->get(1)); |
|
|
} |
|
|
} |
|
|
NumberDictionary* dictionary = NumberDictionary::cast(backing_store); |
|
|
NumberDictionary* dictionary = NumberDictionary::cast(backing_store); |
|
|
int entry = dictionary->FindEntry(index); |
|
|
int entry = dictionary->FindEntry(key); |
|
|
if (entry != NumberDictionary::kNotFound) { |
|
|
if (entry != NumberDictionary::kNotFound) { |
|
|
Object* result = dictionary->DeleteProperty(entry, mode); |
|
|
Object* result = dictionary->DeleteProperty(entry, mode); |
|
|
if (result == heap->true_value()) { |
|
|
if (result == heap->true_value()) { |
|
|
MaybeObject* maybe_elements = dictionary->Shrink(index); |
|
|
MaybeObject* maybe_elements = dictionary->Shrink(key); |
|
|
FixedArray* new_elements = NULL; |
|
|
FixedArray* new_elements = NULL; |
|
|
if (!maybe_elements->To(&new_elements)) { |
|
|
if (!maybe_elements->To(&new_elements)) { |
|
|
return maybe_elements; |
|
|
return maybe_elements; |
|
@ -378,7 +427,7 @@ class DictionaryElementsAccessor |
|
|
// throws an exception.
|
|
|
// throws an exception.
|
|
|
HandleScope scope(isolate); |
|
|
HandleScope scope(isolate); |
|
|
Handle<Object> holder(obj); |
|
|
Handle<Object> holder(obj); |
|
|
Handle<Object> name = isolate->factory()->NewNumberFromUint(index); |
|
|
Handle<Object> name = isolate->factory()->NewNumberFromUint(key); |
|
|
Handle<Object> args[2] = { name, holder }; |
|
|
Handle<Object> args[2] = { name, holder }; |
|
|
Handle<Object> error = |
|
|
Handle<Object> error = |
|
|
isolate->factory()->NewTypeError("strict_delete_property", |
|
|
isolate->factory()->NewTypeError("strict_delete_property", |
|
@ -389,32 +438,40 @@ class DictionaryElementsAccessor |
|
|
return heap->true_value(); |
|
|
return heap->true_value(); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
protected: |
|
|
|
|
|
friend class ElementsAccessorBase<DictionaryElementsAccessor, |
|
|
|
|
|
NumberDictionary>; |
|
|
|
|
|
|
|
|
virtual MaybeObject* Delete(JSObject* obj, |
|
|
virtual MaybeObject* Delete(JSObject* obj, |
|
|
uint32_t index, |
|
|
uint32_t key, |
|
|
JSReceiver::DeleteMode mode) { |
|
|
JSReceiver::DeleteMode mode) { |
|
|
return DeleteCommon(obj, index, mode); |
|
|
return DeleteCommon(obj, key, mode); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
virtual MaybeObject* GetWithReceiver(JSObject* obj, |
|
|
static MaybeObject* Get(NumberDictionary* backing_store, |
|
|
Object* receiver, |
|
|
uint32_t key, |
|
|
uint32_t index) { |
|
|
JSObject* obj, |
|
|
return GetNumberDictionaryElement(obj, |
|
|
Object* receiver) { |
|
|
receiver, |
|
|
int entry = backing_store->FindEntry(key); |
|
|
obj->element_dictionary(), |
|
|
if (entry != NumberDictionary::kNotFound) { |
|
|
index); |
|
|
Object* element = backing_store->ValueAt(entry); |
|
|
|
|
|
PropertyDetails details = backing_store->DetailsAt(entry); |
|
|
|
|
|
if (details.type() == CALLBACKS) { |
|
|
|
|
|
return obj->GetElementWithCallback(receiver, |
|
|
|
|
|
element, |
|
|
|
|
|
key, |
|
|
|
|
|
obj); |
|
|
|
|
|
} else { |
|
|
|
|
|
return element; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
static uint32_t GetCapacity(NumberDictionary* dict) { |
|
|
|
|
|
return dict->Capacity(); |
|
|
|
|
|
} |
|
|
} |
|
|
|
|
|
return obj->GetHeap()->the_hole_value(); |
|
|
static MaybeObject* GetElementAtCapacityIndex(NumberDictionary* dict, |
|
|
|
|
|
int index) { |
|
|
|
|
|
if (dict->IsKey(dict->KeyAt(index))) { |
|
|
|
|
|
return dict->ValueAt(index); |
|
|
|
|
|
} else { |
|
|
|
|
|
return dict->GetHeap()->the_hole_value(); |
|
|
|
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static uint32_t GetKeyForIndex(NumberDictionary* dict, |
|
|
|
|
|
uint32_t index) { |
|
|
|
|
|
Object* key = dict->KeyAt(index); |
|
|
|
|
|
return Smi::cast(key)->value(); |
|
|
} |
|
|
} |
|
|
}; |
|
|
}; |
|
|
|
|
|
|
|
@ -422,15 +479,16 @@ class DictionaryElementsAccessor |
|
|
class NonStrictArgumentsElementsAccessor |
|
|
class NonStrictArgumentsElementsAccessor |
|
|
: public ElementsAccessorBase<NonStrictArgumentsElementsAccessor, |
|
|
: public ElementsAccessorBase<NonStrictArgumentsElementsAccessor, |
|
|
FixedArray> { |
|
|
FixedArray> { |
|
|
public: |
|
|
protected: |
|
|
virtual MaybeObject* GetWithReceiver(JSObject* obj, |
|
|
friend class ElementsAccessorBase<NonStrictArgumentsElementsAccessor, |
|
|
Object* receiver, |
|
|
FixedArray>; |
|
|
uint32_t index) { |
|
|
|
|
|
FixedArray* parameter_map = FixedArray::cast(obj->elements()); |
|
|
static MaybeObject* Get(FixedArray* parameter_map, |
|
|
uint32_t length = parameter_map->length(); |
|
|
uint32_t key, |
|
|
Object* probe = |
|
|
JSObject* obj, |
|
|
(index < length - 2) ? parameter_map->get(index + 2) : NULL; |
|
|
Object* receiver) { |
|
|
if (probe != NULL && !probe->IsTheHole()) { |
|
|
Object* probe = GetParameterMapArg(parameter_map, key); |
|
|
|
|
|
if (!probe->IsTheHole()) { |
|
|
Context* context = Context::cast(parameter_map->get(0)); |
|
|
Context* context = Context::cast(parameter_map->get(0)); |
|
|
int context_index = Smi::cast(probe)->value(); |
|
|
int context_index = Smi::cast(probe)->value(); |
|
|
ASSERT(!context->get(context_index)->IsTheHole()); |
|
|
ASSERT(!context->get(context_index)->IsTheHole()); |
|
@ -438,56 +496,105 @@ class NonStrictArgumentsElementsAccessor |
|
|
} else { |
|
|
} else { |
|
|
// Object is not mapped, defer to the arguments.
|
|
|
// Object is not mapped, defer to the arguments.
|
|
|
FixedArray* arguments = FixedArray::cast(parameter_map->get(1)); |
|
|
FixedArray* arguments = FixedArray::cast(parameter_map->get(1)); |
|
|
if (arguments->IsDictionary()) { |
|
|
return ElementsAccessor::ForArray(arguments)->Get(arguments, |
|
|
return DictionaryElementsAccessor::GetNumberDictionaryElement( |
|
|
key, |
|
|
obj, |
|
|
obj, |
|
|
receiver, |
|
|
receiver); |
|
|
NumberDictionary::cast(arguments), |
|
|
|
|
|
index); |
|
|
|
|
|
} else if (index < static_cast<uint32_t>(arguments->length())) { |
|
|
|
|
|
return arguments->get(index); |
|
|
|
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
return obj->GetHeap()->the_hole_value(); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
virtual MaybeObject* Delete(JSObject* obj, |
|
|
virtual MaybeObject* Delete(JSObject* obj, |
|
|
uint32_t index, |
|
|
uint32_t key |
|
|
|
|
|
, |
|
|
JSReceiver::DeleteMode mode) { |
|
|
JSReceiver::DeleteMode mode) { |
|
|
FixedArray* parameter_map = FixedArray::cast(obj->elements()); |
|
|
FixedArray* parameter_map = FixedArray::cast(obj->elements()); |
|
|
uint32_t length = parameter_map->length(); |
|
|
Object* probe = GetParameterMapArg(parameter_map, key); |
|
|
Object* probe = |
|
|
if (!probe->IsTheHole()) { |
|
|
index < (length - 2) ? parameter_map->get(index + 2) : NULL; |
|
|
|
|
|
if (probe != NULL && !probe->IsTheHole()) { |
|
|
|
|
|
// TODO(kmillikin): We could check if this was the last aliased
|
|
|
// TODO(kmillikin): We could check if this was the last aliased
|
|
|
// parameter, and revert to normal elements in that case. That
|
|
|
// parameter, and revert to normal elements in that case. That
|
|
|
// would enable GC of the context.
|
|
|
// would enable GC of the context.
|
|
|
parameter_map->set_the_hole(index + 2); |
|
|
parameter_map->set_the_hole(key + 2); |
|
|
} else { |
|
|
} else { |
|
|
FixedArray* arguments = FixedArray::cast(parameter_map->get(1)); |
|
|
FixedArray* arguments = FixedArray::cast(parameter_map->get(1)); |
|
|
if (arguments->IsDictionary()) { |
|
|
if (arguments->IsDictionary()) { |
|
|
return DictionaryElementsAccessor::DeleteCommon(obj, index, mode); |
|
|
return DictionaryElementsAccessor::DeleteCommon(obj, key, mode); |
|
|
} else { |
|
|
} else { |
|
|
return FastElementsAccessor::DeleteCommon(obj, index); |
|
|
return FastElementsAccessor::DeleteCommon(obj, key); |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
return obj->GetHeap()->true_value(); |
|
|
return obj->GetHeap()->true_value(); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
static uint32_t GetCapacity(FixedArray* obj) { |
|
|
static uint32_t GetCapacity(FixedArray* parameter_map) { |
|
|
// TODO(danno): Return max of parameter map length or backing store
|
|
|
FixedArrayBase* arguments = FixedArrayBase::cast(parameter_map->get(1)); |
|
|
// capacity.
|
|
|
return Max(static_cast<uint32_t>(parameter_map->length() - 2), |
|
|
return 0; |
|
|
ForArray(arguments)->GetCapacity(arguments)); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
static MaybeObject* GetElementAtCapacityIndex(FixedArray* obj, int index) { |
|
|
static uint32_t GetKeyForIndex(FixedArray* dict, |
|
|
// TODO(danno): Return either value from parameter map of backing
|
|
|
uint32_t index) { |
|
|
// store value at index.
|
|
|
return index; |
|
|
return obj->GetHeap()->the_hole_value(); |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static bool HasElementAtIndex(FixedArray* parameter_map, |
|
|
|
|
|
uint32_t index, |
|
|
|
|
|
JSObject* holder, |
|
|
|
|
|
Object* receiver) { |
|
|
|
|
|
Object* probe = GetParameterMapArg(parameter_map, index); |
|
|
|
|
|
if (!probe->IsTheHole()) { |
|
|
|
|
|
return true; |
|
|
|
|
|
} else { |
|
|
|
|
|
FixedArrayBase* arguments = FixedArrayBase::cast(parameter_map->get(1)); |
|
|
|
|
|
ElementsAccessor* accessor = ElementsAccessor::ForArray(arguments); |
|
|
|
|
|
return !accessor->Get(arguments, index, holder, receiver)->IsTheHole(); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
private: |
|
|
|
|
|
static Object* GetParameterMapArg(FixedArray* parameter_map, |
|
|
|
|
|
uint32_t key) { |
|
|
|
|
|
uint32_t length = parameter_map->length(); |
|
|
|
|
|
return key < (length - 2 ) |
|
|
|
|
|
? parameter_map->get(key + 2) |
|
|
|
|
|
: parameter_map->GetHeap()->the_hole_value(); |
|
|
} |
|
|
} |
|
|
}; |
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
ElementsAccessor* ElementsAccessor::ForArray(FixedArrayBase* array) { |
|
|
|
|
|
switch (array->map()->instance_type()) { |
|
|
|
|
|
case FIXED_ARRAY_TYPE: |
|
|
|
|
|
if (array->IsDictionary()) { |
|
|
|
|
|
return elements_accessors_[JSObject::DICTIONARY_ELEMENTS]; |
|
|
|
|
|
} else { |
|
|
|
|
|
return elements_accessors_[JSObject::FAST_ELEMENTS]; |
|
|
|
|
|
} |
|
|
|
|
|
case EXTERNAL_BYTE_ARRAY_TYPE: |
|
|
|
|
|
return elements_accessors_[JSObject::EXTERNAL_BYTE_ELEMENTS]; |
|
|
|
|
|
case EXTERNAL_UNSIGNED_BYTE_ARRAY_TYPE: |
|
|
|
|
|
return elements_accessors_[JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS]; |
|
|
|
|
|
case EXTERNAL_SHORT_ARRAY_TYPE: |
|
|
|
|
|
return elements_accessors_[JSObject::EXTERNAL_SHORT_ELEMENTS]; |
|
|
|
|
|
case EXTERNAL_UNSIGNED_SHORT_ARRAY_TYPE: |
|
|
|
|
|
return elements_accessors_[JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS]; |
|
|
|
|
|
case EXTERNAL_INT_ARRAY_TYPE: |
|
|
|
|
|
return elements_accessors_[JSObject::EXTERNAL_INT_ELEMENTS]; |
|
|
|
|
|
case EXTERNAL_UNSIGNED_INT_ARRAY_TYPE: |
|
|
|
|
|
return elements_accessors_[JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS]; |
|
|
|
|
|
case EXTERNAL_FLOAT_ARRAY_TYPE: |
|
|
|
|
|
return elements_accessors_[JSObject::EXTERNAL_FLOAT_ELEMENTS]; |
|
|
|
|
|
case EXTERNAL_DOUBLE_ARRAY_TYPE: |
|
|
|
|
|
return elements_accessors_[JSObject::EXTERNAL_DOUBLE_ELEMENTS]; |
|
|
|
|
|
case EXTERNAL_PIXEL_ARRAY_TYPE: |
|
|
|
|
|
return elements_accessors_[JSObject::EXTERNAL_PIXEL_ELEMENTS]; |
|
|
|
|
|
default: |
|
|
|
|
|
UNREACHABLE(); |
|
|
|
|
|
return NULL; |
|
|
|
|
|
break; |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void ElementsAccessor::InitializeOncePerProcess() { |
|
|
void ElementsAccessor::InitializeOncePerProcess() { |
|
|
static struct ConcreteElementsAccessors { |
|
|
static struct ConcreteElementsAccessors { |
|
|
FastElementsAccessor fast_elements_handler; |
|
|
FastElementsAccessor fast_elements_handler; |
|
|