Commit 3eabf5a5 authored by Toon Verwaest's avatar Toon Verwaest Committed by Commit Bot

[runtime] Drop PrototypeOptimizationMode to unify prototype handling

Don't treat new prototypes differently depending on how they become a
prototype. This is work towards always keeping prototypes in slow-mode.


Bug: v8:6471
Change-Id: I62de1018e21d91fda3a5da044615f32c718910b1
Reviewed-on: https://chromium-review.googlesource.com/526596Reviewed-by: 's avatarJakob Kummerow <jkummerow@chromium.org>
Reviewed-by: 's avatarMichael Starzinger <mstarzinger@chromium.org>
Commit-Queue: Toon Verwaest <verwaest@chromium.org>
Cr-Commit-Position: refs/heads/master@{#45781}
parent b3802dbb
...@@ -402,7 +402,7 @@ MaybeHandle<JSObject> InstantiateObject(Isolate* isolate, ...@@ -402,7 +402,7 @@ MaybeHandle<JSObject> InstantiateObject(Isolate* isolate,
ASSIGN_RETURN_ON_EXCEPTION(isolate, object, ASSIGN_RETURN_ON_EXCEPTION(isolate, object,
JSObject::New(constructor, new_target), JSObject); JSObject::New(constructor, new_target), JSObject);
if (is_prototype) JSObject::OptimizeAsPrototype(object, FAST_PROTOTYPE); if (is_prototype) JSObject::OptimizeAsPrototype(object);
ASSIGN_RETURN_ON_EXCEPTION( ASSIGN_RETURN_ON_EXCEPTION(
isolate, result, isolate, result,
......
...@@ -1298,7 +1298,7 @@ Reduction JSBuiltinReducer::ReduceFunctionBind(Node* node) { ...@@ -1298,7 +1298,7 @@ Reduction JSBuiltinReducer::ReduceFunctionBind(Node* node) {
? isolate()->bound_function_with_constructor_map() ? isolate()->bound_function_with_constructor_map()
: isolate()->bound_function_without_constructor_map(); : isolate()->bound_function_without_constructor_map();
if (map->prototype() != *prototype) { if (map->prototype() != *prototype) {
map = Map::TransitionToPrototype(map, prototype, REGULAR_PROTOTYPE); map = Map::TransitionToPrototype(map, prototype);
} }
DCHECK_EQ(target_function->IsConstructor(), map->is_constructor()); DCHECK_EQ(target_function->IsConstructor(), map->is_constructor());
......
...@@ -2329,7 +2329,7 @@ MaybeHandle<JSBoundFunction> Factory::NewJSBoundFunction( ...@@ -2329,7 +2329,7 @@ MaybeHandle<JSBoundFunction> Factory::NewJSBoundFunction(
? isolate()->bound_function_with_constructor_map() ? isolate()->bound_function_with_constructor_map()
: isolate()->bound_function_without_constructor_map(); : isolate()->bound_function_without_constructor_map();
if (map->prototype() != *prototype) { if (map->prototype() != *prototype) {
map = Map::TransitionToPrototype(map, prototype, REGULAR_PROTOTYPE); map = Map::TransitionToPrototype(map, prototype);
} }
DCHECK_EQ(target_function->IsConstructor(), map->is_constructor()); DCHECK_EQ(target_function->IsConstructor(), map->is_constructor());
......
...@@ -3855,7 +3855,7 @@ void JSObject::ForceSetPrototype(Handle<JSObject> object, ...@@ -3855,7 +3855,7 @@ void JSObject::ForceSetPrototype(Handle<JSObject> object,
// object.__proto__ = proto; // object.__proto__ = proto;
Handle<Map> old_map = Handle<Map>(object->map()); Handle<Map> old_map = Handle<Map>(object->map());
Handle<Map> new_map = Map::Copy(old_map, "ForceSetPrototype"); Handle<Map> new_map = Map::Copy(old_map, "ForceSetPrototype");
Map::SetPrototype(new_map, proto, FAST_PROTOTYPE); Map::SetPrototype(new_map, proto);
JSObject::MigrateToMap(object, new_map); JSObject::MigrateToMap(object, new_map);
} }
...@@ -4732,7 +4732,7 @@ Handle<Map> Map::GetObjectCreateMap(Handle<HeapObject> prototype) { ...@@ -4732,7 +4732,7 @@ Handle<Map> Map::GetObjectCreateMap(Handle<HeapObject> prototype) {
if (prototype->IsJSObject()) { if (prototype->IsJSObject()) {
Handle<JSObject> js_prototype = Handle<JSObject>::cast(prototype); Handle<JSObject> js_prototype = Handle<JSObject>::cast(prototype);
if (!js_prototype->map()->is_prototype_map()) { if (!js_prototype->map()->is_prototype_map()) {
JSObject::OptimizeAsPrototype(js_prototype, FAST_PROTOTYPE); JSObject::OptimizeAsPrototype(js_prototype);
} }
Handle<PrototypeInfo> info = Handle<PrototypeInfo> info =
Map::GetOrCreatePrototypeInfo(js_prototype, isolate); Map::GetOrCreatePrototypeInfo(js_prototype, isolate);
...@@ -4741,13 +4741,13 @@ Handle<Map> Map::GetObjectCreateMap(Handle<HeapObject> prototype) { ...@@ -4741,13 +4741,13 @@ Handle<Map> Map::GetObjectCreateMap(Handle<HeapObject> prototype) {
map = handle(info->ObjectCreateMap(), isolate); map = handle(info->ObjectCreateMap(), isolate);
} else { } else {
map = Map::CopyInitialMap(map); map = Map::CopyInitialMap(map);
Map::SetPrototype(map, prototype, FAST_PROTOTYPE); Map::SetPrototype(map, prototype);
PrototypeInfo::SetObjectCreateMap(info, map); PrototypeInfo::SetObjectCreateMap(info, map);
} }
return map; return map;
} }
return Map::TransitionToPrototype(map, prototype, REGULAR_PROTOTYPE); return Map::TransitionToPrototype(map, prototype);
} }
template <class T> template <class T>
...@@ -12197,16 +12197,15 @@ void JSObject::MakePrototypesFast(Handle<Object> receiver, ...@@ -12197,16 +12197,15 @@ void JSObject::MakePrototypesFast(Handle<Object> receiver,
if (current_map->should_be_fast_prototype_map()) return; if (current_map->should_be_fast_prototype_map()) return;
Handle<Map> map(current_map); Handle<Map> map(current_map);
Map::SetShouldBeFastPrototypeMap(map, true, isolate); Map::SetShouldBeFastPrototypeMap(map, true, isolate);
JSObject::OptimizeAsPrototype(current_obj, FAST_PROTOTYPE); JSObject::OptimizeAsPrototype(current_obj);
} }
} }
} }
// static // static
void JSObject::OptimizeAsPrototype(Handle<JSObject> object, void JSObject::OptimizeAsPrototype(Handle<JSObject> object) {
PrototypeOptimizationMode mode) {
if (object->IsJSGlobalObject()) return; if (object->IsJSGlobalObject()) return;
if (mode == FAST_PROTOTYPE && PrototypeBenefitsFromNormalization(object)) { if (PrototypeBenefitsFromNormalization(object)) {
// First normalize to ensure all JSFunctions are DATA_CONSTANT. // First normalize to ensure all JSFunctions are DATA_CONSTANT.
JSObject::NormalizeProperties(object, KEEP_INOBJECT_PROPERTIES, 0, JSObject::NormalizeProperties(object, KEEP_INOBJECT_PROPERTIES, 0,
"NormalizeAsPrototype"); "NormalizeAsPrototype");
...@@ -12246,7 +12245,7 @@ void JSObject::OptimizeAsPrototype(Handle<JSObject> object, ...@@ -12246,7 +12245,7 @@ void JSObject::OptimizeAsPrototype(Handle<JSObject> object,
void JSObject::ReoptimizeIfPrototype(Handle<JSObject> object) { void JSObject::ReoptimizeIfPrototype(Handle<JSObject> object) {
if (!object->map()->is_prototype_map()) return; if (!object->map()->is_prototype_map()) return;
if (!object->map()->should_be_fast_prototype_map()) return; if (!object->map()->should_be_fast_prototype_map()) return;
OptimizeAsPrototype(object, FAST_PROTOTYPE); OptimizeAsPrototype(object);
} }
...@@ -12453,14 +12452,13 @@ Handle<WeakCell> Map::GetOrCreatePrototypeWeakCell(Handle<JSObject> prototype, ...@@ -12453,14 +12452,13 @@ Handle<WeakCell> Map::GetOrCreatePrototypeWeakCell(Handle<JSObject> prototype,
} }
// static // static
void Map::SetPrototype(Handle<Map> map, Handle<Object> prototype, void Map::SetPrototype(Handle<Map> map, Handle<Object> prototype) {
PrototypeOptimizationMode proto_mode) {
RuntimeCallTimerScope stats_scope(*map, &RuntimeCallStats::Map_SetPrototype); RuntimeCallTimerScope stats_scope(*map, &RuntimeCallStats::Map_SetPrototype);
bool is_hidden = false; bool is_hidden = false;
if (prototype->IsJSObject()) { if (prototype->IsJSObject()) {
Handle<JSObject> prototype_jsobj = Handle<JSObject>::cast(prototype); Handle<JSObject> prototype_jsobj = Handle<JSObject>::cast(prototype);
JSObject::OptimizeAsPrototype(prototype_jsobj, proto_mode); JSObject::OptimizeAsPrototype(prototype_jsobj);
Object* maybe_constructor = prototype_jsobj->map()->GetConstructor(); Object* maybe_constructor = prototype_jsobj->map()->GetConstructor();
if (maybe_constructor->IsJSFunction()) { if (maybe_constructor->IsJSFunction()) {
...@@ -12556,8 +12554,7 @@ void SetInstancePrototype(Isolate* isolate, Handle<JSFunction> function, ...@@ -12556,8 +12554,7 @@ void SetInstancePrototype(Isolate* isolate, Handle<JSFunction> function,
function->set_prototype_or_initial_map(*value); function->set_prototype_or_initial_map(*value);
if (value->IsJSObject()) { if (value->IsJSObject()) {
// Optimize as prototype to detach it from its transition tree. // Optimize as prototype to detach it from its transition tree.
JSObject::OptimizeAsPrototype(Handle<JSObject>::cast(value), JSObject::OptimizeAsPrototype(Handle<JSObject>::cast(value));
FAST_PROTOTYPE);
} }
} }
isolate->heap()->ClearInstanceofCache(); isolate->heap()->ClearInstanceofCache();
...@@ -12630,9 +12627,7 @@ bool JSFunction::RemovePrototype() { ...@@ -12630,9 +12627,7 @@ bool JSFunction::RemovePrototype() {
void JSFunction::SetInitialMap(Handle<JSFunction> function, Handle<Map> map, void JSFunction::SetInitialMap(Handle<JSFunction> function, Handle<Map> map,
Handle<Object> prototype) { Handle<Object> prototype) {
if (map->prototype() != *prototype) { if (map->prototype() != *prototype) Map::SetPrototype(map, prototype);
Map::SetPrototype(map, prototype, FAST_PROTOTYPE);
}
function->set_prototype_or_initial_map(*map); function->set_prototype_or_initial_map(*map);
map->SetConstructor(*function); map->SetConstructor(*function);
#if V8_TRACE_MAPS #if V8_TRACE_MAPS
...@@ -12864,9 +12859,7 @@ MaybeHandle<Map> JSFunction::GetDerivedMap(Isolate* isolate, ...@@ -12864,9 +12859,7 @@ MaybeHandle<Map> JSFunction::GetDerivedMap(Isolate* isolate,
Handle<Map> map = Map::CopyInitialMap(constructor_initial_map); Handle<Map> map = Map::CopyInitialMap(constructor_initial_map);
map->set_new_target_is_base(false); map->set_new_target_is_base(false);
DCHECK(prototype->IsJSReceiver()); DCHECK(prototype->IsJSReceiver());
if (map->prototype() != *prototype) { if (map->prototype() != *prototype) Map::SetPrototype(map, prototype);
Map::SetPrototype(map, prototype, FAST_PROTOTYPE);
}
map->SetConstructor(*constructor); map->SetConstructor(*constructor);
return map; return map;
} }
...@@ -15173,15 +15166,13 @@ const char* DependentCode::DependencyGroupName(DependencyGroup group) { ...@@ -15173,15 +15166,13 @@ const char* DependentCode::DependencyGroupName(DependencyGroup group) {
UNREACHABLE(); UNREACHABLE();
} }
Handle<Map> Map::TransitionToPrototype(Handle<Map> map, Handle<Map> Map::TransitionToPrototype(Handle<Map> map,
Handle<Object> prototype, Handle<Object> prototype) {
PrototypeOptimizationMode mode) {
Handle<Map> new_map = TransitionArray::GetPrototypeTransition(map, prototype); Handle<Map> new_map = TransitionArray::GetPrototypeTransition(map, prototype);
if (new_map.is_null()) { if (new_map.is_null()) {
new_map = Copy(map, "TransitionToPrototype"); new_map = Copy(map, "TransitionToPrototype");
TransitionArray::PutPrototypeTransition(map, prototype, new_map); TransitionArray::PutPrototypeTransition(map, prototype, new_map);
Map::SetPrototype(new_map, prototype, mode); Map::SetPrototype(new_map, prototype);
} }
return new_map; return new_map;
} }
...@@ -15356,9 +15347,7 @@ Maybe<bool> JSObject::SetPrototype(Handle<JSObject> object, ...@@ -15356,9 +15347,7 @@ Maybe<bool> JSObject::SetPrototype(Handle<JSObject> object,
isolate->UpdateArrayProtectorOnSetPrototype(real_receiver); isolate->UpdateArrayProtectorOnSetPrototype(real_receiver);
PrototypeOptimizationMode mode = Handle<Map> new_map = Map::TransitionToPrototype(map, value);
from_javascript ? REGULAR_PROTOTYPE : FAST_PROTOTYPE;
Handle<Map> new_map = Map::TransitionToPrototype(map, value, mode);
DCHECK(new_map->prototype() == *value); DCHECK(new_map->prototype() == *value);
JSObject::MigrateToMap(real_receiver, new_map); JSObject::MigrateToMap(real_receiver, new_map);
......
...@@ -227,14 +227,6 @@ enum PropertyNormalizationMode { ...@@ -227,14 +227,6 @@ enum PropertyNormalizationMode {
}; };
// Indicates how aggressively the prototype should be optimized. FAST_PROTOTYPE
// will give the fastest result by tailoring the map to the prototype, but that
// will cause polymorphism with other objects. REGULAR_PROTOTYPE is to be used
// (at least for now) when dynamically modifying the prototype chain of an
// object using __proto__ or Object.setPrototypeOf.
enum PrototypeOptimizationMode { REGULAR_PROTOTYPE, FAST_PROTOTYPE };
// Indicates whether transitions can be added to a source map or not. // Indicates whether transitions can be added to a source map or not.
enum TransitionFlag { enum TransitionFlag {
INSERT_TRANSITION, INSERT_TRANSITION,
...@@ -2283,8 +2275,7 @@ class JSObject: public JSReceiver { ...@@ -2283,8 +2275,7 @@ class JSObject: public JSReceiver {
Handle<Object> value, Handle<Object> value,
PropertyAttributes attributes); PropertyAttributes attributes);
static void OptimizeAsPrototype(Handle<JSObject> object, static void OptimizeAsPrototype(Handle<JSObject> object);
PrototypeOptimizationMode mode);
static void ReoptimizeIfPrototype(Handle<JSObject> object); static void ReoptimizeIfPrototype(Handle<JSObject> object);
static void MakePrototypesFast(Handle<Object> receiver, static void MakePrototypesFast(Handle<Object> receiver,
WhereToStart where_to_start, Isolate* isolate); WhereToStart where_to_start, Isolate* isolate);
......
...@@ -326,9 +326,7 @@ class Map : public HeapObject { ...@@ -326,9 +326,7 @@ class Map : public HeapObject {
// [prototype]: implicit prototype object. // [prototype]: implicit prototype object.
DECL_ACCESSORS(prototype, Object) DECL_ACCESSORS(prototype, Object)
// TODO(jkummerow): make set_prototype private. // TODO(jkummerow): make set_prototype private.
static void SetPrototype( static void SetPrototype(Handle<Map> map, Handle<Object> prototype);
Handle<Map> map, Handle<Object> prototype,
PrototypeOptimizationMode proto_mode = FAST_PROTOTYPE);
// [constructor]: points back to the function or FunctionTemplateInfo // [constructor]: points back to the function or FunctionTemplateInfo
// responsible for this map. // responsible for this map.
...@@ -574,8 +572,7 @@ class Map : public HeapObject { ...@@ -574,8 +572,7 @@ class Map : public HeapObject {
inline void set_visitor_id(int visitor_id); inline void set_visitor_id(int visitor_id);
static Handle<Map> TransitionToPrototype(Handle<Map> map, static Handle<Map> TransitionToPrototype(Handle<Map> map,
Handle<Object> prototype, Handle<Object> prototype);
PrototypeOptimizationMode mode);
static Handle<Map> TransitionToImmutableProto(Handle<Map> map); static Handle<Map> TransitionToImmutableProto(Handle<Map> map);
......
...@@ -2343,7 +2343,7 @@ TEST(PrototypeTransitionFromMapOwningDescriptor) { ...@@ -2343,7 +2343,7 @@ TEST(PrototypeTransitionFromMapOwningDescriptor) {
} }
Handle<Map> Transition(Handle<Map> map, Expectations& expectations) { Handle<Map> Transition(Handle<Map> map, Expectations& expectations) {
return Map::TransitionToPrototype(map, prototype_, REGULAR_PROTOTYPE); return Map::TransitionToPrototype(map, prototype_);
} }
// TODO(ishell): remove once IS_PROTO_TRANS_ISSUE_FIXED is removed. // TODO(ishell): remove once IS_PROTO_TRANS_ISSUE_FIXED is removed.
bool generalizes_representations() const { bool generalizes_representations() const {
...@@ -2389,7 +2389,7 @@ TEST(PrototypeTransitionFromMapNotOwningDescriptor) { ...@@ -2389,7 +2389,7 @@ TEST(PrototypeTransitionFromMapNotOwningDescriptor) {
.ToHandleChecked(); .ToHandleChecked();
CHECK(!map->owns_descriptors()); CHECK(!map->owns_descriptors());
return Map::TransitionToPrototype(map, prototype_, REGULAR_PROTOTYPE); return Map::TransitionToPrototype(map, prototype_);
} }
// TODO(ishell): remove once IS_PROTO_TRANS_ISSUE_FIXED is removed. // TODO(ishell): remove once IS_PROTO_TRANS_ISSUE_FIXED is removed.
bool generalizes_representations() const { bool generalizes_representations() const {
......
...@@ -33,9 +33,9 @@ function __f_1(__v_4, add_first, __v_6, same_map_as) { ...@@ -33,9 +33,9 @@ function __f_1(__v_4, add_first, __v_6, same_map_as) {
assertFalse(%HasFastProperties(__v_1)); assertFalse(%HasFastProperties(__v_1));
} else { } else {
__f_0(__v_1, __v_6); __f_0(__v_1, __v_6);
assertTrue(__v_4 || %HasFastProperties(__v_1)); assertTrue(__v_4 || !%HasFastProperties(__v_1));
__f_4(__v_1); __f_4(__v_1);
assertTrue(__v_4 || %HasFastProperties(__v_1)); assertTrue(__v_4 || !%HasFastProperties(__v_1));
} }
} }
gc(); gc();
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment