diff options
Diffstat (limited to 'deps/v8/src/objects.cc')
-rw-r--r-- | deps/v8/src/objects.cc | 3066 |
1 files changed, 1662 insertions, 1404 deletions
diff --git a/deps/v8/src/objects.cc b/deps/v8/src/objects.cc index 35646b8be5..f7c89175da 100644 --- a/deps/v8/src/objects.cc +++ b/deps/v8/src/objects.cc @@ -28,6 +28,7 @@ #include "v8.h" #include "accessors.h" +#include "allocation-site-scopes.h" #include "api.h" #include "arguments.h" #include "bootstrapper.h" @@ -142,6 +143,20 @@ void Object::Lookup(Name* name, LookupResult* result) { } +Handle<Object> Object::GetPropertyWithReceiver( + Handle<Object> object, + Handle<Object> receiver, + Handle<Name> name, + PropertyAttributes* attributes) { + LookupResult lookup(name->GetIsolate()); + object->Lookup(*name, &lookup); + Handle<Object> result = + GetProperty(object, receiver, &lookup, name, attributes); + ASSERT(*attributes <= ABSENT); + return result; +} + + MaybeObject* Object::GetPropertyWithReceiver(Object* receiver, Name* name, PropertyAttributes* attributes) { @@ -328,9 +343,18 @@ static MaybeObject* GetDeclaredAccessorProperty(Object* receiver, } -MaybeObject* JSObject::GetPropertyWithCallback(Object* receiver, - Object* structure, - Name* name) { +Handle<FixedArray> JSObject::EnsureWritableFastElements( + Handle<JSObject> object) { + CALL_HEAP_FUNCTION(object->GetIsolate(), + object->EnsureWritableFastElements(), + FixedArray); +} + + +Handle<Object> JSObject::GetPropertyWithCallback(Handle<JSObject> object, + Handle<Object> receiver, + Handle<Object> structure, + Handle<Name> name) { Isolate* isolate = name->GetIsolate(); // To accommodate both the old and the new api we switch on the // data structure used to store the callbacks. Eventually foreign @@ -338,66 +362,71 @@ MaybeObject* JSObject::GetPropertyWithCallback(Object* receiver, if (structure->IsForeign()) { AccessorDescriptor* callback = reinterpret_cast<AccessorDescriptor*>( - Foreign::cast(structure)->foreign_address()); - MaybeObject* value = (callback->getter)(isolate, receiver, callback->data); - RETURN_IF_SCHEDULED_EXCEPTION(isolate); - return value; + Handle<Foreign>::cast(structure)->foreign_address()); + CALL_HEAP_FUNCTION(isolate, + (callback->getter)(isolate, *receiver, callback->data), + Object); } // api style callbacks. if (structure->IsAccessorInfo()) { - if (!AccessorInfo::cast(structure)->IsCompatibleReceiver(receiver)) { - Handle<Object> name_handle(name, isolate); - Handle<Object> receiver_handle(receiver, isolate); - Handle<Object> args[2] = { name_handle, receiver_handle }; + Handle<AccessorInfo> accessor_info = Handle<AccessorInfo>::cast(structure); + if (!accessor_info->IsCompatibleReceiver(*receiver)) { + Handle<Object> args[2] = { name, receiver }; Handle<Object> error = isolate->factory()->NewTypeError("incompatible_method_receiver", HandleVector(args, ARRAY_SIZE(args))); - return isolate->Throw(*error); + isolate->Throw(*error); + return Handle<Object>::null(); } // TODO(rossberg): Handling symbols in the API requires changing the API, // so we do not support it for now. - if (name->IsSymbol()) return isolate->heap()->undefined_value(); + if (name->IsSymbol()) return isolate->factory()->undefined_value(); if (structure->IsDeclaredAccessorInfo()) { - return GetDeclaredAccessorProperty(receiver, - DeclaredAccessorInfo::cast(structure), - isolate); + CALL_HEAP_FUNCTION( + isolate, + GetDeclaredAccessorProperty(*receiver, + DeclaredAccessorInfo::cast(*structure), + isolate), + Object); } - ExecutableAccessorInfo* data = ExecutableAccessorInfo::cast(structure); - Object* fun_obj = data->getter(); + + Handle<ExecutableAccessorInfo> data = + Handle<ExecutableAccessorInfo>::cast(structure); v8::AccessorGetterCallback call_fun = - v8::ToCData<v8::AccessorGetterCallback>(fun_obj); - if (call_fun == NULL) return isolate->heap()->undefined_value(); + v8::ToCData<v8::AccessorGetterCallback>(data->getter()); + if (call_fun == NULL) return isolate->factory()->undefined_value(); + HandleScope scope(isolate); - JSObject* self = JSObject::cast(receiver); - Handle<String> key(String::cast(name)); - LOG(isolate, ApiNamedPropertyAccess("load", self, name)); - PropertyCallbackArguments args(isolate, data->data(), self, this); + Handle<JSObject> self = Handle<JSObject>::cast(receiver); + Handle<String> key = Handle<String>::cast(name); + LOG(isolate, ApiNamedPropertyAccess("load", *self, *name)); + PropertyCallbackArguments args(isolate, data->data(), *self, *object); v8::Handle<v8::Value> result = args.Call(call_fun, v8::Utils::ToLocal(key)); - RETURN_IF_SCHEDULED_EXCEPTION(isolate); + RETURN_HANDLE_IF_SCHEDULED_EXCEPTION(isolate, Object); if (result.IsEmpty()) { - return isolate->heap()->undefined_value(); + return isolate->factory()->undefined_value(); } - Object* return_value = *v8::Utils::OpenHandle(*result); + Handle<Object> return_value = v8::Utils::OpenHandle(*result); return_value->VerifyApiCallResultType(); - return return_value; + return scope.CloseAndEscape(return_value); } // __defineGetter__ callback - if (structure->IsAccessorPair()) { - Object* getter = AccessorPair::cast(structure)->getter(); - if (getter->IsSpecFunction()) { - // TODO(rossberg): nicer would be to cast to some JSCallable here... - return GetPropertyWithDefinedGetter(receiver, JSReceiver::cast(getter)); - } - // Getter is not a function. - return isolate->heap()->undefined_value(); + Handle<Object> getter(Handle<AccessorPair>::cast(structure)->getter(), + isolate); + if (getter->IsSpecFunction()) { + // TODO(rossberg): nicer would be to cast to some JSCallable here... + CALL_HEAP_FUNCTION( + isolate, + object->GetPropertyWithDefinedGetter(*receiver, + JSReceiver::cast(*getter)), + Object); } - - UNREACHABLE(); - return NULL; + // Getter is not a function. + return isolate->factory()->undefined_value(); } @@ -455,18 +484,15 @@ Handle<Object> JSProxy::SetElementWithHandler(Handle<JSProxy> proxy, 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); + return SetPropertyWithHandler( + proxy, receiver, name, value, NONE, strict_mode); } -bool JSProxy::HasElementWithHandler(uint32_t index) { - String* name; - MaybeObject* maybe = GetHeap()->Uint32ToString(index); - if (!maybe->To<String>(&name)) return maybe; - return HasPropertyWithHandler(name); +bool JSProxy::HasElementWithHandler(Handle<JSProxy> proxy, uint32_t index) { + Isolate* isolate = proxy->GetIsolate(); + Handle<String> name = isolate->factory()->Uint32ToString(index); + return HasPropertyWithHandler(proxy, name); } @@ -496,56 +522,51 @@ MaybeObject* Object::GetPropertyWithDefinedGetter(Object* receiver, // Only deal with CALLBACKS and INTERCEPTOR -MaybeObject* JSObject::GetPropertyWithFailedAccessCheck( - Object* receiver, +Handle<Object> JSObject::GetPropertyWithFailedAccessCheck( + Handle<JSObject> object, + Handle<Object> receiver, LookupResult* result, - Name* name, + Handle<Name> name, PropertyAttributes* attributes) { + Isolate* isolate = name->GetIsolate(); if (result->IsProperty()) { switch (result->type()) { case CALLBACKS: { // Only allow API accessors. - Object* obj = result->GetCallbackObject(); - if (obj->IsAccessorInfo()) { - AccessorInfo* info = AccessorInfo::cast(obj); - if (info->all_can_read()) { - *attributes = result->GetAttributes(); - 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); - } + Handle<Object> callback_obj(result->GetCallbackObject(), isolate); + if (callback_obj->IsAccessorInfo()) { + if (!AccessorInfo::cast(*callback_obj)->all_can_read()) break; + *attributes = result->GetAttributes(); + // Fall through to GetPropertyWithCallback. + } else if (callback_obj->IsAccessorPair()) { + if (!AccessorPair::cast(*callback_obj)->all_can_read()) break; + // Fall through to GetPropertyWithCallback. + } else { + break; } - break; + Handle<JSObject> holder(result->holder(), isolate); + return GetPropertyWithCallback(holder, receiver, callback_obj, name); } case NORMAL: case FIELD: case CONSTANT: { // Search ALL_CAN_READ accessors in prototype chain. - LookupResult r(GetIsolate()); - result->holder()->LookupRealNamedPropertyInPrototypes(name, &r); + LookupResult r(isolate); + result->holder()->LookupRealNamedPropertyInPrototypes(*name, &r); if (r.IsProperty()) { - return GetPropertyWithFailedAccessCheck(receiver, - &r, - name, - attributes); + return GetPropertyWithFailedAccessCheck( + object, receiver, &r, name, attributes); } break; } case INTERCEPTOR: { // If the object has an interceptor, try real named properties. // No access check in GetPropertyAttributeWithInterceptor. - LookupResult r(GetIsolate()); - result->holder()->LookupRealNamedProperty(name, &r); + LookupResult r(isolate); + result->holder()->LookupRealNamedProperty(*name, &r); if (r.IsProperty()) { - return GetPropertyWithFailedAccessCheck(receiver, - &r, - name, - attributes); + return GetPropertyWithFailedAccessCheck( + object, receiver, &r, name, attributes); } break; } @@ -556,11 +577,9 @@ MaybeObject* JSObject::GetPropertyWithFailedAccessCheck( // No accessible property found. *attributes = ABSENT; - Heap* heap = name->GetHeap(); - Isolate* isolate = heap->isolate(); - isolate->ReportFailedAccessCheck(this, v8::ACCESS_GET); - RETURN_IF_SCHEDULED_EXCEPTION(isolate); - return heap->undefined_value(); + isolate->ReportFailedAccessCheck(*object, v8::ACCESS_GET); + RETURN_HANDLE_IF_SCHEDULED_EXCEPTION(isolate, Object); + return isolate->factory()->undefined_value(); } @@ -643,67 +662,63 @@ Object* JSObject::GetNormalizedProperty(LookupResult* result) { } -Handle<Object> JSObject::SetNormalizedProperty(Handle<JSObject> object, - LookupResult* result, - Handle<Object> value) { - CALL_HEAP_FUNCTION(object->GetIsolate(), - object->SetNormalizedProperty(result, *value), - Object); -} - - -MaybeObject* JSObject::SetNormalizedProperty(LookupResult* result, - Object* value) { - ASSERT(!HasFastProperties()); - if (IsGlobalObject()) { - PropertyCell* cell = PropertyCell::cast( - property_dictionary()->ValueAt(result->GetDictionaryEntry())); - MaybeObject* maybe_type = cell->SetValueInferType(value); - if (maybe_type->IsFailure()) return maybe_type; +void JSObject::SetNormalizedProperty(Handle<JSObject> object, + LookupResult* result, + Handle<Object> value) { + ASSERT(!object->HasFastProperties()); + NameDictionary* property_dictionary = object->property_dictionary(); + if (object->IsGlobalObject()) { + Handle<PropertyCell> cell(PropertyCell::cast( + property_dictionary->ValueAt(result->GetDictionaryEntry()))); + PropertyCell::SetValueInferType(cell, value); } else { - property_dictionary()->ValueAtPut(result->GetDictionaryEntry(), value); + property_dictionary->ValueAtPut(result->GetDictionaryEntry(), *value); } - return value; } -Handle<Object> JSObject::SetNormalizedProperty(Handle<JSObject> object, - Handle<Name> key, - Handle<Object> value, - PropertyDetails details) { - CALL_HEAP_FUNCTION(object->GetIsolate(), - object->SetNormalizedProperty(*key, *value, details), - Object); +// TODO(mstarzinger): Temporary wrapper until handlified. +static Handle<NameDictionary> NameDictionaryAdd(Handle<NameDictionary> dict, + Handle<Name> name, + Handle<Object> value, + PropertyDetails details) { + CALL_HEAP_FUNCTION(dict->GetIsolate(), + dict->Add(*name, *value, details), + NameDictionary); } -MaybeObject* JSObject::SetNormalizedProperty(Name* name, - Object* value, - PropertyDetails details) { - ASSERT(!HasFastProperties()); - int entry = property_dictionary()->FindEntry(name); +void JSObject::SetNormalizedProperty(Handle<JSObject> object, + Handle<Name> name, + Handle<Object> value, + PropertyDetails details) { + ASSERT(!object->HasFastProperties()); + Handle<NameDictionary> property_dictionary(object->property_dictionary()); + + if (!name->IsUniqueName()) { + name = object->GetIsolate()->factory()->InternalizedStringFromString( + Handle<String>::cast(name)); + } + + int entry = property_dictionary->FindEntry(*name); if (entry == NameDictionary::kNotFound) { - Object* store_value = value; - if (IsGlobalObject()) { - Heap* heap = name->GetHeap(); - MaybeObject* maybe_store_value = heap->AllocatePropertyCell(value); - if (!maybe_store_value->ToObject(&store_value)) return maybe_store_value; - } - Object* dict; - { MaybeObject* maybe_dict = - property_dictionary()->Add(name, store_value, details); - if (!maybe_dict->ToObject(&dict)) return maybe_dict; + Handle<Object> store_value = value; + if (object->IsGlobalObject()) { + store_value = object->GetIsolate()->factory()->NewPropertyCell(value); } - set_properties(NameDictionary::cast(dict)); - return value; + + property_dictionary = + NameDictionaryAdd(property_dictionary, name, store_value, details); + object->set_properties(*property_dictionary); + return; } - PropertyDetails original_details = property_dictionary()->DetailsAt(entry); + PropertyDetails original_details = property_dictionary->DetailsAt(entry); int enumeration_index; // Preserve the enumeration index unless the property was deleted. if (original_details.IsDeleted()) { - enumeration_index = property_dictionary()->NextEnumerationIndex(); - property_dictionary()->SetNextEnumerationIndex(enumeration_index + 1); + enumeration_index = property_dictionary->NextEnumerationIndex(); + property_dictionary->SetNextEnumerationIndex(enumeration_index + 1); } else { enumeration_index = original_details.dictionary_index(); ASSERT(enumeration_index > 0); @@ -712,17 +727,15 @@ MaybeObject* JSObject::SetNormalizedProperty(Name* name, details = PropertyDetails( details.attributes(), details.type(), enumeration_index); - if (IsGlobalObject()) { - PropertyCell* cell = - PropertyCell::cast(property_dictionary()->ValueAt(entry)); - MaybeObject* maybe_type = cell->SetValueInferType(value); - if (maybe_type->IsFailure()) return maybe_type; + if (object->IsGlobalObject()) { + Handle<PropertyCell> cell( + PropertyCell::cast(property_dictionary->ValueAt(entry))); + PropertyCell::SetValueInferType(cell, value); // Please note we have to update the property details. - property_dictionary()->DetailsAtPut(entry, details); + property_dictionary->DetailsAtPut(entry, details); } else { - property_dictionary()->SetEntry(entry, name, value, details); + property_dictionary->SetEntry(entry, *name, *value, details); } - return value; } @@ -733,12 +746,6 @@ Handle<NameDictionary> NameDictionaryShrink(Handle<NameDictionary> dict, } -static void CellSetValueInferType(Handle<PropertyCell> cell, - Handle<Object> value) { - CALL_HEAP_FUNCTION_VOID(cell->GetIsolate(), cell->SetValueInferType(*value)); -} - - Handle<Object> JSObject::DeleteNormalizedProperty(Handle<JSObject> object, Handle<Name> name, DeleteMode mode) { @@ -761,7 +768,8 @@ Handle<Object> JSObject::DeleteNormalizedProperty(Handle<JSObject> object, object->set_map(*new_map); } Handle<PropertyCell> cell(PropertyCell::cast(dictionary->ValueAt(entry))); - CellSetValueInferType(cell, isolate->factory()->the_hole_value()); + Handle<Object> value = isolate->factory()->the_hole_value(); + PropertyCell::SetValueInferType(cell, value); dictionary->DetailsAtPut(entry, details.AsDeleted()); } else { Handle<Object> deleted(dictionary->DeleteProperty(entry, mode), isolate); @@ -817,17 +825,24 @@ MaybeObject* Object::GetPropertyOrFail(Handle<Object> object, } +// TODO(yangguo): handlify this and get rid of. MaybeObject* Object::GetProperty(Object* receiver, LookupResult* result, Name* name, PropertyAttributes* attributes) { - // Make sure that the top context does not change when doing - // callbacks or interceptor calls. - AssertNoContextChangeWithHandleScope ncc; - Isolate* isolate = name->GetIsolate(); Heap* heap = isolate->heap(); +#ifdef DEBUG + // TODO(mstarzinger): Only because of the AssertNoContextChange, drop as soon + // as this method has been fully handlified. + HandleScope scope(isolate); +#endif + + // Make sure that the top context does not change when doing + // callbacks or interceptor calls. + AssertNoContextChange ncc(isolate); + // Traverse the prototype chain from the current object (this) to // the holder and check for access rights. This avoids traversing the // objects more than once in case of interceptors, because the @@ -849,11 +864,16 @@ MaybeObject* Object::GetProperty(Object* receiver, // property from the current object, we still check that we have // access to it. JSObject* checked = JSObject::cast(current); - if (!heap->isolate()->MayNamedAccess(checked, name, v8::ACCESS_GET)) { - return checked->GetPropertyWithFailedAccessCheck(receiver, - result, - name, - attributes); + if (!isolate->MayNamedAccess(checked, name, v8::ACCESS_GET)) { + HandleScope scope(isolate); + Handle<Object> value = JSObject::GetPropertyWithFailedAccessCheck( + handle(checked, isolate), + handle(receiver, isolate), + result, + handle(name, isolate), + attributes); + RETURN_IF_EMPTY_HANDLE(isolate, value); + return *value; } } // Stop traversing the chain once we reach the last object in the @@ -884,14 +904,28 @@ MaybeObject* Object::GetProperty(Object* receiver, } case CONSTANT: return result->GetConstant(); - case CALLBACKS: - return result->holder()->GetPropertyWithCallback( - receiver, result->GetCallbackObject(), name); + case CALLBACKS: { + HandleScope scope(isolate); + Handle<Object> value = JSObject::GetPropertyWithCallback( + handle(result->holder(), isolate), + handle(receiver, isolate), + handle(result->GetCallbackObject(), isolate), + handle(name, isolate)); + RETURN_IF_EMPTY_HANDLE(isolate, value); + return *value; + } case HANDLER: return result->proxy()->GetPropertyWithHandler(receiver, name); - case INTERCEPTOR: - return result->holder()->GetPropertyWithInterceptor( - receiver, name, attributes); + case INTERCEPTOR: { + HandleScope scope(isolate); + Handle<Object> value = JSObject::GetPropertyWithInterceptor( + handle(result->holder(), isolate), + handle(receiver, isolate), + handle(name, isolate), + attributes); + RETURN_IF_EMPTY_HANDLE(isolate, value); + return *value; + } case TRANSITION: case NONEXISTENT: UNREACHABLE(); @@ -1026,8 +1060,11 @@ bool Object::SameValue(Object* other) { if (IsNumber() && other->IsNumber()) { double this_value = Number(); double other_value = other->Number(); - return (this_value == other_value) || - (std::isnan(this_value) && std::isnan(other_value)); + bool equal = this_value == other_value; + // SameValue(NaN, NaN) is true. + if (!equal) return std::isnan(this_value) && std::isnan(other_value); + // SameValue(0.0, -0.0) is false. + return (this_value != 0) || ((1 / this_value) == (1 / other_value)); } if (IsString() && other->IsString()) { return String::cast(this)->Equals(String::cast(other)); @@ -1167,7 +1204,7 @@ bool String::MakeExternal(v8::String::ExternalStringResource* resource) { // Externalizing twice leaks the external resource, so it's // prohibited by the API. ASSERT(!this->IsExternalString()); -#ifdef DEBUG +#ifdef ENABLE_SLOW_ASSERTS if (FLAG_enable_slow_asserts) { // Assert that the resource and the string are equivalent. ASSERT(static_cast<size_t>(this->length()) == resource->length()); @@ -1224,7 +1261,7 @@ bool String::MakeExternal(v8::String::ExternalStringResource* resource) { bool String::MakeExternal(v8::String::ExternalAsciiStringResource* resource) { -#ifdef DEBUG +#ifdef ENABLE_SLOW_ASSERTS if (FLAG_enable_slow_asserts) { // Assert that the resource and the string are equivalent. ASSERT(static_cast<size_t>(this->length()) == resource->length()); @@ -1709,6 +1746,9 @@ void HeapObject::IterateBody(InstanceType type, int object_size, case FIXED_ARRAY_TYPE: FixedArray::BodyDescriptor::IterateBody(this, object_size, v); break; + case CONSTANT_POOL_ARRAY_TYPE: + reinterpret_cast<ConstantPoolArray*>(this)->ConstantPoolIterateBody(v); + break; case FIXED_DOUBLE_ARRAY_TYPE: break; case JS_OBJECT_TYPE: @@ -1871,211 +1911,248 @@ String* JSReceiver::constructor_name() { } -MaybeObject* JSObject::AddFastPropertyUsingMap(Map* new_map, - Name* name, - Object* value, - int field_index, - Representation representation) { +// TODO(mstarzinger): Temporary wrapper until handlified. +static Handle<Object> NewStorageFor(Isolate* isolate, + Handle<Object> object, + Representation representation) { + Heap* heap = isolate->heap(); + CALL_HEAP_FUNCTION(isolate, + object->AllocateNewStorageFor(heap, representation), + Object); +} + + +void JSObject::AddFastPropertyUsingMap(Handle<JSObject> object, + Handle<Map> new_map, + Handle<Name> name, + Handle<Object> value, + int field_index, + Representation representation) { + Isolate* isolate = object->GetIsolate(); + // This method is used to transition to a field. If we are transitioning to a // double field, allocate new storage. - Object* storage; - MaybeObject* maybe_storage = - value->AllocateNewStorageFor(GetHeap(), representation); - if (!maybe_storage->To(&storage)) return maybe_storage; + Handle<Object> storage = NewStorageFor(isolate, value, representation); - if (map()->unused_property_fields() == 0) { + if (object->map()->unused_property_fields() == 0) { int new_unused = new_map->unused_property_fields(); - FixedArray* values; - MaybeObject* maybe_values = - properties()->CopySize(properties()->length() + new_unused + 1); - if (!maybe_values->To(&values)) return maybe_values; + Handle<FixedArray> properties(object->properties()); + Handle<FixedArray> values = isolate->factory()->CopySizeFixedArray( + properties, properties->length() + new_unused + 1); + object->set_properties(*values); + } - set_properties(values); + object->set_map(*new_map); + object->FastPropertyAtPut(field_index, *storage); +} + + +static MaybeObject* CopyAddFieldDescriptor(Map* map, + Name* name, + int index, + PropertyAttributes attributes, + Representation representation, + TransitionFlag flag) { + Map* new_map; + FieldDescriptor new_field_desc(name, index, attributes, representation); + MaybeObject* maybe_map = map->CopyAddDescriptor(&new_field_desc, flag); + if (!maybe_map->To(&new_map)) return maybe_map; + int unused_property_fields = map->unused_property_fields() - 1; + if (unused_property_fields < 0) { + unused_property_fields += JSObject::kFieldsAdded; } + new_map->set_unused_property_fields(unused_property_fields); + return new_map; +} - set_map(new_map); - FastPropertyAtPut(field_index, storage); - return value; +static Handle<Map> CopyAddFieldDescriptor(Handle<Map> map, + Handle<Name> name, + int index, + PropertyAttributes attributes, + Representation representation, + TransitionFlag flag) { + CALL_HEAP_FUNCTION(map->GetIsolate(), + CopyAddFieldDescriptor( + *map, *name, index, attributes, representation, flag), + Map); } -MaybeObject* JSObject::AddFastProperty(Name* name, - Object* value, - PropertyAttributes attributes, - StoreFromKeyed store_mode, - ValueType value_type, - TransitionFlag flag) { - ASSERT(!IsJSGlobalProxy()); +void JSObject::AddFastProperty(Handle<JSObject> object, + Handle<Name> name, + Handle<Object> value, + PropertyAttributes attributes, + StoreFromKeyed store_mode, + ValueType value_type, + TransitionFlag flag) { + ASSERT(!object->IsJSGlobalProxy()); ASSERT(DescriptorArray::kNotFound == - map()->instance_descriptors()->Search( - name, map()->NumberOfOwnDescriptors())); + object->map()->instance_descriptors()->Search( + *name, object->map()->NumberOfOwnDescriptors())); // Normalize the object if the name is an actual name (not the // 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->IsCacheable(isolate) || TooManyFastProperties(store_mode)) { - MaybeObject* maybe_failure = - NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0); - if (maybe_failure->IsFailure()) return maybe_failure; - return AddSlowProperty(name, value, attributes); + Isolate* isolate = object->GetIsolate(); + if (!name->IsCacheable(isolate) || + object->TooManyFastProperties(store_mode)) { + NormalizeProperties(object, CLEAR_INOBJECT_PROPERTIES, 0); + AddSlowProperty(object, name, value, attributes); + return; } // Compute the new index for new field. - int index = map()->NextFreePropertyIndex(); + int index = object->map()->NextFreePropertyIndex(); // Allocate new instance descriptors with (name, index) added - if (IsJSContextExtensionObject()) value_type = FORCE_TAGGED; + if (object->IsJSContextExtensionObject()) value_type = FORCE_TAGGED; Representation representation = value->OptimalRepresentation(value_type); + Handle<Map> new_map = CopyAddFieldDescriptor( + handle(object->map()), name, index, attributes, representation, flag); - FieldDescriptor new_field(name, index, attributes, representation); - - Map* new_map; - MaybeObject* maybe_new_map = map()->CopyAddDescriptor(&new_field, flag); - if (!maybe_new_map->To(&new_map)) return maybe_new_map; + AddFastPropertyUsingMap(object, new_map, name, value, index, representation); +} - 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); - return AddFastPropertyUsingMap(new_map, name, value, index, representation); +static MaybeObject* CopyAddConstantDescriptor(Map* map, + Name* name, + Object* value, + PropertyAttributes attributes, + TransitionFlag flag) { + ConstantDescriptor new_constant_desc(name, value, attributes); + return map->CopyAddDescriptor(&new_constant_desc, flag); } -MaybeObject* JSObject::AddConstantProperty( - Name* name, - Object* constant, - PropertyAttributes attributes, - TransitionFlag initial_flag) { - // Allocate new instance descriptors with (name, constant) added - ConstantDescriptor d(name, constant, attributes); +static Handle<Map> CopyAddConstantDescriptor(Handle<Map> map, + Handle<Name> name, + Handle<Object> value, + PropertyAttributes attributes, + TransitionFlag flag) { + CALL_HEAP_FUNCTION(map->GetIsolate(), + CopyAddConstantDescriptor( + *map, *name, *value, attributes, flag), + Map); +} + +void JSObject::AddConstantProperty(Handle<JSObject> object, + Handle<Name> name, + Handle<Object> constant, + PropertyAttributes attributes, + TransitionFlag initial_flag) { TransitionFlag flag = // Do not add transitions to global objects. - (IsGlobalObject() || + (object->IsGlobalObject() || // Don't add transitions to special properties with non-trivial // attributes. attributes != NONE) ? OMIT_TRANSITION : initial_flag; - Map* new_map; - MaybeObject* maybe_new_map = map()->CopyAddDescriptor(&d, flag); - if (!maybe_new_map->To(&new_map)) return maybe_new_map; + // Allocate new instance descriptors with (name, constant) added. + Handle<Map> new_map = CopyAddConstantDescriptor( + handle(object->map()), name, constant, attributes, flag); - set_map(new_map); - return constant; + object->set_map(*new_map); } -// Add property in slow mode -MaybeObject* JSObject::AddSlowProperty(Name* name, - Object* value, - PropertyAttributes attributes) { - ASSERT(!HasFastProperties()); - NameDictionary* dict = property_dictionary(); - Object* store_value = value; - if (IsGlobalObject()) { +void JSObject::AddSlowProperty(Handle<JSObject> object, + Handle<Name> name, + Handle<Object> value, + PropertyAttributes attributes) { + ASSERT(!object->HasFastProperties()); + Isolate* isolate = object->GetIsolate(); + Handle<NameDictionary> dict(object->property_dictionary()); + if (object->IsGlobalObject()) { // In case name is an orphaned property reuse the cell. - int entry = dict->FindEntry(name); + int entry = dict->FindEntry(*name); if (entry != NameDictionary::kNotFound) { - store_value = dict->ValueAt(entry); - MaybeObject* maybe_type = - PropertyCell::cast(store_value)->SetValueInferType(value); - if (maybe_type->IsFailure()) return maybe_type; + Handle<PropertyCell> cell(PropertyCell::cast(dict->ValueAt(entry))); + PropertyCell::SetValueInferType(cell, value); // Assign an enumeration index to the property and update // SetNextEnumerationIndex. int index = dict->NextEnumerationIndex(); PropertyDetails details = PropertyDetails(attributes, NORMAL, index); dict->SetNextEnumerationIndex(index + 1); - dict->SetEntry(entry, name, store_value, details); - return value; - } - Heap* heap = GetHeap(); - { MaybeObject* maybe_store_value = - heap->AllocatePropertyCell(value); - if (!maybe_store_value->ToObject(&store_value)) return maybe_store_value; + dict->SetEntry(entry, *name, *cell, details); + return; } - MaybeObject* maybe_type = - PropertyCell::cast(store_value)->SetValueInferType(value); - if (maybe_type->IsFailure()) return maybe_type; + Handle<PropertyCell> cell = isolate->factory()->NewPropertyCell(value); + PropertyCell::SetValueInferType(cell, value); + value = cell; } PropertyDetails details = PropertyDetails(attributes, NORMAL, 0); - Object* result; - { MaybeObject* maybe_result = dict->Add(name, store_value, details); - if (!maybe_result->ToObject(&result)) return maybe_result; - } - if (dict != result) set_properties(NameDictionary::cast(result)); - return value; + Handle<NameDictionary> result = NameDictionaryAdd(dict, name, value, details); + if (*dict != *result) object->set_properties(*result); } -MaybeObject* JSObject::AddProperty(Name* name, - Object* value, - PropertyAttributes attributes, - StrictModeFlag strict_mode, - JSReceiver::StoreFromKeyed store_mode, - ExtensibilityCheck extensibility_check, - ValueType value_type, - StoreMode mode, - TransitionFlag transition_flag) { - ASSERT(!IsJSGlobalProxy()); - Map* map_of_this = map(); - Heap* heap = GetHeap(); - Isolate* isolate = heap->isolate(); - MaybeObject* result; +Handle<Object> JSObject::AddProperty(Handle<JSObject> object, + Handle<Name> name, + Handle<Object> value, + PropertyAttributes attributes, + StrictModeFlag strict_mode, + JSReceiver::StoreFromKeyed store_mode, + ExtensibilityCheck extensibility_check, + ValueType value_type, + StoreMode mode, + TransitionFlag transition_flag) { + ASSERT(!object->IsJSGlobalProxy()); + Isolate* isolate = object->GetIsolate(); + + if (!name->IsUniqueName()) { + name = isolate->factory()->InternalizedStringFromString( + Handle<String>::cast(name)); + } + if (extensibility_check == PERFORM_EXTENSIBILITY_CHECK && - !map_of_this->is_extensible()) { + !object->map()->is_extensible()) { if (strict_mode == kNonStrictMode) { return value; } else { - Handle<Object> args[1] = {Handle<Name>(name)}; - return isolate->Throw( - *isolate->factory()->NewTypeError("object_not_extensible", - HandleVector(args, 1))); + Handle<Object> args[1] = { name }; + Handle<Object> error = isolate->factory()->NewTypeError( + "object_not_extensible", HandleVector(args, ARRAY_SIZE(args))); + isolate->Throw(*error); + return Handle<Object>(); } } - if (HasFastProperties()) { + if (object->HasFastProperties()) { // Ensure the descriptor array does not get too big. - if (map_of_this->NumberOfOwnDescriptors() < + if (object->map()->NumberOfOwnDescriptors() < DescriptorArray::kMaxNumberOfDescriptors) { // TODO(verwaest): Support other constants. // if (mode == ALLOW_AS_CONSTANT && // !value->IsTheHole() && // !value->IsConsString()) { if (value->IsJSFunction()) { - result = AddConstantProperty(name, value, attributes, transition_flag); + AddConstantProperty(object, name, value, attributes, transition_flag); } else { - result = AddFastProperty( - name, value, attributes, store_mode, value_type, transition_flag); + AddFastProperty(object, name, value, attributes, store_mode, + value_type, transition_flag); } } else { // Normalize the object to prevent very large instance descriptors. // This eliminates unwanted N^2 allocation and lookup behavior. - Object* obj; - MaybeObject* maybe = NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0); - if (!maybe->To(&obj)) return maybe; - result = AddSlowProperty(name, value, attributes); + NormalizeProperties(object, CLEAR_INOBJECT_PROPERTIES, 0); + AddSlowProperty(object, name, value, attributes); } } else { - result = AddSlowProperty(name, value, attributes); + AddSlowProperty(object, name, value, attributes); } - Handle<Object> hresult; - if (!result->ToHandle(&hresult, isolate)) return result; - - if (FLAG_harmony_observation && map()->is_observed()) { - EnqueueChangeRecord(handle(this, isolate), - "new", - handle(name, isolate), - handle(heap->the_hole_value(), isolate)); + if (FLAG_harmony_observation && + object->map()->is_observed() && + *name != isolate->heap()->hidden_string()) { + Handle<Object> old_value = isolate->factory()->the_hole_value(); + EnqueueChangeRecord(object, "new", name, old_value); } - return *hresult; + return value; } @@ -2115,37 +2192,39 @@ void JSObject::DeliverChangeRecords(Isolate* isolate) { } -MaybeObject* JSObject::SetPropertyPostInterceptor( - Name* name, - Object* value, +Handle<Object> JSObject::SetPropertyPostInterceptor( + Handle<JSObject> object, + Handle<Name> name, + Handle<Object> value, PropertyAttributes attributes, - StrictModeFlag strict_mode, - StoreMode mode) { + StrictModeFlag strict_mode) { // Check local property, ignore interceptor. - LookupResult result(GetIsolate()); - LocalLookupRealNamedProperty(name, &result); - if (!result.IsFound()) map()->LookupTransition(this, name, &result); + LookupResult result(object->GetIsolate()); + object->LocalLookupRealNamedProperty(*name, &result); + if (!result.IsFound()) { + object->map()->LookupTransition(*object, *name, &result); + } if (result.IsFound()) { // An existing property or a map transition was found. Use set property to // handle all these cases. - return SetProperty(&result, name, value, attributes, strict_mode); + return SetPropertyForResult(object, &result, name, value, attributes, + strict_mode, MAY_BE_STORE_FROM_KEYED); } bool done = false; - MaybeObject* result_object = - SetPropertyViaPrototypes(name, value, attributes, strict_mode, &done); + Handle<Object> result_object = SetPropertyViaPrototypes( + object, 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, PERFORM_EXTENSIBILITY_CHECK, - OPTIMAL_REPRESENTATION, mode); + return AddProperty(object, name, value, attributes, strict_mode); } -MaybeObject* JSObject::ReplaceSlowProperty(Name* name, - Object* value, - PropertyAttributes attributes) { - NameDictionary* dictionary = property_dictionary(); - int old_index = dictionary->FindEntry(name); +static void ReplaceSlowProperty(Handle<JSObject> object, + Handle<Name> name, + Handle<Object> value, + PropertyAttributes attributes) { + NameDictionary* dictionary = object->property_dictionary(); + int old_index = dictionary->FindEntry(*name); int new_enumeration_index = 0; // 0 means "Use the next available index." if (old_index != -1) { // All calls to ReplaceSlowProperty have had all transitions removed. @@ -2153,7 +2232,7 @@ MaybeObject* JSObject::ReplaceSlowProperty(Name* name, } PropertyDetails new_details(attributes, NORMAL, new_enumeration_index); - return SetNormalizedProperty(name, value, new_details); + JSObject::SetNormalizedProperty(object, name, value, new_details); } @@ -2219,6 +2298,13 @@ static void RightTrimFixedArray(Heap* heap, FixedArray* elms, int to_trim) { MemoryChunk::IncrementLiveBytesFromMutator(elms->address(), -size_delta); } } + + // The array may not be moved during GC, + // and size has to be adjusted nevertheless. + HeapProfiler* profiler = heap->isolate()->heap_profiler(); + if (profiler->is_tracking_allocations()) { + profiler->UpdateObjectSizeEvent(elms->address(), elms->Size()); + } } @@ -2275,28 +2361,27 @@ bool Map::InstancesNeedRewriting(Map* target, // to temporarily store the inobject properties. // * If there are properties left in the backing store, install the backing // store. -MaybeObject* JSObject::MigrateToMap(Map* new_map) { - Heap* heap = GetHeap(); - Map* old_map = map(); +void JSObject::MigrateToMap(Handle<JSObject> object, Handle<Map> new_map) { + Isolate* isolate = object->GetIsolate(); + Handle<Map> old_map(object->map()); int number_of_fields = new_map->NumberOfFields(); int inobject = new_map->inobject_properties(); int unused = new_map->unused_property_fields(); - // Nothing to do if no functions were converted to fields. + // Nothing to do if no functions were converted to fields and no smis were + // converted to doubles. if (!old_map->InstancesNeedRewriting( - new_map, number_of_fields, inobject, unused)) { - set_map(new_map); - return this; + *new_map, number_of_fields, inobject, unused)) { + object->set_map(*new_map); + return; } int total_size = number_of_fields + unused; int external = total_size - inobject; - FixedArray* array; - MaybeObject* maybe_array = heap->AllocateFixedArray(total_size); - if (!maybe_array->To(&array)) return maybe_array; + Handle<FixedArray> array = isolate->factory()->NewFixedArray(total_size); - DescriptorArray* old_descriptors = old_map->instance_descriptors(); - DescriptorArray* new_descriptors = new_map->instance_descriptors(); + Handle<DescriptorArray> old_descriptors(old_map->instance_descriptors()); + Handle<DescriptorArray> new_descriptors(new_map->instance_descriptors()); int descriptors = new_map->NumberOfOwnDescriptors(); for (int i = 0; i < descriptors; i++) { @@ -2309,69 +2394,72 @@ MaybeObject* JSObject::MigrateToMap(Map* new_map) { } ASSERT(old_details.type() == CONSTANT || old_details.type() == FIELD); - Object* value = old_details.type() == CONSTANT + Object* raw_value = old_details.type() == CONSTANT ? old_descriptors->GetValue(i) - : RawFastPropertyAt(old_descriptors->GetFieldIndex(i)); + : object->RawFastPropertyAt(old_descriptors->GetFieldIndex(i)); + Handle<Object> value(raw_value, isolate); if (FLAG_track_double_fields && !old_details.representation().IsDouble() && details.representation().IsDouble()) { - if (old_details.representation().IsNone()) value = Smi::FromInt(0); - // Objects must be allocated in the old object space, since the - // overall number of HeapNumbers needed for the conversion might - // exceed the capacity of new space, and we would fail repeatedly - // trying to migrate the instance. - MaybeObject* maybe_storage = - value->AllocateNewStorageFor(heap, details.representation(), TENURED); - if (!maybe_storage->To(&value)) return maybe_storage; + if (old_details.representation().IsNone()) { + value = handle(Smi::FromInt(0), isolate); + } + value = NewStorageFor(isolate, value, details.representation()); } ASSERT(!(FLAG_track_double_fields && details.representation().IsDouble() && value->IsSmi())); int target_index = new_descriptors->GetFieldIndex(i) - inobject; if (target_index < 0) target_index += total_size; - array->set(target_index, value); + array->set(target_index, *value); } - // From here on we cannot fail anymore. + // From here on we cannot fail and we shouldn't GC anymore. + DisallowHeapAllocation no_allocation; // Copy (real) inobject properties. If necessary, stop at number_of_fields to // avoid overwriting |one_pointer_filler_map|. int limit = Min(inobject, number_of_fields); for (int i = 0; i < limit; i++) { - FastPropertyAtPut(i, array->get(external + i)); + object->FastPropertyAtPut(i, array->get(external + i)); } // Create filler object past the new instance size. int new_instance_size = new_map->instance_size(); int instance_size_delta = old_map->instance_size() - new_instance_size; ASSERT(instance_size_delta >= 0); - Address address = this->address() + new_instance_size; - heap->CreateFillerObjectAt(address, instance_size_delta); + Address address = object->address() + new_instance_size; + isolate->heap()->CreateFillerObjectAt(address, instance_size_delta); // If there are properties in the new backing store, trim it to the correct // size and install the backing store into the object. if (external > 0) { - RightTrimFixedArray<FROM_MUTATOR>(heap, array, inobject); - set_properties(array); + RightTrimFixedArray<FROM_MUTATOR>(isolate->heap(), *array, inobject); + object->set_properties(*array); } - set_map(new_map); - - return this; + object->set_map(*new_map); } -MaybeObject* JSObject::GeneralizeFieldRepresentation( - int modify_index, - Representation new_representation, - StoreMode store_mode) { - Map* new_map; - 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; +Handle<TransitionArray> Map::AddTransition(Handle<Map> map, + Handle<Name> key, + Handle<Map> target, + SimpleTransitionFlag flag) { + CALL_HEAP_FUNCTION(map->GetIsolate(), + map->AddTransition(*key, *target, flag), + TransitionArray); +} + - return MigrateToMap(new_map); +void JSObject::GeneralizeFieldRepresentation(Handle<JSObject> object, + int modify_index, + Representation new_representation, + StoreMode store_mode) { + Handle<Map> new_map = Map::GeneralizeRepresentation( + handle(object->map()), modify_index, new_representation, store_mode); + if (object->map() == *new_map) return; + return MigrateToMap(object, new_map); } @@ -2385,14 +2473,12 @@ int Map::NumberOfFields() { } -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; +Handle<Map> Map::CopyGeneralizeAllRepresentations(Handle<Map> map, + int modify_index, + StoreMode store_mode, + PropertyAttributes attributes, + const char* reason) { + Handle<Map> new_map = Copy(map); DescriptorArray* descriptors = new_map->instance_descriptors(); descriptors->InitializeRepresentations(Representation::Tagged()); @@ -2414,7 +2500,7 @@ MaybeObject* Map::CopyGeneralizeAllRepresentations( } if (FLAG_trace_generalization) { - PrintGeneralization(stdout, reason, modify_index, + map->PrintGeneralization(stdout, reason, modify_index, new_map->NumberOfOwnDescriptors(), new_map->NumberOfOwnDescriptors(), details.type() == CONSTANT && store_mode == FORCE_FIELD, @@ -2562,11 +2648,11 @@ Map* Map::FindLastMatchMap(int verbatim, // - If |updated| == |split_map|, |updated| is in the expected state. Return it. // - 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, - StoreMode store_mode) { - Map* old_map = this; - DescriptorArray* old_descriptors = old_map->instance_descriptors(); +Handle<Map> Map::GeneralizeRepresentation(Handle<Map> old_map, + int modify_index, + Representation new_representation, + StoreMode store_mode) { + Handle<DescriptorArray> old_descriptors(old_map->instance_descriptors()); PropertyDetails old_details = old_descriptors->GetDetails(modify_index); Representation old_representation = old_details.representation(); @@ -2582,37 +2668,37 @@ MaybeObject* Map::GeneralizeRepresentation(int modify_index, } int descriptors = old_map->NumberOfOwnDescriptors(); - Map* root_map = old_map->FindRootMap(); + Handle<Map> root_map(old_map->FindRootMap()); // Check the state of the root map. - if (!old_map->EquivalentToForTransition(root_map)) { - return CopyGeneralizeAllRepresentations( - modify_index, store_mode, old_details.attributes(), "not equivalent"); + if (!old_map->EquivalentToForTransition(*root_map)) { + return CopyGeneralizeAllRepresentations(old_map, 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, + return CopyGeneralizeAllRepresentations(old_map, modify_index, store_mode, old_details.attributes(), "root modification"); } - Map* updated = root_map->FindUpdatedMap( - verbatim, descriptors, old_descriptors); - if (updated == NULL) { - return CopyGeneralizeAllRepresentations( - modify_index, store_mode, old_details.attributes(), "incompatible"); + Map* raw_updated = root_map->FindUpdatedMap( + verbatim, descriptors, *old_descriptors); + if (raw_updated == NULL) { + return CopyGeneralizeAllRepresentations(old_map, modify_index, store_mode, + old_details.attributes(), "incompatible"); } - DescriptorArray* updated_descriptors = updated->instance_descriptors(); + Handle<Map> updated(raw_updated); + Handle<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 = @@ -2620,10 +2706,9 @@ MaybeObject* Map::GeneralizeRepresentation(int modify_index, if (new_representation.fits_into(updated_representation)) return updated; } - DescriptorArray* new_descriptors; - MaybeObject* maybe_descriptors = updated_descriptors->Merge( - verbatim, valid, descriptors, modify_index, store_mode, old_descriptors); - if (!maybe_descriptors->To(&new_descriptors)) return maybe_descriptors; + Handle<DescriptorArray> new_descriptors = DescriptorArray::Merge( + updated_descriptors, verbatim, valid, descriptors, modify_index, + store_mode, old_descriptors); ASSERT(store_mode == ALLOW_AS_CONSTANT || new_descriptors->GetDetails(modify_index).type() == FIELD); @@ -2635,8 +2720,8 @@ MaybeObject* Map::GeneralizeRepresentation(int modify_index, new_descriptors->SetRepresentation(modify_index, updated_representation); } - Map* split_map = root_map->FindLastMatchMap( - verbatim, descriptors, new_descriptors); + Handle<Map> split_map(root_map->FindLastMatchMap( + verbatim, descriptors, *new_descriptors)); int split_descriptors = split_map->NumberOfOwnDescriptors(); // This is shadowed by |updated_descriptors| being more general than @@ -2645,28 +2730,20 @@ MaybeObject* Map::GeneralizeRepresentation(int modify_index, int descriptor = split_descriptors; split_map->DeprecateTarget( - old_descriptors->GetKey(descriptor), new_descriptors); + old_descriptors->GetKey(descriptor), *new_descriptors); if (FLAG_trace_generalization) { - PrintGeneralization( + old_map->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; // Add missing transitions. + Handle<Map> new_map = split_map; for (; descriptor < descriptors; descriptor++) { - MaybeObject* maybe_map = new_map->CopyInstallDescriptors( - descriptor, new_descriptors); - if (!maybe_map->To(&new_map)) { - // Create a handle for the last created map to ensure it stays alive - // during GC. Its descriptor array is too large, but it will be - // overwritten during retry anyway. - Handle<Map>(new_map); - return maybe_map; - } + new_map = Map::CopyInstallDescriptors(new_map, descriptor, new_descriptors); new_map->set_migration_target(true); } @@ -2675,6 +2752,21 @@ MaybeObject* Map::GeneralizeRepresentation(int modify_index, } +// Generalize the representation of all FIELD descriptors. +Handle<Map> Map::GeneralizeAllFieldRepresentations( + Handle<Map> map, + Representation new_representation) { + Handle<DescriptorArray> descriptors(map->instance_descriptors()); + for (int i = 0; i < map->NumberOfOwnDescriptors(); i++) { + PropertyDetails details = descriptors->GetDetails(i); + if (details.type() == FIELD) { + map = GeneralizeRepresentation(map, i, new_representation, FORCE_FIELD); + } + } + return map; +} + + Map* Map::CurrentMapForDeprecated() { DisallowHeapAllocation no_allocation; if (!is_deprecated()) return this; @@ -2703,94 +2795,66 @@ Map* Map::CurrentMapForDeprecated() { } -MaybeObject* JSObject::SetPropertyWithInterceptor( - Name* name, - Object* value, +Handle<Object> JSObject::SetPropertyWithInterceptor( + Handle<JSObject> object, + Handle<Name> name, + Handle<Object> value, PropertyAttributes attributes, StrictModeFlag strict_mode) { // TODO(rossberg): Support symbols in the API. if (name->IsSymbol()) return value; - Isolate* isolate = GetIsolate(); - HandleScope scope(isolate); - Handle<JSObject> this_handle(this); - Handle<String> name_handle(String::cast(name)); - Handle<Object> value_handle(value, isolate); - Handle<InterceptorInfo> interceptor(GetNamedInterceptor()); + Isolate* isolate = object->GetIsolate(); + Handle<String> name_string = Handle<String>::cast(name); + Handle<InterceptorInfo> interceptor(object->GetNamedInterceptor()); if (!interceptor->setter()->IsUndefined()) { - LOG(isolate, ApiNamedPropertyAccess("interceptor-named-set", this, name)); - PropertyCallbackArguments args(isolate, interceptor->data(), this, this); + LOG(isolate, + ApiNamedPropertyAccess("interceptor-named-set", *object, *name)); + PropertyCallbackArguments args( + isolate, interceptor->data(), *object, *object); v8::NamedPropertySetterCallback setter = v8::ToCData<v8::NamedPropertySetterCallback>(interceptor->setter()); - Handle<Object> value_unhole(value->IsTheHole() ? - isolate->heap()->undefined_value() : - value, - isolate); + Handle<Object> value_unhole = value->IsTheHole() + ? Handle<Object>(isolate->factory()->undefined_value()) : value; v8::Handle<v8::Value> result = args.Call(setter, - v8::Utils::ToLocal(name_handle), + v8::Utils::ToLocal(name_string), v8::Utils::ToLocal(value_unhole)); - RETURN_IF_SCHEDULED_EXCEPTION(isolate); - if (!result.IsEmpty()) return *value_handle; + RETURN_HANDLE_IF_SCHEDULED_EXCEPTION(isolate, Object); + if (!result.IsEmpty()) return value; } - MaybeObject* raw_result = - this_handle->SetPropertyPostInterceptor(*name_handle, - *value_handle, - attributes, - strict_mode); - RETURN_IF_SCHEDULED_EXCEPTION(isolate); - return raw_result; + Handle<Object> result = + SetPropertyPostInterceptor(object, name, value, attributes, strict_mode); + RETURN_HANDLE_IF_SCHEDULED_EXCEPTION(isolate, Object); + return result; } Handle<Object> JSReceiver::SetProperty(Handle<JSReceiver> object, - Handle<Name> key, + Handle<Name> name, Handle<Object> value, PropertyAttributes attributes, - StrictModeFlag strict_mode) { - CALL_HEAP_FUNCTION(object->GetIsolate(), - object->SetProperty(*key, *value, attributes, strict_mode), - Object); -} - - -MaybeObject* JSReceiver::SetPropertyOrFail( - Handle<JSReceiver> object, - Handle<Name> key, - Handle<Object> value, - PropertyAttributes attributes, - StrictModeFlag strict_mode, - JSReceiver::StoreFromKeyed store_mode) { - CALL_HEAP_FUNCTION_PASS_EXCEPTION( - object->GetIsolate(), - object->SetProperty(*key, *value, attributes, strict_mode, store_mode)); -} - - -MaybeObject* JSReceiver::SetProperty(Name* name, - Object* value, - PropertyAttributes attributes, - StrictModeFlag strict_mode, - JSReceiver::StoreFromKeyed store_mode) { - LookupResult result(GetIsolate()); - LocalLookup(name, &result, true); + StrictModeFlag strict_mode, + StoreFromKeyed store_mode) { + LookupResult result(object->GetIsolate()); + object->LocalLookup(*name, &result, true); if (!result.IsFound()) { - map()->LookupTransition(JSObject::cast(this), name, &result); + object->map()->LookupTransition(JSObject::cast(*object), *name, &result); } - return SetProperty(&result, name, value, attributes, strict_mode, store_mode); + return SetProperty(object, &result, name, value, attributes, strict_mode, + store_mode); } -MaybeObject* JSObject::SetPropertyWithCallback(Object* structure, - Name* name, - Object* value, - JSObject* holder, - StrictModeFlag strict_mode) { - Isolate* isolate = GetIsolate(); - HandleScope scope(isolate); +Handle<Object> JSObject::SetPropertyWithCallback(Handle<JSObject> object, + Handle<Object> structure, + Handle<Name> name, + Handle<Object> value, + Handle<JSObject> holder, + StrictModeFlag strict_mode) { + Isolate* isolate = object->GetIsolate(); // We should never get here to initialize a const with the hole // value since a const declaration would conflict with the setter. ASSERT(!value->IsTheHole()); - Handle<Object> value_handle(value, isolate); // To accommodate both the old and the new api we switch on the // data structure used to store the callbacks. Eventually foreign @@ -2798,26 +2862,27 @@ MaybeObject* JSObject::SetPropertyWithCallback(Object* structure, if (structure->IsForeign()) { AccessorDescriptor* callback = reinterpret_cast<AccessorDescriptor*>( - Foreign::cast(structure)->foreign_address()); - MaybeObject* obj = (callback->setter)( - isolate, this, value, callback->data); - RETURN_IF_SCHEDULED_EXCEPTION(isolate); - if (obj->IsFailure()) return obj; - return *value_handle; + Handle<Foreign>::cast(structure)->foreign_address()); + CALL_AND_RETRY_OR_DIE(isolate, + (callback->setter)( + isolate, *object, *value, callback->data), + break, + return Handle<Object>()); + RETURN_HANDLE_IF_SCHEDULED_EXCEPTION(isolate, Object); + return value; } if (structure->IsExecutableAccessorInfo()) { // api style callbacks - ExecutableAccessorInfo* data = ExecutableAccessorInfo::cast(structure); - if (!data->IsCompatibleReceiver(this)) { - Handle<Object> name_handle(name, isolate); - Handle<Object> receiver_handle(this, isolate); - Handle<Object> args[2] = { name_handle, receiver_handle }; + ExecutableAccessorInfo* data = ExecutableAccessorInfo::cast(*structure); + if (!data->IsCompatibleReceiver(*object)) { + Handle<Object> args[2] = { name, object }; Handle<Object> error = isolate->factory()->NewTypeError("incompatible_method_receiver", HandleVector(args, ARRAY_SIZE(args))); - return isolate->Throw(*error); + isolate->Throw(*error); + return Handle<Object>(); } // TODO(rossberg): Support symbols in the API. if (name->IsSymbol()) return value; @@ -2825,32 +2890,33 @@ MaybeObject* JSObject::SetPropertyWithCallback(Object* structure, 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)); + Handle<String> key = Handle<String>::cast(name); + LOG(isolate, ApiNamedPropertyAccess("store", *object, *name)); PropertyCallbackArguments args( - isolate, data->data(), this, JSObject::cast(holder)); + isolate, data->data(), *object, JSObject::cast(*holder)); args.Call(call_fun, v8::Utils::ToLocal(key), - v8::Utils::ToLocal(value_handle)); - RETURN_IF_SCHEDULED_EXCEPTION(isolate); - return *value_handle; + v8::Utils::ToLocal(value)); + RETURN_HANDLE_IF_SCHEDULED_EXCEPTION(isolate, Object); + return value; } if (structure->IsAccessorPair()) { - Object* setter = AccessorPair::cast(structure)->setter(); + Handle<Object> setter(AccessorPair::cast(*structure)->setter(), isolate); if (setter->IsSpecFunction()) { // TODO(rossberg): nicer would be to cast to some JSCallable here... - return SetPropertyWithDefinedSetter(JSReceiver::cast(setter), value); + return SetPropertyWithDefinedSetter( + object, Handle<JSReceiver>::cast(setter), value); } else { if (strict_mode == kNonStrictMode) { return value; } - Handle<Name> key(name); - Handle<Object> holder_handle(holder, isolate); - Handle<Object> args[2] = { key, holder_handle }; - return isolate->Throw( - *isolate->factory()->NewTypeError("no_setter_in_callback", - HandleVector(args, 2))); + Handle<Object> args[2] = { name, holder }; + Handle<Object> error = + isolate->factory()->NewTypeError("no_setter_in_callback", + HandleVector(args, 2)); + isolate->Throw(*error); + return Handle<Object>(); } } @@ -2860,32 +2926,33 @@ MaybeObject* JSObject::SetPropertyWithCallback(Object* structure, } UNREACHABLE(); - return NULL; + return Handle<Object>(); } -MaybeObject* JSReceiver::SetPropertyWithDefinedSetter(JSReceiver* setter, - Object* value) { - Isolate* isolate = GetIsolate(); - Handle<Object> value_handle(value, isolate); - Handle<JSReceiver> fun(setter, isolate); - Handle<JSReceiver> self(this, isolate); +Handle<Object> JSReceiver::SetPropertyWithDefinedSetter( + Handle<JSReceiver> object, + Handle<JSReceiver> setter, + Handle<Object> value) { + Isolate* isolate = object->GetIsolate(); + #ifdef ENABLE_DEBUGGER_SUPPORT Debug* debug = isolate->debug(); // Handle stepping into a setter if step into is active. // TODO(rossberg): should this apply to getters that are function proxies? - if (debug->StepInActive() && fun->IsJSFunction()) { + if (debug->StepInActive() && setter->IsJSFunction()) { debug->HandleStepIn( - Handle<JSFunction>::cast(fun), Handle<Object>::null(), 0, false); + Handle<JSFunction>::cast(setter), Handle<Object>::null(), 0, false); } #endif + bool has_pending_exception; - Handle<Object> argv[] = { value_handle }; + Handle<Object> argv[] = { value }; Execution::Call( - isolate, fun, self, ARRAY_SIZE(argv), argv, &has_pending_exception); + isolate, setter, object, 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; + if (has_pending_exception) return Handle<Object>(); + return value; } @@ -2899,14 +2966,16 @@ MaybeObject* JSObject::SetElementWithCallbackSetterInPrototypes( pt != heap->null_value(); pt = pt->GetPrototype(GetIsolate())) { if (pt->IsJSProxy()) { - String* name; - MaybeObject* maybe = heap->Uint32ToString(index); - if (!maybe->To<String>(&name)) { - *found = true; // Force abort - return maybe; - } - return JSProxy::cast(pt)->SetPropertyViaPrototypesWithHandler( - this, name, value, NONE, strict_mode, found); + Isolate* isolate = GetIsolate(); + HandleScope scope(isolate); + Handle<JSProxy> proxy(JSProxy::cast(pt)); + Handle<JSObject> self(this, isolate); + Handle<String> name = isolate->factory()->Uint32ToString(index); + Handle<Object> value_handle(value, isolate); + Handle<Object> result = JSProxy::SetPropertyViaPrototypesWithHandler( + proxy, self, name, value_handle, NONE, strict_mode, found); + RETURN_IF_EMPTY_HANDLE(isolate, result); + return *result; } if (!JSObject::cast(pt)->HasDictionaryElements()) { continue; @@ -2918,11 +2987,16 @@ MaybeObject* JSObject::SetElementWithCallbackSetterInPrototypes( PropertyDetails details = dictionary->DetailsAt(entry); if (details.type() == CALLBACKS) { *found = true; - return SetElementWithCallback(dictionary->ValueAt(entry), - index, - value, - JSObject::cast(pt), - strict_mode); + Isolate* isolate = GetIsolate(); + HandleScope scope(isolate); + Handle<JSObject> self(this, isolate); + Handle<Object> structure(dictionary->ValueAt(entry), isolate); + Handle<Object> value_handle(value, isolate); + Handle<JSObject> holder(JSObject::cast(pt)); + Handle<Object> result = SetElementWithCallback( + self, structure, index, value_handle, holder, strict_mode); + RETURN_IF_EMPTY_HANDLE(isolate, result); + return *result; } } } @@ -2930,21 +3004,21 @@ MaybeObject* JSObject::SetElementWithCallbackSetterInPrototypes( return heap->the_hole_value(); } -MaybeObject* JSObject::SetPropertyViaPrototypes( - Name* name, - Object* value, - PropertyAttributes attributes, - StrictModeFlag strict_mode, - bool* done) { - Heap* heap = GetHeap(); - Isolate* isolate = heap->isolate(); + +Handle<Object> JSObject::SetPropertyViaPrototypes(Handle<JSObject> object, + Handle<Name> name, + Handle<Object> value, + PropertyAttributes attributes, + StrictModeFlag strict_mode, + bool* done) { + Isolate* isolate = object->GetIsolate(); *done = false; // We could not find a local property so let's check whether there is an // accessor that wants to handle the property, or whether the property is // read-only on the prototype chain. LookupResult result(isolate); - LookupRealNamedPropertyInPrototypes(name, &result); + object->LookupRealNamedPropertyInPrototypes(*name, &result); if (result.IsFound()) { switch (result.type()) { case NORMAL: @@ -2955,19 +3029,21 @@ MaybeObject* JSObject::SetPropertyViaPrototypes( case INTERCEPTOR: { PropertyAttributes attr = result.holder()->GetPropertyAttributeWithInterceptor( - this, name, true); + *object, *name, true); *done = !!(attr & READ_ONLY); break; } case CALLBACKS: { if (!FLAG_es5_readonly && result.IsReadOnly()) break; *done = true; - return SetPropertyWithCallback(result.GetCallbackObject(), - name, value, result.holder(), strict_mode); + Handle<Object> callback_object(result.GetCallbackObject(), isolate); + return SetPropertyWithCallback(object, callback_object, name, value, + handle(result.holder()), strict_mode); } case HANDLER: { - return result.proxy()->SetPropertyViaPrototypesWithHandler( - this, name, value, attributes, strict_mode, done); + Handle<JSProxy> proxy(result.proxy()); + return JSProxy::SetPropertyViaPrototypesWithHandler( + proxy, object, name, value, attributes, strict_mode, done); } case TRANSITION: case NONEXISTENT: @@ -2980,12 +3056,13 @@ MaybeObject* JSObject::SetPropertyViaPrototypes( if (!FLAG_es5_readonly) *done = false; if (*done) { if (strict_mode == kNonStrictMode) return value; - Handle<Object> args[] = { Handle<Object>(name, isolate), - Handle<Object>(this, isolate)}; - return isolate->Throw(*isolate->factory()->NewTypeError( - "strict_read_only_property", HandleVector(args, ARRAY_SIZE(args)))); + Handle<Object> args[] = { name, object }; + Handle<Object> error = isolate->factory()->NewTypeError( + "strict_read_only_property", HandleVector(args, ARRAY_SIZE(args))); + isolate->Throw(*error); + return Handle<Object>(); } - return heap->the_hole_value(); + return isolate->factory()->the_hole_value(); } @@ -3340,14 +3417,15 @@ void JSObject::LookupRealNamedPropertyInPrototypes(Name* name, // We only need to deal with CALLBACKS and INTERCEPTORS -MaybeObject* JSObject::SetPropertyWithFailedAccessCheck( +Handle<Object> JSObject::SetPropertyWithFailedAccessCheck( + Handle<JSObject> object, LookupResult* result, - Name* name, - Object* value, + Handle<Name> name, + Handle<Object> value, bool check_prototype, StrictModeFlag strict_mode) { if (check_prototype && !result->IsProperty()) { - LookupRealNamedPropertyInPrototypes(name, result); + object->LookupRealNamedPropertyInPrototypes(*name, result); } if (result->IsProperty()) { @@ -3356,21 +3434,23 @@ MaybeObject* JSObject::SetPropertyWithFailedAccessCheck( case CALLBACKS: { Object* obj = result->GetCallbackObject(); if (obj->IsAccessorInfo()) { - AccessorInfo* info = AccessorInfo::cast(obj); + Handle<AccessorInfo> info(AccessorInfo::cast(obj)); if (info->all_can_write()) { - return SetPropertyWithCallback(result->GetCallbackObject(), + return SetPropertyWithCallback(object, + info, name, value, - result->holder(), + handle(result->holder()), strict_mode); } } else if (obj->IsAccessorPair()) { - AccessorPair* pair = AccessorPair::cast(obj); + Handle<AccessorPair> pair(AccessorPair::cast(obj)); if (pair->all_can_read()) { - return SetPropertyWithCallback(result->GetCallbackObject(), + return SetPropertyWithCallback(object, + pair, name, value, - result->holder(), + handle(result->holder()), strict_mode); } } @@ -3379,10 +3459,11 @@ MaybeObject* JSObject::SetPropertyWithFailedAccessCheck( case INTERCEPTOR: { // Try lookup real named properties. Note that only property can be // set is callbacks marked as ALL_CAN_WRITE on the prototype chain. - LookupResult r(GetIsolate()); - LookupRealNamedProperty(name, &r); + LookupResult r(object->GetIsolate()); + object->LookupRealNamedProperty(*name, &r); if (r.IsProperty()) { - return SetPropertyWithFailedAccessCheck(&r, + return SetPropertyWithFailedAccessCheck(object, + &r, name, value, check_prototype, @@ -3397,42 +3478,38 @@ MaybeObject* JSObject::SetPropertyWithFailedAccessCheck( } } - Isolate* isolate = GetIsolate(); - HandleScope scope(isolate); - Handle<Object> value_handle(value, isolate); - isolate->ReportFailedAccessCheck(this, v8::ACCESS_SET); - RETURN_IF_SCHEDULED_EXCEPTION(isolate); - return *value_handle; + Isolate* isolate = object->GetIsolate(); + isolate->ReportFailedAccessCheck(*object, v8::ACCESS_SET); + RETURN_HANDLE_IF_SCHEDULED_EXCEPTION(isolate, Object); + return value; } -MaybeObject* JSReceiver::SetProperty(LookupResult* result, - Name* key, - Object* value, - PropertyAttributes attributes, - StrictModeFlag strict_mode, - JSReceiver::StoreFromKeyed store_mode) { +Handle<Object> JSReceiver::SetProperty(Handle<JSReceiver> object, + LookupResult* result, + Handle<Name> key, + Handle<Object> value, + PropertyAttributes attributes, + StrictModeFlag strict_mode, + StoreFromKeyed store_mode) { if (result->IsHandler()) { - return result->proxy()->SetPropertyWithHandler( - this, key, value, attributes, strict_mode); + return JSProxy::SetPropertyWithHandler(handle(result->proxy()), + object, key, value, attributes, strict_mode); } else { - return JSObject::cast(this)->SetPropertyForResult( + return JSObject::SetPropertyForResult(Handle<JSObject>::cast(object), result, key, value, attributes, strict_mode, store_mode); } } -bool JSProxy::HasPropertyWithHandler(Name* name_raw) { - Isolate* isolate = GetIsolate(); - HandleScope scope(isolate); - Handle<Object> receiver(this, isolate); - Handle<Object> name(name_raw, isolate); +bool JSProxy::HasPropertyWithHandler(Handle<JSProxy> proxy, Handle<Name> name) { + Isolate* isolate = proxy->GetIsolate(); // TODO(rossberg): adjust once there is a story for symbols vs proxies. if (name->IsSymbol()) return false; Handle<Object> args[] = { name }; - Handle<Object> result = CallTrap( + Handle<Object> result = proxy->CallTrap( "has", isolate->derived_has_trap(), ARRAY_SIZE(args), args); if (isolate->has_pending_exception()) return false; @@ -3440,58 +3517,51 @@ bool JSProxy::HasPropertyWithHandler(Name* name_raw) { } -MUST_USE_RESULT MaybeObject* JSProxy::SetPropertyWithHandler( - JSReceiver* receiver_raw, - Name* name_raw, - Object* value_raw, - PropertyAttributes attributes, - StrictModeFlag strict_mode) { - Isolate* isolate = GetIsolate(); - HandleScope scope(isolate); - Handle<JSReceiver> receiver(receiver_raw); - Handle<Object> name(name_raw, isolate); - Handle<Object> value(value_raw, isolate); +Handle<Object> JSProxy::SetPropertyWithHandler(Handle<JSProxy> proxy, + Handle<JSReceiver> receiver, + Handle<Name> name, + Handle<Object> value, + PropertyAttributes attributes, + StrictModeFlag strict_mode) { + Isolate* isolate = proxy->GetIsolate(); // TODO(rossberg): adjust once there is a story for symbols vs proxies. - if (name->IsSymbol()) return *value; + if (name->IsSymbol()) return value; Handle<Object> args[] = { receiver, name, value }; - CallTrap("set", isolate->derived_set_trap(), ARRAY_SIZE(args), args); - if (isolate->has_pending_exception()) return Failure::Exception(); + proxy->CallTrap("set", isolate->derived_set_trap(), ARRAY_SIZE(args), args); + if (isolate->has_pending_exception()) return Handle<Object>(); - return *value; + return value; } -MUST_USE_RESULT MaybeObject* JSProxy::SetPropertyViaPrototypesWithHandler( - JSReceiver* receiver_raw, - Name* name_raw, - Object* value_raw, +Handle<Object> JSProxy::SetPropertyViaPrototypesWithHandler( + Handle<JSProxy> proxy, + Handle<JSReceiver> receiver, + Handle<Name> name, + Handle<Object> value, PropertyAttributes attributes, StrictModeFlag strict_mode, bool* done) { - Isolate* isolate = GetIsolate(); - Handle<JSProxy> proxy(this); - Handle<JSReceiver> receiver(receiver_raw); - Handle<Name> name(name_raw); - Handle<Object> value(value_raw, isolate); - Handle<Object> handler(this->handler(), isolate); // Trap might morph proxy. + Isolate* isolate = proxy->GetIsolate(); + Handle<Object> handler(proxy->handler(), isolate); // Trap might morph proxy. // TODO(rossberg): adjust once there is a story for symbols vs proxies. if (name->IsSymbol()) { *done = false; - return isolate->heap()->the_hole_value(); + return isolate->factory()->the_hole_value(); } *done = true; // except where redefined... Handle<Object> args[] = { name }; Handle<Object> result = proxy->CallTrap( "getPropertyDescriptor", Handle<Object>(), ARRAY_SIZE(args), args); - if (isolate->has_pending_exception()) return Failure::Exception(); + if (isolate->has_pending_exception()) return Handle<Object>(); if (result->IsUndefined()) { *done = false; - return isolate->heap()->the_hole_value(); + return isolate->factory()->the_hole_value(); } // Emulate [[GetProperty]] semantics for proxies. @@ -3500,7 +3570,7 @@ MUST_USE_RESULT MaybeObject* JSProxy::SetPropertyViaPrototypesWithHandler( 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(); + if (has_pending_exception) return Handle<Object>(); // [[GetProperty]] requires to check that all properties are configurable. Handle<String> configurable_name = @@ -3517,7 +3587,8 @@ MUST_USE_RESULT MaybeObject* JSProxy::SetPropertyViaPrototypesWithHandler( Handle<Object> args[] = { handler, trap, name }; Handle<Object> error = isolate->factory()->NewTypeError( "proxy_prop_not_configurable", HandleVector(args, ARRAY_SIZE(args))); - return isolate->Throw(*error); + isolate->Throw(*error); + return Handle<Object>(); } ASSERT(configurable->IsTrue()); @@ -3538,12 +3609,13 @@ MUST_USE_RESULT MaybeObject* JSProxy::SetPropertyViaPrototypesWithHandler( ASSERT(!isolate->has_pending_exception()); ASSERT(writable->IsTrue() || writable->IsFalse()); *done = writable->IsFalse(); - if (!*done) return GetHeap()->the_hole_value(); - if (strict_mode == kNonStrictMode) return *value; + if (!*done) return isolate->factory()->the_hole_value(); + if (strict_mode == kNonStrictMode) return value; Handle<Object> args[] = { name, receiver }; Handle<Object> error = isolate->factory()->NewTypeError( "strict_read_only_property", HandleVector(args, ARRAY_SIZE(args))); - return isolate->Throw(*error); + isolate->Throw(*error); + return Handle<Object>(); } // We have an AccessorDescriptor. @@ -3553,15 +3625,16 @@ MUST_USE_RESULT MaybeObject* JSProxy::SetPropertyViaPrototypesWithHandler( ASSERT(!isolate->has_pending_exception()); if (!setter->IsUndefined()) { // TODO(rossberg): nicer would be to cast to some JSCallable here... - return receiver->SetPropertyWithDefinedSetter( - JSReceiver::cast(*setter), *value); + return SetPropertyWithDefinedSetter( + receiver, Handle<JSReceiver>::cast(setter), value); } - if (strict_mode == kNonStrictMode) return *value; + if (strict_mode == kNonStrictMode) return value; Handle<Object> args2[] = { name, proxy }; Handle<Object> error = isolate->factory()->NewTypeError( "no_setter_in_callback", HandleVector(args2, ARRAY_SIZE(args2))); - return isolate->Throw(*error); + isolate->Throw(*error); + return Handle<Object>(); } @@ -3726,44 +3799,74 @@ MUST_USE_RESULT Handle<Object> JSProxy::CallTrap(const char* name, } -void JSObject::AllocateStorageForMap(Handle<JSObject> object, Handle<Map> map) { - CALL_HEAP_FUNCTION_VOID( - object->GetIsolate(), - object->AllocateStorageForMap(*map)); +// TODO(mstarzinger): Temporary wrapper until handlified. +static Handle<Map> MapAsElementsKind(Handle<Map> map, ElementsKind kind) { + CALL_HEAP_FUNCTION(map->GetIsolate(), map->AsElementsKind(kind), Map); } -void JSObject::MigrateInstance(Handle<JSObject> object) { - CALL_HEAP_FUNCTION_VOID( - object->GetIsolate(), - object->MigrateInstance()); +void JSObject::AllocateStorageForMap(Handle<JSObject> object, Handle<Map> map) { + ASSERT(object->map()->inobject_properties() == map->inobject_properties()); + ElementsKind obj_kind = object->map()->elements_kind(); + ElementsKind map_kind = map->elements_kind(); + if (map_kind != obj_kind) { + ElementsKind to_kind = map_kind; + if (IsMoreGeneralElementsKindTransition(map_kind, obj_kind) || + IsDictionaryElementsKind(obj_kind)) { + to_kind = obj_kind; + } + if (IsDictionaryElementsKind(to_kind)) { + NormalizeElements(object); + } else { + TransitionElementsKind(object, to_kind); + } + map = MapAsElementsKind(map, to_kind); + } + int total_size = + map->NumberOfOwnDescriptors() + map->unused_property_fields(); + int out_of_object = total_size - map->inobject_properties(); + if (out_of_object != object->properties()->length()) { + Isolate* isolate = object->GetIsolate(); + Handle<FixedArray> new_properties = isolate->factory()->CopySizeFixedArray( + handle(object->properties()), out_of_object); + object->set_properties(*new_properties); + } + object->set_map(*map); } -Handle<Object> JSObject::TryMigrateInstance(Handle<JSObject> object) { - CALL_HEAP_FUNCTION( - object->GetIsolate(), - object->MigrateInstance(), - Object); +void JSObject::MigrateInstance(Handle<JSObject> object) { + // Converting any field to the most specific type will cause the + // GeneralizeFieldRepresentation algorithm to create the most general existing + // transition that matches the object. This achieves what is needed. + Handle<Map> original_map(object->map()); + GeneralizeFieldRepresentation( + object, 0, Representation::None(), ALLOW_AS_CONSTANT); + if (FLAG_trace_migration) { + object->PrintInstanceMigration(stdout, *original_map, object->map()); + } } -Handle<Map> Map::GeneralizeRepresentation(Handle<Map> map, - int modify_index, - Representation representation, - StoreMode store_mode) { - CALL_HEAP_FUNCTION( - map->GetIsolate(), - map->GeneralizeRepresentation(modify_index, representation, store_mode), - Map); +Handle<Object> JSObject::TryMigrateInstance(Handle<JSObject> object) { + Map* new_map = object->map()->CurrentMapForDeprecated(); + if (new_map == NULL) return Handle<Object>(); + Handle<Map> original_map(object->map()); + JSObject::MigrateToMap(object, handle(new_map)); + if (FLAG_trace_migration) { + object->PrintInstanceMigration(stdout, *original_map, object->map()); + } + return object; } -static MaybeObject* SetPropertyUsingTransition(LookupResult* lookup, - Handle<Name> name, - Handle<Object> value, - PropertyAttributes attributes) { - Map* transition_map = lookup->GetTransitionTarget(); +Handle<Object> JSObject::SetPropertyUsingTransition( + Handle<JSObject> object, + LookupResult* lookup, + Handle<Name> name, + Handle<Object> value, + PropertyAttributes attributes) { + Handle<Map> transition_map(lookup->GetTransitionTarget()); int descriptor = transition_map->LastAdded(); DescriptorArray* descriptors = transition_map->instance_descriptors(); @@ -3773,8 +3876,8 @@ static MaybeObject* SetPropertyUsingTransition(LookupResult* lookup, // 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, + return JSObject::AddProperty( + object, name, value, attributes, kNonStrictMode, JSReceiver::CERTAINLY_NOT_STORE_FROM_KEYED, JSReceiver::OMIT_EXTENSIBILITY_CHECK, JSObject::FORCE_TAGGED, FORCE_FIELD, OMIT_TRANSITION); @@ -3785,45 +3888,41 @@ static MaybeObject* SetPropertyUsingTransition(LookupResult* lookup, // (value->IsUninitialized) as constant. if (details.type() == CONSTANT && descriptors->GetValue(descriptor) == *value) { - lookup->holder()->set_map(transition_map); - return *value; + object->set_map(*transition_map); + return value; } Representation representation = details.representation(); if (!value->FitsRepresentation(representation) || details.type() == CONSTANT) { - MaybeObject* maybe_map = transition_map->GeneralizeRepresentation( + transition_map = Map::GeneralizeRepresentation(transition_map, 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; + MigrateToMap(object, handle(Map::cast(back))); } 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); + AddFastPropertyUsingMap( + object, transition_map, name, value, field_index, representation); + return value; } -static MaybeObject* SetPropertyToField(LookupResult* lookup, - Handle<Name> name, - Handle<Object> value) { +static void 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; + JSObject::GeneralizeFieldRepresentation(handle(lookup->holder()), + lookup->GetDescriptorIndex(), + value->OptimalRepresentation(), + FORCE_FIELD); DescriptorArray* desc = lookup->holder()->map()->instance_descriptors(); int descriptor = lookup->GetDescriptorIndex(); representation = desc->GetDetails(descriptor).representation(); @@ -3833,199 +3932,182 @@ static MaybeObject* SetPropertyToField(LookupResult* lookup, HeapNumber* storage = HeapNumber::cast(lookup->holder()->RawFastPropertyAt( lookup->GetFieldIndex().field_index())); storage->set_value(value->Number()); - return *value; + return; } 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(); +static void ConvertAndSetLocalProperty(LookupResult* lookup, + Handle<Name> name, + Handle<Object> value, + PropertyAttributes attributes) { + Handle<JSObject> object(lookup->holder()); if (object->TooManyFastProperties()) { - MaybeObject* maybe_failure = object->NormalizeProperties( - CLEAR_INOBJECT_PROPERTIES, 0); - if (maybe_failure->IsFailure()) return maybe_failure; + JSObject::NormalizeProperties(object, CLEAR_INOBJECT_PROPERTIES, 0); } if (!object->HasFastProperties()) { - return object->ReplaceSlowProperty(name, value, attributes); + ReplaceSlowProperty(object, name, value, attributes); + return; } 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; + JSObject::GeneralizeFieldRepresentation( + object, descriptor_index, Representation::Tagged(), FORCE_FIELD); } else { - Map* map; - MaybeObject* maybe_map = object->map()->CopyGeneralizeAllRepresentations( + Handle<Map> old_map(object->map()); + Handle<Map> new_map = Map::CopyGeneralizeAllRepresentations(old_map, 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; + JSObject::MigrateToMap(object, new_map); } DescriptorArray* descriptors = object->map()->instance_descriptors(); int index = descriptors->GetDetails(descriptor_index).field_index(); - object->FastPropertyAtPut(index, value); - return value; + object->FastPropertyAtPut(index, *value); } -static MaybeObject* SetPropertyToFieldWithAttributes( - LookupResult* lookup, - Handle<Name> name, - Handle<Object> value, - PropertyAttributes attributes) { +static void 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); + if (value->IsUninitialized()) return; + SetPropertyToField(lookup, name, value); } else { - return ConvertAndSetLocalProperty(lookup, *name, *value, attributes); + ConvertAndSetLocalProperty(lookup, name, value, attributes); } } -MaybeObject* JSObject::SetPropertyForResult(LookupResult* lookup, - Name* name_raw, - Object* value_raw, - PropertyAttributes attributes, - StrictModeFlag strict_mode, - StoreFromKeyed store_mode) { - Heap* heap = GetHeap(); - Isolate* isolate = heap->isolate(); +Handle<Object> JSObject::SetPropertyForResult(Handle<JSObject> object, + LookupResult* lookup, + Handle<Name> name, + Handle<Object> value, + PropertyAttributes attributes, + StrictModeFlag strict_mode, + StoreFromKeyed store_mode) { + Isolate* isolate = object->GetIsolate(); // Make sure that the top context does not change when doing callbacks or // interceptor calls. - AssertNoContextChangeWithHandleScope ncc; + AssertNoContextChange ncc(isolate); // Optimization for 2-byte strings often used as keys in a decompression // dictionary. We internalize these short keys to avoid constantly // reallocating them. - if (name_raw->IsString() && !name_raw->IsInternalizedString() && - String::cast(name_raw)->length() <= 2) { - Object* internalized_version; - { MaybeObject* maybe_string_version = - heap->InternalizeString(String::cast(name_raw)); - if (maybe_string_version->ToObject(&internalized_version)) { - name_raw = String::cast(internalized_version); - } - } + if (name->IsString() && !name->IsInternalizedString() && + Handle<String>::cast(name)->length() <= 2) { + name = isolate->factory()->InternalizeString(Handle<String>::cast(name)); } // Check access rights if needed. - if (IsAccessCheckNeeded()) { - if (!isolate->MayNamedAccess(this, name_raw, v8::ACCESS_SET)) { - return SetPropertyWithFailedAccessCheck( - lookup, name_raw, value_raw, true, strict_mode); + if (object->IsAccessCheckNeeded()) { + if (!isolate->MayNamedAccess(*object, *name, v8::ACCESS_SET)) { + return SetPropertyWithFailedAccessCheck(object, lookup, name, value, + true, strict_mode); } } - if (IsJSGlobalProxy()) { - Object* proto = GetPrototype(); - if (proto->IsNull()) return value_raw; + if (object->IsJSGlobalProxy()) { + Handle<Object> proto(object->GetPrototype(), isolate); + if (proto->IsNull()) return value; ASSERT(proto->IsJSGlobalObject()); - return JSObject::cast(proto)->SetPropertyForResult( - lookup, name_raw, value_raw, attributes, strict_mode, store_mode); + return SetPropertyForResult(Handle<JSObject>::cast(proto), + lookup, name, value, attributes, strict_mode, store_mode); } - ASSERT(!lookup->IsFound() || lookup->holder() == this || + ASSERT(!lookup->IsFound() || lookup->holder() == *object || lookup->holder()->map()->is_hidden_prototype()); - // From this point on everything needs to be handlified, because - // SetPropertyViaPrototypes might call back into JavaScript. - HandleScope scope(isolate); - Handle<JSObject> self(this); - Handle<Name> name(name_raw); - Handle<Object> value(value_raw, isolate); - - if (!lookup->IsProperty() && !self->IsJSContextExtensionObject()) { + if (!lookup->IsProperty() && !object->IsJSContextExtensionObject()) { bool done = false; - MaybeObject* result_object = self->SetPropertyViaPrototypes( - *name, *value, attributes, strict_mode, &done); + Handle<Object> result_object = SetPropertyViaPrototypes( + object, name, value, attributes, strict_mode, &done); if (done) return result_object; } if (!lookup->IsFound()) { // Neither properties nor transitions found. - return self->AddProperty( - *name, *value, attributes, strict_mode, store_mode); + return AddProperty( + object, name, value, attributes, strict_mode, store_mode); } if (lookup->IsProperty() && lookup->IsReadOnly()) { if (strict_mode == kStrictMode) { - Handle<Object> args[] = { name, self }; - return isolate->Throw(*isolate->factory()->NewTypeError( - "strict_read_only_property", HandleVector(args, ARRAY_SIZE(args)))); + Handle<Object> args[] = { name, object }; + Handle<Object> error = isolate->factory()->NewTypeError( + "strict_read_only_property", HandleVector(args, ARRAY_SIZE(args))); + isolate->Throw(*error); + return Handle<Object>(); } else { - return *value; + return value; } } - Handle<Object> old_value(heap->the_hole_value(), isolate); - if (FLAG_harmony_observation && - map()->is_observed() && lookup->IsDataProperty()) { - old_value = Object::GetProperty(self, name); + Handle<Object> old_value = isolate->factory()->the_hole_value(); + bool is_observed = FLAG_harmony_observation && + object->map()->is_observed() && + *name != isolate->heap()->hidden_string(); + if (is_observed && lookup->IsDataProperty()) { + old_value = Object::GetProperty(object, name); } // This is a real property that is not read-only, or it is a // transition or null descriptor and there are no setters in the prototypes. - MaybeObject* result = *value; + Handle<Object> result = value; switch (lookup->type()) { case NORMAL: - result = lookup->holder()->SetNormalizedProperty(lookup, *value); + SetNormalizedProperty(handle(lookup->holder()), lookup, value); break; case FIELD: - result = SetPropertyToField(lookup, name, value); + SetPropertyToField(lookup, name, value); break; case CONSTANT: // Only replace the constant if necessary. - if (*value == lookup->GetConstant()) return *value; - result = SetPropertyToField(lookup, name, value); + if (*value == lookup->GetConstant()) return value; + SetPropertyToField(lookup, name, value); break; case CALLBACKS: { - Object* callback_object = lookup->GetCallbackObject(); - return self->SetPropertyWithCallback( - callback_object, *name, *value, lookup->holder(), strict_mode); + Handle<Object> callback_object(lookup->GetCallbackObject(), isolate); + return SetPropertyWithCallback(object, callback_object, name, value, + handle(lookup->holder()), strict_mode); } case INTERCEPTOR: - result = lookup->holder()->SetPropertyWithInterceptor( - *name, *value, attributes, strict_mode); + result = SetPropertyWithInterceptor(handle(lookup->holder()), name, value, + attributes, strict_mode); break; - case TRANSITION: { - result = SetPropertyUsingTransition(lookup, name, value, attributes); + case TRANSITION: + result = SetPropertyUsingTransition(handle(lookup->holder()), lookup, + name, value, attributes); break; - } case HANDLER: case NONEXISTENT: UNREACHABLE(); } - Handle<Object> hresult; - if (!result->ToHandle(&hresult, isolate)) return result; + RETURN_IF_EMPTY_HANDLE_VALUE(isolate, result, Handle<Object>()); - if (FLAG_harmony_observation && self->map()->is_observed()) { + if (is_observed) { if (lookup->IsTransition()) { - EnqueueChangeRecord(self, "new", name, old_value); + EnqueueChangeRecord(object, "new", name, old_value); } else { LookupResult new_lookup(isolate); - self->LocalLookup(*name, &new_lookup, true); + object->LocalLookup(*name, &new_lookup, true); if (new_lookup.IsDataProperty()) { - Handle<Object> new_value = Object::GetProperty(self, name); + Handle<Object> new_value = Object::GetProperty(object, name); if (!new_value->SameValue(*old_value)) { - EnqueueChangeRecord(self, "updated", name, old_value); + EnqueueChangeRecord(object, "updated", name, old_value); } } } } - return *hresult; + return result; } @@ -4063,142 +4145,116 @@ MaybeObject* JSObject::SetLocalPropertyIgnoreAttributesTrampoline( // doesn't handle function prototypes correctly. Handle<Object> JSObject::SetLocalPropertyIgnoreAttributes( Handle<JSObject> object, - Handle<Name> key, + Handle<Name> name, Handle<Object> value, PropertyAttributes attributes, ValueType value_type, StoreMode mode, ExtensibilityCheck extensibility_check) { - CALL_HEAP_FUNCTION( - object->GetIsolate(), - object->SetLocalPropertyIgnoreAttributes( - *key, *value, attributes, value_type, mode, extensibility_check), - Object); -} - + Isolate* isolate = object->GetIsolate(); -MaybeObject* JSObject::SetLocalPropertyIgnoreAttributes( - Name* name_raw, - Object* value_raw, - PropertyAttributes attributes, - ValueType value_type, - StoreMode mode, - ExtensibilityCheck extensibility_check) { // Make sure that the top context does not change when doing callbacks or // interceptor calls. - AssertNoContextChangeWithHandleScope ncc; - Isolate* isolate = GetIsolate(); + AssertNoContextChange ncc(isolate); + LookupResult lookup(isolate); - LocalLookup(name_raw, &lookup, true); - if (!lookup.IsFound()) map()->LookupTransition(this, name_raw, &lookup); + object->LocalLookup(*name, &lookup, true); + if (!lookup.IsFound()) { + object->map()->LookupTransition(*object, *name, &lookup); + } + // Check access rights if needed. - if (IsAccessCheckNeeded()) { - if (!isolate->MayNamedAccess(this, name_raw, v8::ACCESS_SET)) { - return SetPropertyWithFailedAccessCheck(&lookup, - name_raw, - value_raw, - false, - kNonStrictMode); + if (object->IsAccessCheckNeeded()) { + if (!isolate->MayNamedAccess(*object, *name, v8::ACCESS_SET)) { + return SetPropertyWithFailedAccessCheck(object, &lookup, name, value, + false, kNonStrictMode); } } - if (IsJSGlobalProxy()) { - Object* proto = GetPrototype(); - if (proto->IsNull()) return value_raw; + if (object->IsJSGlobalProxy()) { + Handle<Object> proto(object->GetPrototype(), isolate); + if (proto->IsNull()) return value; ASSERT(proto->IsJSGlobalObject()); - return JSObject::cast(proto)->SetLocalPropertyIgnoreAttributes( - name_raw, - value_raw, - attributes, - value_type, - mode, - extensibility_check); + return SetLocalPropertyIgnoreAttributes(Handle<JSObject>::cast(proto), + name, value, attributes, value_type, mode, extensibility_check); } if (lookup.IsFound() && (lookup.type() == INTERCEPTOR || lookup.type() == CALLBACKS)) { - LocalLookupRealNamedProperty(name_raw, &lookup); + object->LocalLookupRealNamedProperty(*name, &lookup); } // Check for accessor in prototype chain removed here in clone. if (!lookup.IsFound()) { // Neither properties nor transitions found. - return AddProperty( - name_raw, value_raw, attributes, kNonStrictMode, + return AddProperty(object, name, value, attributes, kNonStrictMode, MAY_BE_STORE_FROM_KEYED, extensibility_check, value_type, mode); } - // From this point on everything needs to be handlified. - HandleScope scope(isolate); - Handle<JSObject> self(this); - Handle<Name> name(name_raw); - Handle<Object> value(value_raw, isolate); - - Handle<Object> old_value(isolate->heap()->the_hole_value(), isolate); + Handle<Object> old_value = isolate->factory()->the_hole_value(); PropertyAttributes old_attributes = ABSENT; - bool is_observed = FLAG_harmony_observation && self->map()->is_observed(); + bool is_observed = FLAG_harmony_observation && + object->map()->is_observed() && + *name != isolate->heap()->hidden_string(); if (is_observed && lookup.IsProperty()) { if (lookup.IsDataProperty()) old_value = - Object::GetProperty(self, name); + Object::GetProperty(object, name); old_attributes = lookup.GetAttributes(); } // Check of IsReadOnly removed from here in clone. - MaybeObject* result = *value; switch (lookup.type()) { case NORMAL: - result = self->ReplaceSlowProperty(*name, *value, attributes); + ReplaceSlowProperty(object, name, value, attributes); break; case FIELD: - result = SetPropertyToFieldWithAttributes( - &lookup, name, value, attributes); + SetPropertyToFieldWithAttributes(&lookup, name, value, attributes); break; case CONSTANT: // Only replace the constant if necessary. if (lookup.GetAttributes() != attributes || *value != lookup.GetConstant()) { - result = SetPropertyToFieldWithAttributes( - &lookup, name, value, attributes); + SetPropertyToFieldWithAttributes(&lookup, name, value, attributes); } break; case CALLBACKS: - result = ConvertAndSetLocalProperty(&lookup, *name, *value, attributes); + ConvertAndSetLocalProperty(&lookup, name, value, attributes); break; - case TRANSITION: - result = SetPropertyUsingTransition(&lookup, name, value, attributes); + case TRANSITION: { + Handle<Object> result = SetPropertyUsingTransition( + handle(lookup.holder()), &lookup, name, value, attributes); + RETURN_IF_EMPTY_HANDLE_VALUE(isolate, result, Handle<Object>()); break; + } case NONEXISTENT: case HANDLER: case INTERCEPTOR: UNREACHABLE(); } - Handle<Object> hresult; - if (!result->ToHandle(&hresult, isolate)) return result; - if (is_observed) { if (lookup.IsTransition()) { - EnqueueChangeRecord(self, "new", name, old_value); + EnqueueChangeRecord(object, "new", name, old_value); } else if (old_value->IsTheHole()) { - EnqueueChangeRecord(self, "reconfigured", name, old_value); + EnqueueChangeRecord(object, "reconfigured", name, old_value); } else { LookupResult new_lookup(isolate); - self->LocalLookup(*name, &new_lookup, true); + object->LocalLookup(*name, &new_lookup, true); bool value_changed = false; if (new_lookup.IsDataProperty()) { - Handle<Object> new_value = Object::GetProperty(self, name); + Handle<Object> new_value = Object::GetProperty(object, name); value_changed = !old_value->SameValue(*new_value); } if (new_lookup.GetAttributes() != old_attributes) { if (!value_changed) old_value = isolate->factory()->the_hole_value(); - EnqueueChangeRecord(self, "reconfigured", name, old_value); + EnqueueChangeRecord(object, "reconfigured", name, old_value); } else if (value_changed) { - EnqueueChangeRecord(self, "updated", name, old_value); + EnqueueChangeRecord(object, "updated", name, old_value); } } } - return *hresult; + return value; } @@ -4235,7 +4291,7 @@ PropertyAttributes JSObject::GetPropertyAttributeWithInterceptor( // Make sure that the top context does not change when doing // callbacks or interceptor calls. - AssertNoContextChange ncc; + AssertNoContextChange ncc(isolate); Handle<InterceptorInfo> interceptor(GetNamedInterceptor()); Handle<JSObject> receiver_handle(receiver); @@ -4370,7 +4426,7 @@ PropertyAttributes JSObject::GetElementAttributeWithInterceptor( // Make sure that the top context does not change when doing // callbacks or interceptor calls. - AssertNoContextChange ncc; + AssertNoContextChange ncc(isolate); Handle<InterceptorInfo> interceptor(GetIndexedInterceptor()); Handle<JSReceiver> hreceiver(receiver); @@ -4422,52 +4478,49 @@ PropertyAttributes JSObject::GetElementAttributeWithoutInterceptor( } -MaybeObject* NormalizedMapCache::Get(JSObject* obj, - PropertyNormalizationMode mode) { - Isolate* isolate = obj->GetIsolate(); - Map* fast = obj->map(); - int index = fast->Hash() % kEntries; - Object* result = get(index); +Handle<Map> NormalizedMapCache::Get(Handle<NormalizedMapCache> cache, + Handle<JSObject> obj, + PropertyNormalizationMode mode) { + int index = obj->map()->Hash() % kEntries; + Handle<Object> result = handle(cache->get(index), cache->GetIsolate()); if (result->IsMap() && - Map::cast(result)->EquivalentToForNormalization(fast, mode)) { + Handle<Map>::cast(result)->EquivalentToForNormalization(obj->map(), + mode)) { #ifdef VERIFY_HEAP if (FLAG_verify_heap) { - Map::cast(result)->SharedMapVerify(); + Handle<Map>::cast(result)->SharedMapVerify(); } #endif -#ifdef DEBUG +#ifdef ENABLE_SLOW_ASSERTS if (FLAG_enable_slow_asserts) { // The cached map should match newly created normalized map bit-by-bit, // except for the code cache, which can contain some ics which can be // applied to the shared map. - Object* fresh; - MaybeObject* maybe_fresh = - fast->CopyNormalized(mode, SHARED_NORMALIZED_MAP); - if (maybe_fresh->ToObject(&fresh)) { - ASSERT(memcmp(Map::cast(fresh)->address(), - Map::cast(result)->address(), - Map::kCodeCacheOffset) == 0); - STATIC_ASSERT(Map::kDependentCodeOffset == - Map::kCodeCacheOffset + kPointerSize); - int offset = Map::kDependentCodeOffset + kPointerSize; - ASSERT(memcmp(Map::cast(fresh)->address() + offset, - Map::cast(result)->address() + offset, - Map::kSize - offset) == 0); - } + Handle<Map> fresh = Map::CopyNormalized(handle(obj->map()), mode, + SHARED_NORMALIZED_MAP); + + ASSERT(memcmp(fresh->address(), + Handle<Map>::cast(result)->address(), + Map::kCodeCacheOffset) == 0); + STATIC_ASSERT(Map::kDependentCodeOffset == + Map::kCodeCacheOffset + kPointerSize); + int offset = Map::kDependentCodeOffset + kPointerSize; + ASSERT(memcmp(fresh->address() + offset, + Handle<Map>::cast(result)->address() + offset, + Map::kSize - offset) == 0); } #endif - return result; + return Handle<Map>::cast(result); } - { MaybeObject* maybe_result = - fast->CopyNormalized(mode, SHARED_NORMALIZED_MAP); - if (!maybe_result->ToObject(&result)) return maybe_result; - } - ASSERT(Map::cast(result)->is_dictionary_map()); - set(index, result); + Isolate* isolate = cache->GetIsolate(); + Handle<Map> map = Map::CopyNormalized(handle(obj->map()), mode, + SHARED_NORMALIZED_MAP); + ASSERT(map->is_dictionary_map()); + cache->set(index, *map); isolate->counters()->normalized_maps()->Increment(); - return result; + return map; } @@ -4483,16 +4536,6 @@ 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(!receiver->HasFastProperties()); - // Replace the map with an identical copy that can be safely modified. - map = Map::CopyNormalized(map, KEEP_INOBJECT_PROPERTIES, - UNIQUE_NORMALIZED_MAP); - receiver->GetIsolate()->counters()->normalized_maps()->Increment(); - receiver->set_map(*map); - } Map::UpdateCodeCache(map, name, code); } @@ -4500,65 +4543,55 @@ void HeapObject::UpdateMapCodeCache(Handle<HeapObject> object, void JSObject::NormalizeProperties(Handle<JSObject> object, PropertyNormalizationMode mode, int expected_additional_properties) { - CALL_HEAP_FUNCTION_VOID(object->GetIsolate(), - object->NormalizeProperties( - mode, expected_additional_properties)); -} - - -MaybeObject* JSObject::NormalizeProperties(PropertyNormalizationMode mode, - int expected_additional_properties) { - if (!HasFastProperties()) return this; + if (!object->HasFastProperties()) return; // The global object is always normalized. - ASSERT(!IsGlobalObject()); + ASSERT(!object->IsGlobalObject()); // JSGlobalProxy must never be normalized - ASSERT(!IsJSGlobalProxy()); + ASSERT(!object->IsJSGlobalProxy()); - Map* map_of_this = map(); + Isolate* isolate = object->GetIsolate(); + HandleScope scope(isolate); + Handle<Map> map(object->map()); // Allocate new content. - int real_size = map_of_this->NumberOfOwnDescriptors(); + int real_size = map->NumberOfOwnDescriptors(); int property_count = real_size; if (expected_additional_properties > 0) { property_count += expected_additional_properties; } else { property_count += 2; // Make space for two more properties. } - NameDictionary* dictionary; - MaybeObject* maybe_dictionary = - NameDictionary::Allocate(GetHeap(), property_count); - if (!maybe_dictionary->To(&dictionary)) return maybe_dictionary; + Handle<NameDictionary> dictionary = + isolate->factory()->NewNameDictionary(property_count); - DescriptorArray* descs = map_of_this->instance_descriptors(); + Handle<DescriptorArray> descs(map->instance_descriptors()); for (int i = 0; i < real_size; i++) { PropertyDetails details = descs->GetDetails(i); switch (details.type()) { case CONSTANT: { + Handle<Name> key(descs->GetKey(i)); + Handle<Object> value(descs->GetConstant(i), isolate); PropertyDetails d = PropertyDetails( details.attributes(), NORMAL, i + 1); - Object* value = descs->GetConstant(i); - MaybeObject* maybe_dictionary = - dictionary->Add(descs->GetKey(i), value, d); - if (!maybe_dictionary->To(&dictionary)) return maybe_dictionary; + dictionary = NameDictionaryAdd(dictionary, key, value, d); break; } case FIELD: { + Handle<Name> key(descs->GetKey(i)); + Handle<Object> value( + object->RawFastPropertyAt(descs->GetFieldIndex(i)), isolate); PropertyDetails d = PropertyDetails(details.attributes(), NORMAL, i + 1); - Object* value = RawFastPropertyAt(descs->GetFieldIndex(i)); - MaybeObject* maybe_dictionary = - dictionary->Add(descs->GetKey(i), value, d); - if (!maybe_dictionary->To(&dictionary)) return maybe_dictionary; + dictionary = NameDictionaryAdd(dictionary, key, value, d); break; } case CALLBACKS: { - Object* value = descs->GetCallbacksObject(i); + Handle<Name> key(descs->GetKey(i)); + Handle<Object> value(descs->GetCallbacksObject(i), isolate); PropertyDetails d = PropertyDetails( details.attributes(), CALLBACKS, i + 1); - MaybeObject* maybe_dictionary = - dictionary->Add(descs->GetKey(i), value, d); - if (!maybe_dictionary->To(&dictionary)) return maybe_dictionary; + dictionary = NameDictionaryAdd(dictionary, key, value, d); break; } case INTERCEPTOR: @@ -4572,62 +4605,52 @@ MaybeObject* JSObject::NormalizeProperties(PropertyNormalizationMode mode, } } - Heap* current_heap = GetHeap(); - // Copy the next enumeration index from instance descriptor. dictionary->SetNextEnumerationIndex(real_size + 1); - Map* new_map; - MaybeObject* maybe_map = - current_heap->isolate()->context()->native_context()-> - normalized_map_cache()->Get(this, mode); - if (!maybe_map->To(&new_map)) return maybe_map; + Handle<NormalizedMapCache> cache( + isolate->context()->native_context()->normalized_map_cache()); + Handle<Map> new_map = NormalizedMapCache::Get(cache, object, mode); ASSERT(new_map->is_dictionary_map()); - // We have now successfully allocated all the necessary objects. - // Changes can now be made with the guarantee that all of them take effect. + // From here on we cannot fail and we shouldn't GC anymore. + DisallowHeapAllocation no_allocation; // Resize the object in the heap if necessary. int new_instance_size = new_map->instance_size(); - int instance_size_delta = map_of_this->instance_size() - new_instance_size; + int instance_size_delta = map->instance_size() - new_instance_size; ASSERT(instance_size_delta >= 0); - current_heap->CreateFillerObjectAt(this->address() + new_instance_size, - instance_size_delta); - if (Marking::IsBlack(Marking::MarkBitFrom(this))) { - MemoryChunk::IncrementLiveBytesFromMutator(this->address(), + isolate->heap()->CreateFillerObjectAt(object->address() + new_instance_size, + instance_size_delta); + if (Marking::IsBlack(Marking::MarkBitFrom(*object))) { + MemoryChunk::IncrementLiveBytesFromMutator(object->address(), -instance_size_delta); } - set_map(new_map); - map_of_this->NotifyLeafMapLayoutChange(); + object->set_map(*new_map); + map->NotifyLeafMapLayoutChange(); - set_properties(dictionary); + object->set_properties(*dictionary); - current_heap->isolate()->counters()->props_to_dictionary()->Increment(); + isolate->counters()->props_to_dictionary()->Increment(); #ifdef DEBUG if (FLAG_trace_normalization) { PrintF("Object properties have been normalized:\n"); - Print(); + object->Print(); } #endif - return this; } void JSObject::TransformToFastProperties(Handle<JSObject> object, int unused_property_fields) { + if (object->HasFastProperties()) return; + ASSERT(!object->IsGlobalObject()); CALL_HEAP_FUNCTION_VOID( object->GetIsolate(), - object->TransformToFastProperties(unused_property_fields)); -} - - -MaybeObject* JSObject::TransformToFastProperties(int unused_property_fields) { - if (HasFastProperties()) return this; - ASSERT(!IsGlobalObject()); - return property_dictionary()-> - TransformPropertiesToFastFor(this, unused_property_fields); + object->property_dictionary()->TransformPropertiesToFastFor( + *object, unused_property_fields)); } @@ -4667,6 +4690,18 @@ static MUST_USE_RESULT MaybeObject* CopyFastElementsToDictionary( } +static Handle<SeededNumberDictionary> CopyFastElementsToDictionary( + Handle<FixedArrayBase> array, + int length, + Handle<SeededNumberDictionary> dict) { + Isolate* isolate = array->GetIsolate(); + CALL_HEAP_FUNCTION(isolate, + CopyFastElementsToDictionary( + isolate, *array, length, *dict), + SeededNumberDictionary); +} + + Handle<SeededNumberDictionary> JSObject::NormalizeElements( Handle<JSObject> object) { CALL_HEAP_FUNCTION(object->GetIsolate(), @@ -5089,7 +5124,7 @@ Handle<Object> JSObject::DeleteElementWithInterceptor(Handle<JSObject> object, // Make sure that the top context does not change when doing // callbacks or interceptor calls. - AssertNoContextChange ncc; + AssertNoContextChange ncc(isolate); Handle<InterceptorInfo> interceptor(object->GetIndexedInterceptor()); if (interceptor->deleter()->IsUndefined()) return factory->false_value(); @@ -5152,7 +5187,7 @@ Handle<Object> JSObject::DeleteElement(Handle<JSObject> object, Handle<Object> old_value; bool should_enqueue_change_record = false; if (FLAG_harmony_observation && object->map()->is_observed()) { - should_enqueue_change_record = object->HasLocalElement(index); + should_enqueue_change_record = HasLocalElement(object, index); if (should_enqueue_change_record) { old_value = object->GetLocalElementAccessorPair(index) != NULL ? Handle<Object>::cast(factory->the_hole_value()) @@ -5168,7 +5203,7 @@ Handle<Object> JSObject::DeleteElement(Handle<JSObject> object, result = AccessorDelete(object, index, mode); } - if (should_enqueue_change_record && !object->HasLocalElement(index)) { + if (should_enqueue_change_record && !HasLocalElement(object, index)) { Handle<String> name = factory->Uint32ToString(index); EnqueueChangeRecord(object, "deleted", name, old_value); } @@ -5222,7 +5257,9 @@ Handle<Object> JSObject::DeleteProperty(Handle<JSObject> object, } Handle<Object> old_value = isolate->factory()->the_hole_value(); - bool is_observed = FLAG_harmony_observation && object->map()->is_observed(); + bool is_observed = FLAG_harmony_observation && + object->map()->is_observed() && + *name != isolate->heap()->hidden_string(); if (is_observed && lookup.IsDataProperty()) { old_value = Object::GetProperty(object, name); } @@ -5243,7 +5280,7 @@ Handle<Object> JSObject::DeleteProperty(Handle<JSObject> object, result = DeleteNormalizedProperty(object, name, mode); } - if (is_observed && !object->HasLocalProperty(*name)) { + if (is_observed && !HasLocalProperty(object, name)) { EnqueueChangeRecord(object, "deleted", name, old_value); } @@ -5405,59 +5442,50 @@ bool JSObject::ReferencesObject(Object* obj) { Handle<Object> JSObject::PreventExtensions(Handle<JSObject> object) { - CALL_HEAP_FUNCTION(object->GetIsolate(), object->PreventExtensions(), Object); -} - - -MaybeObject* JSObject::PreventExtensions() { - Isolate* isolate = GetIsolate(); - if (IsAccessCheckNeeded() && - !isolate->MayNamedAccess(this, + Isolate* isolate = object->GetIsolate(); + if (object->IsAccessCheckNeeded() && + !isolate->MayNamedAccess(*object, isolate->heap()->undefined_value(), v8::ACCESS_KEYS)) { - isolate->ReportFailedAccessCheck(this, v8::ACCESS_KEYS); - RETURN_IF_SCHEDULED_EXCEPTION(isolate); - return isolate->heap()->false_value(); + isolate->ReportFailedAccessCheck(*object, v8::ACCESS_KEYS); + RETURN_HANDLE_IF_SCHEDULED_EXCEPTION(isolate, Object); + return isolate->factory()->false_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)->PreventExtensions(); + return PreventExtensions(Handle<JSObject>::cast(proto)); } // It's not possible to seal objects with external array elements - if (HasExternalArrayElements()) { - HandleScope scope(isolate); - Handle<Object> object(this, isolate); + if (object->HasExternalArrayElements()) { Handle<Object> error = isolate->factory()->NewTypeError( "cant_prevent_ext_external_array_elements", HandleVector(&object, 1)); - return isolate->Throw(*error); + isolate->Throw(*error); + return Handle<Object>(); } // If there are fast elements we normalize. - SeededNumberDictionary* dictionary = NULL; - { MaybeObject* maybe = NormalizeElements(); - if (!maybe->To<SeededNumberDictionary>(&dictionary)) return maybe; - } - ASSERT(HasDictionaryElements() || HasDictionaryArgumentsElements()); + Handle<SeededNumberDictionary> dictionary = NormalizeElements(object); + ASSERT(object->HasDictionaryElements() || + object->HasDictionaryArgumentsElements()); + // Make sure that we never go back to fast case. dictionary->set_requires_slow_elements(); // Do a map transition, other objects with this map may still // be extensible. // TODO(adamk): Extend the NormalizedMapCache to handle non-extensible maps. - Map* new_map; - MaybeObject* maybe = map()->Copy(); - if (!maybe->To(&new_map)) return maybe; + Handle<Map> new_map = Map::Copy(handle(object->map())); new_map->set_is_extensible(false); - set_map(new_map); - ASSERT(!map()->is_extensible()); - return new_map; + object->set_map(*new_map); + ASSERT(!object->map()->is_extensible()); + return object; } @@ -5482,223 +5510,318 @@ static void FreezeDictionary(Dictionary* dictionary) { } -MUST_USE_RESULT MaybeObject* JSObject::Freeze(Isolate* isolate) { +Handle<Object> JSObject::Freeze(Handle<JSObject> object) { // Freezing non-strict arguments should be handled elsewhere. - ASSERT(!HasNonStrictArgumentsElements()); - - Heap* heap = isolate->heap(); + ASSERT(!object->HasNonStrictArgumentsElements()); - if (map()->is_frozen()) return this; + if (object->map()->is_frozen()) return object; - if (IsAccessCheckNeeded() && - !isolate->MayNamedAccess(this, - heap->undefined_value(), + Isolate* isolate = object->GetIsolate(); + if (object->IsAccessCheckNeeded() && + !isolate->MayNamedAccess(*object, + isolate->heap()->undefined_value(), v8::ACCESS_KEYS)) { - isolate->ReportFailedAccessCheck(this, v8::ACCESS_KEYS); - RETURN_IF_SCHEDULED_EXCEPTION(isolate); - return heap->false_value(); + isolate->ReportFailedAccessCheck(*object, v8::ACCESS_KEYS); + RETURN_HANDLE_IF_SCHEDULED_EXCEPTION(isolate, Object); + return isolate->factory()->false_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)->Freeze(isolate); + return Freeze(Handle<JSObject>::cast(proto)); } // It's not possible to freeze objects with external array elements - if (HasExternalArrayElements()) { - HandleScope scope(isolate); - Handle<Object> object(this, isolate); + if (object->HasExternalArrayElements()) { Handle<Object> error = isolate->factory()->NewTypeError( "cant_prevent_ext_external_array_elements", HandleVector(&object, 1)); - return isolate->Throw(*error); + isolate->Throw(*error); + return Handle<Object>(); } - SeededNumberDictionary* new_element_dictionary = NULL; - if (!elements()->IsDictionary()) { - int length = IsJSArray() - ? Smi::cast(JSArray::cast(this)->length())->value() - : elements()->length(); + Handle<SeededNumberDictionary> new_element_dictionary; + if (!object->elements()->IsDictionary()) { + int length = object->IsJSArray() + ? Smi::cast(Handle<JSArray>::cast(object)->length())->value() + : object->elements()->length(); if (length > 0) { int capacity = 0; int used = 0; - GetElementsCapacityAndUsage(&capacity, &used); - MaybeObject* maybe_dict = SeededNumberDictionary::Allocate(heap, used); - if (!maybe_dict->To(&new_element_dictionary)) return maybe_dict; + object->GetElementsCapacityAndUsage(&capacity, &used); + new_element_dictionary = + isolate->factory()->NewSeededNumberDictionary(used); // Move elements to a dictionary; avoid calling NormalizeElements to avoid // unnecessary transitions. - maybe_dict = CopyFastElementsToDictionary(isolate, elements(), length, - new_element_dictionary); - if (!maybe_dict->To(&new_element_dictionary)) return maybe_dict; + new_element_dictionary = CopyFastElementsToDictionary( + handle(object->elements()), length, new_element_dictionary); } else { // No existing elements, use a pre-allocated empty backing store - new_element_dictionary = heap->empty_slow_element_dictionary(); + new_element_dictionary = + isolate->factory()->empty_slow_element_dictionary(); } } LookupResult result(isolate); - map()->LookupTransition(this, heap->frozen_symbol(), &result); + Handle<Map> old_map(object->map()); + old_map->LookupTransition(*object, isolate->heap()->frozen_symbol(), &result); if (result.IsTransition()) { Map* transition_map = result.GetTransitionTarget(); ASSERT(transition_map->has_dictionary_elements()); ASSERT(transition_map->is_frozen()); ASSERT(!transition_map->is_extensible()); - set_map(transition_map); - } else if (HasFastProperties() && map()->CanHaveMoreTransitions()) { + object->set_map(transition_map); + } else if (object->HasFastProperties() && old_map->CanHaveMoreTransitions()) { // Create a new descriptor array with fully-frozen properties - int num_descriptors = map()->NumberOfOwnDescriptors(); - DescriptorArray* new_descriptors; - MaybeObject* maybe_descriptors = - map()->instance_descriptors()->CopyUpToAddAttributes(num_descriptors, - FROZEN); - if (!maybe_descriptors->To(&new_descriptors)) return maybe_descriptors; - - Map* new_map; - MaybeObject* maybe_new_map = map()->CopyReplaceDescriptors( - new_descriptors, INSERT_TRANSITION, heap->frozen_symbol()); - if (!maybe_new_map->To(&new_map)) return maybe_new_map; + int num_descriptors = old_map->NumberOfOwnDescriptors(); + Handle<DescriptorArray> new_descriptors = + DescriptorArray::CopyUpToAddAttributes( + handle(old_map->instance_descriptors()), num_descriptors, FROZEN); + Handle<Map> new_map = Map::CopyReplaceDescriptors( + old_map, new_descriptors, INSERT_TRANSITION, + isolate->factory()->frozen_symbol()); new_map->freeze(); new_map->set_is_extensible(false); new_map->set_elements_kind(DICTIONARY_ELEMENTS); - set_map(new_map); + object->set_map(*new_map); } else { // Slow path: need to normalize properties for safety - MaybeObject* maybe = NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0); - if (maybe->IsFailure()) return maybe; + NormalizeProperties(object, CLEAR_INOBJECT_PROPERTIES, 0); // Create a new map, since other objects with this map may be extensible. // TODO(adamk): Extend the NormalizedMapCache to handle non-extensible maps. - Map* new_map; - MaybeObject* maybe_copy = map()->Copy(); - if (!maybe_copy->To(&new_map)) return maybe_copy; + Handle<Map> new_map = Map::Copy(handle(object->map())); new_map->freeze(); new_map->set_is_extensible(false); new_map->set_elements_kind(DICTIONARY_ELEMENTS); - set_map(new_map); + object->set_map(*new_map); // Freeze dictionary-mode properties - FreezeDictionary(property_dictionary()); + FreezeDictionary(object->property_dictionary()); } - ASSERT(map()->has_dictionary_elements()); - if (new_element_dictionary != NULL) { - set_elements(new_element_dictionary); + ASSERT(object->map()->has_dictionary_elements()); + if (!new_element_dictionary.is_null()) { + object->set_elements(*new_element_dictionary); } - if (elements() != heap->empty_slow_element_dictionary()) { - SeededNumberDictionary* dictionary = element_dictionary(); + if (object->elements() != isolate->heap()->empty_slow_element_dictionary()) { + SeededNumberDictionary* dictionary = object->element_dictionary(); // Make sure we never go back to the fast case dictionary->set_requires_slow_elements(); // Freeze all elements in the dictionary FreezeDictionary(dictionary); } - return this; + return object; } -MUST_USE_RESULT MaybeObject* JSObject::SetObserved(Isolate* isolate) { - if (map()->is_observed()) - return isolate->heap()->undefined_value(); +void JSObject::SetObserved(Handle<JSObject> object) { + Isolate* isolate = object->GetIsolate(); - Heap* heap = isolate->heap(); + if (object->map()->is_observed()) + return; - if (!HasExternalArrayElements()) { + if (!object->HasExternalArrayElements()) { // Go to dictionary mode, so that we don't skip map checks. - MaybeObject* maybe = NormalizeElements(); - if (maybe->IsFailure()) return maybe; - ASSERT(!HasFastElements()); + NormalizeElements(object); + ASSERT(!object->HasFastElements()); } LookupResult result(isolate); - map()->LookupTransition(this, heap->observed_symbol(), &result); + object->map()->LookupTransition(*object, + isolate->heap()->observed_symbol(), + &result); - Map* new_map; + Handle<Map> new_map; if (result.IsTransition()) { - new_map = result.GetTransitionTarget(); + new_map = handle(result.GetTransitionTarget()); ASSERT(new_map->is_observed()); - } else if (map()->CanHaveMoreTransitions()) { - MaybeObject* maybe_new_map = map()->CopyForObserved(); - if (!maybe_new_map->To(&new_map)) return maybe_new_map; + } else if (object->map()->CanHaveMoreTransitions()) { + new_map = Map::CopyForObserved(handle(object->map())); } else { - MaybeObject* maybe_copy = map()->Copy(); - if (!maybe_copy->To(&new_map)) return maybe_copy; + new_map = Map::Copy(handle(object->map())); new_map->set_is_observed(true); } - set_map(new_map); + object->set_map(*new_map); +} - return heap->undefined_value(); + +Handle<JSObject> JSObject::Copy(Handle<JSObject> object, + Handle<AllocationSite> site) { + Isolate* isolate = object->GetIsolate(); + CALL_HEAP_FUNCTION(isolate, + isolate->heap()->CopyJSObject(*object, *site), JSObject); } -MUST_USE_RESULT MaybeObject* JSObject::DeepCopy(Isolate* isolate) { - StackLimitCheck check(isolate); - if (check.HasOverflowed()) return isolate->StackOverflow(); +Handle<JSObject> JSObject::Copy(Handle<JSObject> object) { + Isolate* isolate = object->GetIsolate(); + CALL_HEAP_FUNCTION(isolate, + isolate->heap()->CopyJSObject(*object), JSObject); +} - if (map()->is_deprecated()) { - MaybeObject* maybe_failure = MigrateInstance(); - if (maybe_failure->IsFailure()) return maybe_failure; + +class JSObjectWalkVisitor { + public: + explicit JSObjectWalkVisitor(AllocationSiteContext* site_context) : + site_context_(site_context) {} + virtual ~JSObjectWalkVisitor() {} + + Handle<JSObject> Visit(Handle<JSObject> object) { + return StructureWalk(object); } - Heap* heap = isolate->heap(); - Object* result; - { MaybeObject* maybe_result = heap->CopyJSObject(this); - if (!maybe_result->ToObject(&result)) return maybe_result; + virtual bool is_copying() = 0; + + protected: + Handle<JSObject> StructureWalk(Handle<JSObject> object); + + // The returned handle will be used for the object in all subsequent usages. + // This allows VisitObject to make a copy of the object if desired. + virtual Handle<JSObject> VisitObject(Handle<JSObject> object) = 0; + virtual Handle<JSObject> VisitElementOrProperty(Handle<JSObject> object, + Handle<JSObject> value) = 0; + + AllocationSiteContext* site_context() { return site_context_; } + + private: + AllocationSiteContext* site_context_; +}; + + +class JSObjectCopyVisitor: public JSObjectWalkVisitor { + public: + explicit JSObjectCopyVisitor(AllocationSiteContext* site_context) + : JSObjectWalkVisitor(site_context) {} + + virtual bool is_copying() V8_OVERRIDE { return true; } + + // The returned handle will be used for the object in all + // subsequent usages. This allows VisitObject to make a copy + // of the object if desired. + virtual Handle<JSObject> VisitObject(Handle<JSObject> object) V8_OVERRIDE { + // Only create a memento if + // 1) we have a JSArray, and + // 2) the elements kind is palatable + // 3) allow_mementos is true + Handle<JSObject> copy; + if (site_context()->activated() && + AllocationSite::CanTrack(object->map()->instance_type()) && + AllocationSite::GetMode(object->GetElementsKind()) == + TRACK_ALLOCATION_SITE) { + copy = JSObject::Copy(object, site_context()->current()); + } else { + copy = JSObject::Copy(object); + } + + return copy; + } + + virtual Handle<JSObject> VisitElementOrProperty( + Handle<JSObject> object, + Handle<JSObject> value) V8_OVERRIDE { + Handle<AllocationSite> current_site = site_context()->EnterNewScope(); + Handle<JSObject> copy_of_value = StructureWalk(value); + site_context()->ExitScope(current_site, value); + return copy_of_value; + } +}; + + +class JSObjectCreateAllocationSitesVisitor: public JSObjectWalkVisitor { + public: + explicit JSObjectCreateAllocationSitesVisitor( + AllocationSiteContext* site_context) + : JSObjectWalkVisitor(site_context) {} + + virtual bool is_copying() V8_OVERRIDE { return false; } + + // The returned handle will be used for the object in all + // subsequent usages. This allows VisitObject to make a copy + // of the object if desired. + virtual Handle<JSObject> VisitObject(Handle<JSObject> object) V8_OVERRIDE { + return object; + } + + virtual Handle<JSObject> VisitElementOrProperty( + Handle<JSObject> object, + Handle<JSObject> value) V8_OVERRIDE { + Handle<AllocationSite> current_site = site_context()->EnterNewScope(); + value = StructureWalk(value); + site_context()->ExitScope(current_site, value); + return value; + } +}; + + +Handle<JSObject> JSObjectWalkVisitor::StructureWalk(Handle<JSObject> object) { + bool copying = is_copying(); + Isolate* isolate = object->GetIsolate(); + StackLimitCheck check(isolate); + if (check.HasOverflowed()) { + isolate->StackOverflow(); + return Handle<JSObject>::null(); } - JSObject* copy = JSObject::cast(result); + + if (object->map()->is_deprecated()) { + JSObject::MigrateInstance(object); + } + + Handle<JSObject> copy = VisitObject(object); + ASSERT(copying || copy.is_identical_to(object)); + + HandleScope scope(isolate); // Deep copy local properties. if (copy->HasFastProperties()) { - DescriptorArray* descriptors = copy->map()->instance_descriptors(); + Handle<DescriptorArray> descriptors(copy->map()->instance_descriptors()); int limit = copy->map()->NumberOfOwnDescriptors(); for (int i = 0; i < limit; i++) { PropertyDetails details = descriptors->GetDetails(i); if (details.type() != FIELD) continue; int index = descriptors->GetFieldIndex(i); - Object* value = RawFastPropertyAt(index); + Handle<Object> value(object->RawFastPropertyAt(index), isolate); if (value->IsJSObject()) { - JSObject* js_object = JSObject::cast(value); - MaybeObject* maybe_copy = js_object->DeepCopy(isolate); - if (!maybe_copy->To(&value)) return maybe_copy; + value = VisitElementOrProperty(copy, Handle<JSObject>::cast(value)); + RETURN_IF_EMPTY_HANDLE_VALUE(isolate, value, Handle<JSObject>()); } else { Representation representation = details.representation(); - MaybeObject* maybe_storage = - value->AllocateNewStorageFor(heap, representation); - if (!maybe_storage->To(&value)) return maybe_storage; + value = NewStorageFor(isolate, value, representation); + } + if (copying) { + copy->FastPropertyAtPut(index, *value); } - copy->FastPropertyAtPut(index, value); } } else { - { MaybeObject* maybe_result = - heap->AllocateFixedArray(copy->NumberOfLocalProperties()); - if (!maybe_result->ToObject(&result)) return maybe_result; - } - FixedArray* names = FixedArray::cast(result); - copy->GetLocalPropertyNames(names, 0); + Handle<FixedArray> names = + isolate->factory()->NewFixedArray(copy->NumberOfLocalProperties()); + copy->GetLocalPropertyNames(*names, 0); for (int i = 0; i < names->length(); i++) { ASSERT(names->get(i)->IsString()); - String* key_string = String::cast(names->get(i)); + Handle<String> key_string(String::cast(names->get(i))); PropertyAttributes attributes = - copy->GetLocalPropertyAttribute(key_string); + copy->GetLocalPropertyAttribute(*key_string); // Only deep copy fields from the object literal expression. // In particular, don't try to copy the length attribute of // an array. if (attributes != NONE) continue; - Object* value = - copy->GetProperty(key_string, &attributes)->ToObjectUnchecked(); + Handle<Object> value( + copy->GetProperty(*key_string, &attributes)->ToObjectUnchecked(), + isolate); if (value->IsJSObject()) { - JSObject* js_object = JSObject::cast(value); - { MaybeObject* maybe_result = js_object->DeepCopy(isolate); - if (!maybe_result->ToObject(&result)) return maybe_result; - } - { MaybeObject* maybe_result = - // Creating object copy for literals. No strict mode needed. - copy->SetProperty(key_string, result, NONE, kNonStrictMode); - if (!maybe_result->ToObject(&result)) return maybe_result; + Handle<JSObject> result = VisitElementOrProperty( + copy, Handle<JSObject>::cast(value)); + RETURN_IF_EMPTY_HANDLE_VALUE(isolate, result, Handle<JSObject>()); + if (copying) { + // Creating object copy for literals. No strict mode needed. + CHECK_NOT_EMPTY_HANDLE(isolate, JSObject::SetProperty( + copy, key_string, result, NONE, kNonStrictMode)); } } } @@ -5712,8 +5835,8 @@ MUST_USE_RESULT MaybeObject* JSObject::DeepCopy(Isolate* isolate) { case FAST_ELEMENTS: case FAST_HOLEY_SMI_ELEMENTS: case FAST_HOLEY_ELEMENTS: { - FixedArray* elements = FixedArray::cast(copy->elements()); - if (elements->map() == heap->fixed_cow_array_map()) { + Handle<FixedArray> elements(FixedArray::cast(copy->elements())); + if (elements->map() == isolate->heap()->fixed_cow_array_map()) { isolate->counters()->cow_arrays_created_runtime()->Increment(); #ifdef DEBUG for (int i = 0; i < elements->length(); i++) { @@ -5722,34 +5845,37 @@ MUST_USE_RESULT MaybeObject* JSObject::DeepCopy(Isolate* isolate) { #endif } else { for (int i = 0; i < elements->length(); i++) { - Object* value = elements->get(i); + Handle<Object> value(elements->get(i), isolate); ASSERT(value->IsSmi() || value->IsTheHole() || (IsFastObjectElementsKind(copy->GetElementsKind()))); if (value->IsJSObject()) { - JSObject* js_object = JSObject::cast(value); - { MaybeObject* maybe_result = js_object->DeepCopy(isolate); - if (!maybe_result->ToObject(&result)) return maybe_result; + Handle<JSObject> result = VisitElementOrProperty( + copy, Handle<JSObject>::cast(value)); + RETURN_IF_EMPTY_HANDLE_VALUE(isolate, result, Handle<JSObject>()); + if (copying) { + elements->set(i, *result); } - elements->set(i, result); } } } break; } case DICTIONARY_ELEMENTS: { - SeededNumberDictionary* element_dictionary = copy->element_dictionary(); + Handle<SeededNumberDictionary> element_dictionary( + copy->element_dictionary()); int capacity = element_dictionary->Capacity(); for (int i = 0; i < capacity; i++) { Object* k = element_dictionary->KeyAt(i); if (element_dictionary->IsKey(k)) { - Object* value = element_dictionary->ValueAt(i); + Handle<Object> value(element_dictionary->ValueAt(i), isolate); if (value->IsJSObject()) { - JSObject* js_object = JSObject::cast(value); - { MaybeObject* maybe_result = js_object->DeepCopy(isolate); - if (!maybe_result->ToObject(&result)) return maybe_result; + Handle<JSObject> result = VisitElementOrProperty( + copy, Handle<JSObject>::cast(value)); + RETURN_IF_EMPTY_HANDLE_VALUE(isolate, result, Handle<JSObject>()); + if (copying) { + element_dictionary->ValueAtPut(i, *result); } - element_dictionary->ValueAtPut(i, result); } } } @@ -5776,6 +5902,25 @@ MUST_USE_RESULT MaybeObject* JSObject::DeepCopy(Isolate* isolate) { } +Handle<JSObject> JSObject::DeepWalk(Handle<JSObject> object, + AllocationSiteContext* site_context) { + JSObjectCreateAllocationSitesVisitor v(site_context); + Handle<JSObject> result = v.Visit(object); + ASSERT(!v.is_copying() && + (result.is_null() || result.is_identical_to(object))); + return result; +} + + +Handle<JSObject> JSObject::DeepCopy(Handle<JSObject> object, + AllocationSiteContext* site_context) { + JSObjectCopyVisitor v(site_context); + Handle<JSObject> copy = v.Visit(object); + ASSERT(v.is_copying() && !copy.is_identical_to(object)); + return copy; +} + + // Tests for the fast common case for property enumeration: // - This object and all prototypes has an enum cache (which means that // it is no proxy, has no interceptors and needs no access checks). @@ -6175,7 +6320,7 @@ void JSObject::DefineAccessor(Handle<JSObject> object, // Make sure that the top context does not change when doing callbacks or // interceptor calls. - AssertNoContextChangeWithHandleScope ncc; + AssertNoContextChange ncc(isolate); // Try to flatten before operating on the string. if (name->IsString()) String::cast(*name)->TryFlatten(); @@ -6186,11 +6331,13 @@ void JSObject::DefineAccessor(Handle<JSObject> object, bool is_element = name->AsArrayIndex(&index); Handle<Object> old_value = isolate->factory()->the_hole_value(); - bool is_observed = FLAG_harmony_observation && object->map()->is_observed(); + bool is_observed = FLAG_harmony_observation && + object->map()->is_observed() && + *name != isolate->heap()->hidden_string(); bool preexists = false; if (is_observed) { if (is_element) { - preexists = object->HasLocalElement(index); + preexists = HasLocalElement(object, index); if (preexists && object->GetLocalElementAccessorPair(index) == NULL) { old_value = Object::GetElement(isolate, object, index); } @@ -6361,7 +6508,7 @@ Handle<Object> JSObject::SetAccessor(Handle<JSObject> object, // Make sure that the top context does not change when doing callbacks or // interceptor calls. - AssertNoContextChange ncc; + AssertNoContextChange ncc(isolate); // Try to flatten before operating on the string. if (name->IsString()) FlattenString(Handle<String>::cast(name)); @@ -6420,58 +6567,62 @@ Handle<Object> JSObject::SetAccessor(Handle<JSObject> object, } -MaybeObject* JSObject::LookupAccessor(Name* name, AccessorComponent component) { - Heap* heap = GetHeap(); +Handle<Object> JSObject::GetAccessor(Handle<JSObject> object, + Handle<Name> name, + AccessorComponent component) { + Isolate* isolate = object->GetIsolate(); // Make sure that the top context does not change when doing callbacks or // interceptor calls. - AssertNoContextChangeWithHandleScope ncc; + AssertNoContextChange ncc(isolate); // Check access rights if needed. - if (IsAccessCheckNeeded() && - !heap->isolate()->MayNamedAccess(this, name, v8::ACCESS_HAS)) { - heap->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_HAS); - RETURN_IF_SCHEDULED_EXCEPTION(heap->isolate()); - return heap->undefined_value(); + if (object->IsAccessCheckNeeded() && + !isolate->MayNamedAccess(*object, *name, v8::ACCESS_HAS)) { + isolate->ReportFailedAccessCheck(*object, v8::ACCESS_HAS); + RETURN_HANDLE_IF_SCHEDULED_EXCEPTION(isolate, Object); + return isolate->factory()->undefined_value(); } // Make the lookup and include prototypes. uint32_t index = 0; if (name->AsArrayIndex(&index)) { - for (Object* obj = this; - obj != heap->null_value(); - obj = JSReceiver::cast(obj)->GetPrototype()) { - if (obj->IsJSObject() && JSObject::cast(obj)->HasDictionaryElements()) { - JSObject* js_object = JSObject::cast(obj); + for (Handle<Object> obj = object; + !obj->IsNull(); + obj = handle(JSReceiver::cast(*obj)->GetPrototype(), isolate)) { + if (obj->IsJSObject() && JSObject::cast(*obj)->HasDictionaryElements()) { + JSObject* js_object = JSObject::cast(*obj); SeededNumberDictionary* dictionary = js_object->element_dictionary(); int entry = dictionary->FindEntry(index); if (entry != SeededNumberDictionary::kNotFound) { Object* element = dictionary->ValueAt(entry); if (dictionary->DetailsAt(entry).type() == CALLBACKS && element->IsAccessorPair()) { - return AccessorPair::cast(element)->GetComponent(component); + return handle(AccessorPair::cast(element)->GetComponent(component), + isolate); } } } } } else { - for (Object* obj = this; - obj != heap->null_value(); - obj = JSReceiver::cast(obj)->GetPrototype()) { - LookupResult result(heap->isolate()); - JSReceiver::cast(obj)->LocalLookup(name, &result); + for (Handle<Object> obj = object; + !obj->IsNull(); + obj = handle(JSReceiver::cast(*obj)->GetPrototype(), isolate)) { + LookupResult result(isolate); + JSReceiver::cast(*obj)->LocalLookup(*name, &result); if (result.IsFound()) { - if (result.IsReadOnly()) return heap->undefined_value(); + if (result.IsReadOnly()) return isolate->factory()->undefined_value(); if (result.IsPropertyCallbacks()) { Object* obj = result.GetCallbackObject(); if (obj->IsAccessorPair()) { - return AccessorPair::cast(obj)->GetComponent(component); + return handle(AccessorPair::cast(obj)->GetComponent(component), + isolate); } } } } } - return heap->undefined_value(); + return isolate->factory()->undefined_value(); } @@ -6504,6 +6655,14 @@ Object* JSObject::SlowReverseLookup(Object* value) { } +Handle<Map> Map::RawCopy(Handle<Map> map, + int instance_size) { + CALL_HEAP_FUNCTION(map->GetIsolate(), + map->RawCopy(instance_size), + Map); +} + + MaybeObject* Map::RawCopy(int instance_size) { Map* result; MaybeObject* maybe_result = @@ -6528,25 +6687,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(); + int new_instance_size = map->instance_size(); if (mode == CLEAR_INOBJECT_PROPERTIES) { - new_instance_size -= inobject_properties() * kPointerSize; + new_instance_size -= map->inobject_properties() * kPointerSize; } - Map* result; - MaybeObject* maybe_result = RawCopy(new_instance_size); - if (!maybe_result->To(&result)) return maybe_result; + Handle<Map> result = Map::RawCopy(map, new_instance_size); if (mode != CLEAR_INOBJECT_PROPERTIES) { - result->set_inobject_properties(inobject_properties()); + result->set_inobject_properties(map->inobject_properties()); } result->set_is_shared(sharing == SHARED_NORMALIZED_MAP); @@ -6660,6 +6809,16 @@ MaybeObject* Map::ShareDescriptor(DescriptorArray* descriptors, } +Handle<Map> Map::CopyReplaceDescriptors(Handle<Map> map, + Handle<DescriptorArray> descriptors, + TransitionFlag flag, + Handle<Name> name) { + CALL_HEAP_FUNCTION(map->GetIsolate(), + map->CopyReplaceDescriptors(*descriptors, flag, *name), + Map); +} + + MaybeObject* Map::CopyReplaceDescriptors(DescriptorArray* descriptors, TransitionFlag flag, Name* name, @@ -6688,20 +6847,19 @@ MaybeObject* Map::CopyReplaceDescriptors(DescriptorArray* descriptors, // Since this method is used to rewrite an existing transition tree, it can // always insert transitions without checking. -MaybeObject* Map::CopyInstallDescriptors(int new_descriptor, - DescriptorArray* descriptors) { +Handle<Map> Map::CopyInstallDescriptors(Handle<Map> map, + int new_descriptor, + Handle<DescriptorArray> descriptors) { ASSERT(descriptors->IsSortedNoDuplicates()); - Map* result; - MaybeObject* maybe_result = CopyDropDescriptors(); - if (!maybe_result->To(&result)) return maybe_result; + Handle<Map> result = Map::CopyDropDescriptors(map); - result->InitializeDescriptors(descriptors); + result->InitializeDescriptors(*descriptors); result->SetNumberOfOwnDescriptors(new_descriptor + 1); - int unused_property_fields = this->unused_property_fields(); + int unused_property_fields = map->unused_property_fields(); if (descriptors->GetDetails(new_descriptor).type() == FIELD) { - unused_property_fields = this->unused_property_fields() - 1; + unused_property_fields = map->unused_property_fields() - 1; if (unused_property_fields < 0) { unused_property_fields += JSObject::kFieldsAdded; } @@ -6710,14 +6868,12 @@ MaybeObject* Map::CopyInstallDescriptors(int new_descriptor, result->set_unused_property_fields(unused_property_fields); result->set_owns_descriptors(false); - Name* name = descriptors->GetKey(new_descriptor); - TransitionArray* transitions; - MaybeObject* maybe_transitions = - AddTransition(name, result, SIMPLE_TRANSITION); - if (!maybe_transitions->To(&transitions)) return maybe_transitions; + Handle<Name> name = handle(descriptors->GetKey(new_descriptor)); + Handle<TransitionArray> transitions = Map::AddTransition(map, name, result, + SIMPLE_TRANSITION); - set_transitions(transitions); - result->SetBackPointer(this); + map->set_transitions(*transitions); + result->SetBackPointer(*map); return result; } @@ -6775,35 +6931,34 @@ MaybeObject* Map::CopyAsElementsKind(ElementsKind kind, TransitionFlag flag) { } -MaybeObject* Map::CopyForObserved() { - ASSERT(!is_observed()); +Handle<Map> Map::CopyForObserved(Handle<Map> map) { + ASSERT(!map->is_observed()); + + Isolate* isolate = map->GetIsolate(); // In case the map owned its own descriptors, share the descriptors and // transfer ownership to the new map. - Map* new_map; - MaybeObject* maybe_new_map; - if (owns_descriptors()) { - maybe_new_map = CopyDropDescriptors(); + Handle<Map> new_map; + if (map->owns_descriptors()) { + new_map = Map::CopyDropDescriptors(map); } else { - maybe_new_map = Copy(); + new_map = Map::Copy(map); } - if (!maybe_new_map->To(&new_map)) return maybe_new_map; - TransitionArray* transitions; - MaybeObject* maybe_transitions = AddTransition(GetHeap()->observed_symbol(), - new_map, - FULL_TRANSITION); - if (!maybe_transitions->To(&transitions)) return maybe_transitions; - set_transitions(transitions); + Handle<TransitionArray> transitions = + Map::AddTransition(map, isolate->factory()->observed_symbol(), new_map, + FULL_TRANSITION); + + map->set_transitions(*transitions); new_map->set_is_observed(true); - if (owns_descriptors()) { - new_map->InitializeDescriptors(instance_descriptors()); - set_owns_descriptors(false); + if (map->owns_descriptors()) { + new_map->InitializeDescriptors(map->instance_descriptors()); + map->set_owns_descriptors(false); } - new_map->SetBackPointer(this); + new_map->SetBackPointer(*map); return new_map; } @@ -6904,6 +7059,16 @@ MaybeObject* Map::CopyInsertDescriptor(Descriptor* descriptor, } +Handle<DescriptorArray> DescriptorArray::CopyUpToAddAttributes( + Handle<DescriptorArray> desc, + int enumeration_index, + PropertyAttributes attributes) { + CALL_HEAP_FUNCTION(desc->GetIsolate(), + desc->CopyUpToAddAttributes(enumeration_index, attributes), + DescriptorArray); +} + + MaybeObject* DescriptorArray::CopyUpToAddAttributes( int enumeration_index, PropertyAttributes attributes) { if (enumeration_index == 0) return GetHeap()->empty_descriptor_array(); @@ -6992,8 +7157,6 @@ void Map::UpdateCodeCache(Handle<Map> map, MaybeObject* Map::UpdateCodeCache(Name* name, Code* code) { - ASSERT(!is_shared() || code->allowed_in_shared_map_code_cache()); - // Allocate the code cache if not present. if (code_cache()->IsFixedArray()) { Object* result; @@ -7320,11 +7483,10 @@ MaybeObject* CodeCache::UpdateNormalTypeCache(Name* name, Code* code) { Object* CodeCache::Lookup(Name* name, Code::Flags flags) { - if (Code::ExtractTypeFromFlags(flags) == Code::NORMAL) { - return LookupNormalTypeCache(name, flags); - } else { - return LookupDefaultCache(name, flags); - } + flags = Code::RemoveTypeFromFlags(flags); + Object* result = LookupDefaultCache(name, flags); + if (result->IsCode()) return result; + return LookupNormalTypeCache(name, flags); } @@ -7338,7 +7500,7 @@ Object* CodeCache::LookupDefaultCache(Name* name, Code::Flags flags) { if (key->IsUndefined()) return key; if (name->Equals(Name::cast(key))) { Code* code = Code::cast(cache->get(i + kCodeCacheEntryCodeOffset)); - if (code->flags() == flags) { + if (Code::RemoveTypeFromFlags(code->flags()) == flags) { return code; } } @@ -7402,9 +7564,7 @@ class CodeCacheHashTableKey : public HashTableKey { : name_(name), flags_(flags), code_(NULL) { } CodeCacheHashTableKey(Name* name, Code* code) - : name_(name), - flags_(code->flags()), - code_(code) { } + : name_(name), flags_(code->flags()), code_(code) { } bool IsMatch(Object* other) { @@ -7676,7 +7836,7 @@ MaybeObject* FixedArray::AddKeysFromJSArray(JSArray* array) { accessor->AddElementsToFixedArray(array, array, this); FixedArray* result; if (!maybe_result->To<FixedArray>(&result)) return maybe_result; -#ifdef DEBUG +#ifdef ENABLE_SLOW_ASSERTS if (FLAG_enable_slow_asserts) { for (int i = 0; i < result->length(); i++) { Object* current = result->get(i); @@ -7694,7 +7854,7 @@ MaybeObject* FixedArray::UnionOfKeys(FixedArray* other) { accessor->AddElementsToFixedArray(NULL, NULL, this, other); FixedArray* result; if (!maybe_result->To(&result)) return maybe_result; -#ifdef DEBUG +#ifdef ENABLE_SLOW_ASSERTS if (FLAG_enable_slow_asserts) { for (int i = 0; i < result->length(); i++) { Object* current = result->get(i); @@ -7706,11 +7866,11 @@ MaybeObject* FixedArray::UnionOfKeys(FixedArray* other) { } -MaybeObject* FixedArray::CopySize(int new_length) { +MaybeObject* FixedArray::CopySize(int new_length, PretenureFlag pretenure) { Heap* heap = GetHeap(); if (new_length == 0) return heap->empty_fixed_array(); Object* obj; - { MaybeObject* maybe_obj = heap->AllocateFixedArray(new_length); + { MaybeObject* maybe_obj = heap->AllocateFixedArray(new_length, pretenure); if (!maybe_obj->ToObject(&obj)) return maybe_obj; } FixedArray* result = FixedArray::cast(obj); @@ -7798,6 +7958,20 @@ void DescriptorArray::CopyFrom(int dst_index, } +Handle<DescriptorArray> DescriptorArray::Merge(Handle<DescriptorArray> desc, + int verbatim, + int valid, + int new_size, + int modify_index, + StoreMode store_mode, + Handle<DescriptorArray> other) { + CALL_HEAP_FUNCTION(desc->GetIsolate(), + desc->Merge(verbatim, valid, new_size, modify_index, + store_mode, *other), + DescriptorArray); +} + + // Generalize the |other| descriptor array by merging it into the (at least // partly) updated |this| descriptor array. // The method merges two descriptor array in three parts. Both descriptor arrays @@ -8735,7 +8909,7 @@ bool String::SlowEquals(String* other) { // Fast check: if hash code is computed for both strings // a fast negative check can be performed. if (HasHashCode() && other->HasHashCode()) { -#ifdef DEBUG +#ifdef ENABLE_SLOW_ASSERTS if (FLAG_enable_slow_asserts) { if (Hash() != other->Hash()) { bool found_difference = false; @@ -8990,7 +9164,7 @@ Handle<String> SeqString::Truncate(Handle<SeqString> string, int new_length) { if (newspace->Contains(start_of_string) && newspace->top() == start_of_string + old_size) { // Last allocated object in new space. Simply lower allocation top. - *(newspace->allocation_top_address()) = start_of_string + new_size; + newspace->set_top(start_of_string + new_size); } else { // Sizes are pointer size aligned, so that we can use filler objects // that are a multiple of pointer size. @@ -9006,17 +9180,22 @@ Handle<String> SeqString::Truncate(Handle<SeqString> string, int new_length) { } -AllocationMemento* AllocationMemento::FindForJSObject(JSObject* object) { +AllocationMemento* AllocationMemento::FindForJSObject(JSObject* object, + bool in_GC) { // Currently, AllocationMemento objects are only allocated immediately // after JSArrays in NewSpace, and detecting whether a JSArray has one // 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) <= - object->GetHeap()->NewSpaceTop()) { + Address top; + if (in_GC) { + top = object->GetHeap()->new_space()->FromSpacePageHigh(); + } else { + top = object->GetHeap()->NewSpaceTop(); + } + if ((ptr_end + AllocationMemento::kSize) <= top) { // There is room in newspace for allocation info. Do we have some? Map** possible_allocation_memento_map = reinterpret_cast<Map**>(ptr_end); @@ -9221,6 +9400,7 @@ void Map::ClearNonLiveTransitions(Heap* heap) { if (number_of_own_descriptors > 0) { TrimDescriptorArray(heap, this, descriptors, number_of_own_descriptors); ASSERT(descriptors->number_of_descriptors() == number_of_own_descriptors); + set_owns_descriptors(true); } else { ASSERT(descriptors == GetHeap()->empty_descriptor_array()); } @@ -9277,6 +9457,16 @@ bool Map::EquivalentToForNormalization(Map* other, } +void ConstantPoolArray::ConstantPoolIterateBody(ObjectVisitor* v) { + int first_ptr_offset = OffsetOfElementAt(first_ptr_index()); + int last_ptr_offset = + OffsetOfElementAt(first_ptr_index() + count_of_ptr_entries()); + v->VisitPointers( + HeapObject::RawField(this, first_ptr_offset), + HeapObject::RawField(this, last_ptr_offset)); +} + + void JSFunction::JSFunctionIterateBody(int object_size, ObjectVisitor* v) { // Iterate over all fields in the body but take care in dealing with // the code entry. @@ -9722,9 +9912,13 @@ bool JSFunction::PassesFilter(const char* raw_filter) { String* name = shared()->DebugName(); 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()))) { + if (filter[0] == '-') { + if (filter.length() == 1) { + return (name->length() != 0); + } else if (!name->IsUtf8EqualTo(filter.SubVector(1, filter.length()))) { + return true; + } + } else if (name->IsUtf8EqualTo(filter)) { return true; } if (filter[filter.length() - 1] == '*' && @@ -9768,7 +9962,8 @@ bool SharedFunctionInfo::HasSourceCode() { Handle<Object> SharedFunctionInfo::GetSourceCode() { if (!HasSourceCode()) return GetIsolate()->factory()->undefined_value(); Handle<String> source(String::cast(Script::cast(script())->source())); - return SubString(source, start_position(), end_position()); + return GetIsolate()->factory()->NewSubString( + source, start_position(), end_position()); } @@ -10128,7 +10323,7 @@ void ObjectVisitor::VisitEmbeddedPointer(RelocInfo* rinfo) { void ObjectVisitor::VisitExternalReference(RelocInfo* rinfo) { Address* p = rinfo->target_reference_address(); - VisitExternalReferences(p, p + 1); + VisitExternalReference(p); } @@ -10185,6 +10380,10 @@ void Code::CopyFrom(const CodeDesc& desc) { } else if (RelocInfo::IsRuntimeEntry(mode)) { Address p = it.rinfo()->target_runtime_entry(origin); it.rinfo()->set_target_runtime_entry(p, SKIP_WRITE_BARRIER); + } else if (mode == RelocInfo::CODE_AGE_SEQUENCE) { + Handle<Object> p = it.rinfo()->code_age_stub_handle(origin); + Code* code = Code::cast(*p); + it.rinfo()->set_code_age_stub(code); } else { it.rinfo()->apply(delta); } @@ -10317,31 +10516,35 @@ void Code::ReplaceFirstMap(Map* replace_with) { } -Code* Code::FindFirstCode() { +Code* Code::FindFirstHandler() { ASSERT(is_inline_cache_stub()); DisallowHeapAllocation no_allocation; int mask = RelocInfo::ModeMask(RelocInfo::CODE_TARGET); for (RelocIterator it(this, mask); !it.done(); it.next()) { RelocInfo* info = it.rinfo(); - return Code::GetCodeFromTargetAddress(info->target_address()); + Code* code = Code::GetCodeFromTargetAddress(info->target_address()); + if (code->kind() == Code::HANDLER) return code; } return NULL; } -void Code::FindAllCode(CodeHandleList* code_list, int length) { +bool Code::FindHandlers(CodeHandleList* code_list, int length) { ASSERT(is_inline_cache_stub()); DisallowHeapAllocation no_allocation; int mask = RelocInfo::ModeMask(RelocInfo::CODE_TARGET); int i = 0; for (RelocIterator it(this, mask); !it.done(); it.next()) { - if (i++ == length) return; + if (i == length) return true; RelocInfo* info = it.rinfo(); Code* code = Code::GetCodeFromTargetAddress(info->target_address()); - ASSERT(code->kind() == Code::STUB); + // IC stubs with handlers never contain non-handler code objects before + // handler targets. + if (code->kind() != Code::HANDLER) break; code_list->Add(Handle<Code>(code)); + i++; } - UNREACHABLE(); + return i == length; } @@ -10409,24 +10612,22 @@ 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(); + BackEdgeTable back_edges(this, &no_gc); + for (uint32_t i = 0; i < back_edges.length(); i++) { + if (back_edges.pc_offset(i) == pc_offset) return back_edges.ast_id(i); } return BailoutId::None(); } -bool Code::allowed_in_shared_map_code_cache() { - return is_keyed_load_stub() || is_keyed_store_stub() || - (is_compare_ic_stub() && - ICCompareStub::CompareState(stub_info()) == CompareIC::KNOWN_OBJECT); +void Code::MakeCodeAgeSequenceYoung(byte* sequence, Isolate* isolate) { + PatchPlatformCodeAge(isolate, sequence, kNoAgeCodeAge, NO_MARKING_PARITY); } -void Code::MakeCodeAgeSequenceYoung(byte* sequence) { - PatchPlatformCodeAge(sequence, kNoAge, NO_MARKING_PARITY); +void Code::MarkCodeAsExecuted(byte* sequence, Isolate* isolate) { + PatchPlatformCodeAge(isolate, sequence, kExecutedOnceCodeAge, + NO_MARKING_PARITY); } @@ -10437,7 +10638,9 @@ void Code::MakeOlder(MarkingParity current_parity) { MarkingParity code_parity; GetCodeAgeAndParity(sequence, &age, &code_parity); if (age != kLastCodeAge && code_parity != current_parity) { - PatchPlatformCodeAge(sequence, static_cast<Age>(age + 1), + PatchPlatformCodeAge(GetIsolate(), + sequence, + static_cast<Age>(age + 1), current_parity); } } @@ -10445,18 +10648,14 @@ void Code::MakeOlder(MarkingParity current_parity) { bool Code::IsOld() { - byte* sequence = FindCodeAgeSequence(); - if (sequence == NULL) return false; - Age age; - MarkingParity parity; - GetCodeAgeAndParity(sequence, &age, &parity); - return age >= kSexagenarianCodeAge; + Age age = GetAge(); + return age >= kIsOldCodeAge; } byte* Code::FindCodeAgeSequence() { return FLAG_age_code && - prologue_offset() != kPrologueOffsetNotSet && + prologue_offset() != Code::kPrologueOffsetNotSet && (kind() == OPTIMIZED_FUNCTION || (kind() == FUNCTION && !has_debug_break_slots())) ? instruction_start() + prologue_offset() @@ -10464,10 +10663,10 @@ byte* Code::FindCodeAgeSequence() { } -int Code::GetAge() { +Code::Age Code::GetAge() { byte* sequence = FindCodeAgeSequence(); if (sequence == NULL) { - return Code::kNoAge; + return Code::kNoAgeCodeAge; } Age age; MarkingParity parity; @@ -10496,12 +10695,25 @@ void Code::GetCodeAgeAndParity(Code* code, Age* age, } CODE_AGE_LIST(HANDLE_CODE_AGE) #undef HANDLE_CODE_AGE + stub = *builtins->MarkCodeAsExecutedOnce(); + if (code == stub) { + // Treat that's never been executed as old immediatly. + *age = kIsOldCodeAge; + *parity = NO_MARKING_PARITY; + return; + } + stub = *builtins->MarkCodeAsExecutedTwice(); + if (code == stub) { + // Pre-age code that has only been executed once. + *age = kPreAgedCodeAge; + *parity = NO_MARKING_PARITY; + return; + } UNREACHABLE(); } -Code* Code::GetCodeAgeStub(Age age, MarkingParity parity) { - Isolate* isolate = Isolate::Current(); +Code* Code::GetCodeAgeStub(Isolate* isolate, Age age, MarkingParity parity) { Builtins* builtins = isolate->builtins(); switch (age) { #define HANDLE_CODE_AGE(AGE) \ @@ -10513,6 +10725,14 @@ Code* Code::GetCodeAgeStub(Age age, MarkingParity parity) { } CODE_AGE_LIST(HANDLE_CODE_AGE) #undef HANDLE_CODE_AGE + case kNotExecutedCodeAge: { + ASSERT(parity == NO_MARKING_PARITY); + return *builtins->MarkCodeAsExecutedOnce(); + } + case kExecutedOnceCodeAge: { + ASSERT(parity == NO_MARKING_PARITY); + return *builtins->MarkCodeAsExecutedTwice(); + } default: UNREACHABLE(); break; @@ -10772,7 +10992,7 @@ const char* Code::StubType2String(StubType type) { case CONSTANT: return "CONSTANT"; case CALLBACKS: return "CALLBACKS"; case INTERCEPTOR: return "INTERCEPTOR"; - case MAP_TRANSITION: return "MAP_TRANSITION"; + case TRANSITION: return "TRANSITION"; case NONEXISTENT: return "NONEXISTENT"; } UNREACHABLE(); // keep the compiler happy @@ -10879,15 +11099,15 @@ void Code::Disassemble(const char* name, FILE* out) { // (due to alignment) the end of the instruction stream. if (static_cast<int>(offset) < instruction_size()) { DisallowHeapAllocation no_gc; - FullCodeGenerator::BackEdgeTableIterator back_edges(this, &no_gc); + BackEdgeTable back_edges(this, &no_gc); - PrintF(out, "Back edges (size = %u)\n", back_edges.table_length()); + PrintF(out, "Back edges (size = %u)\n", back_edges.length()); PrintF(out, "ast_id pc_offset loop_depth\n"); - for ( ; !back_edges.Done(); back_edges.Next()) { - PrintF(out, "%6d %9u %10u\n", back_edges.ast_id().ToInt(), - back_edges.pc_offset(), - back_edges.loop_depth()); + for (uint32_t i = 0; i < back_edges.length(); i++) { + PrintF(out, "%6d %9u %10u\n", back_edges.ast_id(i).ToInt(), + back_edges.pc_offset(i), + back_edges.loop_depth(i)); } PrintF(out, "\n"); @@ -10958,6 +11178,10 @@ MaybeObject* JSObject::SetFastElementsCapacityAndLength( } ValidateElements(); set_map_and_elements(new_map, new_elements); + + // Transition through the allocation site as well if present. + maybe_obj = UpdateAllocationSite(new_elements_kind); + if (maybe_obj->IsFailure()) return maybe_obj; } else { FixedArray* parameter_map = FixedArray::cast(old_elements); parameter_map->set(1, new_elements); @@ -10975,6 +11199,22 @@ MaybeObject* JSObject::SetFastElementsCapacityAndLength( } +bool Code::IsWeakEmbeddedObject(Kind kind, Object* object) { + if (kind != Code::OPTIMIZED_FUNCTION) return false; + + if (object->IsMap()) { + return Map::cast(object)->CanTransition() && + FLAG_collect_maps && + FLAG_weak_embedded_maps_in_optimized_code; + } + + if (object->IsJSObject()) { + return FLAG_weak_embedded_objects_in_optimized_code; + } + + return false; +} + MaybeObject* JSObject::SetFastDoubleElementsCapacityAndLength( int capacity, int length) { @@ -11335,7 +11575,7 @@ Handle<DependentCode> DependentCode::Insert(Handle<DependentCode> entries, int capacity = kCodesStartIndex + number_of_entries + 1; if (capacity > 5) capacity = capacity * 5 / 4; Handle<DependentCode> new_entries = Handle<DependentCode>::cast( - factory->CopySizeFixedArray(entries, capacity)); + factory->CopySizeFixedArray(entries, capacity, TENURED)); // The number of codes can change after GC. starts.Recompute(*entries); start = starts.at(group); @@ -11569,22 +11809,6 @@ MaybeObject* JSObject::EnsureCanContainElements(Arguments* args, } -PropertyType JSObject::GetLocalPropertyType(Name* name) { - uint32_t index = 0; - if (name->AsArrayIndex(&index)) { - return GetLocalElementType(index); - } - LookupResult lookup(GetIsolate()); - LocalLookup(name, &lookup, true); - return lookup.type(); -} - - -PropertyType JSObject::GetLocalElementType(uint32_t index) { - return GetElementsAccessor()->GetType(this, this, index); -} - - AccessorPair* JSObject::GetLocalPropertyAccessorPair(Name* name) { uint32_t index = 0; if (name->AsArrayIndex(&index)) { @@ -11628,7 +11852,7 @@ MaybeObject* JSObject::SetElementWithInterceptor(uint32_t index, // Make sure that the top context does not change when doing // callbacks or interceptor calls. - AssertNoContextChange ncc; + AssertNoContextChange ncc(isolate); Handle<InterceptorInfo> interceptor(GetIndexedInterceptor()); Handle<JSObject> this_handle(this); @@ -11709,18 +11933,17 @@ MaybeObject* JSObject::GetElementWithCallback(Object* receiver, } -MaybeObject* JSObject::SetElementWithCallback(Object* structure, - uint32_t index, - Object* value, - JSObject* holder, - StrictModeFlag strict_mode) { - Isolate* isolate = GetIsolate(); - HandleScope scope(isolate); +Handle<Object> JSObject::SetElementWithCallback(Handle<JSObject> object, + Handle<Object> structure, + uint32_t index, + Handle<Object> value, + Handle<JSObject> holder, + StrictModeFlag strict_mode) { + Isolate* isolate = object->GetIsolate(); // We should never get here to initialize a const with the hole // value since a const declaration would conflict with the setter. ASSERT(!value->IsTheHole()); - Handle<Object> value_handle(value, isolate); // To accommodate both the old and the new api we switch on the // data structure used to store the callbacks. Eventually foreign @@ -11729,41 +11952,40 @@ MaybeObject* JSObject::SetElementWithCallback(Object* structure, if (structure->IsExecutableAccessorInfo()) { // api style callbacks - Handle<JSObject> self(this); - Handle<JSObject> holder_handle(JSObject::cast(holder)); - Handle<ExecutableAccessorInfo> data( - ExecutableAccessorInfo::cast(structure)); + Handle<ExecutableAccessorInfo> data = + Handle<ExecutableAccessorInfo>::cast(structure); Object* call_obj = data->setter(); 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)); - LOG(isolate, ApiNamedPropertyAccess("store", *self, *key)); + LOG(isolate, ApiNamedPropertyAccess("store", *object, *key)); PropertyCallbackArguments - args(isolate, data->data(), *self, *holder_handle); + args(isolate, data->data(), *object, *holder); args.Call(call_fun, v8::Utils::ToLocal(key), - v8::Utils::ToLocal(value_handle)); - RETURN_IF_SCHEDULED_EXCEPTION(isolate); - return *value_handle; + v8::Utils::ToLocal(value)); + RETURN_HANDLE_IF_SCHEDULED_EXCEPTION(isolate, Object); + return value; } if (structure->IsAccessorPair()) { - Handle<Object> setter(AccessorPair::cast(structure)->setter(), isolate); + Handle<Object> setter(AccessorPair::cast(*structure)->setter(), isolate); if (setter->IsSpecFunction()) { // TODO(rossberg): nicer would be to cast to some JSCallable here... - return SetPropertyWithDefinedSetter(JSReceiver::cast(*setter), value); + return SetPropertyWithDefinedSetter( + object, Handle<JSReceiver>::cast(setter), value); } else { if (strict_mode == kNonStrictMode) { return value; } - Handle<Object> holder_handle(holder, isolate); Handle<Object> key(isolate->factory()->NewNumberFromUint(index)); - Handle<Object> args[2] = { key, holder_handle }; - return isolate->Throw( - *isolate->factory()->NewTypeError("no_setter_in_callback", - HandleVector(args, 2))); + Handle<Object> args[2] = { key, holder }; + Handle<Object> error = isolate->factory()->NewTypeError( + "no_setter_in_callback", HandleVector(args, 2)); + isolate->Throw(*error); + return Handle<Object>(); } } @@ -11771,7 +11993,7 @@ MaybeObject* JSObject::SetElementWithCallback(Object* structure, if (structure->IsDeclaredAccessorInfo()) return value; UNREACHABLE(); - return NULL; + return Handle<Object>(); } @@ -11968,10 +12190,13 @@ MaybeObject* JSObject::SetDictionaryElement(uint32_t index, int entry = dictionary->FindEntry(index); if (entry != SeededNumberDictionary::kNotFound) { - Object* element = dictionary->ValueAt(entry); + Handle<Object> element(dictionary->ValueAt(entry), isolate); PropertyDetails details = dictionary->DetailsAt(entry); if (details.type() == CALLBACKS && set_mode == SET_PROPERTY) { - return SetElementWithCallback(element, index, *value, this, strict_mode); + Handle<Object> result = SetElementWithCallback(self, element, index, + value, self, strict_mode); + RETURN_IF_EMPTY_HANDLE(isolate, result); + return *result; } else { dictionary->UpdateMaxNumberKey(index); // If a value has not been initialized we allow writing to it even if it @@ -11996,13 +12221,13 @@ MaybeObject* JSObject::SetDictionaryElement(uint32_t index, } // Elements of the arguments object in slow mode might be slow aliases. if (is_arguments && element->IsAliasedArgumentsEntry()) { - AliasedArgumentsEntry* entry = AliasedArgumentsEntry::cast(element); + AliasedArgumentsEntry* entry = AliasedArgumentsEntry::cast(*element); Context* context = Context::cast(elements->get(0)); int context_index = entry->aliased_context_slot(); ASSERT(!context->get(context_index)->IsTheHole()); context->set(context_index, *value); // For elements that are still writable we keep slow aliasing. - if (!details.IsReadOnly()) value = handle(element, isolate); + if (!details.IsReadOnly()) value = element; } dictionary->ValueAtPut(entry, *value); } @@ -12465,11 +12690,24 @@ MaybeObject* JSObject::SetElementWithoutInterceptor(uint32_t index, } -Handle<Object> JSObject::TransitionElementsKind(Handle<JSObject> object, - ElementsKind to_kind) { - CALL_HEAP_FUNCTION(object->GetIsolate(), - object->TransitionElementsKind(to_kind), - Object); +void JSObject::TransitionElementsKind(Handle<JSObject> object, + ElementsKind to_kind) { + CALL_HEAP_FUNCTION_VOID(object->GetIsolate(), + object->TransitionElementsKind(to_kind)); +} + + +bool AllocationSite::IsNestedSite() { + ASSERT(FLAG_trace_track_allocation_sites); + Object* current = GetHeap()->allocation_sites_list(); + while (current != NULL && current->IsAllocationSite()) { + AllocationSite* current_site = AllocationSite::cast(current); + if (current_site->nested_site() == this) { + return true; + } + current = current_site->weak_next(); + } + return false; } @@ -12485,23 +12723,26 @@ MaybeObject* JSObject::UpdateAllocationSite(ElementsKind to_kind) { // Walk through to the Allocation Site AllocationSite* site = memento->GetAllocationSite(); - if (site->IsLiteralSite()) { + if (site->SitePointsToLiteral() && + site->transition_info()->IsJSArray()) { JSArray* transition_info = JSArray::cast(site->transition_info()); ElementsKind kind = transition_info->GetElementsKind(); // if kind is holey ensure that to_kind is as well. if (IsHoleyElementsKind(kind)) { to_kind = GetHoleyElementsKind(to_kind); } - if (AllocationSite::GetMode(kind, to_kind) == TRACK_ALLOCATION_SITE) { + if (IsMoreGeneralElementsKindTransition(kind, to_kind)) { // If the array is huge, it's not likely to be defined in a local // function, so we shouldn't make new instances of it very often. uint32_t length = 0; CHECK(transition_info->length()->ToArrayIndex(&length)); if (length <= AllocationSite::kMaximumArrayBytesToPretransition) { if (FLAG_trace_track_allocation_sites) { + bool is_nested = site->IsNestedSite(); PrintF( - "AllocationSite: JSArray %p boilerplate updated %s->%s\n", + "AllocationSite: JSArray %p boilerplate %s updated %s->%s\n", reinterpret_cast<void*>(this), + is_nested ? "(nested)" : "", ElementsKindToString(kind), ElementsKindToString(to_kind)); } @@ -12514,7 +12755,7 @@ MaybeObject* JSObject::UpdateAllocationSite(ElementsKind to_kind) { if (IsHoleyElementsKind(kind)) { to_kind = GetHoleyElementsKind(to_kind); } - if (AllocationSite::GetMode(kind, to_kind) == TRACK_ALLOCATION_SITE) { + if (IsMoreGeneralElementsKindTransition(kind, to_kind)) { if (FLAG_trace_track_allocation_sites) { PrintF("AllocationSite: JSArray %p site updated %s->%s\n", reinterpret_cast<void*>(this), @@ -12640,7 +12881,7 @@ MaybeObject* JSObject::GetElementWithInterceptor(Object* receiver, // Make sure that the top context does not change when doing // callbacks or interceptor calls. - AssertNoContextChange ncc; + AssertNoContextChange ncc(isolate); Handle<InterceptorInfo> interceptor(GetIndexedInterceptor(), isolate); Handle<Object> this_handle(receiver, isolate); @@ -12904,21 +13145,26 @@ InterceptorInfo* JSObject::GetIndexedInterceptor() { } -MaybeObject* JSObject::GetPropertyPostInterceptor( - Object* receiver, - Name* name, +Handle<Object> JSObject::GetPropertyPostInterceptor( + Handle<JSObject> object, + Handle<Object> receiver, + Handle<Name> name, PropertyAttributes* attributes) { // Check local property in holder, ignore interceptor. - LookupResult result(GetIsolate()); - LocalLookupRealNamedProperty(name, &result); - if (result.IsFound()) { - return GetProperty(receiver, &result, name, attributes); + Isolate* isolate = object->GetIsolate(); + LookupResult lookup(isolate); + object->LocalLookupRealNamedProperty(*name, &lookup); + Handle<Object> result; + if (lookup.IsFound()) { + result = GetProperty(object, receiver, &lookup, name, attributes); + } else { + // Continue searching via the prototype chain. + Handle<Object> prototype(object->GetPrototype(), isolate); + *attributes = ABSENT; + if (prototype->IsNull()) return isolate->factory()->undefined_value(); + result = GetPropertyWithReceiver(prototype, receiver, name, attributes); } - // Continue searching via the prototype chain. - Object* pt = GetPrototype(); - *attributes = ABSENT; - if (pt->IsNull()) return GetHeap()->undefined_value(); - return pt->GetPropertyWithReceiver(receiver, name, attributes); + return result; } @@ -12936,93 +13182,98 @@ MaybeObject* JSObject::GetLocalPropertyPostInterceptor( } -MaybeObject* JSObject::GetPropertyWithInterceptor( - Object* receiver, - Name* name, +Handle<Object> JSObject::GetPropertyWithInterceptor( + Handle<JSObject> object, + Handle<Object> receiver, + Handle<Name> name, PropertyAttributes* attributes) { + Isolate* isolate = object->GetIsolate(); + // TODO(rossberg): Support symbols in the API. - if (name->IsSymbol()) return GetHeap()->undefined_value(); + if (name->IsSymbol()) return isolate->factory()->undefined_value(); - Isolate* isolate = GetIsolate(); - InterceptorInfo* interceptor = GetNamedInterceptor(); - HandleScope scope(isolate); - Handle<Object> receiver_handle(receiver, isolate); - Handle<JSObject> holder_handle(this); - Handle<String> name_handle(String::cast(name)); + Handle<InterceptorInfo> interceptor(object->GetNamedInterceptor(), isolate); + Handle<String> name_string = Handle<String>::cast(name); if (!interceptor->getter()->IsUndefined()) { v8::NamedPropertyGetterCallback getter = v8::ToCData<v8::NamedPropertyGetterCallback>(interceptor->getter()); LOG(isolate, - ApiNamedPropertyAccess("interceptor-named-get", *holder_handle, name)); + ApiNamedPropertyAccess("interceptor-named-get", *object, *name)); PropertyCallbackArguments - args(isolate, interceptor->data(), receiver, this); + args(isolate, interceptor->data(), *receiver, *object); v8::Handle<v8::Value> result = - args.Call(getter, v8::Utils::ToLocal(name_handle)); - RETURN_IF_SCHEDULED_EXCEPTION(isolate); + args.Call(getter, v8::Utils::ToLocal(name_string)); + RETURN_HANDLE_IF_SCHEDULED_EXCEPTION(isolate, Object); if (!result.IsEmpty()) { *attributes = NONE; Handle<Object> result_internal = v8::Utils::OpenHandle(*result); result_internal->VerifyApiCallResultType(); - return *result_internal; + // Rebox handle to escape this scope. + return handle(*result_internal, isolate); } } - MaybeObject* result = holder_handle->GetPropertyPostInterceptor( - *receiver_handle, - *name_handle, - attributes); - RETURN_IF_SCHEDULED_EXCEPTION(isolate); - return result; + return GetPropertyPostInterceptor(object, receiver, name, attributes); } -bool JSObject::HasRealNamedProperty(Isolate* isolate, Name* key) { +bool JSObject::HasRealNamedProperty(Handle<JSObject> object, + Handle<Name> key) { + Isolate* isolate = object->GetIsolate(); + SealHandleScope shs(isolate); // Check access rights if needed. - if (IsAccessCheckNeeded()) { - if (!isolate->MayNamedAccess(this, key, v8::ACCESS_HAS)) { - isolate->ReportFailedAccessCheck(this, v8::ACCESS_HAS); + if (object->IsAccessCheckNeeded()) { + if (!isolate->MayNamedAccess(*object, *key, v8::ACCESS_HAS)) { + isolate->ReportFailedAccessCheck(*object, v8::ACCESS_HAS); return false; } } LookupResult result(isolate); - LocalLookupRealNamedProperty(key, &result); + object->LocalLookupRealNamedProperty(*key, &result); return result.IsFound() && !result.IsInterceptor(); } -bool JSObject::HasRealElementProperty(Isolate* isolate, uint32_t index) { +bool JSObject::HasRealElementProperty(Handle<JSObject> object, uint32_t index) { + Isolate* isolate = object->GetIsolate(); + SealHandleScope shs(isolate); // Check access rights if needed. - if (IsAccessCheckNeeded()) { - if (!isolate->MayIndexedAccess(this, index, v8::ACCESS_HAS)) { - isolate->ReportFailedAccessCheck(this, v8::ACCESS_HAS); + if (object->IsAccessCheckNeeded()) { + if (!isolate->MayIndexedAccess(*object, index, v8::ACCESS_HAS)) { + isolate->ReportFailedAccessCheck(*object, v8::ACCESS_HAS); return false; } } - if (IsJSGlobalProxy()) { - Object* proto = GetPrototype(); + if (object->IsJSGlobalProxy()) { + HandleScope scope(isolate); + Handle<Object> proto(object->GetPrototype(), isolate); if (proto->IsNull()) return false; ASSERT(proto->IsJSGlobalObject()); - return JSObject::cast(proto)->HasRealElementProperty(isolate, index); + return HasRealElementProperty(Handle<JSObject>::cast(proto), index); } - return GetElementAttributeWithoutInterceptor(this, index, false) != ABSENT; + return object->GetElementAttributeWithoutInterceptor( + *object, index, false) != ABSENT; } -bool JSObject::HasRealNamedCallbackProperty(Isolate* isolate, Name* key) { +bool JSObject::HasRealNamedCallbackProperty(Handle<JSObject> object, + Handle<Name> key) { + Isolate* isolate = object->GetIsolate(); + SealHandleScope shs(isolate); // Check access rights if needed. - if (IsAccessCheckNeeded()) { - if (!isolate->MayNamedAccess(this, key, v8::ACCESS_HAS)) { - isolate->ReportFailedAccessCheck(this, v8::ACCESS_HAS); + if (object->IsAccessCheckNeeded()) { + if (!isolate->MayNamedAccess(*object, *key, v8::ACCESS_HAS)) { + isolate->ReportFailedAccessCheck(*object, v8::ACCESS_HAS); return false; } } LookupResult result(isolate); - LocalLookupRealNamedProperty(key, &result); + object->LocalLookupRealNamedProperty(*key, &result); return result.IsPropertyCallbacks(); } @@ -13856,7 +14107,9 @@ void HashTable<Shape, Key>::Rehash(Key key) { template<typename Shape, typename Key> -MaybeObject* HashTable<Shape, Key>::EnsureCapacity(int n, Key key) { +MaybeObject* HashTable<Shape, Key>::EnsureCapacity(int n, + Key key, + PretenureFlag pretenure) { int capacity = Capacity(); int nof = NumberOfElements() + n; int nod = NumberOfDeletedElements(); @@ -13869,14 +14122,14 @@ MaybeObject* HashTable<Shape, Key>::EnsureCapacity(int n, Key key) { } const int kMinCapacityForPretenure = 256; - bool pretenure = - (capacity > kMinCapacityForPretenure) && !GetHeap()->InNewSpace(this); + bool should_pretenure = pretenure == TENURED || + ((capacity > kMinCapacityForPretenure) && !GetHeap()->InNewSpace(this)); Object* obj; { MaybeObject* maybe_obj = Allocate(GetHeap(), nof * 2, USE_DEFAULT_MINIMUM_CAPACITY, - pretenure ? TENURED : NOT_TENURED); + should_pretenure ? TENURED : NOT_TENURED); if (!maybe_obj->ToObject(&obj)) return maybe_obj; } @@ -13944,6 +14197,8 @@ template class HashTable<ObjectHashTableShape<1>, Object*>; template class HashTable<ObjectHashTableShape<2>, Object*>; +template class HashTable<WeakHashTableShape<2>, Object*>; + template class Dictionary<NameDictionaryShape, Name*>; template class Dictionary<SeededNumberDictionaryShape, uint32_t>; @@ -14044,6 +14299,14 @@ template int HashTable<SeededNumberDictionaryShape, uint32_t>::FindEntry(uint32_t); +Handle<Object> JSObject::PrepareSlowElementsForSort( + Handle<JSObject> object, uint32_t limit) { + CALL_HEAP_FUNCTION(object->GetIsolate(), + object->PrepareSlowElementsForSort(limit), + Object); +} + + // Collates undefined and unexisting elements below limit from position // zero of the elements. The object stays in Dictionary mode. MaybeObject* JSObject::PrepareSlowElementsForSort(uint32_t limit) { @@ -14146,74 +14409,57 @@ MaybeObject* JSObject::PrepareSlowElementsForSort(uint32_t limit) { // the start of the elements array. // If the object is in dictionary mode, it is converted to fast elements // mode. -MaybeObject* JSObject::PrepareElementsForSort(uint32_t limit) { - Heap* heap = GetHeap(); +Handle<Object> JSObject::PrepareElementsForSort(Handle<JSObject> object, + uint32_t limit) { + Isolate* isolate = object->GetIsolate(); - ASSERT(!map()->is_observed()); - if (HasDictionaryElements()) { + ASSERT(!object->map()->is_observed()); + if (object->HasDictionaryElements()) { // Convert to fast elements containing only the existing properties. // Ordering is irrelevant, since we are going to sort anyway. - SeededNumberDictionary* dict = element_dictionary(); - if (IsJSArray() || dict->requires_slow_elements() || + Handle<SeededNumberDictionary> dict(object->element_dictionary()); + if (object->IsJSArray() || dict->requires_slow_elements() || dict->max_number_key() >= limit) { - return PrepareSlowElementsForSort(limit); + return JSObject::PrepareSlowElementsForSort(object, limit); } // Convert to fast elements. - Object* obj; - MaybeObject* maybe_obj = GetElementsTransitionMap(GetIsolate(), - FAST_HOLEY_ELEMENTS); - if (!maybe_obj->ToObject(&obj)) return maybe_obj; - Map* new_map = Map::cast(obj); + Handle<Map> new_map = + JSObject::GetElementsTransitionMap(object, FAST_HOLEY_ELEMENTS); - PretenureFlag tenure = heap->InNewSpace(this) ? NOT_TENURED: TENURED; - Object* new_array; - { MaybeObject* maybe_new_array = - heap->AllocateFixedArray(dict->NumberOfElements(), tenure); - if (!maybe_new_array->ToObject(&new_array)) return maybe_new_array; - } - FixedArray* fast_elements = FixedArray::cast(new_array); - dict->CopyValuesTo(fast_elements); - ValidateElements(); + PretenureFlag tenure = isolate->heap()->InNewSpace(*object) ? + NOT_TENURED: TENURED; + Handle<FixedArray> fast_elements = + isolate->factory()->NewFixedArray(dict->NumberOfElements(), tenure); + dict->CopyValuesTo(*fast_elements); + object->ValidateElements(); - set_map_and_elements(new_map, fast_elements); - } else if (HasExternalArrayElements()) { + object->set_map_and_elements(*new_map, *fast_elements); + } else if (object->HasExternalArrayElements()) { // External arrays cannot have holes or undefined elements. - return Smi::FromInt(ExternalArray::cast(elements())->length()); - } else if (!HasFastDoubleElements()) { - Object* obj; - { MaybeObject* maybe_obj = EnsureWritableFastElements(); - if (!maybe_obj->ToObject(&obj)) return maybe_obj; - } + return handle(Smi::FromInt( + ExternalArray::cast(object->elements())->length()), isolate); + } else if (!object->HasFastDoubleElements()) { + JSObject::EnsureWritableFastElements(object); } - ASSERT(HasFastSmiOrObjectElements() || HasFastDoubleElements()); + ASSERT(object->HasFastSmiOrObjectElements() || + object->HasFastDoubleElements()); // Collect holes at the end, undefined before that and the rest at the // start, and return the number of non-hole, non-undefined values. - FixedArrayBase* elements_base = FixedArrayBase::cast(this->elements()); + Handle<FixedArrayBase> elements_base(object->elements()); uint32_t elements_length = static_cast<uint32_t>(elements_base->length()); if (limit > elements_length) { limit = elements_length ; } if (limit == 0) { - return Smi::FromInt(0); - } - - HeapNumber* result_double = NULL; - if (limit > static_cast<uint32_t>(Smi::kMaxValue)) { - // Pessimistically allocate space for return value before - // we start mutating the array. - Object* new_double; - { MaybeObject* maybe_new_double = heap->AllocateHeapNumber(0.0); - if (!maybe_new_double->ToObject(&new_double)) return maybe_new_double; - } - result_double = HeapNumber::cast(new_double); + return handle(Smi::FromInt(0), isolate); } uint32_t result = 0; - if (elements_base->map() == heap->fixed_double_array_map()) { - FixedDoubleArray* elements = FixedDoubleArray::cast(elements_base); + if (elements_base->map() == isolate->heap()->fixed_double_array_map()) { + FixedDoubleArray* elements = FixedDoubleArray::cast(*elements_base); // Split elements into defined and the_hole, in that order. unsigned int holes = limit; // Assume most arrays contain no holes and undefined values, so minimize the @@ -14240,7 +14486,7 @@ MaybeObject* JSObject::PrepareElementsForSort(uint32_t limit) { holes++; } } else { - FixedArray* elements = FixedArray::cast(elements_base); + FixedArray* elements = FixedArray::cast(*elements_base); DisallowHeapAllocation no_gc; // Split elements into defined, undefined and the_hole, in that order. Only @@ -14285,12 +14531,7 @@ MaybeObject* JSObject::PrepareElementsForSort(uint32_t limit) { } } - if (result <= static_cast<uint32_t>(Smi::kMaxValue)) { - return Smi::FromInt(static_cast<int>(result)); - } - ASSERT_NE(NULL, result_double); - result_double->set_value(static_cast<double>(result)); - return result_double; + return isolate->factory()->NewNumberFromUint(result); } @@ -14508,17 +14749,6 @@ PropertyCell* GlobalObject::GetPropertyCell(LookupResult* result) { } -// TODO(mstarzinger): Temporary wrapper until handlified. -static Handle<NameDictionary> NameDictionaryAdd(Handle<NameDictionary> dict, - Handle<Name> name, - Handle<Object> value, - PropertyDetails details) { - CALL_HEAP_FUNCTION(dict->GetIsolate(), - dict->Add(*name, *value, details), - NameDictionary); -} - - Handle<PropertyCell> GlobalObject::EnsurePropertyCell( Handle<GlobalObject> global, Handle<Name> name) { @@ -15597,6 +15827,41 @@ void ObjectHashTable::RemoveEntry(int entry) { } +Object* WeakHashTable::Lookup(Object* key) { + ASSERT(IsKey(key)); + int entry = FindEntry(key); + if (entry == kNotFound) return GetHeap()->the_hole_value(); + return get(EntryToValueIndex(entry)); +} + + +MaybeObject* WeakHashTable::Put(Object* key, Object* value) { + ASSERT(IsKey(key)); + int entry = FindEntry(key); + // Key is already in table, just overwrite value. + if (entry != kNotFound) { + set(EntryToValueIndex(entry), value); + return this; + } + + // Check whether the hash table should be extended. + Object* obj; + { MaybeObject* maybe_obj = EnsureCapacity(1, key, TENURED); + if (!maybe_obj->ToObject(&obj)) return maybe_obj; + } + WeakHashTable* table = WeakHashTable::cast(obj); + table->AddEntry(table->FindInsertionEntry(Hash(key)), key, value); + return table; +} + + +void WeakHashTable::AddEntry(int entry, Object* key, Object* value) { + set(EntryToIndex(entry), key); + set(EntryToValueIndex(entry), value); + ElementAdded(); +} + + DeclaredAccessorDescriptorIterator::DeclaredAccessorDescriptorIterator( DeclaredAccessorDescriptor* descriptor) : array_(descriptor->serialized_data()->GetDataStartAddress()), @@ -16072,8 +16337,8 @@ void PropertyCell::set_type(Type* type, WriteBarrierMode ignored) { } -Type* PropertyCell::UpdateType(Handle<PropertyCell> cell, - Handle<Object> value) { +Handle<Type> PropertyCell::UpdatedType(Handle<PropertyCell> cell, + Handle<Object> value) { Isolate* isolate = cell->GetIsolate(); Handle<Type> old_type(cell->type(), isolate); // TODO(2803): Do not track ConsString as constant because they cannot be @@ -16083,34 +16348,27 @@ Type* PropertyCell::UpdateType(Handle<PropertyCell> cell, : Type::Constant(value, isolate), isolate); if (new_type->Is(old_type)) { - return *old_type; + return old_type; } cell->dependent_code()->DeoptimizeDependentCodeGroup( isolate, DependentCode::kPropertyCellChangedGroup); if (old_type->Is(Type::None()) || old_type->Is(Type::Undefined())) { - return *new_type; + return new_type; } - return Type::Any(); + return handle(Type::Any(), isolate); } -MaybeObject* PropertyCell::SetValueInferType(Object* value, - WriteBarrierMode ignored) { - set_value(value, ignored); - if (!Type::Any()->Is(type())) { - IdempotentPointerToHandleCodeTrampoline trampoline(GetIsolate()); - MaybeObject* maybe_type = trampoline.CallWithReturnValue( - &PropertyCell::UpdateType, - Handle<PropertyCell>(this), - Handle<Object>(value, GetIsolate())); - Type* new_type = NULL; - if (!maybe_type->To(&new_type)) return maybe_type; - set_type(new_type); +void PropertyCell::SetValueInferType(Handle<PropertyCell> cell, + Handle<Object> value) { + cell->set_value(*value); + if (!Type::Any()->Is(cell->type())) { + Handle<Type> new_type = UpdatedType(cell, value); + cell->set_type(*new_type); } - return value; } |