From 7c22a153e2ba5099523118f5c085b52d887f32ea Mon Sep 17 00:00:00 2001 From: ishell Date: Mon, 31 Oct 2016 07:58:42 -0700 Subject: [PATCH] [ic] Simplify handling of primitive maps. This CL adds support for primitive maps to 1) PrototypeIterator, 2) PropertyHandlerCompiler::CheckPrototypes(), 3) Map::GetOrCreatePrototypeChainValidityCell(), 4) Prototype checks in data-driven ICs. BUG=v8:5561 Review-Url: https://codereview.chromium.org/2466553002 Cr-Commit-Position: refs/heads/master@{#40673} --- src/ic/arm/handler-compiler-arm.cc | 21 ++++----------------- src/ic/arm64/handler-compiler-arm64.cc | 21 ++++----------------- src/ic/handler-compiler.cc | 19 ++----------------- src/ic/handler-compiler.h | 3 +-- src/ic/ia32/handler-compiler-ia32.cc | 21 ++++----------------- src/ic/ic.cc | 2 +- src/ic/mips/handler-compiler-mips.cc | 21 ++++----------------- src/ic/mips64/handler-compiler-mips64.cc | 21 ++++----------------- src/ic/ppc/handler-compiler-ppc.cc | 21 ++++----------------- src/ic/s390/handler-compiler-s390.cc | 20 ++++---------------- src/ic/x64/handler-compiler-x64.cc | 21 ++++----------------- src/ic/x87/handler-compiler-x87.cc | 21 ++++----------------- src/lookup.cc | 3 ++- src/objects.cc | 17 +++++++++++------ src/objects.h | 5 ++++- src/prototype.h | 21 +++++++++++---------- src/string-stream.cc | 2 +- 17 files changed, 69 insertions(+), 191 deletions(-) diff --git a/src/ic/arm/handler-compiler-arm.cc b/src/ic/arm/handler-compiler-arm.cc index c0554cbbaf..61f8f86a55 100644 --- a/src/ic/arm/handler-compiler-arm.cc +++ b/src/ic/arm/handler-compiler-arm.cc @@ -407,10 +407,9 @@ void NamedStoreHandlerCompiler::GenerateFieldTypeChecks(FieldType* field_type, } } - Register PropertyHandlerCompiler::CheckPrototypes( Register object_reg, Register holder_reg, Register scratch1, - Register scratch2, Handle name, Label* miss, PrototypeCheckType check, + Register scratch2, Handle name, Label* miss, ReturnHolder return_what) { Handle receiver_map = map(); @@ -429,17 +428,6 @@ Register PropertyHandlerCompiler::CheckPrototypes( __ b(ne, miss); } - // The prototype chain of primitives (and their JSValue wrappers) depends - // on the native context, which can't be guarded by validity cells. - // |object_reg| holds the native context specific prototype in this case; - // we need to check its map. - if (check == CHECK_ALL_MAPS) { - __ ldr(scratch1, FieldMemOperand(object_reg, HeapObject::kMapOffset)); - Handle cell = Map::WeakCellForMap(receiver_map); - __ CmpWeakValue(scratch1, cell, scratch2); - __ b(ne, miss); - } - // Keep track of the current object in register reg. Register reg = object_reg; int depth = 0; @@ -449,15 +437,14 @@ Register PropertyHandlerCompiler::CheckPrototypes( current = isolate()->global_object(); } - Handle prototype = Handle::null(); - Handle current_map = receiver_map; + Handle current_map(receiver_map->GetPrototypeChainRootMap(isolate()), + isolate()); Handle holder_map(holder()->map()); // Traverse the prototype chain and check the maps in the prototype chain for // fast and global objects or do negative lookup for normal objects. while (!current_map.is_identical_to(holder_map)) { ++depth; - prototype = handle(JSObject::cast(current_map->prototype())); if (current_map->IsJSGlobalObjectMap()) { GenerateCheckPropertyCell(masm(), Handle::cast(current), name, scratch2, miss); @@ -479,7 +466,7 @@ Register PropertyHandlerCompiler::CheckPrototypes( reg = holder_reg; // From now on the object will be in holder_reg. // Go to the next object in the prototype chain. - current = prototype; + current = handle(JSObject::cast(current_map->prototype())); current_map = handle(current->map()); } diff --git a/src/ic/arm64/handler-compiler-arm64.cc b/src/ic/arm64/handler-compiler-arm64.cc index e149bc0e66..8b0ecf5f66 100644 --- a/src/ic/arm64/handler-compiler-arm64.cc +++ b/src/ic/arm64/handler-compiler-arm64.cc @@ -437,10 +437,9 @@ void NamedStoreHandlerCompiler::GenerateFieldTypeChecks(FieldType* field_type, } } - Register PropertyHandlerCompiler::CheckPrototypes( Register object_reg, Register holder_reg, Register scratch1, - Register scratch2, Handle name, Label* miss, PrototypeCheckType check, + Register scratch2, Handle name, Label* miss, ReturnHolder return_what) { Handle receiver_map = map(); @@ -458,17 +457,6 @@ Register PropertyHandlerCompiler::CheckPrototypes( __ B(ne, miss); } - // The prototype chain of primitives (and their JSValue wrappers) depends - // on the native context, which can't be guarded by validity cells. - // |object_reg| holds the native context specific prototype in this case; - // we need to check its map. - if (check == CHECK_ALL_MAPS) { - __ Ldr(scratch1, FieldMemOperand(object_reg, HeapObject::kMapOffset)); - Handle cell = Map::WeakCellForMap(receiver_map); - __ CmpWeakValue(scratch1, cell, scratch2); - __ B(ne, miss); - } - // Keep track of the current object in register reg. Register reg = object_reg; int depth = 0; @@ -478,15 +466,14 @@ Register PropertyHandlerCompiler::CheckPrototypes( current = isolate()->global_object(); } - Handle prototype = Handle::null(); - Handle current_map = receiver_map; + Handle current_map(receiver_map->GetPrototypeChainRootMap(isolate()), + isolate()); Handle holder_map(holder()->map()); // Traverse the prototype chain and check the maps in the prototype chain for // fast and global objects or do negative lookup for normal objects. while (!current_map.is_identical_to(holder_map)) { ++depth; - prototype = handle(JSObject::cast(current_map->prototype())); if (current_map->IsJSGlobalObjectMap()) { GenerateCheckPropertyCell(masm(), Handle::cast(current), name, scratch2, miss); @@ -507,7 +494,7 @@ Register PropertyHandlerCompiler::CheckPrototypes( reg = holder_reg; // From now on the object will be in holder_reg. // Go to the next object in the prototype chain. - current = prototype; + current = handle(JSObject::cast(current_map->prototype())); current_map = handle(current->map()); } diff --git a/src/ic/handler-compiler.cc b/src/ic/handler-compiler.cc index 37933aff50..9b10045f80 100644 --- a/src/ic/handler-compiler.cc +++ b/src/ic/handler-compiler.cc @@ -95,24 +95,9 @@ Register NamedLoadHandlerCompiler::FrontendHeader(Register object_reg, Handle name, Label* miss, ReturnHolder return_what) { - PrototypeCheckType check_type = SKIP_RECEIVER; - int function_index = map()->IsPrimitiveMap() - ? map()->GetConstructorFunctionIndex() - : Map::kNoConstructorFunctionIndex; - if (function_index != Map::kNoConstructorFunctionIndex) { - GenerateDirectLoadGlobalFunctionPrototype(masm(), function_index, - scratch1(), miss); - Object* function = isolate()->native_context()->get(function_index); - Object* prototype = JSFunction::cast(function)->instance_prototype(); - Handle map(JSObject::cast(prototype)->map()); - set_map(map); - object_reg = scratch1(); - check_type = CHECK_ALL_MAPS; - } - // Check that the maps starting from the prototype haven't changed. return CheckPrototypes(object_reg, scratch1(), scratch2(), scratch3(), name, - miss, check_type, return_what); + miss, return_what); } @@ -123,7 +108,7 @@ Register NamedStoreHandlerCompiler::FrontendHeader(Register object_reg, Label* miss, ReturnHolder return_what) { return CheckPrototypes(object_reg, this->name(), scratch1(), scratch2(), name, - miss, SKIP_RECEIVER, return_what); + miss, return_what); } diff --git a/src/ic/handler-compiler.h b/src/ic/handler-compiler.h index 63ca050ca2..1023fafdec 100644 --- a/src/ic/handler-compiler.h +++ b/src/ic/handler-compiler.h @@ -13,7 +13,6 @@ namespace internal { class CallOptimization; -enum PrototypeCheckType { CHECK_ALL_MAPS, SKIP_RECEIVER }; enum ReturnHolder { RETURN_HOLDER, DONT_RETURN_ANYTHING }; class PropertyHandlerCompiler : public PropertyAccessCompiler { @@ -99,7 +98,7 @@ class PropertyHandlerCompiler : public PropertyAccessCompiler { Register CheckPrototypes(Register object_reg, Register holder_reg, Register scratch1, Register scratch2, Handle name, Label* miss, - PrototypeCheckType check, ReturnHolder return_what); + ReturnHolder return_what); Handle GetCode(Code::Kind kind, Handle name); void set_holder(Handle holder) { holder_ = holder; } diff --git a/src/ic/ia32/handler-compiler-ia32.cc b/src/ic/ia32/handler-compiler-ia32.cc index ca1ea9d7db..4961bed95a 100644 --- a/src/ic/ia32/handler-compiler-ia32.cc +++ b/src/ic/ia32/handler-compiler-ia32.cc @@ -411,10 +411,9 @@ void NamedStoreHandlerCompiler::GenerateFieldTypeChecks(FieldType* field_type, } } - Register PropertyHandlerCompiler::CheckPrototypes( Register object_reg, Register holder_reg, Register scratch1, - Register scratch2, Handle name, Label* miss, PrototypeCheckType check, + Register scratch2, Handle name, Label* miss, ReturnHolder return_what) { Handle receiver_map = map(); @@ -433,17 +432,6 @@ Register PropertyHandlerCompiler::CheckPrototypes( __ j(not_equal, miss); } - // The prototype chain of primitives (and their JSValue wrappers) depends - // on the native context, which can't be guarded by validity cells. - // |object_reg| holds the native context specific prototype in this case; - // we need to check its map. - if (check == CHECK_ALL_MAPS) { - __ mov(scratch1, FieldOperand(object_reg, HeapObject::kMapOffset)); - Handle cell = Map::WeakCellForMap(receiver_map); - __ CmpWeakValue(scratch1, cell, scratch2); - __ j(not_equal, miss); - } - // Keep track of the current object in register reg. Register reg = object_reg; int depth = 0; @@ -453,15 +441,14 @@ Register PropertyHandlerCompiler::CheckPrototypes( current = isolate()->global_object(); } - Handle prototype = Handle::null(); - Handle current_map = receiver_map; + Handle current_map(receiver_map->GetPrototypeChainRootMap(isolate()), + isolate()); Handle holder_map(holder()->map()); // Traverse the prototype chain and check the maps in the prototype chain for // fast and global objects or do negative lookup for normal objects. while (!current_map.is_identical_to(holder_map)) { ++depth; - prototype = handle(JSObject::cast(current_map->prototype())); if (current_map->IsJSGlobalObjectMap()) { GenerateCheckPropertyCell(masm(), Handle::cast(current), name, scratch2, miss); @@ -483,7 +470,7 @@ Register PropertyHandlerCompiler::CheckPrototypes( reg = holder_reg; // From now on the object will be in holder_reg. // Go to the next object in the prototype chain. - current = prototype; + current = handle(JSObject::cast(current_map->prototype())); current_map = handle(current->map()); } diff --git a/src/ic/ic.cc b/src/ic/ic.cc index d9fb716ab2..a88746eb8e 100644 --- a/src/ic/ic.cc +++ b/src/ic/ic.cc @@ -862,7 +862,7 @@ int InitPrototypeChecks(Isolate* isolate, Handle receiver_map, DCHECK(holder->HasFastProperties()); // The following kinds of receiver maps require custom handler compilation. - if (receiver_map->IsPrimitiveMap() || receiver_map->IsJSGlobalObjectMap()) { + if (receiver_map->IsJSGlobalObjectMap()) { return -1; } // We don't encode the requirement to check access rights because we already diff --git a/src/ic/mips/handler-compiler-mips.cc b/src/ic/mips/handler-compiler-mips.cc index 6fc07b111b..0541a6a662 100644 --- a/src/ic/mips/handler-compiler-mips.cc +++ b/src/ic/mips/handler-compiler-mips.cc @@ -393,10 +393,9 @@ void NamedStoreHandlerCompiler::GenerateFieldTypeChecks(FieldType* field_type, } } - Register PropertyHandlerCompiler::CheckPrototypes( Register object_reg, Register holder_reg, Register scratch1, - Register scratch2, Handle name, Label* miss, PrototypeCheckType check, + Register scratch2, Handle name, Label* miss, ReturnHolder return_what) { Handle receiver_map = map(); @@ -415,17 +414,6 @@ Register PropertyHandlerCompiler::CheckPrototypes( Operand(Smi::FromInt(Map::kPrototypeChainValid))); } - // The prototype chain of primitives (and their JSValue wrappers) depends - // on the native context, which can't be guarded by validity cells. - // |object_reg| holds the native context specific prototype in this case; - // we need to check its map. - if (check == CHECK_ALL_MAPS) { - __ lw(scratch1, FieldMemOperand(object_reg, HeapObject::kMapOffset)); - Handle cell = Map::WeakCellForMap(receiver_map); - __ GetWeakValue(scratch2, cell); - __ Branch(miss, ne, scratch1, Operand(scratch2)); - } - // Keep track of the current object in register reg. Register reg = object_reg; int depth = 0; @@ -435,15 +423,14 @@ Register PropertyHandlerCompiler::CheckPrototypes( current = isolate()->global_object(); } - Handle prototype = Handle::null(); - Handle current_map = receiver_map; + Handle current_map(receiver_map->GetPrototypeChainRootMap(isolate()), + isolate()); Handle holder_map(holder()->map()); // Traverse the prototype chain and check the maps in the prototype chain for // fast and global objects or do negative lookup for normal objects. while (!current_map.is_identical_to(holder_map)) { ++depth; - prototype = handle(JSObject::cast(current_map->prototype())); if (current_map->IsJSGlobalObjectMap()) { GenerateCheckPropertyCell(masm(), Handle::cast(current), name, scratch2, miss); @@ -465,7 +452,7 @@ Register PropertyHandlerCompiler::CheckPrototypes( reg = holder_reg; // From now on the object will be in holder_reg. // Go to the next object in the prototype chain. - current = prototype; + current = handle(JSObject::cast(current_map->prototype())); current_map = handle(current->map()); } diff --git a/src/ic/mips64/handler-compiler-mips64.cc b/src/ic/mips64/handler-compiler-mips64.cc index 1824d2a712..181534c3bc 100644 --- a/src/ic/mips64/handler-compiler-mips64.cc +++ b/src/ic/mips64/handler-compiler-mips64.cc @@ -393,10 +393,9 @@ void NamedStoreHandlerCompiler::GenerateFieldTypeChecks(FieldType* field_type, } } - Register PropertyHandlerCompiler::CheckPrototypes( Register object_reg, Register holder_reg, Register scratch1, - Register scratch2, Handle name, Label* miss, PrototypeCheckType check, + Register scratch2, Handle name, Label* miss, ReturnHolder return_what) { Handle receiver_map = map(); @@ -415,17 +414,6 @@ Register PropertyHandlerCompiler::CheckPrototypes( Operand(Smi::FromInt(Map::kPrototypeChainValid))); } - // The prototype chain of primitives (and their JSValue wrappers) depends - // on the native context, which can't be guarded by validity cells. - // |object_reg| holds the native context specific prototype in this case; - // we need to check its map. - if (check == CHECK_ALL_MAPS) { - __ ld(scratch1, FieldMemOperand(object_reg, HeapObject::kMapOffset)); - Handle cell = Map::WeakCellForMap(receiver_map); - __ GetWeakValue(scratch2, cell); - __ Branch(miss, ne, scratch1, Operand(scratch2)); - } - // Keep track of the current object in register reg. Register reg = object_reg; int depth = 0; @@ -435,15 +423,14 @@ Register PropertyHandlerCompiler::CheckPrototypes( current = isolate()->global_object(); } - Handle prototype = Handle::null(); - Handle current_map = receiver_map; + Handle current_map(receiver_map->GetPrototypeChainRootMap(isolate()), + isolate()); Handle holder_map(holder()->map()); // Traverse the prototype chain and check the maps in the prototype chain for // fast and global objects or do negative lookup for normal objects. while (!current_map.is_identical_to(holder_map)) { ++depth; - prototype = handle(JSObject::cast(current_map->prototype())); if (current_map->IsJSGlobalObjectMap()) { GenerateCheckPropertyCell(masm(), Handle::cast(current), name, scratch2, miss); @@ -465,7 +452,7 @@ Register PropertyHandlerCompiler::CheckPrototypes( reg = holder_reg; // From now on the object will be in holder_reg. // Go to the next object in the prototype chain. - current = prototype; + current = handle(JSObject::cast(current_map->prototype())); current_map = handle(current->map()); } diff --git a/src/ic/ppc/handler-compiler-ppc.cc b/src/ic/ppc/handler-compiler-ppc.cc index e5e8d54fd7..e81ed770a2 100644 --- a/src/ic/ppc/handler-compiler-ppc.cc +++ b/src/ic/ppc/handler-compiler-ppc.cc @@ -402,10 +402,9 @@ void NamedStoreHandlerCompiler::GenerateFieldTypeChecks(FieldType* field_type, } } - Register PropertyHandlerCompiler::CheckPrototypes( Register object_reg, Register holder_reg, Register scratch1, - Register scratch2, Handle name, Label* miss, PrototypeCheckType check, + Register scratch2, Handle name, Label* miss, ReturnHolder return_what) { Handle receiver_map = map(); @@ -424,17 +423,6 @@ Register PropertyHandlerCompiler::CheckPrototypes( __ bne(miss); } - // The prototype chain of primitives (and their JSValue wrappers) depends - // on the native context, which can't be guarded by validity cells. - // |object_reg| holds the native context specific prototype in this case; - // we need to check its map. - if (check == CHECK_ALL_MAPS) { - __ LoadP(scratch1, FieldMemOperand(object_reg, HeapObject::kMapOffset)); - Handle cell = Map::WeakCellForMap(receiver_map); - __ CmpWeakValue(scratch1, cell, scratch2); - __ b(ne, miss); - } - // Keep track of the current object in register reg. Register reg = object_reg; int depth = 0; @@ -444,8 +432,8 @@ Register PropertyHandlerCompiler::CheckPrototypes( current = isolate()->global_object(); } - Handle prototype = Handle::null(); - Handle current_map = receiver_map; + Handle current_map(receiver_map->GetPrototypeChainRootMap(isolate()), + isolate()); Handle holder_map(holder()->map()); // Traverse the prototype chain and check the maps in the prototype chain for // fast and global objects or do negative lookup for normal objects. @@ -457,7 +445,6 @@ Register PropertyHandlerCompiler::CheckPrototypes( DCHECK(current_map->IsJSGlobalProxyMap() || !current_map->is_access_check_needed()); - prototype = handle(JSObject::cast(current_map->prototype())); if (current_map->IsJSGlobalObjectMap()) { GenerateCheckPropertyCell(masm(), Handle::cast(current), name, scratch2, miss); @@ -479,7 +466,7 @@ Register PropertyHandlerCompiler::CheckPrototypes( reg = holder_reg; // From now on the object will be in holder_reg. // Go to the next object in the prototype chain. - current = prototype; + current = handle(JSObject::cast(current_map->prototype())); current_map = handle(current->map()); } diff --git a/src/ic/s390/handler-compiler-s390.cc b/src/ic/s390/handler-compiler-s390.cc index b35cfbd601..d3a63eb48a 100644 --- a/src/ic/s390/handler-compiler-s390.cc +++ b/src/ic/s390/handler-compiler-s390.cc @@ -385,7 +385,7 @@ void NamedStoreHandlerCompiler::GenerateFieldTypeChecks(FieldType* field_type, Register PropertyHandlerCompiler::CheckPrototypes( Register object_reg, Register holder_reg, Register scratch1, - Register scratch2, Handle name, Label* miss, PrototypeCheckType check, + Register scratch2, Handle name, Label* miss, ReturnHolder return_what) { Handle receiver_map = map(); @@ -404,17 +404,6 @@ Register PropertyHandlerCompiler::CheckPrototypes( __ bne(miss); } - // The prototype chain of primitives (and their JSValue wrappers) depends - // on the native context, which can't be guarded by validity cells. - // |object_reg| holds the native context specific prototype in this case; - // we need to check its map. - if (check == CHECK_ALL_MAPS) { - __ LoadP(scratch1, FieldMemOperand(object_reg, HeapObject::kMapOffset)); - Handle cell = Map::WeakCellForMap(receiver_map); - __ CmpWeakValue(scratch1, cell, scratch2); - __ b(ne, miss); - } - // Keep track of the current object in register reg. Register reg = object_reg; int depth = 0; @@ -424,15 +413,14 @@ Register PropertyHandlerCompiler::CheckPrototypes( current = isolate()->global_object(); } - Handle prototype = Handle::null(); - Handle current_map = receiver_map; + Handle current_map(receiver_map->GetPrototypeChainRootMap(isolate()), + isolate()); Handle holder_map(holder()->map()); // Traverse the prototype chain and check the maps in the prototype chain for // fast and global objects or do negative lookup for normal objects. while (!current_map.is_identical_to(holder_map)) { ++depth; - prototype = handle(JSObject::cast(current_map->prototype())); if (current_map->IsJSGlobalObjectMap()) { GenerateCheckPropertyCell(masm(), Handle::cast(current), name, scratch2, miss); @@ -454,7 +442,7 @@ Register PropertyHandlerCompiler::CheckPrototypes( reg = holder_reg; // From now on the object will be in holder_reg. // Go to the next object in the prototype chain. - current = prototype; + current = handle(JSObject::cast(current_map->prototype())); current_map = handle(current->map()); } diff --git a/src/ic/x64/handler-compiler-x64.cc b/src/ic/x64/handler-compiler-x64.cc index 0139ad97f1..57208f988d 100644 --- a/src/ic/x64/handler-compiler-x64.cc +++ b/src/ic/x64/handler-compiler-x64.cc @@ -401,10 +401,9 @@ void NamedStoreHandlerCompiler::GenerateFieldTypeChecks(FieldType* field_type, } } - Register PropertyHandlerCompiler::CheckPrototypes( Register object_reg, Register holder_reg, Register scratch1, - Register scratch2, Handle name, Label* miss, PrototypeCheckType check, + Register scratch2, Handle name, Label* miss, ReturnHolder return_what) { Handle receiver_map = map(); @@ -424,17 +423,6 @@ Register PropertyHandlerCompiler::CheckPrototypes( __ j(not_equal, miss); } - // The prototype chain of primitives (and their JSValue wrappers) depends - // on the native context, which can't be guarded by validity cells. - // |object_reg| holds the native context specific prototype in this case; - // we need to check its map. - if (check == CHECK_ALL_MAPS) { - __ movp(scratch1, FieldOperand(object_reg, HeapObject::kMapOffset)); - Handle cell = Map::WeakCellForMap(receiver_map); - __ CmpWeakValue(scratch1, cell, scratch2); - __ j(not_equal, miss); - } - // Keep track of the current object in register reg. On the first // iteration, reg is an alias for object_reg, on later iterations, // it is an alias for holder_reg. @@ -446,15 +434,14 @@ Register PropertyHandlerCompiler::CheckPrototypes( current = isolate()->global_object(); } - Handle prototype = Handle::null(); - Handle current_map = receiver_map; + Handle current_map(receiver_map->GetPrototypeChainRootMap(isolate()), + isolate()); Handle holder_map(holder()->map()); // Traverse the prototype chain and check the maps in the prototype chain for // fast and global objects or do negative lookup for normal objects. while (!current_map.is_identical_to(holder_map)) { ++depth; - prototype = handle(JSObject::cast(current_map->prototype())); if (current_map->IsJSGlobalObjectMap()) { GenerateCheckPropertyCell(masm(), Handle::cast(current), name, scratch2, miss); @@ -476,7 +463,7 @@ Register PropertyHandlerCompiler::CheckPrototypes( reg = holder_reg; // From now on the object will be in holder_reg. // Go to the next object in the prototype chain. - current = prototype; + current = handle(JSObject::cast(current_map->prototype())); current_map = handle(current->map()); } diff --git a/src/ic/x87/handler-compiler-x87.cc b/src/ic/x87/handler-compiler-x87.cc index 18e7c19770..5642d0406b 100644 --- a/src/ic/x87/handler-compiler-x87.cc +++ b/src/ic/x87/handler-compiler-x87.cc @@ -411,10 +411,9 @@ void NamedStoreHandlerCompiler::GenerateFieldTypeChecks(FieldType* field_type, } } - Register PropertyHandlerCompiler::CheckPrototypes( Register object_reg, Register holder_reg, Register scratch1, - Register scratch2, Handle name, Label* miss, PrototypeCheckType check, + Register scratch2, Handle name, Label* miss, ReturnHolder return_what) { Handle receiver_map = map(); @@ -433,17 +432,6 @@ Register PropertyHandlerCompiler::CheckPrototypes( __ j(not_equal, miss); } - // The prototype chain of primitives (and their JSValue wrappers) depends - // on the native context, which can't be guarded by validity cells. - // |object_reg| holds the native context specific prototype in this case; - // we need to check its map. - if (check == CHECK_ALL_MAPS) { - __ mov(scratch1, FieldOperand(object_reg, HeapObject::kMapOffset)); - Handle cell = Map::WeakCellForMap(receiver_map); - __ CmpWeakValue(scratch1, cell, scratch2); - __ j(not_equal, miss); - } - // Keep track of the current object in register reg. Register reg = object_reg; int depth = 0; @@ -453,15 +441,14 @@ Register PropertyHandlerCompiler::CheckPrototypes( current = isolate()->global_object(); } - Handle prototype = Handle::null(); - Handle current_map = receiver_map; + Handle current_map(receiver_map->GetPrototypeChainRootMap(isolate()), + isolate()); Handle holder_map(holder()->map()); // Traverse the prototype chain and check the maps in the prototype chain for // fast and global objects or do negative lookup for normal objects. while (!current_map.is_identical_to(holder_map)) { ++depth; - prototype = handle(JSObject::cast(current_map->prototype())); if (current_map->IsJSGlobalObjectMap()) { GenerateCheckPropertyCell(masm(), Handle::cast(current), name, scratch2, miss); @@ -483,7 +470,7 @@ Register PropertyHandlerCompiler::CheckPrototypes( reg = holder_reg; // From now on the object will be in holder_reg. // Go to the next object in the prototype chain. - current = prototype; + current = handle(JSObject::cast(current_map->prototype())); current_map = handle(current->map()); } diff --git a/src/lookup.cc b/src/lookup.cc index 1527032af7..fa6d579122 100644 --- a/src/lookup.cc +++ b/src/lookup.cc @@ -129,7 +129,8 @@ Handle LookupIterator::GetRootForNonJSReceiver( Handle::cast(result)->set_value(*receiver); return result; } - auto root = handle(receiver->GetRootMap(isolate)->prototype(), isolate); + auto root = + handle(receiver->GetPrototypeChainRootMap(isolate)->prototype(), isolate); if (root->IsNull(isolate)) { unsigned int magic = 0xbbbbbbbb; isolate->PushStackTraceAndDie(magic, *receiver, NULL, magic); diff --git a/src/objects.cc b/src/objects.cc index 5a4143b086..fd2cd107a3 100644 --- a/src/objects.cc +++ b/src/objects.cc @@ -1931,7 +1931,7 @@ Maybe JSReceiver::HasInPrototypeChain(Isolate* isolate, } } -Map* Object::GetRootMap(Isolate* isolate) { +Map* Object::GetPrototypeChainRootMap(Isolate* isolate) { DisallowHeapAllocation no_alloc; if (IsSmi()) { Context* native_context = isolate->context()->native_context(); @@ -1941,11 +1941,15 @@ Map* Object::GetRootMap(Isolate* isolate) { // The object is either a number, a string, a symbol, a boolean, a SIMD value, // a real JS object, or a Harmony proxy. HeapObject* heap_object = HeapObject::cast(this); - if (heap_object->IsJSReceiver()) { - return heap_object->map(); + return heap_object->map()->GetPrototypeChainRootMap(isolate); +} + +Map* Map::GetPrototypeChainRootMap(Isolate* isolate) { + DisallowHeapAllocation no_alloc; + if (IsJSReceiverMap()) { + return this; } - int constructor_function_index = - heap_object->map()->GetConstructorFunctionIndex(); + int constructor_function_index = GetConstructorFunctionIndex(); if (constructor_function_index != Map::kNoConstructorFunctionIndex) { Context* native_context = isolate->context()->native_context(); JSFunction* constructor_function = @@ -12734,7 +12738,8 @@ void Map::SetShouldBeFastPrototypeMap(Handle map, bool value, // static Handle Map::GetOrCreatePrototypeChainValidityCell(Handle map, Isolate* isolate) { - Handle maybe_prototype(map->prototype(), isolate); + Handle maybe_prototype( + map->GetPrototypeChainRootMap(isolate)->prototype(), isolate); if (!maybe_prototype->IsJSObject()) return Handle::null(); Handle prototype = Handle::cast(maybe_prototype); // Ensure the prototype is registered with its own prototypes so its cell diff --git a/src/objects.h b/src/objects.h index d1733df374..9e3c0372ce 100644 --- a/src/objects.h +++ b/src/objects.h @@ -1559,7 +1559,7 @@ class Object { friend class StringStream; // Return the map of the root of object's prototype chain. - Map* GetRootMap(Isolate* isolate); + Map* GetPrototypeChainRootMap(Isolate* isolate); // Helper for SetProperty and SetSuperProperty. // Return value is only meaningful if [found] is set to true on return. @@ -6332,6 +6332,9 @@ class Map: public HeapObject { static const int kPrototypeChainValid = 0; static const int kPrototypeChainInvalid = 1; + // Return the map of the root of object's prototype chain. + Map* GetPrototypeChainRootMap(Isolate* isolate); + // Returns a WeakCell object containing given prototype. The cell is cached // in PrototypeInfo which is created lazily. static Handle GetOrCreatePrototypeWeakCell( diff --git a/src/prototype.h b/src/prototype.h index 032d9b6b34..e52d20efd8 100644 --- a/src/prototype.h +++ b/src/prototype.h @@ -32,9 +32,9 @@ class PrototypeIterator { PrototypeIterator(Isolate* isolate, Handle receiver, WhereToStart where_to_start = kStartAtPrototype, WhereToEnd where_to_end = END_AT_NULL) - : object_(NULL), + : isolate_(isolate), + object_(NULL), handle_(receiver), - isolate_(isolate), where_to_end_(where_to_end), is_at_end_(false), seen_proxies_(0) { @@ -45,8 +45,8 @@ class PrototypeIterator { PrototypeIterator(Isolate* isolate, JSReceiver* receiver, WhereToStart where_to_start = kStartAtPrototype, WhereToEnd where_to_end = END_AT_NULL) - : object_(receiver), - isolate_(isolate), + : isolate_(isolate), + object_(receiver), where_to_end_(where_to_end), is_at_end_(false), seen_proxies_(0) { @@ -54,16 +54,17 @@ class PrototypeIterator { } explicit PrototypeIterator(Map* receiver_map) - : object_(receiver_map->prototype()), - isolate_(receiver_map->GetIsolate()), + : isolate_(receiver_map->GetIsolate()), + object_(receiver_map->GetPrototypeChainRootMap(isolate_)->prototype()), where_to_end_(END_AT_NULL), is_at_end_(object_->IsNull(isolate_)), seen_proxies_(0) {} explicit PrototypeIterator(Handle receiver_map) - : object_(NULL), - handle_(handle(receiver_map->prototype(), receiver_map->GetIsolate())), - isolate_(receiver_map->GetIsolate()), + : isolate_(receiver_map->GetIsolate()), + object_(NULL), + handle_(receiver_map->GetPrototypeChainRootMap(isolate_)->prototype(), + isolate_), where_to_end_(END_AT_NULL), is_at_end_(handle_->IsNull(isolate_)), seen_proxies_(0) {} @@ -161,9 +162,9 @@ class PrototypeIterator { bool IsAtEnd() const { return is_at_end_; } private: + Isolate* isolate_; Object* object_; Handle handle_; - Isolate* isolate_; WhereToEnd where_to_end_; bool is_at_end_; int seen_proxies_; diff --git a/src/string-stream.cc b/src/string-stream.cc index 3ae4580709..acfb917414 100644 --- a/src/string-stream.cc +++ b/src/string-stream.cc @@ -533,7 +533,7 @@ void StringStream::PrintPrototype(JSFunction* fun, Object* receiver) { print_name = true; } else if (isolate->context() != nullptr) { if (!receiver->IsJSObject()) { - receiver = receiver->GetRootMap(isolate)->prototype(); + receiver = receiver->GetPrototypeChainRootMap(isolate)->prototype(); } for (PrototypeIterator iter(isolate, JSObject::cast(receiver),