[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}
This commit is contained in:
parent
16310b2e39
commit
7c22a153e2
@ -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> name, Label* miss, PrototypeCheckType check,
|
||||
Register scratch2, Handle<Name> name, Label* miss,
|
||||
ReturnHolder return_what) {
|
||||
Handle<Map> 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<WeakCell> 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<JSObject> prototype = Handle<JSObject>::null();
|
||||
Handle<Map> current_map = receiver_map;
|
||||
Handle<Map> current_map(receiver_map->GetPrototypeChainRootMap(isolate()),
|
||||
isolate());
|
||||
Handle<Map> 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<JSGlobalObject>::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());
|
||||
}
|
||||
|
||||
|
@ -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> name, Label* miss, PrototypeCheckType check,
|
||||
Register scratch2, Handle<Name> name, Label* miss,
|
||||
ReturnHolder return_what) {
|
||||
Handle<Map> 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<WeakCell> 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<JSObject> prototype = Handle<JSObject>::null();
|
||||
Handle<Map> current_map = receiver_map;
|
||||
Handle<Map> current_map(receiver_map->GetPrototypeChainRootMap(isolate()),
|
||||
isolate());
|
||||
Handle<Map> 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<JSGlobalObject>::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());
|
||||
}
|
||||
|
||||
|
@ -95,24 +95,9 @@ Register NamedLoadHandlerCompiler::FrontendHeader(Register object_reg,
|
||||
Handle<Name> 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> 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);
|
||||
}
|
||||
|
||||
|
||||
|
@ -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> name, Label* miss,
|
||||
PrototypeCheckType check, ReturnHolder return_what);
|
||||
ReturnHolder return_what);
|
||||
|
||||
Handle<Code> GetCode(Code::Kind kind, Handle<Name> name);
|
||||
void set_holder(Handle<JSObject> holder) { holder_ = holder; }
|
||||
|
@ -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> name, Label* miss, PrototypeCheckType check,
|
||||
Register scratch2, Handle<Name> name, Label* miss,
|
||||
ReturnHolder return_what) {
|
||||
Handle<Map> 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<WeakCell> 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<JSObject> prototype = Handle<JSObject>::null();
|
||||
Handle<Map> current_map = receiver_map;
|
||||
Handle<Map> current_map(receiver_map->GetPrototypeChainRootMap(isolate()),
|
||||
isolate());
|
||||
Handle<Map> 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<JSGlobalObject>::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());
|
||||
}
|
||||
|
||||
|
@ -862,7 +862,7 @@ int InitPrototypeChecks(Isolate* isolate, Handle<Map> 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
|
||||
|
@ -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> name, Label* miss, PrototypeCheckType check,
|
||||
Register scratch2, Handle<Name> name, Label* miss,
|
||||
ReturnHolder return_what) {
|
||||
Handle<Map> 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<WeakCell> 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<JSObject> prototype = Handle<JSObject>::null();
|
||||
Handle<Map> current_map = receiver_map;
|
||||
Handle<Map> current_map(receiver_map->GetPrototypeChainRootMap(isolate()),
|
||||
isolate());
|
||||
Handle<Map> 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<JSGlobalObject>::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());
|
||||
}
|
||||
|
||||
|
@ -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> name, Label* miss, PrototypeCheckType check,
|
||||
Register scratch2, Handle<Name> name, Label* miss,
|
||||
ReturnHolder return_what) {
|
||||
Handle<Map> 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<WeakCell> 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<JSObject> prototype = Handle<JSObject>::null();
|
||||
Handle<Map> current_map = receiver_map;
|
||||
Handle<Map> current_map(receiver_map->GetPrototypeChainRootMap(isolate()),
|
||||
isolate());
|
||||
Handle<Map> 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<JSGlobalObject>::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());
|
||||
}
|
||||
|
||||
|
@ -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> name, Label* miss, PrototypeCheckType check,
|
||||
Register scratch2, Handle<Name> name, Label* miss,
|
||||
ReturnHolder return_what) {
|
||||
Handle<Map> 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<WeakCell> 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<JSObject> prototype = Handle<JSObject>::null();
|
||||
Handle<Map> current_map = receiver_map;
|
||||
Handle<Map> current_map(receiver_map->GetPrototypeChainRootMap(isolate()),
|
||||
isolate());
|
||||
Handle<Map> 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<JSGlobalObject>::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());
|
||||
}
|
||||
|
||||
|
@ -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> name, Label* miss, PrototypeCheckType check,
|
||||
Register scratch2, Handle<Name> name, Label* miss,
|
||||
ReturnHolder return_what) {
|
||||
Handle<Map> 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<WeakCell> 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<JSObject> prototype = Handle<JSObject>::null();
|
||||
Handle<Map> current_map = receiver_map;
|
||||
Handle<Map> current_map(receiver_map->GetPrototypeChainRootMap(isolate()),
|
||||
isolate());
|
||||
Handle<Map> 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<JSGlobalObject>::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());
|
||||
}
|
||||
|
||||
|
@ -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> name, Label* miss, PrototypeCheckType check,
|
||||
Register scratch2, Handle<Name> name, Label* miss,
|
||||
ReturnHolder return_what) {
|
||||
Handle<Map> 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<WeakCell> 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<JSObject> prototype = Handle<JSObject>::null();
|
||||
Handle<Map> current_map = receiver_map;
|
||||
Handle<Map> current_map(receiver_map->GetPrototypeChainRootMap(isolate()),
|
||||
isolate());
|
||||
Handle<Map> 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<JSGlobalObject>::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());
|
||||
}
|
||||
|
||||
|
@ -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> name, Label* miss, PrototypeCheckType check,
|
||||
Register scratch2, Handle<Name> name, Label* miss,
|
||||
ReturnHolder return_what) {
|
||||
Handle<Map> 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<WeakCell> 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<JSObject> prototype = Handle<JSObject>::null();
|
||||
Handle<Map> current_map = receiver_map;
|
||||
Handle<Map> current_map(receiver_map->GetPrototypeChainRootMap(isolate()),
|
||||
isolate());
|
||||
Handle<Map> 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<JSGlobalObject>::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());
|
||||
}
|
||||
|
||||
|
@ -129,7 +129,8 @@ Handle<JSReceiver> LookupIterator::GetRootForNonJSReceiver(
|
||||
Handle<JSValue>::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);
|
||||
|
@ -1931,7 +1931,7 @@ Maybe<bool> 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> map, bool value,
|
||||
// static
|
||||
Handle<Cell> Map::GetOrCreatePrototypeChainValidityCell(Handle<Map> map,
|
||||
Isolate* isolate) {
|
||||
Handle<Object> maybe_prototype(map->prototype(), isolate);
|
||||
Handle<Object> maybe_prototype(
|
||||
map->GetPrototypeChainRootMap(isolate)->prototype(), isolate);
|
||||
if (!maybe_prototype->IsJSObject()) return Handle<Cell>::null();
|
||||
Handle<JSObject> prototype = Handle<JSObject>::cast(maybe_prototype);
|
||||
// Ensure the prototype is registered with its own prototypes so its cell
|
||||
|
@ -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<WeakCell> GetOrCreatePrototypeWeakCell(
|
||||
|
@ -32,9 +32,9 @@ class PrototypeIterator {
|
||||
PrototypeIterator(Isolate* isolate, Handle<JSReceiver> 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<Map> 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<Object> handle_;
|
||||
Isolate* isolate_;
|
||||
WhereToEnd where_to_end_;
|
||||
bool is_at_end_;
|
||||
int seen_proxies_;
|
||||
|
@ -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),
|
||||
|
Loading…
Reference in New Issue
Block a user