diff options
Diffstat (limited to 'deps/v8/src/objects.cc')
-rw-r--r-- | deps/v8/src/objects.cc | 1833 |
1 files changed, 997 insertions, 836 deletions
diff --git a/deps/v8/src/objects.cc b/deps/v8/src/objects.cc index 23eac77f7f..35646b8be5 100644 --- a/deps/v8/src/objects.cc +++ b/deps/v8/src/objects.cc @@ -32,6 +32,7 @@ #include "arguments.h" #include "bootstrapper.h" #include "codegen.h" +#include "cpu-profiler.h" #include "debug.h" #include "deoptimizer.h" #include "date.h" @@ -40,6 +41,7 @@ #include "full-codegen.h" #include "hydrogen.h" #include "isolate-inl.h" +#include "log.h" #include "objects-inl.h" #include "objects-visiting.h" #include "objects-visiting-inl.h" @@ -83,23 +85,19 @@ MaybeObject* Object::ToObject(Context* native_context) { } -MaybeObject* Object::ToObject() { +MaybeObject* Object::ToObject(Isolate* isolate) { if (IsJSReceiver()) { return this; } else if (IsNumber()) { - Isolate* isolate = Isolate::Current(); Context* native_context = isolate->context()->native_context(); return CreateJSValue(native_context->number_function(), this); } else if (IsBoolean()) { - Isolate* isolate = HeapObject::cast(this)->GetIsolate(); Context* native_context = isolate->context()->native_context(); return CreateJSValue(native_context->boolean_function(), this); } else if (IsString()) { - Isolate* isolate = HeapObject::cast(this)->GetIsolate(); Context* native_context = isolate->context()->native_context(); return CreateJSValue(native_context->string_function(), this); } else if (IsSymbol()) { - Isolate* isolate = HeapObject::cast(this)->GetIsolate(); Context* native_context = isolate->context()->native_context(); return CreateJSValue(native_context->symbol_function(), this); } @@ -135,7 +133,7 @@ void Object::Lookup(Name* name, LookupResult* result) { } else if (IsBoolean()) { holder = native_context->boolean_function()->instance_prototype(); } else { - Isolate::Current()->PushStackTraceAndDie( + result->isolate()->PushStackTraceAndDie( 0xDEAD0000, this, JSReceiver::cast(this)->map(), 0xDEAD0001); } } @@ -341,7 +339,7 @@ MaybeObject* JSObject::GetPropertyWithCallback(Object* receiver, AccessorDescriptor* callback = reinterpret_cast<AccessorDescriptor*>( Foreign::cast(structure)->foreign_address()); - MaybeObject* value = (callback->getter)(receiver, callback->data); + MaybeObject* value = (callback->getter)(isolate, receiver, callback->data); RETURN_IF_SCHEDULED_EXCEPTION(isolate); return value; } @@ -368,7 +366,8 @@ MaybeObject* JSObject::GetPropertyWithCallback(Object* receiver, } ExecutableAccessorInfo* data = ExecutableAccessorInfo::cast(structure); Object* fun_obj = data->getter(); - v8::AccessorGetter call_fun = v8::ToCData<v8::AccessorGetter>(fun_obj); + v8::AccessorGetterCallback call_fun = + v8::ToCData<v8::AccessorGetterCallback>(fun_obj); if (call_fun == NULL) return isolate->heap()->undefined_value(); HandleScope scope(isolate); JSObject* self = JSObject::cast(receiver); @@ -421,24 +420,22 @@ MaybeObject* JSProxy::GetPropertyWithHandler(Object* receiver_raw, } -Handle<Object> Object::GetProperty(Handle<Object> object, Handle<Name> name) { +Handle<Object> Object::GetProperty(Handle<Object> object, + Handle<Name> name) { // TODO(rossberg): The index test should not be here but in the GetProperty // method (or somewhere else entirely). Needs more global clean-up. uint32_t index; + Isolate* isolate = name->GetIsolate(); if (name->AsArrayIndex(&index)) - return GetElement(object, index); - Isolate* isolate = object->IsHeapObject() - ? Handle<HeapObject>::cast(object)->GetIsolate() - : Isolate::Current(); + return GetElement(isolate, object, index); CALL_HEAP_FUNCTION(isolate, object->GetProperty(*name), Object); } -Handle<Object> Object::GetElement(Handle<Object> object, uint32_t index) { - Isolate* isolate = object->IsHeapObject() - ? Handle<HeapObject>::cast(object)->GetIsolate() - : Isolate::Current(); - CALL_HEAP_FUNCTION(isolate, object->GetElement(index), Object); +Handle<Object> Object::GetElement(Isolate* isolate, + Handle<Object> object, + uint32_t index) { + CALL_HEAP_FUNCTION(isolate, object->GetElement(isolate, index), Object); } @@ -451,14 +448,17 @@ MaybeObject* JSProxy::GetElementWithHandler(Object* receiver, } -MaybeObject* JSProxy::SetElementWithHandler(JSReceiver* receiver, - uint32_t index, - Object* value, - StrictModeFlag strict_mode) { - String* name; - MaybeObject* maybe = GetHeap()->Uint32ToString(index); - if (!maybe->To<String>(&name)) return maybe; - return SetPropertyWithHandler(receiver, name, value, NONE, strict_mode); +Handle<Object> JSProxy::SetElementWithHandler(Handle<JSProxy> proxy, + Handle<JSReceiver> receiver, + uint32_t index, + Handle<Object> value, + StrictModeFlag strict_mode) { + Isolate* isolate = proxy->GetIsolate(); + Handle<String> name = isolate->factory()->Uint32ToString(index); + CALL_HEAP_FUNCTION(isolate, + proxy->SetPropertyWithHandler( + *receiver, *name, *value, NONE, strict_mode), + Object); } @@ -487,8 +487,8 @@ MaybeObject* Object::GetPropertyWithDefinedGetter(Object* receiver, #endif bool has_pending_exception; - Handle<Object> result = - Execution::Call(fun, self, 0, NULL, &has_pending_exception, true); + Handle<Object> result = Execution::Call( + isolate, fun, self, 0, NULL, &has_pending_exception, true); // Check for pending exception and return the result. if (has_pending_exception) return Failure::Exception(); return *result; @@ -513,6 +513,12 @@ MaybeObject* JSObject::GetPropertyWithFailedAccessCheck( return result->holder()->GetPropertyWithCallback( receiver, result->GetCallbackObject(), name); } + } else if (obj->IsAccessorPair()) { + AccessorPair* pair = AccessorPair::cast(obj); + if (pair->all_can_read()) { + return result->holder()->GetPropertyWithCallback( + receiver, result->GetCallbackObject(), name); + } } break; } @@ -573,6 +579,11 @@ PropertyAttributes JSObject::GetPropertyAttributeWithFailedAccessCheck( if (info->all_can_read()) { return result->GetAttributes(); } + } else if (obj->IsAccessorPair()) { + AccessorPair* pair = AccessorPair::cast(obj); + if (pair->all_can_read()) { + return result->GetAttributes(); + } } break; } @@ -786,9 +797,7 @@ Handle<Object> Object::GetProperty(Handle<Object> object, LookupResult* result, Handle<Name> key, PropertyAttributes* attributes) { - Isolate* isolate = object->IsHeapObject() - ? Handle<HeapObject>::cast(object)->GetIsolate() - : Isolate::Current(); + Isolate* isolate = result->isolate(); CALL_HEAP_FUNCTION( isolate, object->GetProperty(*receiver, result, *key, attributes), @@ -801,9 +810,7 @@ MaybeObject* Object::GetPropertyOrFail(Handle<Object> object, LookupResult* result, Handle<Name> key, PropertyAttributes* attributes) { - Isolate* isolate = object->IsHeapObject() - ? Handle<HeapObject>::cast(object)->GetIsolate() - : Isolate::Current(); + Isolate* isolate = result->isolate(); CALL_HEAP_FUNCTION_PASS_EXCEPTION( isolate, object->GetProperty(*receiver, result, *key, attributes)); @@ -816,7 +823,8 @@ MaybeObject* Object::GetProperty(Object* receiver, PropertyAttributes* attributes) { // Make sure that the top context does not change when doing // callbacks or interceptor calls. - AssertNoContextChange ncc; + AssertNoContextChangeWithHandleScope ncc; + Isolate* isolate = name->GetIsolate(); Heap* heap = isolate->heap(); @@ -894,10 +902,9 @@ MaybeObject* Object::GetProperty(Object* receiver, } -MaybeObject* Object::GetElementWithReceiver(Object* receiver, uint32_t index) { - Isolate* isolate = IsSmi() - ? Isolate::Current() - : HeapObject::cast(this)->GetIsolate(); +MaybeObject* Object::GetElementWithReceiver(Isolate* isolate, + Object* receiver, + uint32_t index) { Heap* heap = isolate->heap(); Object* holder = this; @@ -1449,6 +1456,66 @@ void JSObject::PrintElementsTransition( } +void Map::PrintGeneralization(FILE* file, + const char* reason, + int modify_index, + int split, + int descriptors, + bool constant_to_field, + Representation old_representation, + Representation new_representation) { + PrintF(file, "[generalizing "); + constructor_name()->PrintOn(file); + PrintF(file, "] "); + String::cast(instance_descriptors()->GetKey(modify_index))->PrintOn(file); + if (constant_to_field) { + PrintF(file, ":c->f"); + } else { + PrintF(file, ":%s->%s", + old_representation.Mnemonic(), + new_representation.Mnemonic()); + } + PrintF(file, " ("); + if (strlen(reason) > 0) { + PrintF(file, "%s", reason); + } else { + PrintF(file, "+%i maps", descriptors - split); + } + PrintF(file, ") ["); + JavaScriptFrame::PrintTop(GetIsolate(), file, false, true); + PrintF(file, "]\n"); +} + + +void JSObject::PrintInstanceMigration(FILE* file, + Map* original_map, + Map* new_map) { + PrintF(file, "[migrating "); + map()->constructor_name()->PrintOn(file); + PrintF(file, "] "); + DescriptorArray* o = original_map->instance_descriptors(); + DescriptorArray* n = new_map->instance_descriptors(); + for (int i = 0; i < original_map->NumberOfOwnDescriptors(); i++) { + Representation o_r = o->GetDetails(i).representation(); + Representation n_r = n->GetDetails(i).representation(); + if (!o_r.Equals(n_r)) { + String::cast(o->GetKey(i))->PrintOn(file); + PrintF(file, ":%s->%s ", o_r.Mnemonic(), n_r.Mnemonic()); + } else if (o->GetDetails(i).type() == CONSTANT && + n->GetDetails(i).type() == FIELD) { + Name* name = o->GetKey(i); + if (name->IsString()) { + String::cast(name)->PrintOn(file); + } else { + PrintF(file, "???"); + } + PrintF(file, " "); + } + } + PrintF(file, "\n"); +} + + void HeapObject::HeapObjectShortPrint(StringStream* accumulator) { Heap* heap = GetHeap(); if (!heap->Contains(this)) { @@ -1783,14 +1850,14 @@ String* JSReceiver::class_name() { } -String* JSReceiver::constructor_name() { - if (map()->constructor()->IsJSFunction()) { - JSFunction* constructor = JSFunction::cast(map()->constructor()); +String* Map::constructor_name() { + if (constructor()->IsJSFunction()) { + JSFunction* constructor = JSFunction::cast(this->constructor()); String* name = String::cast(constructor->shared()->name()); if (name->length() > 0) return name; String* inferred_name = constructor->shared()->inferred_name(); if (inferred_name->length() > 0) return inferred_name; - Object* proto = GetPrototype(); + Object* proto = prototype(); if (proto->IsJSObject()) return JSObject::cast(proto)->constructor_name(); } // TODO(rossberg): what about proxies? @@ -1799,6 +1866,11 @@ String* JSReceiver::constructor_name() { } +String* JSReceiver::constructor_name() { + return map()->constructor_name(); +} + + MaybeObject* JSObject::AddFastPropertyUsingMap(Map* new_map, Name* name, Object* value, @@ -1828,30 +1900,12 @@ MaybeObject* JSObject::AddFastPropertyUsingMap(Map* new_map, } -static bool IsIdentifier(UnicodeCache* cache, Name* name) { - // Checks whether the buffer contains an identifier (no escape). - if (!name->IsString()) return false; - String* string = String::cast(name); - if (string->length() == 0) return false; - ConsStringIteratorOp op; - StringCharacterStream stream(string, &op); - if (!cache->IsIdentifierStart(stream.GetNext())) { - return false; - } - while (stream.HasMore()) { - if (!cache->IsIdentifierPart(stream.GetNext())) { - return false; - } - } - return true; -} - - MaybeObject* JSObject::AddFastProperty(Name* name, Object* value, PropertyAttributes attributes, StoreFromKeyed store_mode, - ValueType value_type) { + ValueType value_type, + TransitionFlag flag) { ASSERT(!IsJSGlobalProxy()); ASSERT(DescriptorArray::kNotFound == map()->instance_descriptors()->Search( @@ -1861,15 +1915,10 @@ MaybeObject* JSObject::AddFastProperty(Name* name, // hidden strings) and is not a real identifier. // Normalize the object if it will have too many fast properties. Isolate* isolate = GetHeap()->isolate(); - if ((!name->IsSymbol() && !IsIdentifier(isolate->unicode_cache(), name) - && name != isolate->heap()->hidden_string()) || - (map()->unused_property_fields() == 0 && - TooManyFastProperties(properties()->length(), store_mode))) { - Object* obj; - MaybeObject* maybe_obj = + if (!name->IsCacheable(isolate) || TooManyFastProperties(store_mode)) { + MaybeObject* maybe_failure = NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0); - if (!maybe_obj->ToObject(&obj)) return maybe_obj; - + if (maybe_failure->IsFailure()) return maybe_failure; return AddSlowProperty(name, value, attributes); } @@ -1882,66 +1931,36 @@ MaybeObject* JSObject::AddFastProperty(Name* name, FieldDescriptor new_field(name, index, attributes, representation); - ASSERT(index < map()->inobject_properties() || - (index - map()->inobject_properties()) < properties()->length() || - map()->unused_property_fields() == 0); - - FixedArray* values = NULL; - - // TODO(verwaest): Merge with AddFastPropertyUsingMap. - if (map()->unused_property_fields() == 0) { - // Make room for the new value - MaybeObject* maybe_values = - properties()->CopySize(properties()->length() + kFieldsAdded); - if (!maybe_values->To(&values)) return maybe_values; - } - - TransitionFlag flag = INSERT_TRANSITION; - - Heap* heap = isolate->heap(); - - Object* storage; - MaybeObject* maybe_storage = - value->AllocateNewStorageFor(heap, representation); - if (!maybe_storage->To(&storage)) return maybe_storage; - - // Note that Map::CopyAddDescriptor has side-effects, the new map is already - // inserted in the transition tree. No more allocations that might fail are - // allowed after this point. Map* new_map; MaybeObject* maybe_new_map = map()->CopyAddDescriptor(&new_field, flag); if (!maybe_new_map->To(&new_map)) return maybe_new_map; - if (map()->unused_property_fields() == 0) { - ASSERT(values != NULL); - set_properties(values); - new_map->set_unused_property_fields(kFieldsAdded - 1); - } else { - new_map->set_unused_property_fields(map()->unused_property_fields() - 1); + int unused_property_fields = map()->unused_property_fields() - 1; + if (unused_property_fields < 0) { + unused_property_fields += kFieldsAdded; } + new_map->set_unused_property_fields(unused_property_fields); - set_map(new_map); - - FastPropertyAtPut(index, storage); - return value; + return AddFastPropertyUsingMap(new_map, name, value, index, representation); } MaybeObject* JSObject::AddConstantProperty( Name* name, Object* constant, - PropertyAttributes attributes) { + PropertyAttributes attributes, + TransitionFlag initial_flag) { // Allocate new instance descriptors with (name, constant) added ConstantDescriptor d(name, constant, attributes); TransitionFlag flag = - // Do not add transitions to global objects. + // Do not add transitions to global objects. (IsGlobalObject() || // Don't add transitions to special properties with non-trivial // attributes. attributes != NONE) ? OMIT_TRANSITION - : INSERT_TRANSITION; + : initial_flag; Map* new_map; MaybeObject* maybe_new_map = map()->CopyAddDescriptor(&d, flag); @@ -2001,7 +2020,8 @@ MaybeObject* JSObject::AddProperty(Name* name, JSReceiver::StoreFromKeyed store_mode, ExtensibilityCheck extensibility_check, ValueType value_type, - StoreMode mode) { + StoreMode mode, + TransitionFlag transition_flag) { ASSERT(!IsJSGlobalProxy()); Map* map_of_this = map(); Heap* heap = GetHeap(); @@ -2028,10 +2048,10 @@ MaybeObject* JSObject::AddProperty(Name* name, // !value->IsTheHole() && // !value->IsConsString()) { if (value->IsJSFunction()) { - result = AddConstantProperty(name, value, attributes); + result = AddConstantProperty(name, value, attributes, transition_flag); } else { result = AddFastProperty( - name, value, attributes, store_mode, value_type); + name, value, attributes, store_mode, value_type, transition_flag); } } else { // Normalize the object to prevent very large instance descriptors. @@ -2071,7 +2091,8 @@ void JSObject::EnqueueChangeRecord(Handle<JSObject> object, } Handle<Object> args[] = { type, object, name, old_value }; bool threw; - Execution::Call(Handle<JSFunction>(isolate->observers_notify_change()), + Execution::Call(isolate, + Handle<JSFunction>(isolate->observers_notify_change()), isolate->factory()->undefined_value(), old_value->IsTheHole() ? 3 : 4, args, &threw); @@ -2083,6 +2104,7 @@ void JSObject::DeliverChangeRecords(Isolate* isolate) { ASSERT(isolate->observer_delivery_pending()); bool threw = false; Execution::Call( + isolate, isolate->observers_deliver_changes(), isolate->factory()->undefined_value(), 0, @@ -2098,7 +2120,6 @@ MaybeObject* JSObject::SetPropertyPostInterceptor( Object* value, PropertyAttributes attributes, StrictModeFlag strict_mode, - ExtensibilityCheck extensibility_check, StoreMode mode) { // Check local property, ignore interceptor. LookupResult result(GetIsolate()); @@ -2110,13 +2131,12 @@ MaybeObject* JSObject::SetPropertyPostInterceptor( return SetProperty(&result, name, value, attributes, strict_mode); } bool done = false; - MaybeObject* result_object; - result_object = + MaybeObject* result_object = SetPropertyViaPrototypes(name, value, attributes, strict_mode, &done); if (done) return result_object; // Add a new real property. return AddProperty(name, value, attributes, strict_mode, - MAY_BE_STORE_FROM_KEYED, extensibility_check, + MAY_BE_STORE_FROM_KEYED, PERFORM_EXTENSIBILITY_CHECK, OPTIMAL_REPRESENTATION, mode); } @@ -2137,105 +2157,6 @@ MaybeObject* JSObject::ReplaceSlowProperty(Name* name, } -MaybeObject* JSObject::ConvertTransitionToMapTransition( - int transition_index, - Name* name, - Object* new_value, - PropertyAttributes attributes) { - Map* old_map = map(); - Map* old_target = old_map->GetTransition(transition_index); - Object* result; - - MaybeObject* maybe_result = ConvertDescriptorToField( - name, new_value, attributes, OMIT_TRANSITION_KEEP_REPRESENTATIONS); - if (!maybe_result->To(&result)) return maybe_result; - - if (!HasFastProperties()) return result; - - // This method should only be used to convert existing transitions. - Map* new_map = map(); - - // TODO(verwaest): From here on we lose existing map transitions, causing - // invalid back pointers. This will change once we can store multiple - // transitions with the same key. - bool owned_descriptors = old_map->owns_descriptors(); - if (owned_descriptors || - old_target->instance_descriptors() == old_map->instance_descriptors()) { - // Since the conversion above generated a new fast map with an additional - // property which can be shared as well, install this descriptor pointer - // along the entire chain of smaller maps. - Map* map; - DescriptorArray* new_descriptors = new_map->instance_descriptors(); - DescriptorArray* old_descriptors = old_map->instance_descriptors(); - for (Object* current = old_map; - !current->IsUndefined(); - current = map->GetBackPointer()) { - map = Map::cast(current); - if (map->instance_descriptors() != old_descriptors) break; - map->SetEnumLength(Map::kInvalidEnumCache); - map->set_instance_descriptors(new_descriptors); - } - old_map->set_owns_descriptors(false); - } - - old_target->DeprecateTransitionTree(); - - old_map->SetTransition(transition_index, new_map); - new_map->SetBackPointer(old_map); - return result; -} - - -MaybeObject* JSObject::ConvertDescriptorToField(Name* name, - Object* new_value, - PropertyAttributes attributes, - TransitionFlag flag) { - if (map()->unused_property_fields() == 0 && - TooManyFastProperties(properties()->length(), MAY_BE_STORE_FROM_KEYED)) { - Object* obj; - MaybeObject* maybe_obj = NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0); - if (!maybe_obj->ToObject(&obj)) return maybe_obj; - return ReplaceSlowProperty(name, new_value, attributes); - } - - Representation representation = IsJSContextExtensionObject() - ? Representation::Tagged() : new_value->OptimalRepresentation(); - int index = map()->NextFreePropertyIndex(); - FieldDescriptor new_field(name, index, attributes, representation); - - // Make a new map for the object. - Map* new_map; - MaybeObject* maybe_new_map = map()->CopyInsertDescriptor(&new_field, flag); - if (!maybe_new_map->To(&new_map)) return maybe_new_map; - - // Make new properties array if necessary. - FixedArray* new_properties = NULL; - int new_unused_property_fields = map()->unused_property_fields() - 1; - if (map()->unused_property_fields() == 0) { - new_unused_property_fields = kFieldsAdded - 1; - MaybeObject* maybe_new_properties = - properties()->CopySize(properties()->length() + kFieldsAdded); - if (!maybe_new_properties->To(&new_properties)) return maybe_new_properties; - } - - Heap* heap = GetHeap(); - Object* storage; - MaybeObject* maybe_storage = - new_value->AllocateNewStorageFor(heap, representation); - if (!maybe_storage->To(&storage)) return maybe_storage; - - // Update pointers to commit changes. - // Object points to the new map. - new_map->set_unused_property_fields(new_unused_property_fields); - set_map(new_map); - if (new_properties != NULL) { - set_properties(new_properties); - } - FastPropertyAtPut(index, new_value); - return new_value; -} - - const char* Representation::Mnemonic() const { switch (kind_) { case kNone: return "v"; @@ -2267,9 +2188,9 @@ static void ZapEndOfFixedArray(Address new_end, int to_trim) { template<RightTrimMode trim_mode> static void RightTrimFixedArray(Heap* heap, FixedArray* elms, int to_trim) { - ASSERT(elms->map() != HEAP->fixed_cow_array_map()); + ASSERT(elms->map() != heap->fixed_cow_array_map()); // For now this trick is only applied to fixed arrays in new and paged space. - ASSERT(!HEAP->lo_space()->Contains(elms)); + ASSERT(!heap->lo_space()->Contains(elms)); const int len = elms->length(); @@ -2382,6 +2303,10 @@ MaybeObject* JSObject::MigrateToMap(Map* new_map) { PropertyDetails details = new_descriptors->GetDetails(i); if (details.type() != FIELD) continue; PropertyDetails old_details = old_descriptors->GetDetails(i); + if (old_details.type() == CALLBACKS) { + ASSERT(details.representation().IsTagged()); + continue; + } ASSERT(old_details.type() == CONSTANT || old_details.type() == FIELD); Object* value = old_details.type() == CONSTANT @@ -2438,10 +2363,11 @@ MaybeObject* JSObject::MigrateToMap(Map* new_map) { MaybeObject* JSObject::GeneralizeFieldRepresentation( int modify_index, - Representation new_representation) { + Representation new_representation, + StoreMode store_mode) { Map* new_map; - MaybeObject* maybe_new_map = - map()->GeneralizeRepresentation(modify_index, new_representation); + MaybeObject* maybe_new_map = map()->GeneralizeRepresentation( + modify_index, new_representation, store_mode); if (!maybe_new_map->To(&new_map)) return maybe_new_map; if (map() == new_map) return this; @@ -2459,16 +2385,40 @@ int Map::NumberOfFields() { } -MaybeObject* Map::CopyGeneralizeAllRepresentations() { +MaybeObject* Map::CopyGeneralizeAllRepresentations( + int modify_index, + StoreMode store_mode, + PropertyAttributes attributes, + const char* reason) { Map* new_map; MaybeObject* maybe_map = this->Copy(); if (!maybe_map->To(&new_map)) return maybe_map; - new_map->instance_descriptors()->InitializeRepresentations( - Representation::Tagged()); + DescriptorArray* descriptors = new_map->instance_descriptors(); + descriptors->InitializeRepresentations(Representation::Tagged()); + + // Unless the instance is being migrated, ensure that modify_index is a field. + PropertyDetails details = descriptors->GetDetails(modify_index); + if (store_mode == FORCE_FIELD && details.type() != FIELD) { + FieldDescriptor d(descriptors->GetKey(modify_index), + new_map->NumberOfFields(), + attributes, + Representation::Tagged()); + d.SetSortedKeyIndex(details.pointer()); + descriptors->Set(modify_index, &d); + int unused_property_fields = new_map->unused_property_fields() - 1; + if (unused_property_fields < 0) { + unused_property_fields += JSObject::kFieldsAdded; + } + new_map->set_unused_property_fields(unused_property_fields); + } + if (FLAG_trace_generalization) { - PrintF("failed generalization %p -> %p\n", - static_cast<void*>(this), static_cast<void*>(new_map)); + PrintGeneralization(stdout, reason, modify_index, + new_map->NumberOfOwnDescriptors(), + new_map->NumberOfOwnDescriptors(), + details.type() == CONSTANT && store_mode == FORCE_FIELD, + Representation::Tagged(), Representation::Tagged()); } return new_map; } @@ -2613,11 +2563,12 @@ Map* Map::FindLastMatchMap(int verbatim, // - Otherwise, invalidate the outdated transition target from |updated|, and // replace its transition tree with a new branch for the updated descriptors. MaybeObject* Map::GeneralizeRepresentation(int modify_index, - Representation new_representation) { + Representation new_representation, + StoreMode store_mode) { Map* old_map = this; DescriptorArray* old_descriptors = old_map->instance_descriptors(); - Representation old_representation = - old_descriptors->GetDetails(modify_index).representation(); + PropertyDetails old_details = old_descriptors->GetDetails(modify_index); + Representation old_representation = old_details.representation(); // It's fine to transition from None to anything but double without any // modification to the object, because the default uninitialized value for @@ -2626,12 +2577,6 @@ MaybeObject* Map::GeneralizeRepresentation(int modify_index, if (old_representation.IsNone() && !new_representation.IsNone() && !new_representation.IsDouble()) { - if (FLAG_trace_generalization) { - PrintF("initializing representation %i: %p -> %s\n", - modify_index, - static_cast<void*>(this), - new_representation.Mnemonic()); - } old_descriptors->SetRepresentation(modify_index, new_representation); return old_map; } @@ -2641,40 +2586,46 @@ MaybeObject* Map::GeneralizeRepresentation(int modify_index, // Check the state of the root map. if (!old_map->EquivalentToForTransition(root_map)) { - return CopyGeneralizeAllRepresentations(); + return CopyGeneralizeAllRepresentations( + modify_index, store_mode, old_details.attributes(), "not equivalent"); } int verbatim = root_map->NumberOfOwnDescriptors(); + if (store_mode != ALLOW_AS_CONSTANT && modify_index < verbatim) { + return CopyGeneralizeAllRepresentations( + modify_index, store_mode, + old_details.attributes(), "root modification"); + } + Map* updated = root_map->FindUpdatedMap( verbatim, descriptors, old_descriptors); - if (updated == NULL) return CopyGeneralizeAllRepresentations(); + if (updated == NULL) { + return CopyGeneralizeAllRepresentations( + modify_index, store_mode, old_details.attributes(), "incompatible"); + } DescriptorArray* updated_descriptors = updated->instance_descriptors(); int valid = updated->NumberOfOwnDescriptors(); + + // Directly change the map if the target map is more general. Ensure that the + // target type of the modify_index is a FIELD, unless we are migrating. if (updated_descriptors->IsMoreGeneralThan( - verbatim, valid, descriptors, old_descriptors)) { + verbatim, valid, descriptors, old_descriptors) && + (store_mode == ALLOW_AS_CONSTANT || + updated_descriptors->GetDetails(modify_index).type() == FIELD)) { Representation updated_representation = updated_descriptors->GetDetails(modify_index).representation(); - if (new_representation.fits_into(updated_representation)) { - if (FLAG_trace_generalization && - !(modify_index == 0 && new_representation.IsNone())) { - PropertyDetails old_details = old_descriptors->GetDetails(modify_index); - PrintF("migrating to existing map %p(%s) -> %p(%s)\n", - static_cast<void*>(this), - old_details.representation().Mnemonic(), - static_cast<void*>(updated), - updated_representation.Mnemonic()); - } - return updated; - } + if (new_representation.fits_into(updated_representation)) return updated; } DescriptorArray* new_descriptors; MaybeObject* maybe_descriptors = updated_descriptors->Merge( - verbatim, valid, descriptors, old_descriptors); + verbatim, valid, descriptors, modify_index, store_mode, old_descriptors); if (!maybe_descriptors->To(&new_descriptors)) return maybe_descriptors; + ASSERT(store_mode == ALLOW_AS_CONSTANT || + new_descriptors->GetDetails(modify_index).type() == FIELD); old_representation = new_descriptors->GetDetails(modify_index).representation(); @@ -2696,15 +2647,12 @@ MaybeObject* Map::GeneralizeRepresentation(int modify_index, split_map->DeprecateTarget( old_descriptors->GetKey(descriptor), new_descriptors); - if (FLAG_trace_generalization && - !(modify_index == 0 && new_representation.IsNone())) { - PrintF("migrating to new map %i: %p(%s) -> %p(%s) (%i steps)\n", - modify_index, - static_cast<void*>(this), - old_representation.Mnemonic(), - static_cast<void*>(new_descriptors), - updated_representation.Mnemonic(), - descriptors - descriptor); + if (FLAG_trace_generalization) { + PrintGeneralization( + stdout, "", modify_index, descriptor, descriptors, + old_descriptors->GetDetails(modify_index).type() == CONSTANT && + store_mode == FORCE_FIELD, + old_representation, updated_representation); } Map* new_map = split_map; @@ -2771,8 +2719,8 @@ MaybeObject* JSObject::SetPropertyWithInterceptor( if (!interceptor->setter()->IsUndefined()) { LOG(isolate, ApiNamedPropertyAccess("interceptor-named-set", this, name)); PropertyCallbackArguments args(isolate, interceptor->data(), this, this); - v8::NamedPropertySetter setter = - v8::ToCData<v8::NamedPropertySetter>(interceptor->setter()); + v8::NamedPropertySetterCallback setter = + v8::ToCData<v8::NamedPropertySetterCallback>(interceptor->setter()); Handle<Object> value_unhole(value->IsTheHole() ? isolate->heap()->undefined_value() : value, @@ -2787,8 +2735,7 @@ MaybeObject* JSObject::SetPropertyWithInterceptor( this_handle->SetPropertyPostInterceptor(*name_handle, *value_handle, attributes, - strict_mode, - PERFORM_EXTENSIBILITY_CHECK); + strict_mode); RETURN_IF_SCHEDULED_EXCEPTION(isolate); return raw_result; } @@ -2852,7 +2799,8 @@ MaybeObject* JSObject::SetPropertyWithCallback(Object* structure, AccessorDescriptor* callback = reinterpret_cast<AccessorDescriptor*>( Foreign::cast(structure)->foreign_address()); - MaybeObject* obj = (callback->setter)(this, value, callback->data); + MaybeObject* obj = (callback->setter)( + isolate, this, value, callback->data); RETURN_IF_SCHEDULED_EXCEPTION(isolate); if (obj->IsFailure()) return obj; return *value_handle; @@ -2874,7 +2822,8 @@ MaybeObject* JSObject::SetPropertyWithCallback(Object* structure, // TODO(rossberg): Support symbols in the API. if (name->IsSymbol()) return value; Object* call_obj = data->setter(); - v8::AccessorSetter call_fun = v8::ToCData<v8::AccessorSetter>(call_obj); + v8::AccessorSetterCallback call_fun = + v8::ToCData<v8::AccessorSetterCallback>(call_obj); if (call_fun == NULL) return value; Handle<String> key(String::cast(name)); LOG(isolate, ApiNamedPropertyAccess("store", this, name)); @@ -2932,7 +2881,8 @@ MaybeObject* JSReceiver::SetPropertyWithDefinedSetter(JSReceiver* setter, #endif bool has_pending_exception; Handle<Object> argv[] = { value_handle }; - Execution::Call(fun, self, ARRAY_SIZE(argv), argv, &has_pending_exception); + Execution::Call( + isolate, fun, self, ARRAY_SIZE(argv), argv, &has_pending_exception); // Check for pending exception and return the result. if (has_pending_exception) return Failure::Exception(); return *value_handle; @@ -3056,48 +3006,101 @@ void Map::EnsureDescriptorSlack(Handle<Map> map, int slack) { } -void Map::AppendCallbackDescriptors(Handle<Map> map, - Handle<Object> descriptors) { - Isolate* isolate = map->GetIsolate(); - Handle<DescriptorArray> array(map->instance_descriptors()); - NeanderArray callbacks(descriptors); - int nof_callbacks = callbacks.length(); - - ASSERT(array->NumberOfSlackDescriptors() >= nof_callbacks); +template<class T> +static int AppendUniqueCallbacks(NeanderArray* callbacks, + Handle<typename T::Array> array, + int valid_descriptors) { + int nof_callbacks = callbacks->length(); + Isolate* isolate = array->GetIsolate(); // Ensure the keys are unique names before writing them into the // instance descriptor. Since it may cause a GC, it has to be done before we // temporarily put the heap in an invalid state while appending descriptors. for (int i = 0; i < nof_callbacks; ++i) { - Handle<AccessorInfo> entry(AccessorInfo::cast(callbacks.get(i))); - if (!entry->name()->IsUniqueName()) { - Handle<String> key = - isolate->factory()->InternalizedStringFromString( - Handle<String>(String::cast(entry->name()))); - entry->set_name(*key); - } + Handle<AccessorInfo> entry(AccessorInfo::cast(callbacks->get(i))); + if (entry->name()->IsUniqueName()) continue; + Handle<String> key = + isolate->factory()->InternalizedStringFromString( + Handle<String>(String::cast(entry->name()))); + entry->set_name(*key); } - int nof = map->NumberOfOwnDescriptors(); - // Fill in new callback descriptors. Process the callbacks from // back to front so that the last callback with a given name takes // precedence over previously added callbacks with that name. for (int i = nof_callbacks - 1; i >= 0; i--) { - AccessorInfo* entry = AccessorInfo::cast(callbacks.get(i)); + AccessorInfo* entry = AccessorInfo::cast(callbacks->get(i)); Name* key = Name::cast(entry->name()); // Check if a descriptor with this name already exists before writing. - if (array->Search(key, nof) == DescriptorArray::kNotFound) { - CallbacksDescriptor desc(key, entry, entry->property_attributes()); - array->Append(&desc); - nof += 1; + if (!T::Contains(key, entry, valid_descriptors, array)) { + T::Insert(key, entry, valid_descriptors, array); + valid_descriptors++; } } + return valid_descriptors; +} + +struct DescriptorArrayAppender { + typedef DescriptorArray Array; + static bool Contains(Name* key, + AccessorInfo* entry, + int valid_descriptors, + Handle<DescriptorArray> array) { + return array->Search(key, valid_descriptors) != DescriptorArray::kNotFound; + } + static void Insert(Name* key, + AccessorInfo* entry, + int valid_descriptors, + Handle<DescriptorArray> array) { + CallbacksDescriptor desc(key, entry, entry->property_attributes()); + array->Append(&desc); + } +}; + + +struct FixedArrayAppender { + typedef FixedArray Array; + static bool Contains(Name* key, + AccessorInfo* entry, + int valid_descriptors, + Handle<FixedArray> array) { + for (int i = 0; i < valid_descriptors; i++) { + if (key == AccessorInfo::cast(array->get(i))->name()) return true; + } + return false; + } + static void Insert(Name* key, + AccessorInfo* entry, + int valid_descriptors, + Handle<FixedArray> array) { + array->set(valid_descriptors, entry); + } +}; + + +void Map::AppendCallbackDescriptors(Handle<Map> map, + Handle<Object> descriptors) { + int nof = map->NumberOfOwnDescriptors(); + Handle<DescriptorArray> array(map->instance_descriptors()); + NeanderArray callbacks(descriptors); + ASSERT(array->NumberOfSlackDescriptors() >= callbacks.length()); + nof = AppendUniqueCallbacks<DescriptorArrayAppender>(&callbacks, array, nof); map->SetNumberOfOwnDescriptors(nof); } +int AccessorInfo::AppendUnique(Handle<Object> descriptors, + Handle<FixedArray> array, + int valid_descriptors) { + NeanderArray callbacks(descriptors); + ASSERT(array->length() >= callbacks.length() + valid_descriptors); + return AppendUniqueCallbacks<FixedArrayAppender>(&callbacks, + array, + valid_descriptors); +} + + static bool ContainsMap(MapHandleList* maps, Handle<Map> map) { ASSERT(!map.is_null()); for (int i = 0; i < maps->length(); ++i) { @@ -3361,6 +3364,15 @@ MaybeObject* JSObject::SetPropertyWithFailedAccessCheck( result->holder(), strict_mode); } + } else if (obj->IsAccessorPair()) { + AccessorPair* pair = AccessorPair::cast(obj); + if (pair->all_can_read()) { + return SetPropertyWithCallback(result->GetCallbackObject(), + name, + value, + result->holder(), + strict_mode); + } } break; } @@ -3485,9 +3497,9 @@ MUST_USE_RESULT MaybeObject* JSProxy::SetPropertyViaPrototypesWithHandler( // Emulate [[GetProperty]] semantics for proxies. bool has_pending_exception; Handle<Object> argv[] = { result }; - Handle<Object> desc = - Execution::Call(isolate->to_complete_property_descriptor(), result, - ARRAY_SIZE(argv), argv, &has_pending_exception); + Handle<Object> desc = Execution::Call( + isolate, isolate->to_complete_property_descriptor(), result, + ARRAY_SIZE(argv), argv, &has_pending_exception); if (has_pending_exception) return Failure::Exception(); // [[GetProperty]] requires to check that all properties are configurable. @@ -3554,20 +3566,20 @@ MUST_USE_RESULT MaybeObject* JSProxy::SetPropertyViaPrototypesWithHandler( Handle<Object> JSProxy::DeletePropertyWithHandler( - Handle<JSProxy> object, Handle<Name> name, DeleteMode mode) { - Isolate* isolate = object->GetIsolate(); + Handle<JSProxy> proxy, Handle<Name> name, DeleteMode mode) { + Isolate* isolate = proxy->GetIsolate(); // TODO(rossberg): adjust once there is a story for symbols vs proxies. if (name->IsSymbol()) return isolate->factory()->false_value(); Handle<Object> args[] = { name }; - Handle<Object> result = object->CallTrap( + Handle<Object> result = proxy->CallTrap( "delete", Handle<Object>(), ARRAY_SIZE(args), args); if (isolate->has_pending_exception()) return Handle<Object>(); bool result_bool = result->BooleanValue(); if (mode == STRICT_DELETION && !result_bool) { - Handle<Object> handler(object->handler(), isolate); + Handle<Object> handler(proxy->handler(), isolate); Handle<String> trap_name = isolate->factory()->InternalizeOneByteString( STATIC_ASCII_VECTOR("delete")); Handle<Object> args[] = { handler, trap_name }; @@ -3581,10 +3593,10 @@ Handle<Object> JSProxy::DeletePropertyWithHandler( Handle<Object> JSProxy::DeleteElementWithHandler( - Handle<JSProxy> object, uint32_t index, DeleteMode mode) { - Isolate* isolate = object->GetIsolate(); + Handle<JSProxy> proxy, uint32_t index, DeleteMode mode) { + Isolate* isolate = proxy->GetIsolate(); Handle<String> name = isolate->factory()->Uint32ToString(index); - return JSProxy::DeletePropertyWithHandler(object, name, mode); + return JSProxy::DeletePropertyWithHandler(proxy, name, mode); } @@ -3610,9 +3622,9 @@ MUST_USE_RESULT PropertyAttributes JSProxy::GetPropertyAttributeWithHandler( bool has_pending_exception; Handle<Object> argv[] = { result }; - Handle<Object> desc = - Execution::Call(isolate->to_complete_property_descriptor(), result, - ARRAY_SIZE(argv), argv, &has_pending_exception); + Handle<Object> desc = Execution::Call( + isolate, isolate->to_complete_property_descriptor(), result, + ARRAY_SIZE(argv), argv, &has_pending_exception); if (has_pending_exception) return NONE; // Convert result to PropertyAttributes. @@ -3666,27 +3678,23 @@ MUST_USE_RESULT PropertyAttributes JSProxy::GetElementAttributeWithHandler( } -void JSProxy::Fix() { - Isolate* isolate = GetIsolate(); - HandleScope scope(isolate); - Handle<JSProxy> self(this); +void JSProxy::Fix(Handle<JSProxy> proxy) { + Isolate* isolate = proxy->GetIsolate(); // Save identity hash. - MaybeObject* maybe_hash = GetIdentityHash(OMIT_CREATION); + Handle<Object> hash = JSProxy::GetIdentityHash(proxy, OMIT_CREATION); - if (IsJSFunctionProxy()) { - isolate->factory()->BecomeJSFunction(self); + if (proxy->IsJSFunctionProxy()) { + isolate->factory()->BecomeJSFunction(proxy); // Code will be set on the JavaScript side. } else { - isolate->factory()->BecomeJSObject(self); + isolate->factory()->BecomeJSObject(proxy); } - ASSERT(self->IsJSObject()); + ASSERT(proxy->IsJSObject()); // Inherit identity, if it was present. - Object* hash; - if (maybe_hash->To<Object>(&hash) && hash->IsSmi()) { - Handle<JSObject> new_self(JSObject::cast(*self)); - isolate->factory()->SetIdentityHash(new_self, Smi::cast(hash)); + if (hash->IsSmi()) { + JSObject::SetIdentityHash(Handle<JSObject>::cast(proxy), Smi::cast(*hash)); } } @@ -3714,7 +3722,7 @@ MUST_USE_RESULT Handle<Object> JSProxy::CallTrap(const char* name, } bool threw; - return Execution::Call(trap, handler, argc, argv, &threw); + return Execution::Call(isolate, trap, handler, argc, argv, &threw); } @@ -3726,11 +3734,6 @@ void JSObject::AllocateStorageForMap(Handle<JSObject> object, Handle<Map> map) { void JSObject::MigrateInstance(Handle<JSObject> object) { - if (FLAG_trace_migration) { - PrintF("migrating instance %p (%p)\n", - static_cast<void*>(*object), - static_cast<void*>(object->map())); - } CALL_HEAP_FUNCTION_VOID( object->GetIsolate(), object->MigrateInstance()); @@ -3738,11 +3741,6 @@ void JSObject::MigrateInstance(Handle<JSObject> object) { Handle<Object> JSObject::TryMigrateInstance(Handle<JSObject> object) { - if (FLAG_trace_migration) { - PrintF("migrating instance (no new maps) %p (%p)\n", - static_cast<void*>(*object), - static_cast<void*>(object->map())); - } CALL_HEAP_FUNCTION( object->GetIsolate(), object->MigrateInstance(), @@ -3752,14 +3750,148 @@ Handle<Object> JSObject::TryMigrateInstance(Handle<JSObject> object) { Handle<Map> Map::GeneralizeRepresentation(Handle<Map> map, int modify_index, - Representation representation) { + Representation representation, + StoreMode store_mode) { CALL_HEAP_FUNCTION( map->GetIsolate(), - map->GeneralizeRepresentation(modify_index, representation), + map->GeneralizeRepresentation(modify_index, representation, store_mode), Map); } +static MaybeObject* SetPropertyUsingTransition(LookupResult* lookup, + Handle<Name> name, + Handle<Object> value, + PropertyAttributes attributes) { + Map* transition_map = lookup->GetTransitionTarget(); + int descriptor = transition_map->LastAdded(); + + DescriptorArray* descriptors = transition_map->instance_descriptors(); + PropertyDetails details = descriptors->GetDetails(descriptor); + + if (details.type() == CALLBACKS || attributes != details.attributes()) { + // AddProperty will either normalize the object, or create a new fast copy + // of the map. If we get a fast copy of the map, all field representations + // will be tagged since the transition is omitted. + return lookup->holder()->AddProperty( + *name, *value, attributes, kNonStrictMode, + JSReceiver::CERTAINLY_NOT_STORE_FROM_KEYED, + JSReceiver::OMIT_EXTENSIBILITY_CHECK, + JSObject::FORCE_TAGGED, FORCE_FIELD, OMIT_TRANSITION); + } + + // Keep the target CONSTANT if the same value is stored. + // TODO(verwaest): Also support keeping the placeholder + // (value->IsUninitialized) as constant. + if (details.type() == CONSTANT && + descriptors->GetValue(descriptor) == *value) { + lookup->holder()->set_map(transition_map); + return *value; + } + + Representation representation = details.representation(); + + if (!value->FitsRepresentation(representation) || + details.type() == CONSTANT) { + MaybeObject* maybe_map = transition_map->GeneralizeRepresentation( + descriptor, value->OptimalRepresentation(), FORCE_FIELD); + if (!maybe_map->To(&transition_map)) return maybe_map; + Object* back = transition_map->GetBackPointer(); + if (back->IsMap()) { + MaybeObject* maybe_failure = + lookup->holder()->MigrateToMap(Map::cast(back)); + if (maybe_failure->IsFailure()) return maybe_failure; + } + descriptors = transition_map->instance_descriptors(); + representation = descriptors->GetDetails(descriptor).representation(); + } + + int field_index = descriptors->GetFieldIndex(descriptor); + return lookup->holder()->AddFastPropertyUsingMap( + transition_map, *name, *value, field_index, representation); +} + + +static MaybeObject* SetPropertyToField(LookupResult* lookup, + Handle<Name> name, + Handle<Object> value) { + Representation representation = lookup->representation(); + if (!value->FitsRepresentation(representation) || + lookup->type() == CONSTANT) { + MaybeObject* maybe_failure = + lookup->holder()->GeneralizeFieldRepresentation( + lookup->GetDescriptorIndex(), + value->OptimalRepresentation(), + FORCE_FIELD); + if (maybe_failure->IsFailure()) return maybe_failure; + DescriptorArray* desc = lookup->holder()->map()->instance_descriptors(); + int descriptor = lookup->GetDescriptorIndex(); + representation = desc->GetDetails(descriptor).representation(); + } + + if (FLAG_track_double_fields && representation.IsDouble()) { + HeapNumber* storage = HeapNumber::cast(lookup->holder()->RawFastPropertyAt( + lookup->GetFieldIndex().field_index())); + storage->set_value(value->Number()); + return *value; + } + + lookup->holder()->FastPropertyAtPut( + lookup->GetFieldIndex().field_index(), *value); + return *value; +} + + +static MaybeObject* ConvertAndSetLocalProperty(LookupResult* lookup, + Name* name, + Object* value, + PropertyAttributes attributes) { + JSObject* object = lookup->holder(); + if (object->TooManyFastProperties()) { + MaybeObject* maybe_failure = object->NormalizeProperties( + CLEAR_INOBJECT_PROPERTIES, 0); + if (maybe_failure->IsFailure()) return maybe_failure; + } + + if (!object->HasFastProperties()) { + return object->ReplaceSlowProperty(name, value, attributes); + } + + int descriptor_index = lookup->GetDescriptorIndex(); + if (lookup->GetAttributes() == attributes) { + MaybeObject* maybe_failure = object->GeneralizeFieldRepresentation( + descriptor_index, Representation::Tagged(), FORCE_FIELD); + if (maybe_failure->IsFailure()) return maybe_failure; + } else { + Map* map; + MaybeObject* maybe_map = object->map()->CopyGeneralizeAllRepresentations( + descriptor_index, FORCE_FIELD, attributes, "attributes mismatch"); + if (!maybe_map->To(&map)) return maybe_map; + MaybeObject* maybe_failure = object->MigrateToMap(map); + if (maybe_failure->IsFailure()) return maybe_failure; + } + + DescriptorArray* descriptors = object->map()->instance_descriptors(); + int index = descriptors->GetDetails(descriptor_index).field_index(); + object->FastPropertyAtPut(index, value); + return value; +} + + +static MaybeObject* SetPropertyToFieldWithAttributes( + LookupResult* lookup, + Handle<Name> name, + Handle<Object> value, + PropertyAttributes attributes) { + if (lookup->GetAttributes() == attributes) { + if (value->IsUninitialized()) return *value; + return SetPropertyToField(lookup, name, value); + } else { + return ConvertAndSetLocalProperty(lookup, *name, *value, attributes); + } +} + + MaybeObject* JSObject::SetPropertyForResult(LookupResult* lookup, Name* name_raw, Object* value_raw, @@ -3768,9 +3900,10 @@ MaybeObject* JSObject::SetPropertyForResult(LookupResult* lookup, StoreFromKeyed store_mode) { Heap* heap = GetHeap(); Isolate* isolate = heap->isolate(); + // Make sure that the top context does not change when doing callbacks or // interceptor calls. - AssertNoContextChange ncc; + AssertNoContextChangeWithHandleScope ncc; // Optimization for 2-byte strings often used as keys in a decompression // dictionary. We internalize these short keys to avoid constantly @@ -3848,37 +3981,13 @@ MaybeObject* JSObject::SetPropertyForResult(LookupResult* lookup, case NORMAL: result = lookup->holder()->SetNormalizedProperty(lookup, *value); break; - case FIELD: { - Representation representation = lookup->representation(); - if (!value->FitsRepresentation(representation)) { - MaybeObject* maybe_failure = - lookup->holder()->GeneralizeFieldRepresentation( - lookup->GetDescriptorIndex(), value->OptimalRepresentation()); - if (maybe_failure->IsFailure()) return maybe_failure; - DescriptorArray* desc = lookup->holder()->map()->instance_descriptors(); - int descriptor = lookup->GetDescriptorIndex(); - representation = desc->GetDetails(descriptor).representation(); - } - if (FLAG_track_double_fields && representation.IsDouble()) { - HeapNumber* storage = - HeapNumber::cast(lookup->holder()->RawFastPropertyAt( - lookup->GetFieldIndex().field_index())); - storage->set_value(value->Number()); - result = *value; - break; - } - lookup->holder()->FastPropertyAtPut( - lookup->GetFieldIndex().field_index(), *value); - result = *value; + case FIELD: + result = SetPropertyToField(lookup, name, value); break; - } case CONSTANT: // Only replace the constant if necessary. if (*value == lookup->GetConstant()) return *value; - // Preserve the attributes of this existing property. - attributes = lookup->GetAttributes(); - result = lookup->holder()->ConvertDescriptorToField( - *name, *value, attributes); + result = SetPropertyToField(lookup, name, value); break; case CALLBACKS: { Object* callback_object = lookup->GetCallbackObject(); @@ -3890,55 +3999,7 @@ MaybeObject* JSObject::SetPropertyForResult(LookupResult* lookup, *name, *value, attributes, strict_mode); break; case TRANSITION: { - Map* transition_map = lookup->GetTransitionTarget(); - int descriptor = transition_map->LastAdded(); - - DescriptorArray* descriptors = transition_map->instance_descriptors(); - PropertyDetails details = descriptors->GetDetails(descriptor); - - if (details.type() == FIELD) { - if (attributes == details.attributes()) { - Representation representation = details.representation(); - if (!value->FitsRepresentation(representation)) { - MaybeObject* maybe_map = transition_map->GeneralizeRepresentation( - descriptor, value->OptimalRepresentation()); - if (!maybe_map->To(&transition_map)) return maybe_map; - Object* back = transition_map->GetBackPointer(); - if (back->IsMap()) { - MaybeObject* maybe_failure = - lookup->holder()->MigrateToMap(Map::cast(back)); - if (maybe_failure->IsFailure()) return maybe_failure; - } - descriptors = transition_map->instance_descriptors(); - representation = - descriptors->GetDetails(descriptor).representation(); - } - int field_index = descriptors->GetFieldIndex(descriptor); - result = lookup->holder()->AddFastPropertyUsingMap( - transition_map, *name, *value, field_index, representation); - } else { - result = lookup->holder()->ConvertDescriptorToField( - *name, *value, attributes); - } - } else if (details.type() == CALLBACKS) { - result = lookup->holder()->ConvertDescriptorToField( - *name, *value, attributes); - } else { - ASSERT(details.type() == CONSTANT); - - Object* constant = descriptors->GetValue(descriptor); - if (constant == *value) { - // If the same constant function is being added we can simply - // transition to the target map. - lookup->holder()->set_map(transition_map); - result = constant; - } else { - // Otherwise, replace with a map transition to a new map with a FIELD, - // even if the value is a constant function. - result = lookup->holder()->ConvertTransitionToMapTransition( - lookup->GetTransitionIndex(), *name, *value, attributes); - } - } + result = SetPropertyUsingTransition(lookup, name, value, attributes); break; } case HANDLER: @@ -3968,6 +4029,29 @@ MaybeObject* JSObject::SetPropertyForResult(LookupResult* lookup, } +MaybeObject* JSObject::SetLocalPropertyIgnoreAttributesTrampoline( + Name* key, + Object* value, + PropertyAttributes attributes, + ValueType value_type, + StoreMode mode, + ExtensibilityCheck extensibility_check) { + // TODO(mstarzinger): The trampoline is a giant hack, don't use it anywhere + // else or handlification people will start hating you for all eternity. + HandleScope scope(GetIsolate()); + IdempotentPointerToHandleCodeTrampoline trampoline(GetIsolate()); + return trampoline.CallWithReturnValue( + &JSObject::SetLocalPropertyIgnoreAttributes, + Handle<JSObject>(this), + Handle<Name>(key), + Handle<Object>(value, GetIsolate()), + attributes, + value_type, + mode, + extensibility_check); +} + + // Set a real local property, even if it is READ_ONLY. If the property is not // present, add it with attributes NONE. This code is an exact clone of // SetProperty, with the check for IsReadOnly and the check for a @@ -3983,11 +4067,12 @@ Handle<Object> JSObject::SetLocalPropertyIgnoreAttributes( Handle<Object> value, PropertyAttributes attributes, ValueType value_type, - StoreMode mode) { + StoreMode mode, + ExtensibilityCheck extensibility_check) { CALL_HEAP_FUNCTION( object->GetIsolate(), object->SetLocalPropertyIgnoreAttributes( - *key, *value, attributes, value_type, mode), + *key, *value, attributes, value_type, mode, extensibility_check), Object); } @@ -3997,10 +4082,11 @@ MaybeObject* JSObject::SetLocalPropertyIgnoreAttributes( Object* value_raw, PropertyAttributes attributes, ValueType value_type, - StoreMode mode) { + StoreMode mode, + ExtensibilityCheck extensibility_check) { // Make sure that the top context does not change when doing callbacks or // interceptor calls. - AssertNoContextChange ncc; + AssertNoContextChangeWithHandleScope ncc; Isolate* isolate = GetIsolate(); LookupResult lookup(isolate); LocalLookup(name_raw, &lookup, true); @@ -4025,7 +4111,13 @@ MaybeObject* JSObject::SetLocalPropertyIgnoreAttributes( value_raw, attributes, value_type, - mode); + mode, + extensibility_check); + } + + if (lookup.IsFound() && + (lookup.type() == INTERCEPTOR || lookup.type() == CALLBACKS)) { + LocalLookupRealNamedProperty(name_raw, &lookup); } // Check for accessor in prototype chain removed here in clone. @@ -4033,7 +4125,7 @@ MaybeObject* JSObject::SetLocalPropertyIgnoreAttributes( // Neither properties nor transitions found. return AddProperty( name_raw, value_raw, attributes, kNonStrictMode, - MAY_BE_STORE_FROM_KEYED, PERFORM_EXTENSIBILITY_CHECK, value_type, mode); + MAY_BE_STORE_FROM_KEYED, extensibility_check, value_type, mode); } // From this point on everything needs to be handlified. @@ -4046,101 +4138,38 @@ MaybeObject* JSObject::SetLocalPropertyIgnoreAttributes( PropertyAttributes old_attributes = ABSENT; bool is_observed = FLAG_harmony_observation && self->map()->is_observed(); if (is_observed && lookup.IsProperty()) { - if (lookup.IsDataProperty()) old_value = Object::GetProperty(self, name); + if (lookup.IsDataProperty()) old_value = + Object::GetProperty(self, name); old_attributes = lookup.GetAttributes(); } // Check of IsReadOnly removed from here in clone. MaybeObject* result = *value; switch (lookup.type()) { - case NORMAL: { - PropertyDetails details = PropertyDetails(attributes, NORMAL, 0); - result = self->SetNormalizedProperty(*name, *value, details); + case NORMAL: + result = self->ReplaceSlowProperty(*name, *value, attributes); break; - } - case FIELD: { - Representation representation = lookup.representation(); - Representation value_representation = - value->OptimalRepresentation(value_type); - if (value_representation.IsNone()) break; - if (!value_representation.fits_into(representation)) { - MaybeObject* maybe_failure = self->GeneralizeFieldRepresentation( - lookup.GetDescriptorIndex(), value_representation); - if (maybe_failure->IsFailure()) return maybe_failure; - DescriptorArray* desc = self->map()->instance_descriptors(); - int descriptor = lookup.GetDescriptorIndex(); - representation = desc->GetDetails(descriptor).representation(); - } - if (FLAG_track_double_fields && representation.IsDouble()) { - HeapNumber* storage = - HeapNumber::cast(self->RawFastPropertyAt( - lookup.GetFieldIndex().field_index())); - storage->set_value(value->Number()); - result = *value; - break; - } - self->FastPropertyAtPut(lookup.GetFieldIndex().field_index(), *value); - result = *value; + case FIELD: + result = SetPropertyToFieldWithAttributes( + &lookup, name, value, attributes); break; - } case CONSTANT: - // Only replace the function if necessary. - if (*value != lookup.GetConstant()) { - // Preserve the attributes of this existing property. - attributes = lookup.GetAttributes(); - result = self->ConvertDescriptorToField(*name, *value, attributes); + // Only replace the constant if necessary. + if (lookup.GetAttributes() != attributes || + *value != lookup.GetConstant()) { + result = SetPropertyToFieldWithAttributes( + &lookup, name, value, attributes); } break; case CALLBACKS: - case INTERCEPTOR: - // Override callback in clone - result = self->ConvertDescriptorToField(*name, *value, attributes); + result = ConvertAndSetLocalProperty(&lookup, *name, *value, attributes); break; - case TRANSITION: { - Map* transition_map = lookup.GetTransitionTarget(); - int descriptor = transition_map->LastAdded(); - - DescriptorArray* descriptors = transition_map->instance_descriptors(); - PropertyDetails details = descriptors->GetDetails(descriptor); - - if (details.type() == FIELD) { - if (attributes == details.attributes()) { - Representation representation = details.representation(); - Representation value_representation = - value->OptimalRepresentation(value_type); - if (!value_representation.fits_into(representation)) { - MaybeObject* maybe_map = transition_map->GeneralizeRepresentation( - descriptor, value_representation); - if (!maybe_map->To(&transition_map)) return maybe_map; - Object* back = transition_map->GetBackPointer(); - if (back->IsMap()) { - MaybeObject* maybe_failure = self->MigrateToMap(Map::cast(back)); - if (maybe_failure->IsFailure()) return maybe_failure; - } - descriptors = transition_map->instance_descriptors(); - representation = - descriptors->GetDetails(descriptor).representation(); - } - int field_index = descriptors->GetFieldIndex(descriptor); - result = self->AddFastPropertyUsingMap( - transition_map, *name, *value, field_index, representation); - } else { - result = self->ConvertDescriptorToField(*name, *value, attributes); - } - } else if (details.type() == CALLBACKS) { - result = self->ConvertDescriptorToField(*name, *value, attributes); - } else { - ASSERT(details.type() == CONSTANT); - - // Replace transition to CONSTANT FUNCTION with a map transition to a - // new map with a FIELD, even if the value is a function. - result = self->ConvertTransitionToMapTransition( - lookup.GetTransitionIndex(), *name, *value, attributes); - } + case TRANSITION: + result = SetPropertyUsingTransition(&lookup, name, value, attributes); break; - } - case HANDLER: case NONEXISTENT: + case HANDLER: + case INTERCEPTOR: UNREACHABLE(); } @@ -4202,20 +4231,20 @@ PropertyAttributes JSObject::GetPropertyAttributeWithInterceptor( if (name->IsSymbol()) return ABSENT; Isolate* isolate = GetIsolate(); + HandleScope scope(isolate); // Make sure that the top context does not change when doing // callbacks or interceptor calls. AssertNoContextChange ncc; - HandleScope scope(isolate); Handle<InterceptorInfo> interceptor(GetNamedInterceptor()); Handle<JSObject> receiver_handle(receiver); Handle<JSObject> holder_handle(this); Handle<String> name_handle(String::cast(name)); PropertyCallbackArguments args(isolate, interceptor->data(), receiver, this); if (!interceptor->query()->IsUndefined()) { - v8::NamedPropertyQuery query = - v8::ToCData<v8::NamedPropertyQuery>(interceptor->query()); + v8::NamedPropertyQueryCallback query = + v8::ToCData<v8::NamedPropertyQueryCallback>(interceptor->query()); LOG(isolate, ApiNamedPropertyAccess("interceptor-named-has", *holder_handle, name)); v8::Handle<v8::Integer> result = @@ -4225,8 +4254,8 @@ PropertyAttributes JSObject::GetPropertyAttributeWithInterceptor( return static_cast<PropertyAttributes>(result->Int32Value()); } } else if (!interceptor->getter()->IsUndefined()) { - v8::NamedPropertyGetter getter = - v8::ToCData<v8::NamedPropertyGetter>(interceptor->getter()); + v8::NamedPropertyGetterCallback getter = + v8::ToCData<v8::NamedPropertyGetterCallback>(interceptor->getter()); LOG(isolate, ApiNamedPropertyAccess("interceptor-named-get-has", this, name)); v8::Handle<v8::Value> result = @@ -4337,25 +4366,27 @@ PropertyAttributes JSObject::GetElementAttributeWithReceiver( PropertyAttributes JSObject::GetElementAttributeWithInterceptor( JSReceiver* receiver, uint32_t index, bool continue_search) { Isolate* isolate = GetIsolate(); + HandleScope scope(isolate); + // Make sure that the top context does not change when doing // callbacks or interceptor calls. AssertNoContextChange ncc; - HandleScope scope(isolate); + Handle<InterceptorInfo> interceptor(GetIndexedInterceptor()); Handle<JSReceiver> hreceiver(receiver); Handle<JSObject> holder(this); PropertyCallbackArguments args(isolate, interceptor->data(), receiver, this); if (!interceptor->query()->IsUndefined()) { - v8::IndexedPropertyQuery query = - v8::ToCData<v8::IndexedPropertyQuery>(interceptor->query()); + v8::IndexedPropertyQueryCallback query = + v8::ToCData<v8::IndexedPropertyQueryCallback>(interceptor->query()); LOG(isolate, ApiIndexedPropertyAccess("interceptor-indexed-has", this, index)); v8::Handle<v8::Integer> result = args.Call(query, index); if (!result.IsEmpty()) return static_cast<PropertyAttributes>(result->Int32Value()); } else if (!interceptor->getter()->IsUndefined()) { - v8::IndexedPropertyGetter getter = - v8::ToCData<v8::IndexedPropertyGetter>(interceptor->getter()); + v8::IndexedPropertyGetterCallback getter = + v8::ToCData<v8::IndexedPropertyGetterCallback>(interceptor->getter()); LOG(isolate, ApiIndexedPropertyAccess("interceptor-indexed-get-has", this, index)); v8::Handle<v8::Value> result = args.Call(getter, index); @@ -4448,30 +4479,21 @@ void NormalizedMapCache::Clear() { } -void JSObject::UpdateMapCodeCache(Handle<JSObject> object, - Handle<Name> name, - Handle<Code> code) { - Isolate* isolate = object->GetIsolate(); - CALL_HEAP_FUNCTION_VOID(isolate, - object->UpdateMapCodeCache(*name, *code)); -} - - -MaybeObject* JSObject::UpdateMapCodeCache(Name* name, Code* code) { - if (map()->is_shared()) { +void HeapObject::UpdateMapCodeCache(Handle<HeapObject> object, + Handle<Name> name, + Handle<Code> code) { + Handle<Map> map(object->map()); + if (map->is_shared()) { + Handle<JSObject> receiver = Handle<JSObject>::cast(object); // Fast case maps are never marked as shared. - ASSERT(!HasFastProperties()); + ASSERT(!receiver->HasFastProperties()); // Replace the map with an identical copy that can be safely modified. - Object* obj; - { MaybeObject* maybe_obj = map()->CopyNormalized(KEEP_INOBJECT_PROPERTIES, - UNIQUE_NORMALIZED_MAP); - if (!maybe_obj->ToObject(&obj)) return maybe_obj; - } - GetIsolate()->counters()->normalized_maps()->Increment(); - - set_map(Map::cast(obj)); + map = Map::CopyNormalized(map, KEEP_INOBJECT_PROPERTIES, + UNIQUE_NORMALIZED_MAP); + receiver->GetIsolate()->counters()->normalized_maps()->Increment(); + receiver->set_map(*map); } - return map()->UpdateCodeCache(name, code); + Map::UpdateCodeCache(map, name, code); } @@ -4722,7 +4744,7 @@ Smi* JSReceiver::GenerateIdentityHash() { do { // Generate a random 32-bit hash value but limit range to fit // within a smi. - hash_value = V8::RandomPrivate(isolate) & Smi::kMaxValue; + hash_value = isolate->random_number_generator()->NextInt() & Smi::kMaxValue; attempts++; } while (hash_value == 0 && attempts < 30); hash_value = hash_value != 0 ? hash_value : 1; // never return 0 @@ -4731,17 +4753,16 @@ Smi* JSReceiver::GenerateIdentityHash() { } -MaybeObject* JSObject::SetIdentityHash(Smi* hash, CreationFlag flag) { - MaybeObject* maybe = SetHiddenProperty(GetHeap()->identity_hash_string(), - hash); - if (maybe->IsFailure()) return maybe; - return this; +void JSObject::SetIdentityHash(Handle<JSObject> object, Smi* hash) { + CALL_HEAP_FUNCTION_VOID(object->GetIsolate(), + object->SetHiddenProperty( + object->GetHeap()->identity_hash_string(), hash)); } -int JSObject::GetIdentityHash(Handle<JSObject> obj) { - CALL_AND_RETRY_OR_DIE(obj->GetIsolate(), - obj->GetIdentityHash(ALLOW_CREATION), +int JSObject::GetIdentityHash(Handle<JSObject> object) { + CALL_AND_RETRY_OR_DIE(object->GetIsolate(), + object->GetIdentityHash(ALLOW_CREATION), return Smi::cast(__object__)->value(), return 0); } @@ -4766,6 +4787,12 @@ MaybeObject* JSObject::GetIdentityHash(CreationFlag flag) { } +Handle<Object> JSProxy::GetIdentityHash(Handle<JSProxy> proxy, + CreationFlag flag) { + CALL_HEAP_FUNCTION(proxy->GetIsolate(), proxy->GetIdentityHash(flag), Object); +} + + MaybeObject* JSProxy::GetIdentityHash(CreationFlag flag) { Object* hash = this->hash(); if (!hash->IsSmi() && flag == ALLOW_CREATION) { @@ -4858,30 +4885,27 @@ MaybeObject* JSObject::SetHiddenProperty(Name* key, Object* value) { } -void JSObject::DeleteHiddenProperty(Name* key) { +void JSObject::DeleteHiddenProperty(Handle<JSObject> object, Handle<Name> key) { + Isolate* isolate = object->GetIsolate(); ASSERT(key->IsUniqueName()); - if (IsJSGlobalProxy()) { - // For a proxy, use the prototype as target object. - Object* proxy_parent = GetPrototype(); - // If the proxy is detached, return immediately. - if (proxy_parent->IsNull()) return; - ASSERT(proxy_parent->IsJSGlobalObject()); - JSObject::cast(proxy_parent)->DeleteHiddenProperty(key); - return; + + if (object->IsJSGlobalProxy()) { + Handle<Object> proto(object->GetPrototype(), isolate); + if (proto->IsNull()) return; + ASSERT(proto->IsJSGlobalObject()); + return DeleteHiddenProperty(Handle<JSObject>::cast(proto), key); } - ASSERT(!IsJSGlobalProxy()); + MaybeObject* hidden_lookup = - GetHiddenPropertiesHashTable(ONLY_RETURN_INLINE_VALUE); + object->GetHiddenPropertiesHashTable(ONLY_RETURN_INLINE_VALUE); Object* inline_value = hidden_lookup->ToObjectUnchecked(); // We never delete (inline-stored) identity hashes. - ASSERT(key != GetHeap()->identity_hash_string()); + ASSERT(*key != isolate->heap()->identity_hash_string()); if (inline_value->IsUndefined() || inline_value->IsSmi()) return; - ObjectHashTable* hashtable = ObjectHashTable::cast(inline_value); - MaybeObject* delete_result = hashtable->Put(key, GetHeap()->the_hole_value()); - USE(delete_result); - ASSERT(!delete_result->IsFailure()); // Delete does not cause GC. + Handle<ObjectHashTable> hashtable(ObjectHashTable::cast(inline_value)); + PutIntoObjectHashTable(hashtable, key, isolate->factory()->the_hole_value()); } @@ -4952,13 +4976,13 @@ MaybeObject* JSObject::GetHiddenPropertiesHashTable( ASSERT_EQ(hashtable, new_table); } - MaybeObject* store_result = - SetPropertyPostInterceptor(GetHeap()->hidden_string(), - hashtable, - DONT_ENUM, - kNonStrictMode, - OMIT_EXTENSIBILITY_CHECK, - FORCE_FIELD); + MaybeObject* store_result = SetLocalPropertyIgnoreAttributesTrampoline( + GetHeap()->hidden_string(), + hashtable, + DONT_ENUM, + OPTIMAL_REPRESENTATION, + ALLOW_AS_CONSTANT, + OMIT_EXTENSIBILITY_CHECK); if (store_result->IsFailure()) return store_result; return hashtable; } @@ -4985,13 +5009,13 @@ MaybeObject* JSObject::SetHiddenPropertiesHashTable(Object* value) { } } } - MaybeObject* store_result = - SetPropertyPostInterceptor(GetHeap()->hidden_string(), - value, - DONT_ENUM, - kNonStrictMode, - OMIT_EXTENSIBILITY_CHECK, - FORCE_FIELD); + MaybeObject* store_result = SetLocalPropertyIgnoreAttributesTrampoline( + GetHeap()->hidden_string(), + value, + DONT_ENUM, + OPTIMAL_REPRESENTATION, + ALLOW_AS_CONSTANT, + OMIT_EXTENSIBILITY_CHECK); if (store_result->IsFailure()) return store_result; return this; } @@ -5022,8 +5046,8 @@ Handle<Object> JSObject::DeletePropertyWithInterceptor(Handle<JSObject> object, Handle<InterceptorInfo> interceptor(object->GetNamedInterceptor()); if (!interceptor->deleter()->IsUndefined()) { - v8::NamedPropertyDeleter deleter = - v8::ToCData<v8::NamedPropertyDeleter>(interceptor->deleter()); + v8::NamedPropertyDeleterCallback deleter = + v8::ToCData<v8::NamedPropertyDeleterCallback>(interceptor->deleter()); LOG(isolate, ApiNamedPropertyAccess("interceptor-named-delete", *object, *name)); PropertyCallbackArguments args( @@ -5046,111 +5070,110 @@ Handle<Object> JSObject::DeletePropertyWithInterceptor(Handle<JSObject> object, } -MaybeObject* JSObject::DeleteElementWithInterceptor(uint32_t index) { - Isolate* isolate = GetIsolate(); - Heap* heap = isolate->heap(); +// TODO(mstarzinger): Temporary wrapper until handlified. +static Handle<Object> AccessorDelete(Handle<JSObject> object, + uint32_t index, + JSObject::DeleteMode mode) { + CALL_HEAP_FUNCTION(object->GetIsolate(), + object->GetElementsAccessor()->Delete(*object, + index, + mode), + Object); +} + + +Handle<Object> JSObject::DeleteElementWithInterceptor(Handle<JSObject> object, + uint32_t index) { + Isolate* isolate = object->GetIsolate(); + Factory* factory = isolate->factory(); + // Make sure that the top context does not change when doing // callbacks or interceptor calls. AssertNoContextChange ncc; - HandleScope scope(isolate); - Handle<InterceptorInfo> interceptor(GetIndexedInterceptor()); - if (interceptor->deleter()->IsUndefined()) return heap->false_value(); - v8::IndexedPropertyDeleter deleter = - v8::ToCData<v8::IndexedPropertyDeleter>(interceptor->deleter()); - Handle<JSObject> this_handle(this); + + Handle<InterceptorInfo> interceptor(object->GetIndexedInterceptor()); + if (interceptor->deleter()->IsUndefined()) return factory->false_value(); + v8::IndexedPropertyDeleterCallback deleter = + v8::ToCData<v8::IndexedPropertyDeleterCallback>(interceptor->deleter()); LOG(isolate, - ApiIndexedPropertyAccess("interceptor-indexed-delete", this, index)); - PropertyCallbackArguments args(isolate, interceptor->data(), this, this); + ApiIndexedPropertyAccess("interceptor-indexed-delete", *object, index)); + PropertyCallbackArguments args( + isolate, interceptor->data(), *object, *object); v8::Handle<v8::Boolean> result = args.Call(deleter, index); - RETURN_IF_SCHEDULED_EXCEPTION(isolate); + RETURN_HANDLE_IF_SCHEDULED_EXCEPTION(isolate, Object); if (!result.IsEmpty()) { ASSERT(result->IsBoolean()); Handle<Object> result_internal = v8::Utils::OpenHandle(*result); result_internal->VerifyApiCallResultType(); - return *result_internal; + // Rebox CustomArguments::kReturnValueOffset before returning. + return handle(*result_internal, isolate); } - MaybeObject* raw_result = this_handle->GetElementsAccessor()->Delete( - *this_handle, - index, - NORMAL_DELETION); - RETURN_IF_SCHEDULED_EXCEPTION(isolate); - return raw_result; + Handle<Object> delete_result = AccessorDelete(object, index, NORMAL_DELETION); + RETURN_HANDLE_IF_SCHEDULED_EXCEPTION(isolate, Object); + return delete_result; } -Handle<Object> JSObject::DeleteElement(Handle<JSObject> obj, +Handle<Object> JSObject::DeleteElement(Handle<JSObject> object, uint32_t index, DeleteMode mode) { - CALL_HEAP_FUNCTION(obj->GetIsolate(), - obj->DeleteElement(index, mode), - Object); -} - + Isolate* isolate = object->GetIsolate(); + Factory* factory = isolate->factory(); -MaybeObject* JSObject::DeleteElement(uint32_t index, DeleteMode mode) { - Isolate* isolate = GetIsolate(); // Check access rights if needed. - if (IsAccessCheckNeeded() && - !isolate->MayIndexedAccess(this, index, v8::ACCESS_DELETE)) { - isolate->ReportFailedAccessCheck(this, v8::ACCESS_DELETE); - RETURN_IF_SCHEDULED_EXCEPTION(isolate); - return isolate->heap()->false_value(); + if (object->IsAccessCheckNeeded() && + !isolate->MayIndexedAccess(*object, index, v8::ACCESS_DELETE)) { + isolate->ReportFailedAccessCheck(*object, v8::ACCESS_DELETE); + RETURN_HANDLE_IF_SCHEDULED_EXCEPTION(isolate, Object); + return factory->false_value(); } - if (IsStringObjectWithCharacterAt(index)) { + if (object->IsStringObjectWithCharacterAt(index)) { if (mode == STRICT_DELETION) { // Deleting a non-configurable property in strict mode. - HandleScope scope(isolate); - Handle<Object> holder(this, isolate); - Handle<Object> name = isolate->factory()->NewNumberFromUint(index); - Handle<Object> args[2] = { name, holder }; + Handle<Object> name = factory->NewNumberFromUint(index); + Handle<Object> args[2] = { name, object }; Handle<Object> error = - isolate->factory()->NewTypeError("strict_delete_property", - HandleVector(args, 2)); - return isolate->Throw(*error); + factory->NewTypeError("strict_delete_property", + HandleVector(args, 2)); + isolate->Throw(*error); + return Handle<Object>(); } - return isolate->heap()->false_value(); + return factory->false_value(); } - if (IsJSGlobalProxy()) { - Object* proto = GetPrototype(); - if (proto->IsNull()) return isolate->heap()->false_value(); + if (object->IsJSGlobalProxy()) { + Handle<Object> proto(object->GetPrototype(), isolate); + if (proto->IsNull()) return factory->false_value(); ASSERT(proto->IsJSGlobalObject()); - return JSGlobalObject::cast(proto)->DeleteElement(index, mode); + return DeleteElement(Handle<JSObject>::cast(proto), index, mode); } - // From this point on everything needs to be handlified. - HandleScope scope(isolate); - Handle<JSObject> self(this); - Handle<Object> old_value; bool should_enqueue_change_record = false; - if (FLAG_harmony_observation && self->map()->is_observed()) { - should_enqueue_change_record = self->HasLocalElement(index); + if (FLAG_harmony_observation && object->map()->is_observed()) { + should_enqueue_change_record = object->HasLocalElement(index); if (should_enqueue_change_record) { - old_value = self->GetLocalElementAccessorPair(index) != NULL - ? Handle<Object>::cast(isolate->factory()->the_hole_value()) - : Object::GetElement(self, index); + old_value = object->GetLocalElementAccessorPair(index) != NULL + ? Handle<Object>::cast(factory->the_hole_value()) + : Object::GetElement(isolate, object, index); } } - MaybeObject* result; // Skip interceptor if forcing deletion. - if (self->HasIndexedInterceptor() && mode != FORCE_DELETION) { - result = self->DeleteElementWithInterceptor(index); + Handle<Object> result; + if (object->HasIndexedInterceptor() && mode != FORCE_DELETION) { + result = DeleteElementWithInterceptor(object, index); } else { - result = self->GetElementsAccessor()->Delete(*self, index, mode); + result = AccessorDelete(object, index, mode); } - Handle<Object> hresult; - if (!result->ToHandle(&hresult, isolate)) return result; - - if (should_enqueue_change_record && !self->HasLocalElement(index)) { - Handle<String> name = isolate->factory()->Uint32ToString(index); - EnqueueChangeRecord(self, "deleted", name, old_value); + if (should_enqueue_change_record && !object->HasLocalElement(index)) { + Handle<String> name = factory->Uint32ToString(index); + EnqueueChangeRecord(object, "deleted", name, old_value); } - return *hresult; + return result; } @@ -5923,7 +5946,8 @@ void JSObject::DefineElementAccessor(Handle<JSObject> object, uint32_t index, Handle<Object> getter, Handle<Object> setter, - PropertyAttributes attributes) { + PropertyAttributes attributes, + v8::AccessControl access_control) { switch (object->GetElementsKind()) { case FAST_SMI_ELEMENTS: case FAST_ELEMENTS: @@ -5981,9 +6005,9 @@ void JSObject::DefineElementAccessor(Handle<JSObject> object, Isolate* isolate = object->GetIsolate(); Handle<AccessorPair> accessors = isolate->factory()->NewAccessorPair(); accessors->SetComponents(*getter, *setter); + accessors->set_access_flags(access_control); - CALL_HEAP_FUNCTION_VOID( - isolate, object->SetElementCallback(index, *accessors, attributes)); + SetElementCallback(object, index, accessors, attributes); } @@ -6012,11 +6036,13 @@ void JSObject::DefinePropertyAccessor(Handle<JSObject> object, Handle<Name> name, Handle<Object> getter, Handle<Object> setter, - PropertyAttributes attributes) { + PropertyAttributes attributes, + v8::AccessControl access_control) { // We could assert that the property is configurable here, but we would need // to do a lookup, which seems to be a bit of overkill. bool only_attribute_changes = getter->IsNull() && setter->IsNull(); if (object->HasFastProperties() && !only_attribute_changes && + access_control == v8::DEFAULT && (object->map()->NumberOfOwnDescriptors() < DescriptorArray::kMaxNumberOfDescriptors)) { bool getterOk = getter->IsNull() || @@ -6028,10 +6054,9 @@ void JSObject::DefinePropertyAccessor(Handle<JSObject> object, Handle<AccessorPair> accessors = CreateAccessorPairFor(object, name); accessors->SetComponents(*getter, *setter); + accessors->set_access_flags(access_control); - CALL_HEAP_FUNCTION_VOID( - object->GetIsolate(), - object->SetPropertyCallback(*name, *accessors, attributes)); + SetPropertyCallback(object, name, accessors, attributes); } @@ -6049,82 +6074,75 @@ bool JSObject::CanSetCallback(Name* name) { LookupCallbackProperty(name, &callback_result); if (callback_result.IsFound()) { Object* obj = callback_result.GetCallbackObject(); - if (obj->IsAccessorInfo() && - AccessorInfo::cast(obj)->prohibits_overwriting()) { - return false; + if (obj->IsAccessorInfo()) { + return !AccessorInfo::cast(obj)->prohibits_overwriting(); + } + if (obj->IsAccessorPair()) { + return !AccessorPair::cast(obj)->prohibits_overwriting(); } } - return true; } -MaybeObject* JSObject::SetElementCallback(uint32_t index, - Object* structure, - PropertyAttributes attributes) { +void JSObject::SetElementCallback(Handle<JSObject> object, + uint32_t index, + Handle<Object> structure, + PropertyAttributes attributes) { + Heap* heap = object->GetHeap(); PropertyDetails details = PropertyDetails(attributes, CALLBACKS, 0); // Normalize elements to make this operation simple. - SeededNumberDictionary* dictionary; - { MaybeObject* maybe_dictionary = NormalizeElements(); - if (!maybe_dictionary->To(&dictionary)) return maybe_dictionary; - } - ASSERT(HasDictionaryElements() || HasDictionaryArgumentsElements()); + Handle<SeededNumberDictionary> dictionary = NormalizeElements(object); + ASSERT(object->HasDictionaryElements() || + object->HasDictionaryArgumentsElements()); // Update the dictionary with the new CALLBACKS property. - { MaybeObject* maybe_dictionary = dictionary->Set(index, structure, details); - if (!maybe_dictionary->To(&dictionary)) return maybe_dictionary; - } - + dictionary = SeededNumberDictionary::Set(dictionary, index, structure, + details); dictionary->set_requires_slow_elements(); + // Update the dictionary backing store on the object. - if (elements()->map() == GetHeap()->non_strict_arguments_elements_map()) { + if (object->elements()->map() == heap->non_strict_arguments_elements_map()) { // Also delete any parameter alias. // // TODO(kmillikin): when deleting the last parameter alias we could // switch to a direct backing store without the parameter map. This // would allow GC of the context. - FixedArray* parameter_map = FixedArray::cast(elements()); + FixedArray* parameter_map = FixedArray::cast(object->elements()); if (index < static_cast<uint32_t>(parameter_map->length()) - 2) { - parameter_map->set(index + 2, GetHeap()->the_hole_value()); + parameter_map->set(index + 2, heap->the_hole_value()); } - parameter_map->set(1, dictionary); + parameter_map->set(1, *dictionary); } else { - set_elements(dictionary); + object->set_elements(*dictionary); } - - return GetHeap()->undefined_value(); } -MaybeObject* JSObject::SetPropertyCallback(Name* name, - Object* structure, - PropertyAttributes attributes) { +void JSObject::SetPropertyCallback(Handle<JSObject> object, + Handle<Name> name, + Handle<Object> structure, + PropertyAttributes attributes) { // Normalize object to make this operation simple. - MaybeObject* maybe_ok = NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0); - if (maybe_ok->IsFailure()) return maybe_ok; + NormalizeProperties(object, CLEAR_INOBJECT_PROPERTIES, 0); // For the global object allocate a new map to invalidate the global inline // caches which have a global property cell reference directly in the code. - if (IsGlobalObject()) { - Map* new_map; - MaybeObject* maybe_new_map = map()->CopyDropDescriptors(); - if (!maybe_new_map->To(&new_map)) return maybe_new_map; + if (object->IsGlobalObject()) { + Handle<Map> new_map = Map::CopyDropDescriptors(handle(object->map())); ASSERT(new_map->is_dictionary_map()); + object->set_map(*new_map); - set_map(new_map); // When running crankshaft, changing the map is not enough. We // need to deoptimize all functions that rely on this global // object. - Deoptimizer::DeoptimizeGlobalObject(this); + Deoptimizer::DeoptimizeGlobalObject(*object); } // Update the dictionary with the new CALLBACKS property. PropertyDetails details = PropertyDetails(attributes, CALLBACKS, 0); - maybe_ok = SetNormalizedProperty(name, structure, details); - if (maybe_ok->IsFailure()) return maybe_ok; - - return GetHeap()->undefined_value(); + SetNormalizedProperty(object, name, structure, details); } @@ -6132,7 +6150,8 @@ void JSObject::DefineAccessor(Handle<JSObject> object, Handle<Name> name, Handle<Object> getter, Handle<Object> setter, - PropertyAttributes attributes) { + PropertyAttributes attributes, + v8::AccessControl access_control) { Isolate* isolate = object->GetIsolate(); // Check access rights if needed. if (object->IsAccessCheckNeeded() && @@ -6145,14 +6164,18 @@ void JSObject::DefineAccessor(Handle<JSObject> object, Handle<Object> proto(object->GetPrototype(), isolate); if (proto->IsNull()) return; ASSERT(proto->IsJSGlobalObject()); - DefineAccessor( - Handle<JSObject>::cast(proto), name, getter, setter, attributes); + DefineAccessor(Handle<JSObject>::cast(proto), + name, + getter, + setter, + attributes, + access_control); return; } // Make sure that the top context does not change when doing callbacks or // interceptor calls. - AssertNoContextChange ncc; + AssertNoContextChangeWithHandleScope ncc; // Try to flatten before operating on the string. if (name->IsString()) String::cast(*name)->TryFlatten(); @@ -6169,7 +6192,7 @@ void JSObject::DefineAccessor(Handle<JSObject> object, if (is_element) { preexists = object->HasLocalElement(index); if (preexists && object->GetLocalElementAccessorPair(index) == NULL) { - old_value = Object::GetElement(object, index); + old_value = Object::GetElement(isolate, object, index); } } else { LookupResult lookup(isolate); @@ -6182,9 +6205,11 @@ void JSObject::DefineAccessor(Handle<JSObject> object, } if (is_element) { - DefineElementAccessor(object, index, getter, setter, attributes); + DefineElementAccessor( + object, index, getter, setter, attributes, access_control); } else { - DefinePropertyAccessor(object, name, getter, setter, attributes); + DefinePropertyAccessor( + object, name, getter, setter, attributes, access_control); } if (is_observed) { @@ -6313,22 +6338,25 @@ bool JSObject::DefineFastAccessor(Handle<JSObject> object, } -MaybeObject* JSObject::DefineAccessor(AccessorInfo* info) { - Isolate* isolate = GetIsolate(); - Name* name = Name::cast(info->name()); +Handle<Object> JSObject::SetAccessor(Handle<JSObject> object, + Handle<AccessorInfo> info) { + Isolate* isolate = object->GetIsolate(); + Factory* factory = isolate->factory(); + Handle<Name> name(Name::cast(info->name())); + // Check access rights if needed. - if (IsAccessCheckNeeded() && - !isolate->MayNamedAccess(this, name, v8::ACCESS_SET)) { - isolate->ReportFailedAccessCheck(this, v8::ACCESS_SET); - RETURN_IF_SCHEDULED_EXCEPTION(isolate); - return isolate->heap()->undefined_value(); + if (object->IsAccessCheckNeeded() && + !isolate->MayNamedAccess(*object, *name, v8::ACCESS_SET)) { + isolate->ReportFailedAccessCheck(*object, v8::ACCESS_SET); + RETURN_HANDLE_IF_SCHEDULED_EXCEPTION(isolate, Object); + return factory->undefined_value(); } - if (IsJSGlobalProxy()) { - Object* proto = GetPrototype(); - if (proto->IsNull()) return this; + if (object->IsJSGlobalProxy()) { + Handle<Object> proto(object->GetPrototype(), isolate); + if (proto->IsNull()) return object; ASSERT(proto->IsJSGlobalObject()); - return JSObject::cast(proto)->DefineAccessor(info); + return SetAccessor(Handle<JSObject>::cast(proto), info); } // Make sure that the top context does not change when doing callbacks or @@ -6336,18 +6364,18 @@ MaybeObject* JSObject::DefineAccessor(AccessorInfo* info) { AssertNoContextChange ncc; // Try to flatten before operating on the string. - if (name->IsString()) String::cast(name)->TryFlatten(); + if (name->IsString()) FlattenString(Handle<String>::cast(name)); - if (!CanSetCallback(name)) return isolate->heap()->undefined_value(); + if (!object->CanSetCallback(*name)) return factory->undefined_value(); uint32_t index = 0; bool is_element = name->AsArrayIndex(&index); if (is_element) { - if (IsJSArray()) return isolate->heap()->undefined_value(); + if (object->IsJSArray()) return factory->undefined_value(); // Accessors overwrite previous callbacks (cf. with getters/setters). - switch (GetElementsKind()) { + switch (object->GetElementsKind()) { case FAST_SMI_ELEMENTS: case FAST_ELEMENTS: case FAST_DOUBLE_ELEMENTS: @@ -6366,7 +6394,7 @@ MaybeObject* JSObject::DefineAccessor(AccessorInfo* info) { case EXTERNAL_DOUBLE_ELEMENTS: // Ignore getters and setters on pixel and external array // elements. - return isolate->heap()->undefined_value(); + return factory->undefined_value(); case DICTIONARY_ELEMENTS: break; case NON_STRICT_ARGUMENTS_ELEMENTS: @@ -6374,25 +6402,21 @@ MaybeObject* JSObject::DefineAccessor(AccessorInfo* info) { break; } - MaybeObject* maybe_ok = - SetElementCallback(index, info, info->property_attributes()); - if (maybe_ok->IsFailure()) return maybe_ok; + SetElementCallback(object, index, info, info->property_attributes()); } else { // Lookup the name. LookupResult result(isolate); - LocalLookup(name, &result, true); + object->LocalLookup(*name, &result, true); // ES5 forbids turning a property into an accessor if it's not // configurable (that is IsDontDelete in ES3 and v8), see 8.6.1 (Table 5). if (result.IsFound() && (result.IsReadOnly() || result.IsDontDelete())) { - return isolate->heap()->undefined_value(); + return factory->undefined_value(); } - MaybeObject* maybe_ok = - SetPropertyCallback(name, info, info->property_attributes()); - if (maybe_ok->IsFailure()) return maybe_ok; + SetPropertyCallback(object, name, info, info->property_attributes()); } - return this; + return object; } @@ -6401,7 +6425,7 @@ MaybeObject* JSObject::LookupAccessor(Name* name, AccessorComponent component) { // Make sure that the top context does not change when doing callbacks or // interceptor calls. - AssertNoContextChange ncc; + AssertNoContextChangeWithHandleScope ncc; // Check access rights if needed. if (IsAccessCheckNeeded() && @@ -6501,6 +6525,15 @@ MaybeObject* Map::RawCopy(int instance_size) { } +Handle<Map> Map::CopyNormalized(Handle<Map> map, + PropertyNormalizationMode mode, + NormalizedMapSharingMode sharing) { + CALL_HEAP_FUNCTION(map->GetIsolate(), + map->CopyNormalized(mode, sharing), + Map); +} + + MaybeObject* Map::CopyNormalized(PropertyNormalizationMode mode, NormalizedMapSharingMode sharing) { int new_instance_size = instance_size(); @@ -6580,7 +6613,7 @@ MaybeObject* Map::ShareDescriptor(DescriptorArray* descriptors, } else { // Descriptor arrays grow by 50%. MaybeObject* maybe_descriptors = DescriptorArray::Allocate( - old_size, old_size < 4 ? 1 : old_size / 2); + GetIsolate(), old_size, old_size < 4 ? 1 : old_size / 2); if (!maybe_descriptors->To(&new_descriptors)) return maybe_descriptors; DescriptorArray::WhitenessWitness witness(new_descriptors); @@ -6645,7 +6678,7 @@ MaybeObject* Map::CopyReplaceDescriptors(DescriptorArray* descriptors, if (!maybe_transitions->To(&transitions)) return maybe_transitions; set_transitions(transitions); result->SetBackPointer(this); - } else if (flag != OMIT_TRANSITION_KEEP_REPRESENTATIONS) { + } else { descriptors->InitializeRepresentations(Representation::Tagged()); } @@ -6830,7 +6863,8 @@ MaybeObject* Map::CopyAddDescriptor(Descriptor* descriptor, } DescriptorArray* new_descriptors; - MaybeObject* maybe_descriptors = DescriptorArray::Allocate(old_size, 1); + MaybeObject* maybe_descriptors = + DescriptorArray::Allocate(GetIsolate(), old_size, 1); if (!maybe_descriptors->To(&new_descriptors)) return maybe_descriptors; DescriptorArray::WhitenessWitness witness(new_descriptors); @@ -6877,7 +6911,7 @@ MaybeObject* DescriptorArray::CopyUpToAddAttributes( int size = enumeration_index; DescriptorArray* descriptors; - MaybeObject* maybe_descriptors = Allocate(size); + MaybeObject* maybe_descriptors = Allocate(GetIsolate(), size); if (!maybe_descriptors->To(&descriptors)) return maybe_descriptors; DescriptorArray::WhitenessWitness witness(descriptors); @@ -6924,7 +6958,8 @@ MaybeObject* Map::CopyReplaceDescriptor(DescriptorArray* descriptors, ASSERT_LT(insertion_index, new_size); DescriptorArray* new_descriptors; - MaybeObject* maybe_descriptors = DescriptorArray::Allocate(new_size); + MaybeObject* maybe_descriptors = + DescriptorArray::Allocate(GetIsolate(), new_size); if (!maybe_descriptors->To(&new_descriptors)) return maybe_descriptors; DescriptorArray::WhitenessWitness witness(new_descriptors); @@ -7714,8 +7749,10 @@ bool FixedArray::IsEqualTo(FixedArray* other) { #endif -MaybeObject* DescriptorArray::Allocate(int number_of_descriptors, int slack) { - Heap* heap = Isolate::Current()->heap(); +MaybeObject* DescriptorArray::Allocate(Isolate* isolate, + int number_of_descriptors, + int slack) { + Heap* heap = isolate->heap(); // Do not use DescriptorArray::cast on incomplete object. int size = number_of_descriptors + slack; if (size == 0) return heap->empty_descriptor_array(); @@ -7773,6 +7810,8 @@ void DescriptorArray::CopyFrom(int dst_index, MaybeObject* DescriptorArray::Merge(int verbatim, int valid, int new_size, + int modify_index, + StoreMode store_mode, DescriptorArray* other) { ASSERT(verbatim <= valid); ASSERT(valid <= new_size); @@ -7781,7 +7820,8 @@ MaybeObject* DescriptorArray::Merge(int verbatim, // Allocate a new descriptor array large enough to hold the required // descriptors, with minimally the exact same size as this descriptor array. MaybeObject* maybe_descriptors = DescriptorArray::Allocate( - new_size, Max(new_size, other->number_of_descriptors()) - new_size); + GetIsolate(), new_size, + Max(new_size, other->number_of_descriptors()) - new_size); if (!maybe_descriptors->To(&result)) return maybe_descriptors; ASSERT(result->length() > length() || result->NumberOfSlackDescriptors() > 0 || @@ -7796,7 +7836,7 @@ MaybeObject* DescriptorArray::Merge(int verbatim, int current_offset = 0; for (descriptor = 0; descriptor < verbatim; descriptor++) { if (GetDetails(descriptor).type() == FIELD) current_offset++; - result->CopyFrom(descriptor, this, descriptor, witness); + result->CopyFrom(descriptor, other, descriptor, witness); } // |verbatim| -> |valid| @@ -7806,6 +7846,7 @@ MaybeObject* DescriptorArray::Merge(int verbatim, PropertyDetails other_details = other->GetDetails(descriptor); if (details.type() == FIELD || other_details.type() == FIELD || + (store_mode == FORCE_FIELD && descriptor == modify_index) || (details.type() == CONSTANT && other_details.type() == CONSTANT && GetValue(descriptor) != other->GetValue(descriptor))) { @@ -7824,7 +7865,8 @@ MaybeObject* DescriptorArray::Merge(int verbatim, // |valid| -> |new_size| for (; descriptor < new_size; descriptor++) { PropertyDetails details = other->GetDetails(descriptor); - if (details.type() == FIELD) { + if (details.type() == FIELD || + (store_mode == FORCE_FIELD && descriptor == modify_index)) { Name* key = other->GetKey(descriptor); FieldDescriptor d(key, current_offset++, @@ -7939,19 +7981,21 @@ Object* AccessorPair::GetComponent(AccessorComponent component) { } -MaybeObject* DeoptimizationInputData::Allocate(int deopt_entry_count, +MaybeObject* DeoptimizationInputData::Allocate(Isolate* isolate, + int deopt_entry_count, PretenureFlag pretenure) { ASSERT(deopt_entry_count > 0); - return HEAP->AllocateFixedArray(LengthFor(deopt_entry_count), - pretenure); + return isolate->heap()->AllocateFixedArray(LengthFor(deopt_entry_count), + pretenure); } -MaybeObject* DeoptimizationOutputData::Allocate(int number_of_deopt_points, +MaybeObject* DeoptimizationOutputData::Allocate(Isolate* isolate, + int number_of_deopt_points, PretenureFlag pretenure) { - if (number_of_deopt_points == 0) return HEAP->empty_fixed_array(); - return HEAP->AllocateFixedArray(LengthOfFixedArray(number_of_deopt_points), - pretenure); + if (number_of_deopt_points == 0) return isolate->heap()->empty_fixed_array(); + return isolate->heap()->AllocateFixedArray( + LengthOfFixedArray(number_of_deopt_points), pretenure); } @@ -7968,8 +8012,34 @@ bool DescriptorArray::IsEqualTo(DescriptorArray* other) { #endif +static bool IsIdentifier(UnicodeCache* cache, Name* name) { + // Checks whether the buffer contains an identifier (no escape). + if (!name->IsString()) return false; + String* string = String::cast(name); + if (string->length() == 0) return false; + ConsStringIteratorOp op; + StringCharacterStream stream(string, &op); + if (!cache->IsIdentifierStart(stream.GetNext())) { + return false; + } + while (stream.HasMore()) { + if (!cache->IsIdentifierPart(stream.GetNext())) { + return false; + } + } + return true; +} + + +bool Name::IsCacheable(Isolate* isolate) { + return IsSymbol() || + IsIdentifier(isolate->unicode_cache(), this) || + this == isolate->heap()->hidden_string(); +} + + bool String::LooksValid() { - if (!Isolate::Current()->heap()->Contains(this)) return false; + if (!GetIsolate()->heap()->Contains(this)) return false; return true; } @@ -8129,8 +8199,7 @@ const uc16* SeqTwoByteString::SeqTwoByteStringGetData(unsigned start) { } -void Relocatable::PostGarbageCollectionProcessing() { - Isolate* isolate = Isolate::Current(); +void Relocatable::PostGarbageCollectionProcessing(Isolate* isolate) { Relocatable* current = isolate->relocatable_top(); while (current != NULL) { current->PostGarbageCollection(); @@ -8141,7 +8210,7 @@ void Relocatable::PostGarbageCollectionProcessing() { // Reserve space for statics needing saving and restoring. int Relocatable::ArchiveSpacePerThread() { - return sizeof(Isolate::Current()->relocatable_top()); + return sizeof(Relocatable*); // NOLINT } @@ -8167,8 +8236,7 @@ char* Relocatable::Iterate(ObjectVisitor* v, char* thread_storage) { } -void Relocatable::Iterate(ObjectVisitor* v) { - Isolate* isolate = Isolate::Current(); +void Relocatable::Iterate(Isolate* isolate, ObjectVisitor* v) { Iterate(v, isolate->relocatable_top()); } @@ -8944,6 +9012,7 @@ AllocationMemento* AllocationMemento::FindForJSObject(JSObject* object) { // involves carefully checking the object immediately after the JSArray // (if there is one) to see if it's an AllocationMemento. if (FLAG_track_allocation_sites && object->GetHeap()->InNewSpace(object)) { + ASSERT(object->GetHeap()->InToSpace(object)); Address ptr_end = (reinterpret_cast<Address>(object) - kHeapObjectTag) + object->Size(); if ((ptr_end + AllocationMemento::kSize) <= @@ -8954,7 +9023,7 @@ AllocationMemento* AllocationMemento::FindForJSObject(JSObject* object) { if (*possible_allocation_memento_map == object->GetHeap()->allocation_memento_map()) { AllocationMemento* memento = AllocationMemento::cast( - reinterpret_cast<Object*>(ptr_end + 1)); + reinterpret_cast<Object*>(ptr_end + kHeapObjectTag)); return memento; } } @@ -9229,46 +9298,34 @@ void JSFunction::MarkForLazyRecompilation() { } -void JSFunction::MarkForParallelRecompilation() { +void JSFunction::MarkForConcurrentRecompilation() { ASSERT(is_compiled() || GetIsolate()->DebuggerHasBreakPoints()); ASSERT(!IsOptimized()); ASSERT(shared()->allows_lazy_compilation() || code()->optimizable()); ASSERT(!shared()->is_generator()); - ASSERT(FLAG_parallel_recompilation); - if (FLAG_trace_parallel_recompilation) { + ASSERT(FLAG_concurrent_recompilation); + if (FLAG_trace_concurrent_recompilation) { PrintF(" ** Marking "); PrintName(); - PrintF(" for parallel recompilation.\n"); + PrintF(" for concurrent recompilation.\n"); } set_code_no_write_barrier( - GetIsolate()->builtins()->builtin(Builtins::kParallelRecompile)); - // No write barrier required, since the builtin is part of the root set. -} - - -void JSFunction::MarkForInstallingRecompiledCode() { - // The debugger could have switched the builtin to lazy compile. - // In that case, simply carry on. It will be dealt with later. - ASSERT(!IsOptimized()); - ASSERT(shared()->allows_lazy_compilation() || code()->optimizable()); - ASSERT(FLAG_parallel_recompilation); - set_code_no_write_barrier( - GetIsolate()->builtins()->builtin(Builtins::kInstallRecompiledCode)); + GetIsolate()->builtins()->builtin(Builtins::kConcurrentRecompile)); // No write barrier required, since the builtin is part of the root set. } void JSFunction::MarkInRecompileQueue() { - // We can only arrive here via the parallel-recompilation builtin. If + // We can only arrive here via the concurrent-recompilation builtin. If // break points were set, the code would point to the lazy-compile builtin. ASSERT(!GetIsolate()->DebuggerHasBreakPoints()); - ASSERT(IsMarkedForParallelRecompilation() && !IsOptimized()); + ASSERT(IsMarkedForConcurrentRecompilation() && !IsOptimized()); ASSERT(shared()->allows_lazy_compilation() || code()->optimizable()); - ASSERT(FLAG_parallel_recompilation); - if (FLAG_trace_parallel_recompilation) { + ASSERT(FLAG_concurrent_recompilation); + if (FLAG_trace_concurrent_recompilation) { PrintF(" ** Queueing "); PrintName(); - PrintF(" for parallel recompilation.\n"); + PrintF(" for concurrent recompilation.\n"); } set_code_no_write_barrier( GetIsolate()->builtins()->builtin(Builtins::kInRecompileQueue)); @@ -9282,7 +9339,7 @@ static bool CompileLazyHelper(CompilationInfo* info, ASSERT(info->IsOptimizing() || !info->shared_info()->is_compiled()); ASSERT(!info->isolate()->has_pending_exception()); bool result = Compiler::CompileLazy(info); - ASSERT(result != Isolate::Current()->has_pending_exception()); + ASSERT(result != info->isolate()->has_pending_exception()); if (!result && flag == CLEAR_EXCEPTION) { info->isolate()->clear_pending_exception(); } @@ -9451,11 +9508,25 @@ bool JSFunction::CompileLazy(Handle<JSFunction> function, } +Handle<Code> JSFunction::CompileOsr(Handle<JSFunction> function, + BailoutId osr_ast_id, + ClearExceptionFlag flag) { + CompilationInfoWithZone info(function); + info.SetOptimizing(osr_ast_id); + if (CompileLazyHelper(&info, flag)) { + // TODO(titzer): don't install the OSR code. + // ASSERT(function->code() != *info.code()); + return info.code(); + } else { + return Handle<Code>::null(); + } +} + + bool JSFunction::CompileOptimized(Handle<JSFunction> function, - BailoutId osr_ast_id, ClearExceptionFlag flag) { CompilationInfoWithZone info(function); - info.SetOptimizing(osr_ast_id); + info.SetOptimizing(BailoutId::None()); return CompileLazyHelper(&info, flag); } @@ -9481,21 +9552,13 @@ bool JSFunction::IsInlineable() { void JSObject::OptimizeAsPrototype(Handle<JSObject> object) { - CALL_HEAP_FUNCTION_VOID(object->GetIsolate(), object->OptimizeAsPrototype()); -} - - -MaybeObject* JSObject::OptimizeAsPrototype() { - if (IsGlobalObject()) return this; + if (object->IsGlobalObject()) return; // Make sure prototypes are fast objects and their maps have the bit set // so they remain fast. - if (!HasFastProperties()) { - MaybeObject* new_proto = TransformToFastProperties(0); - if (new_proto->IsFailure()) return new_proto; - ASSERT(new_proto == this); + if (!object->HasFastProperties()) { + TransformToFastProperties(object, 0); } - return this; } @@ -9647,40 +9710,38 @@ Context* JSFunction::NativeContextFromLiterals(FixedArray* literals) { } -bool JSFunction::PassesHydrogenFilter() { +// The filter is a pattern that matches function names in this way: +// "*" all; the default +// "-" all but the top-level function +// "-name" all but the function "name" +// "" only the top-level function +// "name" only the function "name" +// "name*" only functions starting with "name" +bool JSFunction::PassesFilter(const char* raw_filter) { + if (*raw_filter == '*') return true; String* name = shared()->DebugName(); - // The filter string is a pattern that matches functions in this way: - // "*" all; the default - // "-" all but the top-level function - // "-name" all but the function "name" - // "" only the top-level function - // "name" only the function "name" - // "name*" only functions starting with "name" - if (*FLAG_hydrogen_filter != '*') { - Vector<const char> filter = CStrVector(FLAG_hydrogen_filter); - if (filter.length() == 0) return name->length() == 0; - if (filter[0] != '-' && name->IsUtf8EqualTo(filter)) return true; - if (filter[0] == '-' && - !name->IsUtf8EqualTo(filter.SubVector(1, filter.length()))) { - return true; - } - if (filter[filter.length() - 1] == '*' && - name->IsUtf8EqualTo(filter.SubVector(0, filter.length() - 1), true)) { - return true; - } - return false; + Vector<const char> filter = CStrVector(raw_filter); + if (filter.length() == 0) return name->length() == 0; + if (filter[0] != '-' && name->IsUtf8EqualTo(filter)) return true; + if (filter[0] == '-' && + !name->IsUtf8EqualTo(filter.SubVector(1, filter.length()))) { + return true; } - - return true; + if (filter[filter.length() - 1] == '*' && + name->IsUtf8EqualTo(filter.SubVector(0, filter.length() - 1), true)) { + return true; + } + return false; } -MaybeObject* Oddball::Initialize(const char* to_string, +MaybeObject* Oddball::Initialize(Heap* heap, + const char* to_string, Object* to_number, byte kind) { String* internalized_to_string; { MaybeObject* maybe_string = - Isolate::Current()->heap()->InternalizeUtf8String( + heap->InternalizeUtf8String( CStrVector(to_string)); if (!maybe_string->To(&internalized_to_string)) return maybe_string; } @@ -9814,12 +9875,16 @@ void SharedFunctionInfo::DisableOptimization(BailoutReason reason) { // non-optimizable if optimization is disabled for the shared // function info. set_optimization_disabled(true); + set_bailout_reason(reason); // Code should be the lazy compilation stub or else unoptimized. If the // latter, disable optimization for the code too. ASSERT(code()->kind() == Code::FUNCTION || code()->kind() == Code::BUILTIN); if (code()->kind() == Code::FUNCTION) { code()->set_optimizable(false); } + PROFILE(GetIsolate(), + LogExistingFunction(Handle<SharedFunctionInfo>(this), + Handle<Code>(code()))); if (FLAG_trace_opt) { PrintF("[disabled optimization for "); ShortPrint(); @@ -10317,7 +10382,7 @@ void Code::ClearInlineCaches() { RelocInfo* info = it.rinfo(); Code* target(Code::GetCodeFromTargetAddress(info->target_address())); if (target->is_inline_cache_stub()) { - IC::Clear(info->pc()); + IC::Clear(this->GetIsolate(), info->pc()); } } } @@ -10341,6 +10406,18 @@ void Code::ClearTypeFeedbackCells(Heap* heap) { } +BailoutId Code::TranslatePcOffsetToAstId(uint32_t pc_offset) { + DisallowHeapAllocation no_gc; + ASSERT(kind() == FUNCTION); + for (FullCodeGenerator::BackEdgeTableIterator it(this, &no_gc); + !it.Done(); + it.Next()) { + if (it.pc_offset() == pc_offset) return it.ast_id(); + } + return BailoutId::None(); +} + + bool Code::allowed_in_shared_map_code_cache() { return is_keyed_load_stub() || is_keyed_store_stub() || (is_compare_ic_stub() && @@ -10401,7 +10478,7 @@ int Code::GetAge() { void Code::GetCodeAgeAndParity(Code* code, Age* age, MarkingParity* parity) { - Isolate* isolate = Isolate::Current(); + Isolate* isolate = code->GetIsolate(); Builtins* builtins = isolate->builtins(); Code* stub = NULL; #define HANDLE_CODE_AGE(AGE) \ @@ -10801,7 +10878,8 @@ void Code::Disassemble(const char* name, FILE* out) { // If there is no back edge table, the "table start" will be at or after // (due to alignment) the end of the instruction stream. if (static_cast<int>(offset) < instruction_size()) { - FullCodeGenerator::BackEdgeTableIterator back_edges(this); + DisallowHeapAllocation no_gc; + FullCodeGenerator::BackEdgeTableIterator back_edges(this, &no_gc); PrintF(out, "Back edges (size = %u)\n", back_edges.table_length()); PrintF(out, "ast_id pc_offset loop_depth\n"); @@ -10977,7 +11055,7 @@ static bool GetOldValue(Isolate* isolate, ASSERT(attributes != ABSENT); if (attributes == DONT_DELETE) return false; old_values->Add(object->GetLocalElementAccessorPair(index) == NULL - ? Object::GetElement(object, index) + ? Object::GetElement(isolate, object, index) : Handle<Object>::cast(isolate->factory()->the_hole_value())); indices->Add(index); return true; @@ -10997,7 +11075,8 @@ static void EnqueueSpliceRecord(Handle<JSArray> object, { object, index_object, deleted, add_count_object }; bool threw; - Execution::Call(Handle<JSFunction>(isolate->observers_enqueue_splice()), + Execution::Call(isolate, + Handle<JSFunction>(isolate->observers_enqueue_splice()), isolate->factory()->undefined_value(), ARRAY_SIZE(args), args, &threw); ASSERT(!threw); @@ -11010,7 +11089,8 @@ static void BeginPerformSplice(Handle<JSArray> object) { Handle<Object> args[] = { object }; bool threw; - Execution::Call(Handle<JSFunction>(isolate->observers_begin_perform_splice()), + Execution::Call(isolate, + Handle<JSFunction>(isolate->observers_begin_perform_splice()), isolate->factory()->undefined_value(), ARRAY_SIZE(args), args, &threw); ASSERT(!threw); @@ -11023,7 +11103,8 @@ static void EndPerformSplice(Handle<JSArray> object) { Handle<Object> args[] = { object }; bool threw; - Execution::Call(Handle<JSFunction>(isolate->observers_end_perform_splice()), + Execution::Call(isolate, + Handle<JSFunction>(isolate->observers_end_perform_splice()), isolate->factory()->undefined_value(), ARRAY_SIZE(args), args, &threw); ASSERT(!threw); @@ -11343,8 +11424,9 @@ void DependentCode::RemoveCompilationInfo(DependentCode::DependencyGroup group, bool DependentCode::Contains(DependencyGroup group, Code* code) { GroupStartIndexes starts(this); - int number_of_entries = starts.number_of_entries(); - for (int i = 0; i < number_of_entries; i++) { + int start = starts.at(group); + int end = starts.at(group + 1); + for (int i = start; i < end; i++) { if (object_at(i) == code) return true; } return false; @@ -11362,13 +11444,15 @@ void DependentCode::DeoptimizeDependentCodeGroup( int code_entries = starts.number_of_entries(); if (start == end) return; - // Collect all the code to deoptimize. - Zone zone(isolate); - ZoneList<Code*> codes(end - start, &zone); + // Mark all the code that needs to be deoptimized. + bool marked = false; for (int i = start; i < end; i++) { if (is_code_at(i)) { Code* code = code_at(i); - if (!code->marked_for_deoptimization()) codes.Add(code, &zone); + if (!code->marked_for_deoptimization()) { + code->set_marked_for_deoptimization(true); + marked = true; + } } else { CompilationInfo* info = compilation_info_at(i); info->AbortDueToDependencyChange(); @@ -11384,7 +11468,8 @@ void DependentCode::DeoptimizeDependentCodeGroup( clear_at(i); } set_number_of_entries(group, 0); - Deoptimizer::DeoptimizeCodeList(isolate, &codes); + + if (marked) Deoptimizer::DeoptimizeMarkedCode(isolate); } @@ -11539,16 +11624,18 @@ MaybeObject* JSObject::SetElementWithInterceptor(uint32_t index, bool check_prototype, SetPropertyMode set_mode) { Isolate* isolate = GetIsolate(); + HandleScope scope(isolate); + // Make sure that the top context does not change when doing // callbacks or interceptor calls. AssertNoContextChange ncc; - HandleScope scope(isolate); + Handle<InterceptorInfo> interceptor(GetIndexedInterceptor()); Handle<JSObject> this_handle(this); Handle<Object> value_handle(value, isolate); if (!interceptor->setter()->IsUndefined()) { - v8::IndexedPropertySetter setter = - v8::ToCData<v8::IndexedPropertySetter>(interceptor->setter()); + v8::IndexedPropertySetterCallback setter = + v8::ToCData<v8::IndexedPropertySetterCallback>(interceptor->setter()); LOG(isolate, ApiIndexedPropertyAccess("interceptor-indexed-set", this, index)); PropertyCallbackArguments args(isolate, interceptor->data(), this, this); @@ -11581,7 +11668,8 @@ MaybeObject* JSObject::GetElementWithCallback(Object* receiver, Handle<ExecutableAccessorInfo> data( ExecutableAccessorInfo::cast(structure)); Object* fun_obj = data->getter(); - v8::AccessorGetter call_fun = v8::ToCData<v8::AccessorGetter>(fun_obj); + v8::AccessorGetterCallback call_fun = + v8::ToCData<v8::AccessorGetterCallback>(fun_obj); if (call_fun == NULL) return isolate->heap()->undefined_value(); HandleScope scope(isolate); Handle<JSObject> self(JSObject::cast(receiver)); @@ -11646,7 +11734,8 @@ MaybeObject* JSObject::SetElementWithCallback(Object* structure, Handle<ExecutableAccessorInfo> data( ExecutableAccessorInfo::cast(structure)); Object* call_obj = data->setter(); - v8::AccessorSetter call_fun = v8::ToCData<v8::AccessorSetter>(call_obj); + v8::AccessorSetterCallback call_fun = + v8::ToCData<v8::AccessorSetterCallback>(call_obj); if (call_fun == NULL) return value; Handle<Object> number = isolate->factory()->NewNumberFromUint(index); Handle<String> key(isolate->factory()->NumberToString(number)); @@ -12100,18 +12189,17 @@ MUST_USE_RESULT MaybeObject* JSObject::SetFastDoubleElement( } -MaybeObject* JSReceiver::SetElement(uint32_t index, - Object* value, - PropertyAttributes attributes, - StrictModeFlag strict_mode, - bool check_proto) { - if (IsJSProxy()) { - return JSProxy::cast(this)->SetElementWithHandler( - this, index, value, strict_mode); - } else { - return JSObject::cast(this)->SetElement( - index, value, attributes, strict_mode, check_proto); +Handle<Object> JSReceiver::SetElement(Handle<JSReceiver> object, + uint32_t index, + Handle<Object> value, + PropertyAttributes attributes, + StrictModeFlag strict_mode) { + if (object->IsJSProxy()) { + return JSProxy::SetElementWithHandler( + Handle<JSProxy>::cast(object), object, index, value, strict_mode); } + return JSObject::SetElement( + Handle<JSObject>::cast(object), index, value, attributes, strict_mode); } @@ -12136,7 +12224,8 @@ Handle<Object> JSObject::SetElement(Handle<JSObject> object, if (object->HasExternalArrayElements()) { if (!value->IsNumber() && !value->IsUndefined()) { bool has_exception; - Handle<Object> number = Execution::ToNumber(value, &has_exception); + Handle<Object> number = + Execution::ToNumber(object->GetIsolate(), value, &has_exception); if (has_exception) return Handle<Object>(); value = number; } @@ -12213,7 +12302,7 @@ MaybeObject* JSObject::SetElement(uint32_t index, if (old_attributes != ABSENT) { if (self->GetLocalElementAccessorPair(index) == NULL) - old_value = Object::GetElement(self, index); + old_value = Object::GetElement(isolate, self, index); } else if (self->IsJSArray()) { // Store old array length in case adding an element grows the array. old_length_handle = handle(Handle<JSArray>::cast(self)->length(), isolate); @@ -12255,7 +12344,7 @@ MaybeObject* JSObject::SetElement(uint32_t index, } else if (old_value->IsTheHole()) { EnqueueChangeRecord(self, "reconfigured", name, old_value); } else { - Handle<Object> new_value = Object::GetElement(self, index); + Handle<Object> new_value = Object::GetElement(isolate, self, index); bool value_changed = !old_value->SameValue(*new_value); if (old_attributes != new_attributes) { if (!value_changed) old_value = isolate->factory()->the_hole_value(); @@ -12547,16 +12636,18 @@ MaybeObject* JSArray::JSArrayUpdateLengthFromIndex(uint32_t index, MaybeObject* JSObject::GetElementWithInterceptor(Object* receiver, uint32_t index) { Isolate* isolate = GetIsolate(); + HandleScope scope(isolate); + // Make sure that the top context does not change when doing // callbacks or interceptor calls. AssertNoContextChange ncc; - HandleScope scope(isolate); + Handle<InterceptorInfo> interceptor(GetIndexedInterceptor(), isolate); Handle<Object> this_handle(receiver, isolate); Handle<JSObject> holder_handle(this, isolate); if (!interceptor->getter()->IsUndefined()) { - v8::IndexedPropertyGetter getter = - v8::ToCData<v8::IndexedPropertyGetter>(interceptor->getter()); + v8::IndexedPropertyGetterCallback getter = + v8::ToCData<v8::IndexedPropertyGetterCallback>(interceptor->getter()); LOG(isolate, ApiIndexedPropertyAccess("interceptor-indexed-get", this, index)); PropertyCallbackArguments @@ -12581,7 +12672,7 @@ MaybeObject* JSObject::GetElementWithInterceptor(Object* receiver, Object* pt = holder_handle->GetPrototype(); if (pt == heap->null_value()) return heap->undefined_value(); - return pt->GetElementWithReceiver(*this_handle, index); + return pt->GetElementWithReceiver(isolate, *this_handle, index); } @@ -12860,8 +12951,8 @@ MaybeObject* JSObject::GetPropertyWithInterceptor( Handle<String> name_handle(String::cast(name)); if (!interceptor->getter()->IsUndefined()) { - v8::NamedPropertyGetter getter = - v8::ToCData<v8::NamedPropertyGetter>(interceptor->getter()); + v8::NamedPropertyGetterCallback getter = + v8::ToCData<v8::NamedPropertyGetterCallback>(interceptor->getter()); LOG(isolate, ApiNamedPropertyAccess("interceptor-named-get", *holder_handle, name)); PropertyCallbackArguments @@ -13697,6 +13788,74 @@ MaybeObject* HashTable<Shape, Key>::Rehash(HashTable* new_table, Key key) { template<typename Shape, typename Key> +uint32_t HashTable<Shape, Key>::EntryForProbe(Key key, + Object* k, + int probe, + uint32_t expected) { + uint32_t hash = HashTable<Shape, Key>::HashForObject(key, k); + uint32_t capacity = Capacity(); + uint32_t entry = FirstProbe(hash, capacity); + for (int i = 1; i < probe; i++) { + if (entry == expected) return expected; + entry = NextProbe(entry, i, capacity); + } + return entry; +} + + +template<typename Shape, typename Key> +void HashTable<Shape, Key>::Swap(uint32_t entry1, + uint32_t entry2, + WriteBarrierMode mode) { + int index1 = EntryToIndex(entry1); + int index2 = EntryToIndex(entry2); + Object* temp[Shape::kEntrySize]; + for (int j = 0; j < Shape::kEntrySize; j++) { + temp[j] = get(index1 + j); + } + for (int j = 0; j < Shape::kEntrySize; j++) { + set(index1 + j, get(index2 + j), mode); + } + for (int j = 0; j < Shape::kEntrySize; j++) { + set(index2 + j, temp[j], mode); + } +} + + +template<typename Shape, typename Key> +void HashTable<Shape, Key>::Rehash(Key key) { + DisallowHeapAllocation no_gc; + WriteBarrierMode mode = GetWriteBarrierMode(no_gc); + uint32_t capacity = Capacity(); + bool done = false; + for (int probe = 1; !done; probe++) { + // All elements at entries given by one of the first _probe_ probes + // are placed correctly. Other elements might need to be moved. + done = true; + for (uint32_t current = 0; current < capacity; current++) { + Object* current_key = get(EntryToIndex(current)); + if (IsKey(current_key)) { + uint32_t target = EntryForProbe(key, current_key, probe, current); + if (current == target) continue; + Object* target_key = get(EntryToIndex(target)); + if (!IsKey(target_key) || + EntryForProbe(key, target_key, probe, target) != target) { + // Put the current element into the correct position. + Swap(current, target, mode); + // The other element will be processed on the next iteration. + current--; + } else { + // The place for the current element is occupied. Leave the element + // for the next probe. + done = false; + } + } + } + } +} + + +template<typename Shape, typename Key> MaybeObject* HashTable<Shape, Key>::EnsureCapacity(int n, Key key) { int capacity = Capacity(); int nof = NumberOfElements() + n; @@ -15226,7 +15385,7 @@ MaybeObject* NameDictionary::TransformPropertiesToFastFor( // Allocate the instance descriptor. DescriptorArray* descriptors; MaybeObject* maybe_descriptors = - DescriptorArray::Allocate(instance_descriptor_length); + DescriptorArray::Allocate(GetIsolate(), instance_descriptor_length); if (!maybe_descriptors->To(&descriptors)) { return maybe_descriptors; } @@ -15333,6 +15492,7 @@ MaybeObject* ObjectHashSet::Add(Object* key) { int hash; { MaybeObject* maybe_hash = key->GetHash(ALLOW_CREATION); if (maybe_hash->IsFailure()) return maybe_hash; + ASSERT(key->GetHash(OMIT_CREATION) == maybe_hash); hash = Smi::cast(maybe_hash->ToObjectUnchecked())->value(); } int entry = FindEntry(key); @@ -15394,6 +15554,7 @@ MaybeObject* ObjectHashTable::Put(Object* key, Object* value) { int hash; { MaybeObject* maybe_hash = key->GetHash(ALLOW_CREATION); if (maybe_hash->IsFailure()) return maybe_hash; + ASSERT(key->GetHash(OMIT_CREATION) == maybe_hash); hash = Smi::cast(maybe_hash->ToObjectUnchecked())->value(); } int entry = FindEntry(key); @@ -15517,7 +15678,7 @@ void DebugInfo::ClearBreakPoint(Handle<DebugInfo> debug_info, int code_position, Handle<Object> break_point_object) { Handle<Object> break_point_info(debug_info->GetBreakPointInfo(code_position), - Isolate::Current()); + debug_info->GetIsolate()); if (break_point_info->IsUndefined()) return; BreakPointInfo::ClearBreakPoint( Handle<BreakPointInfo>::cast(break_point_info), @@ -15530,7 +15691,7 @@ void DebugInfo::SetBreakPoint(Handle<DebugInfo> debug_info, int source_position, int statement_position, Handle<Object> break_point_object) { - Isolate* isolate = Isolate::Current(); + Isolate* isolate = debug_info->GetIsolate(); Handle<Object> break_point_info(debug_info->GetBreakPointInfo(code_position), isolate); if (!break_point_info->IsUndefined()) { @@ -15644,7 +15805,7 @@ int DebugInfo::GetBreakPointInfoIndex(int code_position) { // Remove the specified break point object. void BreakPointInfo::ClearBreakPoint(Handle<BreakPointInfo> break_point_info, Handle<Object> break_point_object) { - Isolate* isolate = Isolate::Current(); + Isolate* isolate = break_point_info->GetIsolate(); // If there are no break points just ignore. if (break_point_info->break_point_objects()->IsUndefined()) return; // If there is a single break point clear it if it is the same. |