From: verwaest@chromium.org Date: Thu, 7 Aug 2014 16:14:22 +0000 (+0000) Subject: Mark as prototype only after instantiating the function X-Git-Tag: upstream/4.7.83~7735 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=a1f3f02415ab2ee86f6b54543d4e7bfe34e3c5ab;p=platform%2Fupstream%2Fv8.git Mark as prototype only after instantiating the function BUG= R=ishell@chromium.org Review URL: https://codereview.chromium.org/447293002 git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@22979 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 --- diff --git a/src/bootstrapper.cc b/src/bootstrapper.cc index 5ce58a7..44803f8 100644 --- a/src/bootstrapper.cc +++ b/src/bootstrapper.cc @@ -480,8 +480,7 @@ Handle Genesis::CreateEmptyFunction(Isolate* isolate) { Handle object_fun = factory->NewFunction(object_name); Handle object_function_map = factory->NewMap(JS_OBJECT_TYPE, JSObject::kHeaderSize); - object_fun->set_initial_map(*object_function_map); - object_function_map->set_constructor(*object_fun); + JSFunction::SetInitialMap(object_fun, object_function_map); object_function_map->set_unused_property_fields( JSObject::kInitialGlobalObjectUnusedPropertiesCount); @@ -1211,8 +1210,7 @@ void Genesis::InitializeGlobal(Handle global_object, native_context()->set_sloppy_arguments_map(*map); DCHECK(!function->has_initial_map()); - function->set_initial_map(*map); - map->set_constructor(*function); + JSFunction::SetInitialMap(function, map); DCHECK(map->inobject_properties() > Heap::kArgumentsCalleeIndex); DCHECK(map->inobject_properties() > Heap::kArgumentsLengthIndex); @@ -1336,8 +1334,7 @@ void Genesis::InstallTypedArray( JS_TYPED_ARRAY_TYPE, JSTypedArray::kSizeWithInternalFields, elements_kind); - result->set_initial_map(*initial_map); - initial_map->set_constructor(*result); + JSFunction::SetInitialMap(result, initial_map); *fun = result; ElementsKind external_kind = GetNextTransitionElementsKind(elements_kind); @@ -1658,7 +1655,7 @@ Handle Genesis::InstallInternalArray( Handle original_map(array_function->initial_map()); Handle initial_map = Map::Copy(original_map); initial_map->set_elements_kind(elements_kind); - array_function->set_initial_map(*initial_map); + JSFunction::SetInitialMap(array_function, initial_map); // Make "length" magic on instances. Map::EnsureDescriptorSlack(initial_map, 1); diff --git a/src/factory.cc b/src/factory.cc index e3a19a1..a52b957 100644 --- a/src/factory.cc +++ b/src/factory.cc @@ -1268,11 +1268,6 @@ Handle Factory::NewFunction(Handle name, ? isolate()->sloppy_function_with_readonly_prototype_map() : isolate()->sloppy_function_map(); Handle result = NewFunction(map, name, code); - if (!prototype->IsTheHole()) { - Handle js_proto = Handle::cast(prototype); - Handle new_map = Map::CopyAsPrototypeMap(handle(js_proto->map())); - JSObject::MigrateToMap(js_proto, new_map); - } result->set_prototype_or_initial_map(*prototype); return result; } @@ -1293,9 +1288,9 @@ Handle Factory::NewFunction(Handle name, if (prototype->IsTheHole() && !function->shared()->is_generator()) { prototype = NewFunctionPrototype(function); } + initial_map->set_prototype(*prototype); - function->set_initial_map(*initial_map); - initial_map->set_constructor(*function); + JSFunction::SetInitialMap(function, initial_map); return function; } @@ -1323,7 +1318,7 @@ Handle Factory::NewFunctionPrototype(Handle function) { // maps between prototypes of different constructors. Handle object_function(native_context->object_function()); DCHECK(object_function->has_initial_map()); - new_map = Map::CopyAsPrototypeMap(handle(object_function->initial_map())); + new_map = handle(object_function->initial_map()); } Handle prototype = NewJSObjectFromMap(new_map); diff --git a/src/objects-inl.h b/src/objects-inl.h index 7729c20..cfac520 100644 --- a/src/objects-inl.h +++ b/src/objects-inl.h @@ -4451,8 +4451,8 @@ bool Map::is_extensible() { } -void Map::mark_prototype_map() { - set_bit_field2(IsPrototypeMapBits::update(bit_field2(), true)); +void Map::set_is_prototype_map(bool value) { + set_bit_field2(IsPrototypeMapBits::update(bit_field2(), value)); } bool Map::is_prototype_map() { @@ -5940,11 +5940,6 @@ Map* JSFunction::initial_map() { } -void JSFunction::set_initial_map(Map* value) { - set_prototype_or_initial_map(value); -} - - bool JSFunction::has_initial_map() { return prototype_or_initial_map()->IsMap(); } diff --git a/src/objects.cc b/src/objects.cc index 2262e57..645bb4a 100644 --- a/src/objects.cc +++ b/src/objects.cc @@ -7239,14 +7239,6 @@ Handle Map::CopyForObserved(Handle map) { } -Handle Map::CopyAsPrototypeMap(Handle map) { - if (map->is_prototype_map()) return map; - Handle result = Copy(map); - result->mark_prototype_map(); - return result; -} - - Handle Map::Copy(Handle map) { Handle descriptors(map->instance_descriptors()); int number_of_own_descriptors = map->NumberOfOwnDescriptors(); @@ -9874,17 +9866,6 @@ void JSFunction::SetInstancePrototype(Handle function, DCHECK(value->IsJSReceiver()); - // First some logic for the map of the prototype to make sure it is in fast - // mode. - if (value->IsJSObject()) { - Handle js_proto = Handle::cast(value); - JSObject::OptimizeAsPrototype(js_proto); - if (js_proto->HasFastProperties()) { - Handle new_map = Map::CopyAsPrototypeMap(handle(js_proto->map())); - JSObject::MigrateToMap(js_proto, new_map); - } - } - // Now some logic for the maps of the objects that are created by using this // function as a constructor. if (function->has_initial_map()) { @@ -9908,7 +9889,7 @@ void JSFunction::SetInstancePrototype(Handle function, CacheInitialJSArrayMaps(handle(native_context, isolate), new_map); } - function->set_initial_map(*new_map); + JSFunction::SetInitialMap(function, new_map); // Deoptimize all code that embeds the previous initial map. initial_map->dependent_code()->DeoptimizeDependentCodeGroup( @@ -9975,6 +9956,32 @@ bool JSFunction::RemovePrototype() { } +void JSFunction::SetInitialMap(Handle function, Handle map) { + if (map->prototype()->IsJSObject()) { + Handle js_proto = handle(JSObject::cast(map->prototype())); + if (!js_proto->map()->is_prototype_map() && + !js_proto->map()->IsGlobalObjectMap() && + !js_proto->map()->IsJSGlobalProxyMap()) { + // Normalize and turn fast again to make all functions CONSTANT + // properties. + if (!js_proto->GetIsolate()->bootstrapper()->IsActive()) { + JSObject::NormalizeProperties(js_proto, KEEP_INOBJECT_PROPERTIES, 0); + } + if (!js_proto->HasFastProperties()) { + JSObject::MigrateSlowToFast(js_proto, 0); + } + if (js_proto->HasFastProperties()) { + Handle new_map = Map::Copy(handle(js_proto->map())); + JSObject::MigrateToMap(js_proto, new_map); + js_proto->map()->set_is_prototype_map(true); + } + } + } + function->set_prototype_or_initial_map(*map); + map->set_constructor(*function); +} + + void JSFunction::EnsureHasInitialMap(Handle function) { if (function->has_initial_map()) return; Isolate* isolate = function->GetIsolate(); @@ -10008,8 +10015,7 @@ void JSFunction::EnsureHasInitialMap(Handle function) { DCHECK(map->has_fast_object_elements()); // Finally link initial map and constructor function. - function->set_initial_map(*map); - map->set_constructor(*function); + JSFunction::SetInitialMap(function, map); if (!function->shared()->is_generator()) { function->StartInobjectSlackTracking(); diff --git a/src/objects.h b/src/objects.h index eb4af1d..0001eb5 100644 --- a/src/objects.h +++ b/src/objects.h @@ -6205,7 +6205,7 @@ class Map: public HeapObject { inline void set_is_extensible(bool value); inline bool is_extensible(); - inline void mark_prototype_map(); + inline void set_is_prototype_map(bool value); inline bool is_prototype_map(); inline void set_elements_kind(ElementsKind elements_kind) { @@ -6540,7 +6540,6 @@ class Map: public HeapObject { // Returns a copy of the map, with all transitions dropped from the // instance descriptors. static Handle Copy(Handle map); - static Handle CopyAsPrototypeMap(Handle map); static Handle Create(Handle constructor, int extra_inobject_properties); @@ -7781,7 +7780,7 @@ class JSFunction: public JSObject { // The initial map for an object created by this constructor. inline Map* initial_map(); - inline void set_initial_map(Map* value); + static void SetInitialMap(Handle function, Handle map); inline bool has_initial_map(); static void EnsureHasInitialMap(Handle function); diff --git a/test/mjsunit/dictionary-properties.js b/test/mjsunit/dictionary-properties.js index 9563f3a..0659268 100644 --- a/test/mjsunit/dictionary-properties.js +++ b/test/mjsunit/dictionary-properties.js @@ -39,6 +39,7 @@ function SlowPrototype() { SlowPrototype.prototype.bar = 2; SlowPrototype.prototype.baz = 3; delete SlowPrototype.prototype.baz; +new SlowPrototype; // Prototypes stay fast even after deleting properties. assertTrue(%HasFastProperties(SlowPrototype.prototype)); diff --git a/test/mjsunit/fast-prototype.js b/test/mjsunit/fast-prototype.js index 55a0faa..9864761 100644 --- a/test/mjsunit/fast-prototype.js +++ b/test/mjsunit/fast-prototype.js @@ -50,6 +50,8 @@ function DoProtoMagic(proto, set__proto__) { (new Sub()).__proto__ = proto; } else { Sub.prototype = proto; + // Need to instantiate Sub to mark .prototype as prototype. + new Sub(); } }