Index: src/objects.cc |
diff --git a/src/objects.cc b/src/objects.cc |
index 645bb4a74e39f81272c0c9e3c4c4d913976224fc..1ac755f28626219593a437787fb043c39cdd0683 100644 |
--- a/src/objects.cc |
+++ b/src/objects.cc |
@@ -6979,7 +6979,8 @@ Handle<Map> Map::Normalize(Handle<Map> fast_map, |
isolate->context()->native_context()->normalized_map_cache()); |
Handle<Map> new_map; |
- if (cache->Get(fast_map, mode).ToHandle(&new_map)) { |
+ if (!fast_map->is_prototype_map() && |
+ cache->Get(fast_map, mode).ToHandle(&new_map)) { |
#ifdef VERIFY_HEAP |
if (FLAG_verify_heap) { |
new_map->SharedMapVerify(); |
@@ -7006,8 +7007,10 @@ Handle<Map> Map::Normalize(Handle<Map> fast_map, |
#endif |
} else { |
new_map = Map::CopyNormalized(fast_map, mode, SHARED_NORMALIZED_MAP); |
- cache->Set(fast_map, new_map); |
- isolate->counters()->normalized_maps()->Increment(); |
+ if (!fast_map->is_prototype_map()) { |
+ cache->Set(fast_map, new_map); |
+ isolate->counters()->normalized_maps()->Increment(); |
+ } |
} |
fast_map->NotifyLeafMapLayoutChange(); |
return new_map; |
@@ -9876,21 +9879,30 @@ void JSFunction::SetInstancePrototype(Handle<JSFunction> function, |
if (function->IsInobjectSlackTrackingInProgress()) { |
function->CompleteInobjectSlackTracking(); |
} |
+ |
Handle<Map> initial_map(function->initial_map(), isolate); |
- Handle<Map> new_map = Map::Copy(initial_map); |
- new_map->set_prototype(*value); |
- // If the function is used as the global Array function, cache the |
- // initial map (and transitioned versions) in the native context. |
- Context* native_context = function->context()->native_context(); |
- Object* array_function = native_context->get(Context::ARRAY_FUNCTION_INDEX); |
- if (array_function->IsJSFunction() && |
- *function == JSFunction::cast(array_function)) { |
- CacheInitialJSArrayMaps(handle(native_context, isolate), new_map); |
+ if (!initial_map->GetIsolate()->bootstrapper()->IsActive() && |
+ initial_map->instance_type() == JS_OBJECT_TYPE) { |
+ // Put the value in the initial map field until an initial map is needed. |
+ // At that point, a new initial map is created and the prototype is put |
+ // into the initial map where it belongs. |
+ function->set_prototype_or_initial_map(*value); |
+ } else { |
+ Handle<Map> new_map = Map::Copy(initial_map); |
+ JSFunction::SetInitialMap(function, new_map, value); |
+ |
+ // If the function is used as the global Array function, cache the |
+ // initial map (and transitioned versions) in the native context. |
+ Context* native_context = function->context()->native_context(); |
+ Object* array_function = |
+ native_context->get(Context::ARRAY_FUNCTION_INDEX); |
+ if (array_function->IsJSFunction() && |
+ *function == JSFunction::cast(array_function)) { |
+ CacheInitialJSArrayMaps(handle(native_context, isolate), new_map); |
+ } |
} |
- JSFunction::SetInitialMap(function, new_map); |
- |
// Deoptimize all code that embeds the previous initial map. |
initial_map->dependent_code()->DeoptimizeDependentCodeGroup( |
isolate, DependentCode::kInitialMapChangedGroup); |
@@ -9956,9 +9968,10 @@ bool JSFunction::RemovePrototype() { |
} |
-void JSFunction::SetInitialMap(Handle<JSFunction> function, Handle<Map> map) { |
- if (map->prototype()->IsJSObject()) { |
- Handle<JSObject> js_proto = handle(JSObject::cast(map->prototype())); |
+void JSFunction::SetInitialMap(Handle<JSFunction> function, Handle<Map> map, |
+ Handle<Object> prototype) { |
+ if (prototype->IsJSObject()) { |
+ Handle<JSObject> js_proto = Handle<JSObject>::cast(prototype); |
if (!js_proto->map()->is_prototype_map() && |
!js_proto->map()->IsGlobalObjectMap() && |
!js_proto->map()->IsJSGlobalProxyMap()) { |
@@ -9977,6 +9990,7 @@ void JSFunction::SetInitialMap(Handle<JSFunction> function, Handle<Map> map) { |
} |
} |
} |
+ map->set_prototype(*prototype); |
function->set_prototype_or_initial_map(*map); |
map->set_constructor(*function); |
} |
@@ -10011,11 +10025,10 @@ void JSFunction::EnsureHasInitialMap(Handle<JSFunction> function) { |
} |
map->set_inobject_properties(in_object_properties); |
map->set_unused_property_fields(in_object_properties); |
- map->set_prototype(*prototype); |
DCHECK(map->has_fast_object_elements()); |
// Finally link initial map and constructor function. |
- JSFunction::SetInitialMap(function, map); |
+ JSFunction::SetInitialMap(function, map, Handle<JSReceiver>::cast(prototype)); |
if (!function->shared()->is_generator()) { |
function->StartInobjectSlackTracking(); |
@@ -12100,7 +12113,7 @@ Handle<Map> Map::TransitionToPrototype(Handle<Map> map, |
MaybeHandle<Object> JSObject::SetPrototype(Handle<JSObject> object, |
Handle<Object> value, |
- bool skip_hidden_prototypes) { |
+ bool from_javascript) { |
#ifdef DEBUG |
int size = object->Size(); |
#endif |
@@ -12145,7 +12158,7 @@ MaybeHandle<Object> JSObject::SetPrototype(Handle<JSObject> object, |
object->map()->DictionaryElementsInPrototypeChainOnly(); |
Handle<JSObject> real_receiver = object; |
- if (skip_hidden_prototypes) { |
+ if (from_javascript) { |
// Find the first object in the chain whose prototype object is not |
// hidden and set the new prototype on that object. |
PrototypeIterator iter(isolate, real_receiver); |
@@ -12163,7 +12176,19 @@ MaybeHandle<Object> JSObject::SetPrototype(Handle<JSObject> object, |
if (map->prototype() == *value) return value; |
if (value->IsJSObject()) { |
- JSObject::OptimizeAsPrototype(Handle<JSObject>::cast(value)); |
+ Handle<JSObject> js_proto = Handle<JSObject>::cast(value); |
+ if (!from_javascript && !js_proto->IsJSGlobalProxy() && |
+ !js_proto->IsGlobalObject() && !js_proto->map()->is_prototype_map()) { |
+ JSObject::NormalizeProperties(js_proto, KEEP_INOBJECT_PROPERTIES, 0); |
+ JSObject::MigrateSlowToFast(js_proto, 0); |
+ if (js_proto->HasFastProperties()) { |
+ Handle<Map> new_map = Map::Copy(handle(js_proto->map())); |
+ JSObject::MigrateToMap(js_proto, new_map); |
+ js_proto->map()->set_is_prototype_map(true); |
+ } |
Igor Sheludko
2014/08/11 07:42:13
The "make-prototype-super-fast" piece of code look
|
+ } else { |
+ JSObject::OptimizeAsPrototype(js_proto); |
+ } |
} |
Handle<Map> new_map = Map::TransitionToPrototype(map, value); |