From 220c40542b6d401bc4e14d35426c2b11a0a0e1c3 Mon Sep 17 00:00:00 2001 From: "mstarzinger@chromium.org" Date: Thu, 19 Sep 2013 21:26:01 +0000 Subject: [PATCH] Handlify JSObject::Freeze method. R=adamk@chromium.org Review URL: https://codereview.chromium.org/24256004 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@16846 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 --- src/objects.cc | 142 +++++++++++++++++++++++++++++-------------------- src/objects.h | 11 +++- src/runtime.cc | 8 +-- 3 files changed, 97 insertions(+), 64 deletions(-) diff --git a/src/objects.cc b/src/objects.cc index 55bb944892..bb1ff05320 100644 --- a/src/objects.cc +++ b/src/objects.cc @@ -4593,6 +4593,18 @@ static MUST_USE_RESULT MaybeObject* CopyFastElementsToDictionary( } +static Handle CopyFastElementsToDictionary( + Handle array, + int length, + Handle dict) { + Isolate* isolate = array->GetIsolate(); + CALL_HEAP_FUNCTION(isolate, + CopyFastElementsToDictionary( + isolate, *array, length, *dict), + SeededNumberDictionary); +} + + Handle JSObject::NormalizeElements( Handle object) { CALL_HEAP_FUNCTION(object->GetIsolate(), @@ -5408,122 +5420,114 @@ static void FreezeDictionary(Dictionary* dictionary) { } -MUST_USE_RESULT MaybeObject* JSObject::Freeze(Isolate* isolate) { +Handle JSObject::Freeze(Handle object) { // Freezing non-strict arguments should be handled elsewhere. - ASSERT(!HasNonStrictArgumentsElements()); + ASSERT(!object->HasNonStrictArgumentsElements()); - Heap* heap = isolate->heap(); + if (object->map()->is_frozen()) return object; - if (map()->is_frozen()) return this; - - 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 proto(object->GetPrototype(), isolate); + if (proto->IsNull()) return object; ASSERT(proto->IsJSGlobalObject()); - return JSObject::cast(proto)->Freeze(isolate); + return Freeze(Handle::cast(proto)); } // It's not possible to freeze objects with external array elements - if (HasExternalArrayElements()) { - HandleScope scope(isolate); - Handle object(this, isolate); + if (object->HasExternalArrayElements()) { Handle error = isolate->factory()->NewTypeError( "cant_prevent_ext_external_array_elements", HandleVector(&object, 1)); - return isolate->Throw(*error); + isolate->Throw(*error); + return Handle(); } - SeededNumberDictionary* new_element_dictionary = NULL; - if (!elements()->IsDictionary()) { - int length = IsJSArray() - ? Smi::cast(JSArray::cast(this)->length())->value() - : elements()->length(); + Handle new_element_dictionary; + if (!object->elements()->IsDictionary()) { + int length = object->IsJSArray() + ? Smi::cast(Handle::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 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 new_descriptors = + DescriptorArray::CopyUpToAddAttributes( + handle(old_map->instance_descriptors()), num_descriptors, FROZEN); + Handle 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 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; } @@ -6581,6 +6585,16 @@ MaybeObject* Map::ShareDescriptor(DescriptorArray* descriptors, } +Handle Map::CopyReplaceDescriptors(Handle map, + Handle descriptors, + TransitionFlag flag, + Handle name) { + CALL_HEAP_FUNCTION(map->GetIsolate(), + map->CopyReplaceDescriptors(*descriptors, flag, *name), + Map); +} + + MaybeObject* Map::CopyReplaceDescriptors(DescriptorArray* descriptors, TransitionFlag flag, Name* name, @@ -6834,6 +6848,16 @@ MaybeObject* Map::CopyInsertDescriptor(Descriptor* descriptor, } +Handle DescriptorArray::CopyUpToAddAttributes( + Handle 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(); diff --git a/src/objects.h b/src/objects.h index b58b0b3ed1..1b69047f16 100644 --- a/src/objects.h +++ b/src/objects.h @@ -2545,8 +2545,7 @@ class JSObject: public JSReceiver { MUST_USE_RESULT MaybeObject* PreventExtensions(); // ES5 Object.freeze - MUST_USE_RESULT MaybeObject* Freeze(Isolate* isolate); - + static Handle Freeze(Handle object); // Called the first time an object is observed with ES7 Object.observe. MUST_USE_RESULT MaybeObject* SetObserved(Isolate* isolate); @@ -3186,6 +3185,10 @@ class DescriptorArray: public FixedArray { return CopyUpToAddAttributes(enumeration_index, NONE); } + static Handle CopyUpToAddAttributes( + Handle desc, + int enumeration_index, + PropertyAttributes attributes); MUST_USE_RESULT MaybeObject* CopyUpToAddAttributes( int enumeration_index, PropertyAttributes attributes); @@ -5788,6 +5791,10 @@ class Map: public HeapObject { MUST_USE_RESULT MaybeObject* CopyWithPreallocatedFieldDescriptors(); static Handle CopyDropDescriptors(Handle map); MUST_USE_RESULT MaybeObject* CopyDropDescriptors(); + static Handle CopyReplaceDescriptors(Handle map, + Handle descriptors, + TransitionFlag flag, + Handle name); MUST_USE_RESULT MaybeObject* CopyReplaceDescriptors( DescriptorArray* descriptors, TransitionFlag flag, diff --git a/src/runtime.cc b/src/runtime.cc index 0e18586dbb..3787e0c77c 100644 --- a/src/runtime.cc +++ b/src/runtime.cc @@ -3073,10 +3073,12 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_ThrowGeneratorStateError) { RUNTIME_FUNCTION(MaybeObject*, Runtime_ObjectFreeze) { - SealHandleScope shs(isolate); + HandleScope scope(isolate); ASSERT(args.length() == 1); - CONVERT_ARG_CHECKED(JSObject, object, 0); - return object->Freeze(isolate); + CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0); + Handle result = JSObject::Freeze(object); + RETURN_IF_EMPTY_HANDLE(isolate, result); + return *result; }