Merge V8 at 3.8.9.11
Bug: 5688872
Change-Id: Ie3b1dd67a730ec5e82686b7b37dba26f6a9bb24f
diff --git a/src/objects.cc b/src/objects.cc
index 1565504..9f596c4 100644
--- a/src/objects.cc
+++ b/src/objects.cc
@@ -1,4 +1,4 @@
-// Copyright 2011 the V8 project authors. All rights reserved.
+// Copyright 2012 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
@@ -246,8 +246,8 @@
}
// __defineGetter__ callback
- if (structure->IsFixedArray()) {
- Object* getter = FixedArray::cast(structure)->get(kGetterIndex);
+ if (structure->IsAccessorPair()) {
+ Object* getter = AccessorPair::cast(structure)->getter();
if (getter->IsSpecFunction()) {
// TODO(rossberg): nicer would be to cast to some JSCallable here...
return GetPropertyWithDefinedGetter(receiver, JSReceiver::cast(getter));
@@ -485,6 +485,16 @@
}
+Handle<Object> JSObject::SetNormalizedProperty(Handle<JSObject> object,
+ Handle<String> key,
+ Handle<Object> value,
+ PropertyDetails details) {
+ CALL_HEAP_FUNCTION(object->GetIsolate(),
+ object->SetNormalizedProperty(*key, *value, details),
+ Object);
+}
+
+
MaybeObject* JSObject::SetNormalizedProperty(String* name,
Object* value,
PropertyDetails details) {
@@ -961,14 +971,14 @@
// Morph the object to an external string by adjusting the map and
// reinitializing the fields.
if (size >= ExternalString::kSize) {
- this->set_map(
+ this->set_map_no_write_barrier(
is_symbol
? (is_ascii ? heap->external_symbol_with_ascii_data_map()
: heap->external_symbol_map())
: (is_ascii ? heap->external_string_with_ascii_data_map()
: heap->external_string_map()));
} else {
- this->set_map(
+ this->set_map_no_write_barrier(
is_symbol
? (is_ascii ? heap->short_external_symbol_with_ascii_data_map()
: heap->short_external_symbol_map())
@@ -983,7 +993,8 @@
int new_size = this->Size(); // Byte size of the external String object.
heap->CreateFillerObjectAt(this->address() + new_size, size - new_size);
if (Marking::IsBlack(Marking::MarkBitFrom(this))) {
- MemoryChunk::IncrementLiveBytes(this->address(), new_size - size);
+ MemoryChunk::IncrementLiveBytesFromMutator(this->address(),
+ new_size - size);
}
return true;
}
@@ -1011,11 +1022,13 @@
// Morph the object to an external string by adjusting the map and
// reinitializing the fields. Use short version if space is limited.
if (size >= ExternalString::kSize) {
- this->set_map(is_symbol ? heap->external_ascii_symbol_map()
- : heap->external_ascii_string_map());
+ this->set_map_no_write_barrier(
+ is_symbol ? heap->external_ascii_symbol_map()
+ : heap->external_ascii_string_map());
} else {
- this->set_map(is_symbol ? heap->short_external_ascii_symbol_map()
- : heap->short_external_ascii_string_map());
+ this->set_map_no_write_barrier(
+ is_symbol ? heap->short_external_ascii_symbol_map()
+ : heap->short_external_ascii_string_map());
}
ExternalAsciiString* self = ExternalAsciiString::cast(this);
self->set_resource(resource);
@@ -1025,7 +1038,8 @@
int new_size = this->Size(); // Byte size of the external String object.
heap->CreateFillerObjectAt(this->address() + new_size, size - new_size);
if (Marking::IsBlack(Marking::MarkBitFrom(this))) {
- MemoryChunk::IncrementLiveBytes(this->address(), new_size - size);
+ MemoryChunk::IncrementLiveBytesFromMutator(this->address(),
+ new_size - size);
}
return true;
}
@@ -1640,8 +1654,6 @@
String* name,
JSFunction* function,
PropertyAttributes attributes) {
- ASSERT(!GetHeap()->InNewSpace(function));
-
// Allocate new instance descriptors with (name, function) added
ConstantFunctionDescriptor d(name, function, attributes);
Object* new_descriptors;
@@ -1756,7 +1768,7 @@
// Ensure the descriptor array does not get too big.
if (map_of_this->instance_descriptors()->number_of_descriptors() <
DescriptorArray::kMaxNumberOfDescriptors) {
- if (value->IsJSFunction() && !heap->InNewSpace(value)) {
+ if (value->IsJSFunction()) {
return AddConstantFunctionProperty(name,
JSFunction::cast(value),
attributes);
@@ -1961,6 +1973,17 @@
}
+Handle<Object> JSReceiver::SetProperty(Handle<JSReceiver> object,
+ Handle<String> key,
+ Handle<Object> value,
+ PropertyAttributes attributes,
+ StrictModeFlag strict_mode) {
+ CALL_HEAP_FUNCTION(object->GetIsolate(),
+ object->SetProperty(*key, *value, attributes, strict_mode),
+ Object);
+}
+
+
MaybeObject* JSReceiver::SetProperty(String* name,
Object* value,
PropertyAttributes attributes,
@@ -2018,8 +2041,8 @@
return *value_handle;
}
- if (structure->IsFixedArray()) {
- Object* setter = FixedArray::cast(structure)->get(kSetterIndex);
+ if (structure->IsAccessorPair()) {
+ Object* setter = AccessorPair::cast(structure)->setter();
if (setter->IsSpecFunction()) {
// TODO(rossberg): nicer would be to cast to some JSCallable here...
return SetPropertyWithDefinedSetter(JSReceiver::cast(setter), value);
@@ -2107,9 +2130,10 @@
if (!JSObject::cast(pt)->HasDictionaryElements()) {
continue;
}
- NumberDictionary* dictionary = JSObject::cast(pt)->element_dictionary();
+ SeededNumberDictionary* dictionary =
+ JSObject::cast(pt)->element_dictionary();
int entry = dictionary->FindEntry(index);
- if (entry != NumberDictionary::kNotFound) {
+ if (entry != SeededNumberDictionary::kNotFound) {
PropertyDetails details = dictionary->DetailsAt(entry);
if (details.type() == CALLBACKS) {
*found = true;
@@ -2342,7 +2366,9 @@
if (details.type() == ELEMENTS_TRANSITION) {
return descriptors->GetValue(index);
} else {
- *safe_to_add_transition = false;
+ if (safe_to_add_transition != NULL) {
+ *safe_to_add_transition = false;
+ }
}
}
return NULL;
@@ -2995,7 +3021,6 @@
ASSERT(target_descriptors->GetType(number) == CONSTANT_FUNCTION);
JSFunction* function =
JSFunction::cast(target_descriptors->GetValue(number));
- ASSERT(!HEAP->InNewSpace(function));
if (value == function) {
set_map(target_map);
return value;
@@ -3025,6 +3050,18 @@
// Note that this method cannot be used to set the prototype of a function
// because ConvertDescriptorToField() which is called in "case CALLBACKS:"
// doesn't handle function prototypes correctly.
+Handle<Object> JSObject::SetLocalPropertyIgnoreAttributes(
+ Handle<JSObject> object,
+ Handle<String> key,
+ Handle<Object> value,
+ PropertyAttributes attributes) {
+ CALL_HEAP_FUNCTION(
+ object->GetIsolate(),
+ object->SetLocalPropertyIgnoreAttributes(*key, *value, attributes),
+ Object);
+}
+
+
MaybeObject* JSObject::SetLocalPropertyIgnoreAttributes(
String* name,
Object* value,
@@ -3315,6 +3352,15 @@
}
+void JSObject::NormalizeProperties(Handle<JSObject> object,
+ PropertyNormalizationMode mode,
+ int expected_additional_properties) {
+ CALL_HEAP_FUNCTION_VOID(object->GetIsolate(),
+ object->NormalizeProperties(
+ mode, expected_additional_properties));
+}
+
+
MaybeObject* JSObject::NormalizeProperties(PropertyNormalizationMode mode,
int expected_additional_properties) {
if (!HasFastProperties()) return this;
@@ -3416,7 +3462,8 @@
current_heap->CreateFillerObjectAt(this->address() + new_instance_size,
instance_size_delta);
if (Marking::IsBlack(Marking::MarkBitFrom(this))) {
- MemoryChunk::IncrementLiveBytes(this->address(), -instance_size_delta);
+ MemoryChunk::IncrementLiveBytesFromMutator(this->address(),
+ -instance_size_delta);
}
@@ -3437,6 +3484,14 @@
}
+void JSObject::TransformToFastProperties(Handle<JSObject> object,
+ int unused_property_fields) {
+ CALL_HEAP_FUNCTION_VOID(
+ object->GetIsolate(),
+ object->TransformToFastProperties(unused_property_fields));
+}
+
+
MaybeObject* JSObject::TransformToFastProperties(int unused_property_fields) {
if (HasFastProperties()) return this;
ASSERT(!IsGlobalObject());
@@ -3445,6 +3500,14 @@
}
+Handle<SeededNumberDictionary> JSObject::NormalizeElements(
+ Handle<JSObject> object) {
+ CALL_HEAP_FUNCTION(object->GetIsolate(),
+ object->NormalizeElements(),
+ SeededNumberDictionary);
+}
+
+
MaybeObject* JSObject::NormalizeElements() {
ASSERT(!HasExternalArrayElements());
@@ -3469,11 +3532,11 @@
int old_capacity = 0;
int used_elements = 0;
GetElementsCapacityAndUsage(&old_capacity, &used_elements);
- NumberDictionary* dictionary = NULL;
+ SeededNumberDictionary* dictionary = NULL;
{ Object* object;
- MaybeObject* maybe = NumberDictionary::Allocate(used_elements);
+ MaybeObject* maybe = SeededNumberDictionary::Allocate(used_elements);
if (!maybe->ToObject(&object)) return maybe;
- dictionary = NumberDictionary::cast(object);
+ dictionary = SeededNumberDictionary::cast(object);
}
// Copy the elements to the new backing store.
@@ -3504,7 +3567,7 @@
MaybeObject* maybe_result =
dictionary->AddNumberEntry(i, value, details);
if (!maybe_result->ToObject(&result)) return maybe_result;
- dictionary = NumberDictionary::cast(result);
+ dictionary = SeededNumberDictionary::cast(result);
}
}
@@ -3561,6 +3624,14 @@
}
+int JSObject::GetIdentityHash(Handle<JSObject> obj) {
+ CALL_AND_RETRY(obj->GetIsolate(),
+ obj->GetIdentityHash(ALLOW_CREATION),
+ return Smi::cast(__object__)->value(),
+ return 0);
+}
+
+
MaybeObject* JSObject::GetIdentityHash(CreationFlag flag) {
Object* stored_value = GetHiddenProperty(GetHeap()->identity_hash_symbol());
if (stored_value->IsSmi()) return stored_value;
@@ -3613,6 +3684,15 @@
}
+Handle<Object> JSObject::SetHiddenProperty(Handle<JSObject> obj,
+ Handle<String> key,
+ Handle<Object> value) {
+ CALL_HEAP_FUNCTION(obj->GetIsolate(),
+ obj->SetHiddenProperty(*key, *value),
+ Object);
+}
+
+
MaybeObject* JSObject::SetHiddenProperty(String* key, Object* value) {
if (IsJSGlobalProxy()) {
// For a proxy, use the prototype as target object.
@@ -3840,6 +3920,14 @@
}
+Handle<Object> JSObject::DeleteElement(Handle<JSObject> obj,
+ uint32_t index) {
+ CALL_HEAP_FUNCTION(obj->GetIsolate(),
+ obj->DeleteElement(index, JSObject::NORMAL_DELETION),
+ Object);
+}
+
+
MaybeObject* JSObject::DeleteElement(uint32_t index, DeleteMode mode) {
Isolate* isolate = GetIsolate();
// Check access rights if needed.
@@ -3868,19 +3956,11 @@
}
-MaybeObject* JSReceiver::DeleteProperty(String* name, DeleteMode mode) {
- if (IsJSProxy()) {
- return JSProxy::cast(this)->DeletePropertyWithHandler(name, mode);
- }
- return JSObject::cast(this)->DeleteProperty(name, mode);
-}
-
-
-MaybeObject* JSReceiver::DeleteElement(uint32_t index, DeleteMode mode) {
- if (IsJSProxy()) {
- return JSProxy::cast(this)->DeleteElementWithHandler(index, mode);
- }
- return JSObject::cast(this)->DeleteElement(index, mode);
+Handle<Object> JSObject::DeleteProperty(Handle<JSObject> obj,
+ Handle<String> prop) {
+ CALL_HEAP_FUNCTION(obj->GetIsolate(),
+ obj->DeleteProperty(*prop, JSObject::NORMAL_DELETION),
+ Object);
}
@@ -3941,6 +4021,22 @@
}
+MaybeObject* JSReceiver::DeleteElement(uint32_t index, DeleteMode mode) {
+ if (IsJSProxy()) {
+ return JSProxy::cast(this)->DeleteElementWithHandler(index, mode);
+ }
+ return JSObject::cast(this)->DeleteElement(index, mode);
+}
+
+
+MaybeObject* JSReceiver::DeleteProperty(String* name, DeleteMode mode) {
+ if (IsJSProxy()) {
+ return JSProxy::cast(this)->DeletePropertyWithHandler(name, mode);
+ }
+ return JSObject::cast(this)->DeleteProperty(name, mode);
+}
+
+
bool JSObject::ReferencesObjectFromElements(FixedArray* elements,
ElementsKind kind,
Object* object) {
@@ -3955,7 +4051,8 @@
if (!element->IsTheHole() && element == object) return true;
}
} else {
- Object* key = NumberDictionary::cast(elements)->SlowReverseLookup(object);
+ Object* key =
+ SeededNumberDictionary::cast(elements)->SlowReverseLookup(object);
if (!key->IsUndefined()) return true;
}
return false;
@@ -4067,6 +4164,11 @@
}
+Handle<Object> JSObject::PreventExtensions(Handle<JSObject> object) {
+ CALL_HEAP_FUNCTION(object->GetIsolate(), object->PreventExtensions(), Object);
+}
+
+
MaybeObject* JSObject::PreventExtensions() {
Isolate* isolate = GetIsolate();
if (IsAccessCheckNeeded() &&
@@ -4096,9 +4198,9 @@
}
// If there are fast elements we normalize.
- NumberDictionary* dictionary = NULL;
+ SeededNumberDictionary* dictionary = NULL;
{ MaybeObject* maybe = NormalizeElements();
- if (!maybe->To<NumberDictionary>(&dictionary)) return maybe;
+ if (!maybe->To<SeededNumberDictionary>(&dictionary)) return maybe;
}
ASSERT(HasDictionaryElements() || HasDictionaryArgumentsElements());
// Make sure that we never go back to fast case.
@@ -4251,27 +4353,28 @@
current != heap->null_value() && current->IsJSObject();
current = JSObject::cast(current)->GetPrototype()) {
JSObject::cast(current)->LocalLookupRealNamedProperty(name, result);
- if (result->IsProperty() && result->type() == CALLBACKS) return;
+ if (result->IsFound() && result->type() == CALLBACKS) return;
}
result->NotFound();
}
// Search for a getter or setter in an elements dictionary and update its
-// attributes. Returns either undefined if the element is read-only, or the
-// getter/setter pair (fixed array) if there is an existing one, or the hole
-// value if the element does not exist or is a normal non-getter/setter data
-// element.
-static Object* UpdateGetterSetterInDictionary(NumberDictionary* dictionary,
- uint32_t index,
- PropertyAttributes attributes,
- Heap* heap) {
+// attributes. Returns either undefined if the element is non-deletable, or the
+// getter/setter pair if there is an existing one, or the hole value if the
+// element does not exist or is a normal non-getter/setter data element.
+static Object* UpdateGetterSetterInDictionary(
+ SeededNumberDictionary* dictionary,
+ uint32_t index,
+ PropertyAttributes attributes,
+ Heap* heap) {
int entry = dictionary->FindEntry(index);
- if (entry != NumberDictionary::kNotFound) {
+ if (entry != SeededNumberDictionary::kNotFound) {
Object* result = dictionary->ValueAt(entry);
PropertyDetails details = dictionary->DetailsAt(entry);
- if (details.IsReadOnly()) return heap->undefined_value();
- if (details.type() == CALLBACKS && result->IsFixedArray()) {
+ // TODO(mstarzinger): We should check for details.IsDontDelete() here once
+ // we only call into the runtime once to set both getter and setter.
+ if (details.type() == CALLBACKS && result->IsAccessorPair()) {
if (details.attributes() != attributes) {
dictionary->DetailsAtPut(entry,
PropertyDetails(attributes, CALLBACKS, index));
@@ -4338,7 +4441,8 @@
if (probe == NULL || probe->IsTheHole()) {
FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
if (arguments->IsDictionary()) {
- NumberDictionary* dictionary = NumberDictionary::cast(arguments);
+ SeededNumberDictionary* dictionary =
+ SeededNumberDictionary::cast(arguments);
probe = UpdateGetterSetterInDictionary(dictionary,
index,
attributes,
@@ -4352,13 +4456,14 @@
} else {
// Lookup the name.
LookupResult result(heap->isolate());
- LocalLookup(name, &result);
- if (result.IsProperty()) {
- if (result.IsReadOnly()) return heap->undefined_value();
+ LocalLookupRealNamedProperty(name, &result);
+ if (result.IsFound()) {
+ // TODO(mstarzinger): We should check for result.IsDontDelete() here once
+ // we only call into the runtime once to set both getter and setter.
if (result.type() == CALLBACKS) {
Object* obj = result.GetCallbackObject();
// Need to preserve old getters/setters.
- if (obj->IsFixedArray()) {
+ if (obj->IsAccessorPair()) {
// Use set to update attributes.
return SetPropertyCallback(name, obj, attributes);
}
@@ -4366,16 +4471,15 @@
}
}
- // Allocate the fixed array to hold getter and setter.
- Object* structure;
- { MaybeObject* maybe_structure = heap->AllocateFixedArray(2, TENURED);
- if (!maybe_structure->ToObject(&structure)) return maybe_structure;
+ AccessorPair* accessors;
+ { MaybeObject* maybe_accessors = heap->AllocateAccessorPair();
+ if (!maybe_accessors->To<AccessorPair>(&accessors)) return maybe_accessors;
}
if (is_element) {
- return SetElementCallback(index, structure, attributes);
+ return SetElementCallback(index, accessors, attributes);
} else {
- return SetPropertyCallback(name, structure, attributes);
+ return SetPropertyCallback(name, accessors, attributes);
}
}
@@ -4410,11 +4514,11 @@
PropertyDetails details = PropertyDetails(attributes, CALLBACKS);
// Normalize elements to make this operation simple.
- NumberDictionary* dictionary = NULL;
+ SeededNumberDictionary* dictionary = NULL;
{ Object* result;
MaybeObject* maybe = NormalizeElements();
if (!maybe->ToObject(&result)) return maybe;
- dictionary = NumberDictionary::cast(result);
+ dictionary = SeededNumberDictionary::cast(result);
}
ASSERT(HasDictionaryElements() || HasDictionaryArgumentsElements());
@@ -4422,7 +4526,7 @@
{ Object* result;
MaybeObject* maybe = dictionary->Set(index, structure, details);
if (!maybe->ToObject(&result)) return maybe;
- dictionary = NumberDictionary::cast(result);
+ dictionary = SeededNumberDictionary::cast(result);
}
dictionary->set_requires_slow_elements();
@@ -4511,12 +4615,16 @@
fun, attributes);
}
- Object* array;
- { MaybeObject* maybe_array = DefineGetterSetter(name, attributes);
- if (!maybe_array->ToObject(&array)) return maybe_array;
+ Object* accessors;
+ { MaybeObject* maybe_accessors = DefineGetterSetter(name, attributes);
+ if (!maybe_accessors->To<Object>(&accessors)) return maybe_accessors;
}
- if (array->IsUndefined()) return array;
- FixedArray::cast(array)->set(is_getter ? 0 : 1, fun);
+ if (accessors->IsUndefined()) return accessors;
+ if (is_getter) {
+ AccessorPair::cast(accessors)->set_getter(fun);
+ } else {
+ AccessorPair::cast(accessors)->set_setter(fun);
+ }
return this;
}
@@ -4620,11 +4728,6 @@
}
// Make the lookup and include prototypes.
- // Introducing constants below makes static constants usage purely static
- // and avoids linker errors in debug build using gcc.
- const int getter_index = kGetterIndex;
- const int setter_index = kSetterIndex;
- int accessor_index = is_getter ? getter_index : setter_index;
uint32_t index = 0;
if (name->AsArrayIndex(&index)) {
for (Object* obj = this;
@@ -4632,14 +4735,15 @@
obj = JSObject::cast(obj)->GetPrototype()) {
JSObject* js_object = JSObject::cast(obj);
if (js_object->HasDictionaryElements()) {
- NumberDictionary* dictionary = js_object->element_dictionary();
+ SeededNumberDictionary* dictionary = js_object->element_dictionary();
int entry = dictionary->FindEntry(index);
- if (entry != NumberDictionary::kNotFound) {
+ if (entry != SeededNumberDictionary::kNotFound) {
Object* element = dictionary->ValueAt(entry);
PropertyDetails details = dictionary->DetailsAt(entry);
if (details.type() == CALLBACKS) {
- if (element->IsFixedArray()) {
- return FixedArray::cast(element)->get(accessor_index);
+ if (element->IsAccessorPair()) {
+ AccessorPair* accessors = AccessorPair::cast(element);
+ return is_getter ? accessors->getter() : accessors->setter();
}
}
}
@@ -4655,8 +4759,9 @@
if (result.IsReadOnly()) return heap->undefined_value();
if (result.type() == CALLBACKS) {
Object* obj = result.GetCallbackObject();
- if (obj->IsFixedArray()) {
- return FixedArray::cast(obj)->get(accessor_index);
+ if (obj->IsAccessorPair()) {
+ AccessorPair* accessors = AccessorPair::cast(obj);
+ return is_getter ? accessors->getter() : accessors->setter();
}
}
}
@@ -4830,75 +4935,219 @@
}
-void Map::TraverseTransitionTree(TraverseCallback callback, void* data) {
- // Traverse the transition tree without using a stack. We do this by
- // reversing the pointers in the maps and descriptor arrays.
- Map* current = this;
- Map* meta_map = GetHeap()->meta_map();
- Object** map_or_index_field = NULL;
- while (current != meta_map) {
- DescriptorArray* d = reinterpret_cast<DescriptorArray*>(
- *RawField(current, Map::kInstanceDescriptorsOrBitField3Offset));
- if (!d->IsEmpty()) {
- FixedArray* contents = reinterpret_cast<FixedArray*>(
- d->get(DescriptorArray::kContentArrayIndex));
- map_or_index_field = RawField(contents, HeapObject::kMapOffset);
- Object* map_or_index = *map_or_index_field;
- bool map_done = true; // Controls a nested continue statement.
- for (int i = map_or_index->IsSmi() ? Smi::cast(map_or_index)->value() : 0;
- i < contents->length();
- i += 2) {
- PropertyDetails details(Smi::cast(contents->get(i + 1)));
- if (details.IsTransition()) {
- // Found a map in the transition array. We record our progress in
- // the transition array by recording the current map in the map field
- // of the next map and recording the index in the transition array in
- // the map field of the array.
- Map* next = Map::cast(contents->get(i));
- next->set_map_unsafe(current);
- *map_or_index_field = Smi::FromInt(i + 2);
- current = next;
- map_done = false;
+// An iterator over all map transitions in an descriptor array, reusing the map
+// field of the contens array while it is running.
+class IntrusiveMapTransitionIterator {
+ public:
+ explicit IntrusiveMapTransitionIterator(DescriptorArray* descriptor_array)
+ : descriptor_array_(descriptor_array) { }
+
+ void Start() {
+ ASSERT(!IsIterating());
+ if (HasContentArray()) *ContentHeader() = Smi::FromInt(0);
+ }
+
+ bool IsIterating() {
+ return HasContentArray() && (*ContentHeader())->IsSmi();
+ }
+
+ Map* Next() {
+ ASSERT(IsIterating());
+ FixedArray* contents = ContentArray();
+ // Attention, tricky index manipulation ahead: Every entry in the contents
+ // array consists of a value/details pair, so the index is typically even.
+ // An exception is made for CALLBACKS entries: An even index means we look
+ // at its getter, and an odd index means we look at its setter.
+ int index = Smi::cast(*ContentHeader())->value();
+ while (index < contents->length()) {
+ PropertyDetails details(Smi::cast(contents->get(index | 1)));
+ switch (details.type()) {
+ case MAP_TRANSITION:
+ case CONSTANT_TRANSITION:
+ case ELEMENTS_TRANSITION:
+ // We definitely have a map transition.
+ *ContentHeader() = Smi::FromInt(index + 2);
+ return static_cast<Map*>(contents->get(index));
+ case CALLBACKS: {
+ // We might have a map transition in a getter or in a setter.
+ AccessorPair* accessors =
+ static_cast<AccessorPair*>(contents->get(index & ~1));
+ Object* accessor =
+ ((index & 1) == 0) ? accessors->getter() : accessors->setter();
+ index++;
+ if (accessor->IsMap()) {
+ *ContentHeader() = Smi::FromInt(index);
+ return static_cast<Map*>(accessor);
+ }
break;
}
- }
- if (!map_done) continue;
- } else {
- map_or_index_field = NULL;
- }
- // That was the regular transitions, now for the prototype transitions.
- FixedArray* prototype_transitions =
- current->unchecked_prototype_transitions();
- Object** proto_map_or_index_field =
- RawField(prototype_transitions, HeapObject::kMapOffset);
- Object* map_or_index = *proto_map_or_index_field;
- const int start = kProtoTransitionHeaderSize + kProtoTransitionMapOffset;
- int i = map_or_index->IsSmi() ? Smi::cast(map_or_index)->value() : start;
- if (i < prototype_transitions->length()) {
- // Found a map in the prototype transition array. Record progress in
- // an analogous way to the regular transitions array above.
- Object* perhaps_map = prototype_transitions->get(i);
- if (perhaps_map->IsMap()) {
- Map* next = Map::cast(perhaps_map);
- next->set_map_unsafe(current);
- *proto_map_or_index_field =
- Smi::FromInt(i + kProtoTransitionElementsPerEntry);
- current = next;
- continue;
+ case NORMAL:
+ case FIELD:
+ case CONSTANT_FUNCTION:
+ case HANDLER:
+ case INTERCEPTOR:
+ case NULL_DESCRIPTOR:
+ // We definitely have no map transition.
+ index += 2;
+ break;
}
}
- *proto_map_or_index_field = GetHeap()->fixed_array_map();
- if (map_or_index_field != NULL) {
- *map_or_index_field = GetHeap()->fixed_array_map();
- }
+ *ContentHeader() = descriptor_array_->GetHeap()->fixed_array_map();
+ return NULL;
+ }
- // The callback expects a map to have a real map as its map, so we save
- // the map field, which is being used to track the traversal and put the
- // correct map (the meta_map) in place while we do the callback.
- Map* prev = current->map();
- current->set_map_unsafe(meta_map);
- callback(current, data);
- current = prev;
+ private:
+ bool HasContentArray() {
+ return descriptor_array_-> length() > DescriptorArray::kContentArrayIndex;
+ }
+
+ FixedArray* ContentArray() {
+ Object* array = descriptor_array_->get(DescriptorArray::kContentArrayIndex);
+ return static_cast<FixedArray*>(array);
+ }
+
+ Object** ContentHeader() {
+ return HeapObject::RawField(ContentArray(), DescriptorArray::kMapOffset);
+ }
+
+ DescriptorArray* descriptor_array_;
+};
+
+
+// An iterator over all prototype transitions, reusing the map field of the
+// underlying array while it is running.
+class IntrusivePrototypeTransitionIterator {
+ public:
+ explicit IntrusivePrototypeTransitionIterator(FixedArray* proto_trans)
+ : proto_trans_(proto_trans) { }
+
+ void Start() {
+ ASSERT(!IsIterating());
+ if (HasTransitions()) *Header() = Smi::FromInt(0);
+ }
+
+ bool IsIterating() {
+ return HasTransitions() && (*Header())->IsSmi();
+ }
+
+ Map* Next() {
+ ASSERT(IsIterating());
+ int transitionNumber = Smi::cast(*Header())->value();
+ if (transitionNumber < NumberOfTransitions()) {
+ *Header() = Smi::FromInt(transitionNumber + 1);
+ return GetTransition(transitionNumber);
+ }
+ *Header() = proto_trans_->GetHeap()->fixed_array_map();
+ return NULL;
+ }
+
+ private:
+ bool HasTransitions() {
+ return proto_trans_->length() >= Map::kProtoTransitionHeaderSize;
+ }
+
+ Object** Header() {
+ return HeapObject::RawField(proto_trans_, FixedArray::kMapOffset);
+ }
+
+ int NumberOfTransitions() {
+ Object* num = proto_trans_->get(Map::kProtoTransitionNumberOfEntriesOffset);
+ return Smi::cast(num)->value();
+ }
+
+ Map* GetTransition(int transitionNumber) {
+ return Map::cast(proto_trans_->get(IndexFor(transitionNumber)));
+ }
+
+ int IndexFor(int transitionNumber) {
+ return Map::kProtoTransitionHeaderSize +
+ Map::kProtoTransitionMapOffset +
+ transitionNumber * Map::kProtoTransitionElementsPerEntry;
+ }
+
+ FixedArray* proto_trans_;
+};
+
+
+// To traverse the transition tree iteratively, we have to store two kinds of
+// information in a map: The parent map in the traversal and which children of a
+// node have already been visited. To do this without additional memory, we
+// temporarily reuse two maps with known values:
+//
+// (1) The map of the map temporarily holds the parent, and is restored to the
+// meta map afterwards.
+//
+// (2) The info which children have already been visited depends on which part
+// of the map we currently iterate:
+//
+// (a) If we currently follow normal map transitions, we temporarily store
+// the current index in the map of the FixedArray of the desciptor
+// array's contents, and restore it to the fixed array map afterwards.
+// Note that a single descriptor can have 0, 1, or 2 transitions.
+//
+// (b) If we currently follow prototype transitions, we temporarily store
+// the current index in the map of the FixedArray holding the prototype
+// transitions, and restore it to the fixed array map afterwards.
+//
+// Note that the child iterator is just a concatenation of two iterators: One
+// iterating over map transitions and one iterating over prototype transisitons.
+class TraversableMap : public Map {
+ public:
+ // Record the parent in the traversal within this map. Note that this destroys
+ // this map's map!
+ void SetParent(TraversableMap* parent) { set_map_no_write_barrier(parent); }
+
+ // Reset the current map's map, returning the parent previously stored in it.
+ TraversableMap* GetAndResetParent() {
+ TraversableMap* old_parent = static_cast<TraversableMap*>(map());
+ set_map_no_write_barrier(GetHeap()->meta_map());
+ return old_parent;
+ }
+
+ // Start iterating over this map's children, possibly destroying a FixedArray
+ // map (see explanation above).
+ void ChildIteratorStart() {
+ IntrusiveMapTransitionIterator(instance_descriptors()).Start();
+ IntrusivePrototypeTransitionIterator(
+ unchecked_prototype_transitions()).Start();
+ }
+
+ // If we have an unvisited child map, return that one and advance. If we have
+ // none, return NULL and reset any destroyed FixedArray maps.
+ TraversableMap* ChildIteratorNext() {
+ IntrusiveMapTransitionIterator descriptor_iterator(instance_descriptors());
+ if (descriptor_iterator.IsIterating()) {
+ Map* next = descriptor_iterator.Next();
+ if (next != NULL) return static_cast<TraversableMap*>(next);
+ }
+ IntrusivePrototypeTransitionIterator
+ proto_iterator(unchecked_prototype_transitions());
+ if (proto_iterator.IsIterating()) {
+ Map* next = proto_iterator.Next();
+ if (next != NULL) return static_cast<TraversableMap*>(next);
+ }
+ return NULL;
+ }
+};
+
+
+// Traverse the transition tree in postorder without using the C++ stack by
+// doing pointer reversal.
+void Map::TraverseTransitionTree(TraverseCallback callback, void* data) {
+ TraversableMap* current = static_cast<TraversableMap*>(this);
+ current->ChildIteratorStart();
+ while (true) {
+ TraversableMap* child = current->ChildIteratorNext();
+ if (child != NULL) {
+ child->ChildIteratorStart();
+ child->SetParent(current);
+ current = child;
+ } else {
+ TraversableMap* parent = current->GetAndResetParent();
+ callback(current, data);
+ if (current == this) break;
+ current = parent;
+ }
}
}
@@ -5395,7 +5644,9 @@
AssertNoAllocation no_gc;
int len = length();
if (new_length < len) len = new_length;
- result->set_map(map());
+ // We are taking the map from the old fixed array so the map is sure to
+ // be an immortal immutable object.
+ result->set_map_no_write_barrier(map());
WriteBarrierMode mode = result->GetWriteBarrierMode(no_gc);
for (int i = 0; i < len; i++) {
result->set(i, get(i), mode);
@@ -5635,7 +5886,7 @@
}
}
if (child_hash <= parent_hash) break;
- NoWriteBarrierSwapDescriptors(parent_index, child_index);
+ NoIncrementalWriteBarrierSwapDescriptors(parent_index, child_index);
// Now element at child_index could be < its children.
parent_index = child_index; // parent_hash remains correct.
}
@@ -5644,7 +5895,7 @@
// Extract elements and create sorted array.
for (int i = len - 1; i > 0; --i) {
// Put max element at the back of the array.
- NoWriteBarrierSwapDescriptors(0, i);
+ NoIncrementalWriteBarrierSwapDescriptors(0, i);
// Shift down the new top element.
int parent_index = 0;
const uint32_t parent_hash = GetKey(parent_index)->Hash();
@@ -5660,7 +5911,7 @@
}
}
if (child_hash <= parent_hash) break;
- NoWriteBarrierSwapDescriptors(parent_index, child_index);
+ NoIncrementalWriteBarrierSwapDescriptors(parent_index, child_index);
parent_index = child_index;
}
}
@@ -6679,6 +6930,20 @@
// Fast check: if hash code is computed for both strings
// a fast negative check can be performed.
if (HasHashCode() && other->HasHashCode()) {
+#ifdef DEBUG
+ if (FLAG_enable_slow_asserts) {
+ if (Hash() != other->Hash()) {
+ bool found_difference = false;
+ for (int i = 0; i < len; i++) {
+ if (Get(i) != other->Get(i)) {
+ found_difference = true;
+ break;
+ }
+ }
+ ASSERT(found_difference);
+ }
+ }
+#endif
if (Hash() != other->Hash()) return false;
}
@@ -6814,12 +7079,16 @@
// Compute the hash code.
uint32_t field = 0;
if (StringShape(this).IsSequentialAscii()) {
- field = HashSequentialString(SeqAsciiString::cast(this)->GetChars(), len);
+ field = HashSequentialString(SeqAsciiString::cast(this)->GetChars(),
+ len,
+ GetHeap()->HashSeed());
} else if (StringShape(this).IsSequentialTwoByte()) {
- field = HashSequentialString(SeqTwoByteString::cast(this)->GetChars(), len);
+ field = HashSequentialString(SeqTwoByteString::cast(this)->GetChars(),
+ len,
+ GetHeap()->HashSeed());
} else {
StringInputBuffer buffer(this);
- field = ComputeHashField(&buffer, len);
+ field = ComputeHashField(&buffer, len, GetHeap()->HashSeed());
}
// Store the hash code in the object.
@@ -6910,8 +7179,9 @@
uint32_t String::ComputeHashField(unibrow::CharacterStream* buffer,
- int length) {
- StringHasher hasher(length);
+ int length,
+ uint32_t seed) {
+ StringHasher hasher(length, seed);
// Very long strings have a trivial hash that doesn't inspect the
// string contents.
@@ -7346,7 +7616,7 @@
LookupResult result(heap->isolate());
String* name = GetThisPropertyAssignmentName(i);
js_object->LocalLookupRealNamedProperty(name, &result);
- if (result.IsProperty() && result.type() == CALLBACKS) {
+ if (result.IsFound() && result.type() == CALLBACKS) {
return false;
}
}
@@ -7639,6 +7909,22 @@
}
+#define DECLARE_TAG(ignore1, name, ignore2) name,
+const char* const VisitorSynchronization::kTags[
+ VisitorSynchronization::kNumberOfSyncTags] = {
+ VISITOR_SYNCHRONIZATION_TAGS_LIST(DECLARE_TAG)
+};
+#undef DECLARE_TAG
+
+
+#define DECLARE_TAG(ignore1, ignore2, name) name,
+const char* const VisitorSynchronization::kTagNames[
+ VisitorSynchronization::kNumberOfSyncTags] = {
+ VISITOR_SYNCHRONIZATION_TAGS_LIST(DECLARE_TAG)
+};
+#undef DECLARE_TAG
+
+
void ObjectVisitor::VisitCodeTarget(RelocInfo* rinfo) {
ASSERT(RelocInfo::IsCodeTarget(rinfo->rmode()));
Object* target = Code::GetCodeFromTargetAddress(rinfo->target_address());
@@ -7855,8 +8141,11 @@
static_cast<Translation::Opcode>(iterator.Next());
ASSERT(Translation::BEGIN == opcode);
int frame_count = iterator.Next();
- PrintF(out, " %s {count=%d}\n", Translation::StringFor(opcode),
- frame_count);
+ int jsframe_count = iterator.Next();
+ PrintF(out, " %s {frame count=%d, js frame count=%d}\n",
+ Translation::StringFor(opcode),
+ frame_count,
+ jsframe_count);
while (iterator.HasNext() &&
Translation::BEGIN !=
@@ -7868,7 +8157,7 @@
UNREACHABLE();
break;
- case Translation::FRAME: {
+ case Translation::JS_FRAME: {
int ast_id = iterator.Next();
int function_id = iterator.Next();
JSFunction* function =
@@ -7880,6 +8169,12 @@
break;
}
+ case Translation::ARGUMENTS_ADAPTOR_FRAME: {
+ unsigned height = iterator.Next();
+ PrintF(out, "{arguments adaptor, height=%d}", height);
+ break;
+ }
+
case Translation::DUPLICATE:
break;
@@ -8115,21 +8410,35 @@
static void CopyFastElementsToFast(FixedArray* source,
FixedArray* destination,
WriteBarrierMode mode) {
- uint32_t count = static_cast<uint32_t>(source->length());
- for (uint32_t i = 0; i < count; ++i) {
- destination->set(i, source->get(i), mode);
+ int count = source->length();
+ int copy_size = Min(count, destination->length());
+ if (mode == SKIP_WRITE_BARRIER ||
+ !Page::FromAddress(destination->address())->IsFlagSet(
+ MemoryChunk::POINTERS_FROM_HERE_ARE_INTERESTING)) {
+ Address to = destination->address() + FixedArray::kHeaderSize;
+ Address from = source->address() + FixedArray::kHeaderSize;
+ memcpy(reinterpret_cast<void*>(to),
+ reinterpret_cast<void*>(from),
+ kPointerSize * copy_size);
+ } else {
+ for (int i = 0; i < copy_size; ++i) {
+ destination->set(i, source->get(i), mode);
+ }
}
}
-static void CopySlowElementsToFast(NumberDictionary* source,
+static void CopySlowElementsToFast(SeededNumberDictionary* source,
FixedArray* destination,
WriteBarrierMode mode) {
+ int destination_length = destination->length();
for (int i = 0; i < source->Capacity(); ++i) {
Object* key = source->KeyAt(i);
if (key->IsNumber()) {
uint32_t entry = static_cast<uint32_t>(key->Number());
- destination->set(entry, source->ValueAt(i), mode);
+ if (entry < static_cast<uint32_t>(destination_length)) {
+ destination->set(entry, source->ValueAt(i), mode);
+ }
}
}
}
@@ -8155,10 +8464,13 @@
Map* new_map = NULL;
if (elements()->map() != heap->non_strict_arguments_elements_map()) {
Object* object;
+ // The resized array has FAST_SMI_ONLY_ELEMENTS if the capacity mode forces
+ // it, or if it's allowed and the old elements array contained only SMIs.
bool has_fast_smi_only_elements =
- (set_capacity_mode == kAllowSmiOnlyElements) &&
- (elements()->map()->has_fast_smi_only_elements() ||
- elements() == heap->empty_fixed_array());
+ (set_capacity_mode == kForceSmiOnlyElements) ||
+ ((set_capacity_mode == kAllowSmiOnlyElements) &&
+ (elements()->map()->has_fast_smi_only_elements() ||
+ elements() == heap->empty_fixed_array()));
ElementsKind elements_kind = has_fast_smi_only_elements
? FAST_SMI_ONLY_ELEMENTS
: FAST_ELEMENTS;
@@ -8176,18 +8488,16 @@
WriteBarrierMode mode(new_elements->GetWriteBarrierMode(no_gc));
CopyFastElementsToFast(FixedArray::cast(old_elements_raw),
new_elements, mode);
- set_map(new_map);
- set_elements(new_elements);
+ set_map_and_elements(new_map, new_elements);
break;
}
case DICTIONARY_ELEMENTS: {
AssertNoAllocation no_gc;
WriteBarrierMode mode = new_elements->GetWriteBarrierMode(no_gc);
- CopySlowElementsToFast(NumberDictionary::cast(old_elements_raw),
+ CopySlowElementsToFast(SeededNumberDictionary::cast(old_elements_raw),
new_elements,
mode);
- set_map(new_map);
- set_elements(new_elements);
+ set_map_and_elements(new_map, new_elements);
break;
}
case NON_STRICT_ARGUMENTS_ELEMENTS: {
@@ -8198,7 +8508,7 @@
FixedArray* parameter_map = FixedArray::cast(old_elements_raw);
FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
if (arguments->IsDictionary()) {
- CopySlowElementsToFast(NumberDictionary::cast(arguments),
+ CopySlowElementsToFast(SeededNumberDictionary::cast(arguments),
new_elements,
mode);
} else {
@@ -8294,7 +8604,7 @@
break;
}
case DICTIONARY_ELEMENTS: {
- elems->Initialize(NumberDictionary::cast(old_elements));
+ elems->Initialize(SeededNumberDictionary::cast(old_elements));
break;
}
default:
@@ -8340,18 +8650,12 @@
void JSArray::Expand(int required_size) {
- Handle<JSArray> self(this);
- Handle<FixedArray> old_backing(FixedArray::cast(elements()));
- int old_size = old_backing->length();
- int new_size = required_size > old_size ? required_size : old_size;
- Handle<FixedArray> new_backing = FACTORY->NewFixedArray(new_size);
- // Can't use this any more now because we may have had a GC!
- for (int i = 0; i < old_size; i++) new_backing->set(i, old_backing->get(i));
- GetIsolate()->factory()->SetContent(self, new_backing);
+ GetIsolate()->factory()->SetElementsCapacityAndLength(
+ Handle<JSArray>(this), required_size, required_size);
}
-MaybeObject* JSObject::SetElementsLength(Object* len) {
+MaybeObject* JSArray::SetElementsLength(Object* len) {
// We should never end in here with a pixel or external array.
ASSERT(AllowsSetElementsLength());
return GetElementsAccessor()->SetLength(this, len);
@@ -8501,13 +8805,14 @@
MaybeObject* JSObject::EnsureCanContainElements(Arguments* args,
uint32_t first_arg,
- uint32_t arg_count) {
+ uint32_t arg_count,
+ EnsureElementsMode mode) {
// Elements in |Arguments| are ordered backwards (because they're on the
// stack), but the method that's called here iterates over them in forward
// direction.
return EnsureCanContainElements(
args->arguments() - first_arg - (arg_count - 1),
- arg_count);
+ arg_count, mode);
}
@@ -8559,7 +8864,7 @@
}
case DICTIONARY_ELEMENTS: {
if (element_dictionary()->FindEntry(index)
- != NumberDictionary::kNotFound) {
+ != SeededNumberDictionary::kNotFound) {
return true;
}
break;
@@ -8697,7 +9002,7 @@
}
case DICTIONARY_ELEMENTS: {
if (element_dictionary()->FindEntry(index) !=
- NumberDictionary::kNotFound) {
+ SeededNumberDictionary::kNotFound) {
return DICTIONARY_ELEMENT;
}
break;
@@ -8714,8 +9019,9 @@
// If not aliased, check the arguments.
FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
if (arguments->IsDictionary()) {
- NumberDictionary* dictionary = NumberDictionary::cast(arguments);
- if (dictionary->FindEntry(index) != NumberDictionary::kNotFound) {
+ SeededNumberDictionary* dictionary =
+ SeededNumberDictionary::cast(arguments);
+ if (dictionary->FindEntry(index) != SeededNumberDictionary::kNotFound) {
return DICTIONARY_ELEMENT;
}
} else {
@@ -8744,8 +9050,8 @@
return true;
}
} else {
- if (NumberDictionary::cast(elements)->FindEntry(index) !=
- NumberDictionary::kNotFound) {
+ if (SeededNumberDictionary::cast(elements)->FindEntry(index) !=
+ SeededNumberDictionary::kNotFound) {
return true;
}
}
@@ -8812,7 +9118,7 @@
}
case DICTIONARY_ELEMENTS: {
if (element_dictionary()->FindEntry(index)
- != NumberDictionary::kNotFound) {
+ != SeededNumberDictionary::kNotFound) {
return true;
}
break;
@@ -8916,8 +9222,8 @@
}
// __defineGetter__ callback
- if (structure->IsFixedArray()) {
- Object* getter = FixedArray::cast(structure)->get(kGetterIndex);
+ if (structure->IsAccessorPair()) {
+ Object* getter = AccessorPair::cast(structure)->getter();
if (getter->IsSpecFunction()) {
// TODO(rossberg): nicer would be to cast to some JSCallable here...
return GetPropertyWithDefinedGetter(receiver, JSReceiver::cast(getter));
@@ -8973,8 +9279,8 @@
return *value_handle;
}
- if (structure->IsFixedArray()) {
- Handle<Object> setter(FixedArray::cast(structure)->get(kSetterIndex));
+ if (structure->IsAccessorPair()) {
+ Handle<Object> setter(AccessorPair::cast(structure)->setter());
if (setter->IsSpecFunction()) {
// TODO(rossberg): nicer would be to cast to some JSCallable here...
return SetPropertyWithDefinedSetter(JSReceiver::cast(*setter), value);
@@ -9135,15 +9441,15 @@
FixedArray* elements = FixedArray::cast(this->elements());
bool is_arguments =
(elements->map() == heap->non_strict_arguments_elements_map());
- NumberDictionary* dictionary = NULL;
+ SeededNumberDictionary* dictionary = NULL;
if (is_arguments) {
- dictionary = NumberDictionary::cast(elements->get(1));
+ dictionary = SeededNumberDictionary::cast(elements->get(1));
} else {
- dictionary = NumberDictionary::cast(elements);
+ dictionary = SeededNumberDictionary::cast(elements);
}
int entry = dictionary->FindEntry(index);
- if (entry != NumberDictionary::kNotFound) {
+ if (entry != SeededNumberDictionary::kNotFound) {
Object* element = dictionary->ValueAt(entry);
PropertyDetails details = dictionary->DetailsAt(entry);
if (details.type() == CALLBACKS) {
@@ -9188,13 +9494,13 @@
FixedArrayBase* new_dictionary;
MaybeObject* maybe = dictionary->AtNumberPut(index, value);
if (!maybe->To<FixedArrayBase>(&new_dictionary)) return maybe;
- if (dictionary != NumberDictionary::cast(new_dictionary)) {
+ if (dictionary != SeededNumberDictionary::cast(new_dictionary)) {
if (is_arguments) {
elements->set(1, new_dictionary);
} else {
set_elements(new_dictionary);
}
- dictionary = NumberDictionary::cast(new_dictionary);
+ dictionary = SeededNumberDictionary::cast(new_dictionary);
}
}
@@ -9213,11 +9519,20 @@
} else {
new_length = dictionary->max_number_key() + 1;
}
- MaybeObject* result = CanConvertToFastDoubleElements()
+ SetFastElementsCapacityMode set_capacity_mode = FLAG_smi_only_arrays
+ ? kAllowSmiOnlyElements
+ : kDontAllowSmiOnlyElements;
+ bool has_smi_only_elements = false;
+ bool should_convert_to_fast_double_elements =
+ ShouldConvertToFastDoubleElements(&has_smi_only_elements);
+ if (has_smi_only_elements) {
+ set_capacity_mode = kForceSmiOnlyElements;
+ }
+ MaybeObject* result = should_convert_to_fast_double_elements
? SetFastDoubleElementsCapacityAndLength(new_length, new_length)
: SetFastElementsCapacityAndLength(new_length,
new_length,
- kDontAllowSmiOnlyElements);
+ set_capacity_mode);
if (result->IsFailure()) return result;
#ifdef DEBUG
if (FLAG_trace_normalization) {
@@ -9331,6 +9646,35 @@
}
+Handle<Object> JSObject::SetOwnElement(Handle<JSObject> object,
+ uint32_t index,
+ Handle<Object> value,
+ StrictModeFlag strict_mode) {
+ ASSERT(!object->HasExternalArrayElements());
+ CALL_HEAP_FUNCTION(object->GetIsolate(),
+ object->SetElement(index, *value, strict_mode, false),
+ Object);
+}
+
+
+Handle<Object> JSObject::SetElement(Handle<JSObject> object,
+ uint32_t index,
+ Handle<Object> value,
+ StrictModeFlag strict_mode) {
+ if (object->HasExternalArrayElements()) {
+ if (!value->IsSmi() && !value->IsHeapNumber() && !value->IsUndefined()) {
+ bool has_exception;
+ Handle<Object> number = Execution::ToNumber(value, &has_exception);
+ if (has_exception) return Handle<Object>();
+ value = number;
+ }
+ }
+ CALL_HEAP_FUNCTION(object->GetIsolate(),
+ object->SetElement(index, *value, strict_mode, true),
+ Object);
+}
+
+
MaybeObject* JSObject::SetElement(uint32_t index,
Object* value,
StrictModeFlag strict_mode,
@@ -9453,37 +9797,59 @@
}
+Handle<Object> JSObject::TransitionElementsKind(Handle<JSObject> object,
+ ElementsKind to_kind) {
+ CALL_HEAP_FUNCTION(object->GetIsolate(),
+ object->TransitionElementsKind(to_kind),
+ Object);
+}
+
+
MUST_USE_RESULT MaybeObject* JSObject::TransitionElementsKind(
ElementsKind to_kind) {
ElementsKind from_kind = map()->elements_kind();
FixedArrayBase* elms = FixedArrayBase::cast(elements());
uint32_t capacity = static_cast<uint32_t>(elms->length());
uint32_t length = capacity;
+
if (IsJSArray()) {
- CHECK(JSArray::cast(this)->length()->ToArrayIndex(&length));
- }
- if (from_kind == FAST_SMI_ONLY_ELEMENTS) {
- if (to_kind == FAST_DOUBLE_ELEMENTS) {
- MaybeObject* maybe_result =
- SetFastDoubleElementsCapacityAndLength(capacity, length);
- if (maybe_result->IsFailure()) return maybe_result;
- return this;
- } else if (to_kind == FAST_ELEMENTS) {
- MaybeObject* maybe_new_map = GetElementsTransitionMap(FAST_ELEMENTS);
- Map* new_map;
- if (!maybe_new_map->To(&new_map)) return maybe_new_map;
- if (FLAG_trace_elements_transitions) {
- PrintElementsTransition(stdout, from_kind, elms, FAST_ELEMENTS, elms);
- }
- set_map(new_map);
- return this;
+ Object* raw_length = JSArray::cast(this)->length();
+ if (raw_length->IsUndefined()) {
+ // If length is undefined, then JSArray is being initialized and has no
+ // elements, assume a length of zero.
+ length = 0;
+ } else {
+ CHECK(JSArray::cast(this)->length()->ToArrayIndex(&length));
}
- } else if (from_kind == FAST_DOUBLE_ELEMENTS && to_kind == FAST_ELEMENTS) {
+ }
+
+ if ((from_kind == FAST_SMI_ONLY_ELEMENTS && to_kind == FAST_ELEMENTS) ||
+ (length == 0)) {
+ MaybeObject* maybe_new_map = GetElementsTransitionMap(to_kind);
+ Map* new_map;
+ if (!maybe_new_map->To(&new_map)) return maybe_new_map;
+ if (FLAG_trace_elements_transitions) {
+ PrintElementsTransition(stdout, from_kind, elms, to_kind, elms);
+ }
+ set_map(new_map);
+ return this;
+ }
+
+ if (from_kind == FAST_SMI_ONLY_ELEMENTS &&
+ to_kind == FAST_DOUBLE_ELEMENTS) {
+ MaybeObject* maybe_result =
+ SetFastDoubleElementsCapacityAndLength(capacity, length);
+ if (maybe_result->IsFailure()) return maybe_result;
+ return this;
+ }
+
+ if (from_kind == FAST_DOUBLE_ELEMENTS && to_kind == FAST_ELEMENTS) {
MaybeObject* maybe_result = SetFastElementsCapacityAndLength(
capacity, length, kDontAllowSmiOnlyElements);
if (maybe_result->IsFailure()) return maybe_result;
return this;
}
+
// This method should never be called for any other case than the ones
// handled above.
UNREACHABLE();
@@ -9582,7 +9948,8 @@
FixedArray::cast(FixedArray::cast(backing_store_base)->get(1));
backing_store = FixedArray::cast(backing_store_base);
if (backing_store->IsDictionary()) {
- NumberDictionary* dictionary = NumberDictionary::cast(backing_store);
+ SeededNumberDictionary* dictionary =
+ SeededNumberDictionary::cast(backing_store);
*capacity = dictionary->Capacity();
*used = dictionary->NumberOfElements();
break;
@@ -9597,8 +9964,8 @@
}
break;
case DICTIONARY_ELEMENTS: {
- NumberDictionary* dictionary =
- NumberDictionary::cast(FixedArray::cast(elements()));
+ SeededNumberDictionary* dictionary =
+ SeededNumberDictionary::cast(FixedArray::cast(elements()));
*capacity = dictionary->Capacity();
*used = dictionary->NumberOfElements();
break;
@@ -9643,8 +10010,8 @@
int old_capacity = 0;
int used_elements = 0;
GetElementsCapacityAndUsage(&old_capacity, &used_elements);
- int dictionary_size = NumberDictionary::ComputeCapacity(used_elements) *
- NumberDictionary::kEntrySize;
+ int dictionary_size = SeededNumberDictionary::ComputeCapacity(used_elements) *
+ SeededNumberDictionary::kEntrySize;
return 3 * dictionary_size <= new_capacity;
}
@@ -9658,11 +10025,11 @@
if (IsAccessCheckNeeded()) return false;
FixedArray* elements = FixedArray::cast(this->elements());
- NumberDictionary* dictionary = NULL;
+ SeededNumberDictionary* dictionary = NULL;
if (elements->map() == GetHeap()->non_strict_arguments_elements_map()) {
- dictionary = NumberDictionary::cast(elements->get(1));
+ dictionary = SeededNumberDictionary::cast(elements->get(1));
} else {
- dictionary = NumberDictionary::cast(elements);
+ dictionary = SeededNumberDictionary::cast(elements);
}
// If an element has been added at a very high index in the elements
// dictionary, we cannot go back to fast case.
@@ -9677,22 +10044,31 @@
array_size = dictionary->max_number_key();
}
uint32_t dictionary_size = static_cast<uint32_t>(dictionary->Capacity()) *
- NumberDictionary::kEntrySize;
+ SeededNumberDictionary::kEntrySize;
return 2 * dictionary_size >= array_size;
}
-bool JSObject::CanConvertToFastDoubleElements() {
+bool JSObject::ShouldConvertToFastDoubleElements(
+ bool* has_smi_only_elements) {
+ *has_smi_only_elements = false;
if (FLAG_unbox_double_arrays) {
ASSERT(HasDictionaryElements());
- NumberDictionary* dictionary = NumberDictionary::cast(elements());
+ SeededNumberDictionary* dictionary =
+ SeededNumberDictionary::cast(elements());
+ bool found_double = false;
for (int i = 0; i < dictionary->Capacity(); i++) {
Object* key = dictionary->KeyAt(i);
if (key->IsNumber()) {
- if (!dictionary->ValueAt(i)->IsNumber()) return false;
+ Object* value = dictionary->ValueAt(i);
+ if (!value->IsNumber()) return false;
+ if (!value->IsSmi()) {
+ found_double = true;
+ }
}
}
- return true;
+ *has_smi_only_elements = !found_double;
+ return found_double;
} else {
return false;
}
@@ -9899,7 +10275,7 @@
}
case DICTIONARY_ELEMENTS: {
return element_dictionary()->FindEntry(index)
- != NumberDictionary::kNotFound;
+ != SeededNumberDictionary::kNotFound;
}
case NON_STRICT_ARGUMENTS_ELEMENTS:
UNIMPLEMENTED();
@@ -9923,7 +10299,7 @@
LookupResult result(isolate);
LocalLookupRealNamedProperty(key, &result);
- return result.IsProperty() && (result.type() == CALLBACKS);
+ return result.IsFound() && (result.type() == CALLBACKS);
}
@@ -10168,7 +10544,7 @@
if (storage != NULL) {
element_dictionary()->CopyKeysTo(storage,
filter,
- NumberDictionary::SORTED);
+ SeededNumberDictionary::SORTED);
}
counter += element_dictionary()->NumberOfElementsFilterAttributes(filter);
break;
@@ -10180,9 +10556,11 @@
if (arguments->IsDictionary()) {
// Copy the keys from arguments first, because Dictionary::CopyKeysTo
// will insert in storage starting at index 0.
- NumberDictionary* dictionary = NumberDictionary::cast(arguments);
+ SeededNumberDictionary* dictionary =
+ SeededNumberDictionary::cast(arguments);
if (storage != NULL) {
- dictionary->CopyKeysTo(storage, filter, NumberDictionary::UNSORTED);
+ dictionary->CopyKeysTo(
+ storage, filter, SeededNumberDictionary::UNSORTED);
}
counter += dictionary->NumberOfElementsFilterAttributes(filter);
for (int i = 0; i < mapped_length; ++i) {
@@ -10396,8 +10774,8 @@
// Utf8SymbolKey carries a vector of chars as key.
class Utf8SymbolKey : public HashTableKey {
public:
- explicit Utf8SymbolKey(Vector<const char> string)
- : string_(string), hash_field_(0) { }
+ explicit Utf8SymbolKey(Vector<const char> string, uint32_t seed)
+ : string_(string), hash_field_(0), seed_(seed) { }
bool IsMatch(Object* string) {
return String::cast(string)->IsEqualTo(string_);
@@ -10408,7 +10786,7 @@
unibrow::Utf8InputBuffer<> buffer(string_.start(),
static_cast<unsigned>(string_.length()));
chars_ = buffer.Length();
- hash_field_ = String::ComputeHashField(&buffer, chars_);
+ hash_field_ = String::ComputeHashField(&buffer, chars_, seed_);
uint32_t result = hash_field_ >> String::kHashShift;
ASSERT(result != 0); // Ensure that the hash value of 0 is never computed.
return result;
@@ -10427,17 +10805,18 @@
Vector<const char> string_;
uint32_t hash_field_;
int chars_; // Caches the number of characters when computing the hash code.
+ uint32_t seed_;
};
template <typename Char>
class SequentialSymbolKey : public HashTableKey {
public:
- explicit SequentialSymbolKey(Vector<const Char> string)
- : string_(string), hash_field_(0) { }
+ explicit SequentialSymbolKey(Vector<const Char> string, uint32_t seed)
+ : string_(string), hash_field_(0), seed_(seed) { }
uint32_t Hash() {
- StringHasher hasher(string_.length());
+ StringHasher hasher(string_.length(), seed_);
// Very long strings have a trivial hash that doesn't inspect the
// string contents.
@@ -10473,14 +10852,15 @@
Vector<const Char> string_;
uint32_t hash_field_;
+ uint32_t seed_;
};
class AsciiSymbolKey : public SequentialSymbolKey<char> {
public:
- explicit AsciiSymbolKey(Vector<const char> str)
- : SequentialSymbolKey<char>(str) { }
+ AsciiSymbolKey(Vector<const char> str, uint32_t seed)
+ : SequentialSymbolKey<char>(str, seed) { }
bool IsMatch(Object* string) {
return String::cast(string)->IsAsciiEqualTo(string_);
@@ -10497,13 +10877,14 @@
public:
explicit SubStringAsciiSymbolKey(Handle<SeqAsciiString> string,
int from,
- int length)
- : string_(string), from_(from), length_(length) { }
+ int length,
+ uint32_t seed)
+ : string_(string), from_(from), length_(length), seed_(seed) { }
uint32_t Hash() {
ASSERT(length_ >= 0);
ASSERT(from_ + length_ <= string_->length());
- StringHasher hasher(length_);
+ StringHasher hasher(length_, string_->GetHeap()->HashSeed());
// Very long strings have a trivial hash that doesn't inspect the
// string contents.
@@ -10555,13 +10936,14 @@
int from_;
int length_;
uint32_t hash_field_;
+ uint32_t seed_;
};
class TwoByteSymbolKey : public SequentialSymbolKey<uc16> {
public:
- explicit TwoByteSymbolKey(Vector<const uc16> str)
- : SequentialSymbolKey<uc16>(str) { }
+ explicit TwoByteSymbolKey(Vector<const uc16> str, uint32_t seed)
+ : SequentialSymbolKey<uc16>(str, seed) { }
bool IsMatch(Object* string) {
return String::cast(string)->IsTwoByteEqualTo(string_);
@@ -10598,7 +10980,7 @@
// Transform string to symbol if possible.
Map* map = heap->SymbolMapForString(string_);
if (map != NULL) {
- string_->set_map(map);
+ string_->set_map_no_write_barrier(map);
ASSERT(string_->IsSymbol());
return string_;
}
@@ -10659,7 +11041,7 @@
// Optimized for symbol key. Knowledge of the key type allows:
// 1. Move the check if the key is a symbol out of the loop.
- // 2. Avoid comparing hash codes in symbol to symbol comparision.
+ // 2. Avoid comparing hash codes in symbol to symbol comparison.
// 3. Detect a case when a dictionary key is not a symbol but the key is.
// In case of positive result the dictionary key may be replaced by
// the symbol with minimal performance penalty. It gives a chance to
@@ -10711,7 +11093,7 @@
uint32_t from_index = EntryToIndex(i);
Object* k = get(from_index);
if (IsKey(k)) {
- uint32_t hash = Shape::HashForObject(key, k);
+ uint32_t hash = HashTable<Shape, Key>::HashForObject(key, k);
uint32_t insertion_index =
EntryToIndex(new_table->FindInsertionEntry(hash));
for (int j = 0; j < Shape::kEntrySize; j++) {
@@ -10809,38 +11191,49 @@
template class Dictionary<StringDictionaryShape, String*>;
-template class Dictionary<NumberDictionaryShape, uint32_t>;
+template class Dictionary<SeededNumberDictionaryShape, uint32_t>;
-template MaybeObject* Dictionary<NumberDictionaryShape, uint32_t>::Allocate(
- int);
+template class Dictionary<UnseededNumberDictionaryShape, uint32_t>;
+
+template MaybeObject* Dictionary<SeededNumberDictionaryShape, uint32_t>::
+ Allocate(int at_least_space_for);
+
+template MaybeObject* Dictionary<UnseededNumberDictionaryShape, uint32_t>::
+ Allocate(int at_least_space_for);
template MaybeObject* Dictionary<StringDictionaryShape, String*>::Allocate(
int);
-template MaybeObject* Dictionary<NumberDictionaryShape, uint32_t>::AtPut(
+template MaybeObject* Dictionary<SeededNumberDictionaryShape, uint32_t>::AtPut(
uint32_t, Object*);
-template Object* Dictionary<NumberDictionaryShape, uint32_t>::SlowReverseLookup(
- Object*);
+template MaybeObject* Dictionary<UnseededNumberDictionaryShape, uint32_t>::
+ AtPut(uint32_t, Object*);
+
+template Object* Dictionary<SeededNumberDictionaryShape, uint32_t>::
+ SlowReverseLookup(Object* value);
+
+template Object* Dictionary<UnseededNumberDictionaryShape, uint32_t>::
+ SlowReverseLookup(Object* value);
template Object* Dictionary<StringDictionaryShape, String*>::SlowReverseLookup(
Object*);
-template void Dictionary<NumberDictionaryShape, uint32_t>::CopyKeysTo(
+template void Dictionary<SeededNumberDictionaryShape, uint32_t>::CopyKeysTo(
FixedArray*,
PropertyAttributes,
- Dictionary<NumberDictionaryShape, uint32_t>::SortMode);
+ Dictionary<SeededNumberDictionaryShape, uint32_t>::SortMode);
template Object* Dictionary<StringDictionaryShape, String*>::DeleteProperty(
int, JSObject::DeleteMode);
-template Object* Dictionary<NumberDictionaryShape, uint32_t>::DeleteProperty(
- int, JSObject::DeleteMode);
+template Object* Dictionary<SeededNumberDictionaryShape, uint32_t>::
+ DeleteProperty(int, JSObject::DeleteMode);
template MaybeObject* Dictionary<StringDictionaryShape, String*>::Shrink(
String*);
-template MaybeObject* Dictionary<NumberDictionaryShape, uint32_t>::Shrink(
+template MaybeObject* Dictionary<SeededNumberDictionaryShape, uint32_t>::Shrink(
uint32_t);
template void Dictionary<StringDictionaryShape, String*>::CopyKeysTo(
@@ -10859,32 +11252,41 @@
Dictionary<StringDictionaryShape, String*>::GenerateNewEnumerationIndices();
template int
-Dictionary<NumberDictionaryShape, uint32_t>::NumberOfElementsFilterAttributes(
- PropertyAttributes);
+Dictionary<SeededNumberDictionaryShape, uint32_t>::
+ NumberOfElementsFilterAttributes(PropertyAttributes);
-template MaybeObject* Dictionary<NumberDictionaryShape, uint32_t>::Add(
+template MaybeObject* Dictionary<SeededNumberDictionaryShape, uint32_t>::Add(
uint32_t, Object*, PropertyDetails);
-template MaybeObject* Dictionary<NumberDictionaryShape, uint32_t>::
+template MaybeObject* Dictionary<UnseededNumberDictionaryShape, uint32_t>::Add(
+ uint32_t, Object*, PropertyDetails);
+
+template MaybeObject* Dictionary<SeededNumberDictionaryShape, uint32_t>::
+ EnsureCapacity(int, uint32_t);
+
+template MaybeObject* Dictionary<UnseededNumberDictionaryShape, uint32_t>::
EnsureCapacity(int, uint32_t);
template MaybeObject* Dictionary<StringDictionaryShape, String*>::
EnsureCapacity(int, String*);
-template MaybeObject* Dictionary<NumberDictionaryShape, uint32_t>::AddEntry(
- uint32_t, Object*, PropertyDetails, uint32_t);
+template MaybeObject* Dictionary<SeededNumberDictionaryShape, uint32_t>::
+ AddEntry(uint32_t, Object*, PropertyDetails, uint32_t);
+
+template MaybeObject* Dictionary<UnseededNumberDictionaryShape, uint32_t>::
+ AddEntry(uint32_t, Object*, PropertyDetails, uint32_t);
template MaybeObject* Dictionary<StringDictionaryShape, String*>::AddEntry(
String*, Object*, PropertyDetails, uint32_t);
template
-int Dictionary<NumberDictionaryShape, uint32_t>::NumberOfEnumElements();
+int Dictionary<SeededNumberDictionaryShape, uint32_t>::NumberOfEnumElements();
template
int Dictionary<StringDictionaryShape, String*>::NumberOfEnumElements();
template
-int HashTable<NumberDictionaryShape, uint32_t>::FindEntry(uint32_t);
+int HashTable<SeededNumberDictionaryShape, uint32_t>::FindEntry(uint32_t);
// Collates undefined and unexisting elements below limit from position
@@ -10894,7 +11296,7 @@
// Must stay in dictionary mode, either because of requires_slow_elements,
// or because we are not going to sort (and therefore compact) all of the
// elements.
- NumberDictionary* dict = element_dictionary();
+ SeededNumberDictionary* dict = element_dictionary();
HeapNumber* result_double = NULL;
if (limit > static_cast<uint32_t>(Smi::kMaxValue)) {
// Allocate space for result before we start mutating the object.
@@ -10907,10 +11309,10 @@
Object* obj;
{ MaybeObject* maybe_obj =
- NumberDictionary::Allocate(dict->NumberOfElements());
+ SeededNumberDictionary::Allocate(dict->NumberOfElements());
if (!maybe_obj->ToObject(&obj)) return maybe_obj;
}
- NumberDictionary* new_dict = NumberDictionary::cast(obj);
+ SeededNumberDictionary* new_dict = SeededNumberDictionary::cast(obj);
AssertNoAllocation no_alloc;
@@ -10994,7 +11396,7 @@
if (HasDictionaryElements()) {
// Convert to fast elements containing only the existing properties.
// Ordering is irrelevant, since we are going to sort anyway.
- NumberDictionary* dict = element_dictionary();
+ SeededNumberDictionary* dict = element_dictionary();
if (IsJSArray() || dict->requires_slow_elements() ||
dict->max_number_key() >= limit) {
return PrepareSlowElementsForSort(limit);
@@ -11346,10 +11748,12 @@
// algorithm.
class TwoCharHashTableKey : public HashTableKey {
public:
- TwoCharHashTableKey(uint32_t c1, uint32_t c2)
+ TwoCharHashTableKey(uint32_t c1, uint32_t c2, uint32_t seed)
: c1_(c1), c2_(c2) {
// Char 1.
- uint32_t hash = c1 + (c1 << 10);
+ uint32_t hash = seed;
+ hash += c1;
+ hash += hash << 10;
hash ^= hash >> 6;
// Char 2.
hash += c2;
@@ -11359,9 +11763,9 @@
hash += hash << 3;
hash ^= hash >> 11;
hash += hash << 15;
- if (hash == 0) hash = 27;
+ if ((hash & String::kHashBitMask) == 0) hash = String::kZeroHash;
#ifdef DEBUG
- StringHasher hasher(2);
+ StringHasher hasher(2, seed);
hasher.AddCharacter(c1);
hasher.AddCharacter(c2);
// If this assert fails then we failed to reproduce the two-character
@@ -11418,7 +11822,7 @@
bool SymbolTable::LookupTwoCharsSymbolIfExists(uint32_t c1,
uint32_t c2,
String** symbol) {
- TwoCharHashTableKey key(c1, c2);
+ TwoCharHashTableKey key(c1, c2, GetHeap()->HashSeed());
int entry = FindEntry(&key);
if (entry == kNotFound) {
return false;
@@ -11431,15 +11835,16 @@
}
-MaybeObject* SymbolTable::LookupSymbol(Vector<const char> str, Object** s) {
- Utf8SymbolKey key(str);
+MaybeObject* SymbolTable::LookupSymbol(Vector<const char> str,
+ Object** s) {
+ Utf8SymbolKey key(str, GetHeap()->HashSeed());
return LookupKey(&key, s);
}
MaybeObject* SymbolTable::LookupAsciiSymbol(Vector<const char> str,
Object** s) {
- AsciiSymbolKey key(str);
+ AsciiSymbolKey key(str, GetHeap()->HashSeed());
return LookupKey(&key, s);
}
@@ -11448,14 +11853,14 @@
int from,
int length,
Object** s) {
- SubStringAsciiSymbolKey key(str, from, length);
+ SubStringAsciiSymbolKey key(str, from, length, GetHeap()->HashSeed());
return LookupKey(&key, s);
}
MaybeObject* SymbolTable::LookupTwoByteSymbol(Vector<const uc16> str,
Object** s) {
- TwoByteSymbolKey key(str);
+ TwoByteSymbolKey key(str, GetHeap()->HashSeed());
return LookupKey(&key, s);
}
@@ -11794,8 +12199,9 @@
if (!maybe_k->ToObject(&k)) return maybe_k;
}
PropertyDetails details = PropertyDetails(NONE, NORMAL);
- return Dictionary<Shape, Key>::cast(obj)->
- AddEntry(key, value, details, Shape::Hash(key));
+
+ return Dictionary<Shape, Key>::cast(obj)->AddEntry(key, value, details,
+ Dictionary<Shape, Key>::Hash(key));
}
@@ -11810,8 +12216,9 @@
{ MaybeObject* maybe_obj = EnsureCapacity(1, key);
if (!maybe_obj->ToObject(&obj)) return maybe_obj;
}
- return Dictionary<Shape, Key>::cast(obj)->
- AddEntry(key, value, details, Shape::Hash(key));
+
+ return Dictionary<Shape, Key>::cast(obj)->AddEntry(key, value, details,
+ Dictionary<Shape, Key>::Hash(key));
}
@@ -11844,7 +12251,7 @@
}
-void NumberDictionary::UpdateMaxNumberKey(uint32_t key) {
+void SeededNumberDictionary::UpdateMaxNumberKey(uint32_t key) {
// If the dictionary requires slow elements an element has already
// been added at a high index.
if (requires_slow_elements()) return;
@@ -11863,31 +12270,65 @@
}
-MaybeObject* NumberDictionary::AddNumberEntry(uint32_t key,
- Object* value,
- PropertyDetails details) {
+MaybeObject* SeededNumberDictionary::AddNumberEntry(uint32_t key,
+ Object* value,
+ PropertyDetails details) {
UpdateMaxNumberKey(key);
SLOW_ASSERT(this->FindEntry(key) == kNotFound);
return Add(key, value, details);
}
-MaybeObject* NumberDictionary::AtNumberPut(uint32_t key, Object* value) {
+MaybeObject* UnseededNumberDictionary::AddNumberEntry(uint32_t key,
+ Object* value) {
+ SLOW_ASSERT(this->FindEntry(key) == kNotFound);
+ return Add(key, value, PropertyDetails(NONE, NORMAL));
+}
+
+
+MaybeObject* SeededNumberDictionary::AtNumberPut(uint32_t key, Object* value) {
UpdateMaxNumberKey(key);
return AtPut(key, value);
}
-MaybeObject* NumberDictionary::Set(uint32_t key,
- Object* value,
- PropertyDetails details) {
+MaybeObject* UnseededNumberDictionary::AtNumberPut(uint32_t key,
+ Object* value) {
+ return AtPut(key, value);
+}
+
+
+Handle<SeededNumberDictionary> SeededNumberDictionary::Set(
+ Handle<SeededNumberDictionary> dictionary,
+ uint32_t index,
+ Handle<Object> value,
+ PropertyDetails details) {
+ CALL_HEAP_FUNCTION(dictionary->GetIsolate(),
+ dictionary->Set(index, *value, details),
+ SeededNumberDictionary);
+}
+
+
+Handle<UnseededNumberDictionary> UnseededNumberDictionary::Set(
+ Handle<UnseededNumberDictionary> dictionary,
+ uint32_t index,
+ Handle<Object> value) {
+ CALL_HEAP_FUNCTION(dictionary->GetIsolate(),
+ dictionary->Set(index, *value),
+ UnseededNumberDictionary);
+}
+
+
+MaybeObject* SeededNumberDictionary::Set(uint32_t key,
+ Object* value,
+ PropertyDetails details) {
int entry = FindEntry(key);
if (entry == kNotFound) return AddNumberEntry(key, value, details);
// Preserve enumeration index.
details = PropertyDetails(details.attributes(),
details.type(),
DetailsAt(entry).index());
- MaybeObject* maybe_object_key = NumberDictionaryShape::AsObject(key);
+ MaybeObject* maybe_object_key = SeededNumberDictionaryShape::AsObject(key);
Object* object_key;
if (!maybe_object_key->ToObject(&object_key)) return maybe_object_key;
SetEntry(entry, object_key, value, details);
@@ -11895,6 +12336,18 @@
}
+MaybeObject* UnseededNumberDictionary::Set(uint32_t key,
+ Object* value) {
+ int entry = FindEntry(key);
+ if (entry == kNotFound) return AddNumberEntry(key, value);
+ MaybeObject* maybe_object_key = UnseededNumberDictionaryShape::AsObject(key);
+ Object* object_key;
+ if (!maybe_object_key->ToObject(&object_key)) return maybe_object_key;
+ SetEntry(entry, object_key, value);
+ return this;
+}
+
+
template<typename Shape, typename Key>
int Dictionary<Shape, Key>::NumberOfElementsFilterAttributes(