diff options
author | Ben Noordhuis <info@bnoordhuis.nl> | 2015-06-19 13:23:56 +0200 |
---|---|---|
committer | Rod Vagg <rod@vagg.org> | 2015-08-04 11:56:14 -0700 |
commit | 70d1f32f5605465a1a630a64f6f0d35f96c7709d (patch) | |
tree | 0a349040a686eafcb0a09943ebc733477dce2781 /deps/v8/src/ic | |
parent | 4643b8b6671607a7aff60cbbd0b384dcf2f6959e (diff) | |
download | android-node-v8-70d1f32f5605465a1a630a64f6f0d35f96c7709d.tar.gz android-node-v8-70d1f32f5605465a1a630a64f6f0d35f96c7709d.tar.bz2 android-node-v8-70d1f32f5605465a1a630a64f6f0d35f96c7709d.zip |
deps: update v8 to 4.4.63.9
Upgrade the bundled V8 and update code in src/ and lib/ to the new API.
Notable backwards incompatible changes are the removal of the smalloc
module and dropped support for CESU-8 decoding. CESU-8 support can be
brought back if necessary by doing UTF-8 decoding ourselves.
This commit includes https://codereview.chromium.org/1192973004 to fix
a build error on python 2.6 systems. The original commit log follows:
Use optparse in js2c.py for python compatibility
Without this change, V8 won't build on RHEL/CentOS 6 because the
distro python is too old to know about the argparse module.
PR-URL: https://github.com/nodejs/io.js/pull/2022
Reviewed-By: Rod Vagg <rod@vagg.org>
Reviewed-By: Trevor Norris <trev.norris@gmail.com>
Diffstat (limited to 'deps/v8/src/ic')
-rw-r--r-- | deps/v8/src/ic/OWNERS | 1 | ||||
-rw-r--r-- | deps/v8/src/ic/arm/handler-compiler-arm.cc | 68 | ||||
-rw-r--r-- | deps/v8/src/ic/arm64/handler-compiler-arm64.cc | 68 | ||||
-rw-r--r-- | deps/v8/src/ic/handler-compiler.cc | 37 | ||||
-rw-r--r-- | deps/v8/src/ic/handler-compiler.h | 9 | ||||
-rw-r--r-- | deps/v8/src/ic/ia32/handler-compiler-ia32.cc | 65 | ||||
-rw-r--r-- | deps/v8/src/ic/ic-compiler.cc | 13 | ||||
-rw-r--r-- | deps/v8/src/ic/ic-state.cc | 20 | ||||
-rw-r--r-- | deps/v8/src/ic/ic-state.h | 22 | ||||
-rw-r--r-- | deps/v8/src/ic/ic.cc | 126 | ||||
-rw-r--r-- | deps/v8/src/ic/ic.h | 13 | ||||
-rw-r--r-- | deps/v8/src/ic/mips/handler-compiler-mips.cc | 68 | ||||
-rw-r--r-- | deps/v8/src/ic/mips64/handler-compiler-mips64.cc | 68 | ||||
-rw-r--r-- | deps/v8/src/ic/ppc/OWNERS | 1 | ||||
-rw-r--r-- | deps/v8/src/ic/ppc/handler-compiler-ppc.cc | 70 | ||||
-rw-r--r-- | deps/v8/src/ic/x64/handler-compiler-x64.cc | 69 | ||||
-rw-r--r-- | deps/v8/src/ic/x87/handler-compiler-x87.cc | 65 |
17 files changed, 560 insertions, 223 deletions
diff --git a/deps/v8/src/ic/OWNERS b/deps/v8/src/ic/OWNERS new file mode 100644 index 0000000000..81e8577125 --- /dev/null +++ b/deps/v8/src/ic/OWNERS @@ -0,0 +1 @@ +verwaest@chromium.org diff --git a/deps/v8/src/ic/arm/handler-compiler-arm.cc b/deps/v8/src/ic/arm/handler-compiler-arm.cc index 7f857ca5d9..0343193c22 100644 --- a/deps/v8/src/ic/arm/handler-compiler-arm.cc +++ b/deps/v8/src/ic/arm/handler-compiler-arm.cc @@ -411,8 +411,8 @@ void NamedStoreHandlerCompiler::GenerateFieldTypeChecks(HeapType* 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, PrototypeCheckType check, + ReturnHolder return_what) { Handle<Map> receiver_map = map(); // Make sure there's no overlap between holder and object registers. @@ -420,6 +420,30 @@ Register PropertyHandlerCompiler::CheckPrototypes( DCHECK(!scratch2.is(object_reg) && !scratch2.is(holder_reg) && !scratch2.is(scratch1)); + if (FLAG_eliminate_prototype_chain_checks) { + Handle<Cell> validity_cell = + Map::GetOrCreatePrototypeChainValidityCell(receiver_map, isolate()); + if (!validity_cell.is_null()) { + DCHECK_EQ(Smi::FromInt(Map::kPrototypeChainValid), + validity_cell->value()); + __ mov(scratch1, Operand(validity_cell)); + __ ldr(scratch1, FieldMemOperand(scratch1, Cell::kValueOffset)); + __ cmp(scratch1, Operand(Smi::FromInt(Map::kPrototypeChainValid))); + __ 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; @@ -464,30 +488,36 @@ Register PropertyHandlerCompiler::CheckPrototypes( current->property_dictionary()->FindEntry(name) == NameDictionary::kNotFound); + if (FLAG_eliminate_prototype_chain_checks && depth > 1) { + // TODO(jkummerow): Cache and re-use weak cell. + __ LoadWeakValue(reg, isolate()->factory()->NewWeakCell(current), miss); + } GenerateDictionaryNegativeLookup(masm(), miss, reg, name, scratch1, scratch2); - - __ ldr(scratch1, FieldMemOperand(reg, HeapObject::kMapOffset)); - reg = holder_reg; // From now on the object will be in holder_reg. - __ ldr(reg, FieldMemOperand(scratch1, Map::kPrototypeOffset)); + if (!FLAG_eliminate_prototype_chain_checks) { + __ ldr(scratch1, FieldMemOperand(reg, HeapObject::kMapOffset)); + __ ldr(holder_reg, FieldMemOperand(scratch1, Map::kPrototypeOffset)); + } } else { Register map_reg = scratch1; - __ ldr(map_reg, FieldMemOperand(reg, HeapObject::kMapOffset)); - + if (!FLAG_eliminate_prototype_chain_checks) { + __ ldr(map_reg, FieldMemOperand(reg, HeapObject::kMapOffset)); + } if (current_map->IsJSGlobalObjectMap()) { GenerateCheckPropertyCell(masm(), Handle<JSGlobalObject>::cast(current), name, scratch2, miss); - } else if (depth != 1 || check == CHECK_ALL_MAPS) { + } else if (!FLAG_eliminate_prototype_chain_checks && + (depth != 1 || check == CHECK_ALL_MAPS)) { Handle<WeakCell> cell = Map::WeakCellForMap(current_map); __ CmpWeakValue(map_reg, cell, scratch2); __ b(ne, miss); } - - reg = holder_reg; // From now on the object will be in holder_reg. - - __ ldr(reg, FieldMemOperand(map_reg, Map::kPrototypeOffset)); + if (!FLAG_eliminate_prototype_chain_checks) { + __ ldr(holder_reg, FieldMemOperand(map_reg, Map::kPrototypeOffset)); + } } + 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_map = handle(current->map()); @@ -498,7 +528,8 @@ Register PropertyHandlerCompiler::CheckPrototypes( // Log the check depth. LOG(isolate(), IntEvent("check-maps-depth", depth + 1)); - if (depth != 0 || check == CHECK_ALL_MAPS) { + if (!FLAG_eliminate_prototype_chain_checks && + (depth != 0 || check == CHECK_ALL_MAPS)) { // Check the holder map. __ ldr(scratch1, FieldMemOperand(reg, HeapObject::kMapOffset)); Handle<WeakCell> cell = Map::WeakCellForMap(current_map); @@ -506,8 +537,13 @@ Register PropertyHandlerCompiler::CheckPrototypes( __ b(ne, miss); } + bool return_holder = return_what == RETURN_HOLDER; + if (FLAG_eliminate_prototype_chain_checks && return_holder && depth != 0) { + __ LoadWeakValue(reg, isolate()->factory()->NewWeakCell(current), miss); + } + // Return the register containing the holder. - return reg; + return return_holder ? reg : no_reg; } @@ -722,7 +758,7 @@ Handle<Code> NamedLoadHandlerCompiler::CompileLoadGlobal( if (IC::ICUseVector(kind())) { PushVectorAndSlot(); } - FrontendHeader(receiver(), name, &miss); + FrontendHeader(receiver(), name, &miss, DONT_RETURN_ANYTHING); // Get the value from the cell. Register result = StoreDescriptor::ValueRegister(); diff --git a/deps/v8/src/ic/arm64/handler-compiler-arm64.cc b/deps/v8/src/ic/arm64/handler-compiler-arm64.cc index 36d88c0a2c..516bf640d9 100644 --- a/deps/v8/src/ic/arm64/handler-compiler-arm64.cc +++ b/deps/v8/src/ic/arm64/handler-compiler-arm64.cc @@ -339,7 +339,7 @@ Handle<Code> NamedLoadHandlerCompiler::CompileLoadGlobal( if (IC::ICUseVector(kind())) { PushVectorAndSlot(); } - FrontendHeader(receiver(), name, &miss); + FrontendHeader(receiver(), name, &miss, DONT_RETURN_ANYTHING); // Get the value from the cell. Register result = StoreDescriptor::ValueRegister(); @@ -461,14 +461,38 @@ void NamedStoreHandlerCompiler::GenerateFieldTypeChecks(HeapType* 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, PrototypeCheckType check, + ReturnHolder return_what) { Handle<Map> receiver_map = map(); // object_reg and holder_reg registers can alias. DCHECK(!AreAliased(object_reg, scratch1, scratch2)); DCHECK(!AreAliased(holder_reg, scratch1, scratch2)); + if (FLAG_eliminate_prototype_chain_checks) { + Handle<Cell> validity_cell = + Map::GetOrCreatePrototypeChainValidityCell(receiver_map, isolate()); + if (!validity_cell.is_null()) { + DCHECK_EQ(Smi::FromInt(Map::kPrototypeChainValid), + validity_cell->value()); + __ Mov(scratch1, Operand(validity_cell)); + __ Ldr(scratch1, FieldMemOperand(scratch1, Cell::kValueOffset)); + __ Cmp(scratch1, Operand(Smi::FromInt(Map::kPrototypeChainValid))); + __ 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; @@ -513,30 +537,37 @@ Register PropertyHandlerCompiler::CheckPrototypes( DCHECK(current.is_null() || (current->property_dictionary()->FindEntry( name) == NameDictionary::kNotFound)); + if (FLAG_eliminate_prototype_chain_checks && depth > 1) { + // TODO(jkummerow): Cache and re-use weak cell. + __ LoadWeakValue(reg, isolate()->factory()->NewWeakCell(current), miss); + } GenerateDictionaryNegativeLookup(masm(), miss, reg, name, scratch1, scratch2); - __ Ldr(scratch1, FieldMemOperand(reg, HeapObject::kMapOffset)); - reg = holder_reg; // From now on the object will be in holder_reg. - __ Ldr(reg, FieldMemOperand(scratch1, Map::kPrototypeOffset)); + if (!FLAG_eliminate_prototype_chain_checks) { + __ Ldr(scratch1, FieldMemOperand(reg, HeapObject::kMapOffset)); + __ Ldr(holder_reg, FieldMemOperand(scratch1, Map::kPrototypeOffset)); + } } else { Register map_reg = scratch1; - __ Ldr(map_reg, FieldMemOperand(reg, HeapObject::kMapOffset)); - + if (!FLAG_eliminate_prototype_chain_checks) { + __ Ldr(map_reg, FieldMemOperand(reg, HeapObject::kMapOffset)); + } if (current_map->IsJSGlobalObjectMap()) { GenerateCheckPropertyCell(masm(), Handle<JSGlobalObject>::cast(current), name, scratch2, miss); - } else if (depth != 1 || check == CHECK_ALL_MAPS) { + } else if (!FLAG_eliminate_prototype_chain_checks && + (depth != 1 || check == CHECK_ALL_MAPS)) { Handle<WeakCell> cell = Map::WeakCellForMap(current_map); __ CmpWeakValue(map_reg, cell, scratch2); __ B(ne, miss); } - - reg = holder_reg; // From now on the object will be in holder_reg. - - __ Ldr(reg, FieldMemOperand(map_reg, Map::kPrototypeOffset)); + if (!FLAG_eliminate_prototype_chain_checks) { + __ Ldr(holder_reg, FieldMemOperand(map_reg, Map::kPrototypeOffset)); + } } + 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_map = handle(current->map()); @@ -547,8 +578,8 @@ Register PropertyHandlerCompiler::CheckPrototypes( // Log the check depth. LOG(isolate(), IntEvent("check-maps-depth", depth + 1)); - // Check the holder map. - if (depth != 0 || check == CHECK_ALL_MAPS) { + if (!FLAG_eliminate_prototype_chain_checks && + (depth != 0 || check == CHECK_ALL_MAPS)) { // Check the holder map. __ Ldr(scratch1, FieldMemOperand(reg, HeapObject::kMapOffset)); Handle<WeakCell> cell = Map::WeakCellForMap(current_map); @@ -556,8 +587,13 @@ Register PropertyHandlerCompiler::CheckPrototypes( __ B(ne, miss); } + bool return_holder = return_what == RETURN_HOLDER; + if (FLAG_eliminate_prototype_chain_checks && return_holder && depth != 0) { + __ LoadWeakValue(reg, isolate()->factory()->NewWeakCell(current), miss); + } + // Return the register containing the holder. - return reg; + return return_holder ? reg : no_reg; } diff --git a/deps/v8/src/ic/handler-compiler.cc b/deps/v8/src/ic/handler-compiler.cc index f103f8daf1..c434ce515e 100644 --- a/deps/v8/src/ic/handler-compiler.cc +++ b/deps/v8/src/ic/handler-compiler.cc @@ -87,7 +87,8 @@ Handle<Code> PropertyHandlerCompiler::GetCode(Code::Kind kind, Register NamedLoadHandlerCompiler::FrontendHeader(Register object_reg, Handle<Name> name, - Label* miss) { + Label* miss, + ReturnHolder return_what) { PrototypeCheckType check_type = CHECK_ALL_MAPS; int function_index = -1; if (map()->instance_type() < FIRST_NONSTRING_TYPE) { @@ -114,7 +115,7 @@ Register NamedLoadHandlerCompiler::FrontendHeader(Register object_reg, // Check that the maps starting from the prototype haven't changed. return CheckPrototypes(object_reg, scratch1(), scratch2(), scratch3(), name, - miss, check_type); + miss, check_type, return_what); } @@ -122,9 +123,10 @@ Register NamedLoadHandlerCompiler::FrontendHeader(Register object_reg, // miss. Register NamedStoreHandlerCompiler::FrontendHeader(Register object_reg, Handle<Name> name, - Label* miss) { + Label* miss, + ReturnHolder return_what) { return CheckPrototypes(object_reg, this->name(), scratch1(), scratch2(), name, - miss, SKIP_RECEIVER); + miss, SKIP_RECEIVER, return_what); } @@ -133,7 +135,7 @@ Register PropertyHandlerCompiler::Frontend(Handle<Name> name) { if (IC::ICUseVector(kind())) { PushVectorAndSlot(); } - Register reg = FrontendHeader(receiver(), name, &miss); + Register reg = FrontendHeader(receiver(), name, &miss, RETURN_HOLDER); FrontendFooter(name, &miss); // The footer consumes the vector and slot from the stack if miss occurs. if (IC::ICUseVector(kind())) { @@ -156,8 +158,13 @@ void PropertyHandlerCompiler::NonexistentFrontendHeader(Handle<Name> name, // Handle<JSObject>::null(). DCHECK(last_map->prototype() == isolate()->heap()->null_value()); } else { - holder_reg = FrontendHeader(receiver(), name, miss); last_map = handle(holder()->map()); + // This condition matches the branches below. + bool need_holder = + last_map->is_dictionary_map() && !last_map->IsJSGlobalObjectMap(); + holder_reg = + FrontendHeader(receiver(), name, miss, + need_holder ? RETURN_HOLDER : DONT_RETURN_ANYTHING); } if (last_map->is_dictionary_map()) { @@ -328,7 +335,7 @@ Handle<Code> NamedLoadHandlerCompiler::CompileLoadInterceptor( auto last_handle = handle(last); set_holder(last_handle); } - Register reg = FrontendHeader(receiver(), it->name(), &miss); + Register reg = FrontendHeader(receiver(), it->name(), &miss, RETURN_HOLDER); // Reset the holder so further calculations are correct. set_holder(holder_orig); if (lost_holder_register) { @@ -363,7 +370,8 @@ void NamedLoadHandlerCompiler::GenerateLoadPostInterceptor( Label miss; InterceptorVectorSlotPush(interceptor_reg); - Register reg = FrontendHeader(interceptor_reg, it->name(), &miss); + Register reg = + FrontendHeader(interceptor_reg, it->name(), &miss, RETURN_HOLDER); FrontendFooter(it->name(), &miss); // We discard the vector and slot now because we don't miss below this point. InterceptorVectorSlotPop(reg, DISCARD); @@ -428,7 +436,7 @@ Handle<Code> NamedStoreHandlerCompiler::CompileStoreTransition( if (!last.is_null()) set_holder(last); NonexistentFrontendHeader(name, &miss, scratch1(), scratch2()); } else { - FrontendHeader(receiver(), name, &miss); + FrontendHeader(receiver(), name, &miss, DONT_RETURN_ANYTHING); DCHECK(holder()->HasFastProperties()); } @@ -528,6 +536,13 @@ void ElementHandlerCompiler::CompileElementHandlers( } else { bool is_js_array = receiver_map->instance_type() == JS_ARRAY_TYPE; ElementsKind elements_kind = receiver_map->elements_kind(); + + // No need to check for an elements-free prototype chain here, the + // generated stub code needs to check that dynamically anyway. + bool convert_hole_to_undefined = + is_js_array && elements_kind == FAST_HOLEY_ELEMENTS && + *receiver_map == isolate()->get_initial_js_array_map(elements_kind); + if (receiver_map->has_indexed_interceptor()) { cached_stub = LoadIndexedInterceptorStub(isolate()).GetCode(); } else if (IsSloppyArgumentsElements(elements_kind)) { @@ -535,8 +550,8 @@ void ElementHandlerCompiler::CompileElementHandlers( } else if (IsFastElementsKind(elements_kind) || IsExternalArrayElementsKind(elements_kind) || IsFixedTypedArrayElementsKind(elements_kind)) { - cached_stub = LoadFastElementStub(isolate(), is_js_array, elements_kind) - .GetCode(); + cached_stub = LoadFastElementStub(isolate(), is_js_array, elements_kind, + convert_hole_to_undefined).GetCode(); } else { DCHECK(elements_kind == DICTIONARY_ELEMENTS); cached_stub = LoadDictionaryElementStub(isolate()).GetCode(); diff --git a/deps/v8/src/ic/handler-compiler.h b/deps/v8/src/ic/handler-compiler.h index bd3f788e38..077db92307 100644 --- a/deps/v8/src/ic/handler-compiler.h +++ b/deps/v8/src/ic/handler-compiler.h @@ -14,6 +14,7 @@ namespace internal { class CallOptimization; enum PrototypeCheckType { CHECK_ALL_MAPS, SKIP_RECEIVER }; +enum ReturnHolder { RETURN_HOLDER, DONT_RETURN_ANYTHING }; class PropertyHandlerCompiler : public PropertyAccessCompiler { public: @@ -30,7 +31,7 @@ class PropertyHandlerCompiler : public PropertyAccessCompiler { virtual ~PropertyHandlerCompiler() {} virtual Register FrontendHeader(Register object_reg, Handle<Name> name, - Label* miss) { + Label* miss, ReturnHolder return_what) { UNREACHABLE(); return receiver(); } @@ -95,7 +96,7 @@ class PropertyHandlerCompiler : public PropertyAccessCompiler { Register CheckPrototypes(Register object_reg, Register holder_reg, Register scratch1, Register scratch2, Handle<Name> name, Label* miss, - PrototypeCheckType check = CHECK_ALL_MAPS); + PrototypeCheckType check, ReturnHolder return_what); Handle<Code> GetCode(Code::Kind kind, Code::StubType type, Handle<Name> name); void set_holder(Handle<JSObject> holder) { holder_ = holder; } @@ -172,7 +173,7 @@ class NamedLoadHandlerCompiler : public PropertyHandlerCompiler { protected: virtual Register FrontendHeader(Register object_reg, Handle<Name> name, - Label* miss); + Label* miss, ReturnHolder return_what); virtual void FrontendFooter(Handle<Name> name, Label* miss); @@ -246,7 +247,7 @@ class NamedStoreHandlerCompiler : public PropertyHandlerCompiler { protected: virtual Register FrontendHeader(Register object_reg, Handle<Name> name, - Label* miss); + Label* miss, ReturnHolder return_what); virtual void FrontendFooter(Handle<Name> name, Label* miss); void GenerateRestoreName(Label* label, Handle<Name> name); diff --git a/deps/v8/src/ic/ia32/handler-compiler-ia32.cc b/deps/v8/src/ic/ia32/handler-compiler-ia32.cc index c02d83ce46..8a7c2bdb87 100644 --- a/deps/v8/src/ic/ia32/handler-compiler-ia32.cc +++ b/deps/v8/src/ic/ia32/handler-compiler-ia32.cc @@ -414,8 +414,8 @@ void NamedStoreHandlerCompiler::GenerateFieldTypeChecks(HeapType* 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, PrototypeCheckType check, + ReturnHolder return_what) { Handle<Map> receiver_map = map(); // Make sure there's no overlap between holder and object registers. @@ -423,6 +423,30 @@ Register PropertyHandlerCompiler::CheckPrototypes( DCHECK(!scratch2.is(object_reg) && !scratch2.is(holder_reg) && !scratch2.is(scratch1)); + if (FLAG_eliminate_prototype_chain_checks) { + Handle<Cell> validity_cell = + Map::GetOrCreatePrototypeChainValidityCell(receiver_map, isolate()); + if (!validity_cell.is_null()) { + DCHECK_EQ(Smi::FromInt(Map::kPrototypeChainValid), + validity_cell->value()); + // Operand::ForCell(...) points to the cell's payload! + __ cmp(Operand::ForCell(validity_cell), + Immediate(Smi::FromInt(Map::kPrototypeChainValid))); + __ 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; @@ -467,28 +491,37 @@ Register PropertyHandlerCompiler::CheckPrototypes( current->property_dictionary()->FindEntry(name) == NameDictionary::kNotFound); + if (FLAG_eliminate_prototype_chain_checks && depth > 1) { + // TODO(jkummerow): Cache and re-use weak cell. + __ LoadWeakValue(reg, isolate()->factory()->NewWeakCell(current), miss); + } GenerateDictionaryNegativeLookup(masm(), miss, reg, name, scratch1, scratch2); - __ mov(scratch1, FieldOperand(reg, HeapObject::kMapOffset)); - reg = holder_reg; // From now on the object will be in holder_reg. - __ mov(reg, FieldOperand(scratch1, Map::kPrototypeOffset)); + if (!FLAG_eliminate_prototype_chain_checks) { + __ mov(scratch1, FieldOperand(reg, HeapObject::kMapOffset)); + __ mov(holder_reg, FieldOperand(scratch1, Map::kPrototypeOffset)); + } } else { Register map_reg = scratch1; - __ mov(map_reg, FieldOperand(reg, HeapObject::kMapOffset)); + if (!FLAG_eliminate_prototype_chain_checks) { + __ mov(map_reg, FieldOperand(reg, HeapObject::kMapOffset)); + } if (current_map->IsJSGlobalObjectMap()) { GenerateCheckPropertyCell(masm(), Handle<JSGlobalObject>::cast(current), name, scratch2, miss); - } else if (depth != 1 || check == CHECK_ALL_MAPS) { + } else if (!FLAG_eliminate_prototype_chain_checks && + (depth != 1 || check == CHECK_ALL_MAPS)) { Handle<WeakCell> cell = Map::WeakCellForMap(current_map); __ CmpWeakValue(map_reg, cell, scratch2); __ j(not_equal, miss); } - - reg = holder_reg; // From now on the object will be in holder_reg. - __ mov(reg, FieldOperand(map_reg, Map::kPrototypeOffset)); + if (!FLAG_eliminate_prototype_chain_checks) { + __ mov(holder_reg, FieldOperand(map_reg, Map::kPrototypeOffset)); + } } + 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_map = handle(current->map()); @@ -499,7 +532,8 @@ Register PropertyHandlerCompiler::CheckPrototypes( // Log the check depth. LOG(isolate(), IntEvent("check-maps-depth", depth + 1)); - if (depth != 0 || check == CHECK_ALL_MAPS) { + if (!FLAG_eliminate_prototype_chain_checks && + (depth != 0 || check == CHECK_ALL_MAPS)) { // Check the holder map. __ mov(scratch1, FieldOperand(reg, HeapObject::kMapOffset)); Handle<WeakCell> cell = Map::WeakCellForMap(current_map); @@ -507,8 +541,13 @@ Register PropertyHandlerCompiler::CheckPrototypes( __ j(not_equal, miss); } + bool return_holder = return_what == RETURN_HOLDER; + if (FLAG_eliminate_prototype_chain_checks && return_holder && depth != 0) { + __ LoadWeakValue(reg, isolate()->factory()->NewWeakCell(current), miss); + } + // Return the register containing the holder. - return reg; + return return_holder ? reg : no_reg; } @@ -738,7 +777,7 @@ Handle<Code> NamedLoadHandlerCompiler::CompileLoadGlobal( if (IC::ICUseVector(kind())) { PushVectorAndSlot(); } - FrontendHeader(receiver(), name, &miss); + FrontendHeader(receiver(), name, &miss, DONT_RETURN_ANYTHING); // Get the value from the cell. Register result = StoreDescriptor::ValueRegister(); Handle<WeakCell> weak_cell = factory()->NewWeakCell(cell); diff --git a/deps/v8/src/ic/ic-compiler.cc b/deps/v8/src/ic/ic-compiler.cc index f597083e63..dfee0127c6 100644 --- a/deps/v8/src/ic/ic-compiler.cc +++ b/deps/v8/src/ic/ic-compiler.cc @@ -110,7 +110,15 @@ Handle<Code> PropertyICCompiler::ComputeKeyedLoadMonomorphic( Handle<Code> PropertyICCompiler::ComputeKeyedLoadMonomorphicHandler( Handle<Map> receiver_map) { Isolate* isolate = receiver_map->GetIsolate(); + bool is_js_array = receiver_map->instance_type() == JS_ARRAY_TYPE; ElementsKind elements_kind = receiver_map->elements_kind(); + + // No need to check for an elements-free prototype chain here, the generated + // stub code needs to check that dynamically anyway. + bool convert_hole_to_undefined = + is_js_array && elements_kind == FAST_HOLEY_ELEMENTS && + *receiver_map == isolate->get_initial_js_array_map(elements_kind); + Handle<Code> stub; if (receiver_map->has_indexed_interceptor()) { stub = LoadIndexedInterceptorStub(isolate).GetCode(); @@ -122,9 +130,8 @@ Handle<Code> PropertyICCompiler::ComputeKeyedLoadMonomorphicHandler( } else if (receiver_map->has_fast_elements() || receiver_map->has_external_array_elements() || receiver_map->has_fixed_typed_array_elements()) { - stub = LoadFastElementStub(isolate, - receiver_map->instance_type() == JS_ARRAY_TYPE, - elements_kind).GetCode(); + stub = LoadFastElementStub(isolate, is_js_array, elements_kind, + convert_hole_to_undefined).GetCode(); } else { stub = LoadDictionaryElementStub(isolate).GetCode(); } diff --git a/deps/v8/src/ic/ic-state.cc b/deps/v8/src/ic/ic-state.cc index 13c8e64216..0c71949d8a 100644 --- a/deps/v8/src/ic/ic-state.cc +++ b/deps/v8/src/ic/ic-state.cc @@ -52,6 +52,7 @@ BinaryOpICState::BinaryOpICState(Isolate* isolate, ExtraICState extra_ic_state) isolate_(isolate) { op_ = static_cast<Token::Value>(FIRST_TOKEN + OpField::decode(extra_ic_state)); + strong_ = StrongField::decode(extra_ic_state); left_kind_ = LeftKindField::decode(extra_ic_state); right_kind_ = fixed_right_arg_.IsJust() ? (Smi::IsValid(fixed_right_arg_.FromJust()) ? SMI : INT32) @@ -66,6 +67,7 @@ ExtraICState BinaryOpICState::GetExtraICState() const { ExtraICState extra_ic_state = OpField::encode(op_ - FIRST_TOKEN) | LeftKindField::encode(left_kind_) | ResultKindField::encode(result_kind_) | + StrongField::encode(strong_) | HasFixedRightArgField::encode(fixed_right_arg_.IsJust()); if (fixed_right_arg_.IsJust()) { extra_ic_state = FixedRightArgValueField::update( @@ -84,14 +86,14 @@ void BinaryOpICState::GenerateAheadOfTime( // expensive at runtime. When solved we should be able to add most binops to // the snapshot instead of hand-picking them. // Generated list of commonly used stubs -#define GENERATE(op, left_kind, right_kind, result_kind) \ - do { \ - BinaryOpICState state(isolate, op); \ - state.left_kind_ = left_kind; \ - state.fixed_right_arg_ = Nothing<int>(); \ - state.right_kind_ = right_kind; \ - state.result_kind_ = result_kind; \ - Generate(isolate, state); \ +#define GENERATE(op, left_kind, right_kind, result_kind) \ + do { \ + BinaryOpICState state(isolate, op, LanguageMode::SLOPPY); \ + state.left_kind_ = left_kind; \ + state.fixed_right_arg_ = Nothing<int>(); \ + state.right_kind_ = right_kind; \ + state.result_kind_ = result_kind; \ + Generate(isolate, state); \ } while (false) GENERATE(Token::ADD, INT32, INT32, INT32); GENERATE(Token::ADD, INT32, INT32, NUMBER); @@ -188,7 +190,7 @@ void BinaryOpICState::GenerateAheadOfTime( #undef GENERATE #define GENERATE(op, left_kind, fixed_right_arg_value, result_kind) \ do { \ - BinaryOpICState state(isolate, op); \ + BinaryOpICState state(isolate, op, LanguageMode::SLOPPY); \ state.left_kind_ = left_kind; \ state.fixed_right_arg_ = Just(fixed_right_arg_value); \ state.right_kind_ = SMI; \ diff --git a/deps/v8/src/ic/ic-state.h b/deps/v8/src/ic/ic-state.h index f35bac3522..76c0155206 100644 --- a/deps/v8/src/ic/ic-state.h +++ b/deps/v8/src/ic/ic-state.h @@ -22,7 +22,7 @@ class ICUtility : public AllStatic { }; -class CallICState FINAL BASE_EMBEDDED { +class CallICState final BASE_EMBEDDED { public: explicit CallICState(ExtraICState extra_ic_state); @@ -54,12 +54,12 @@ class CallICState FINAL BASE_EMBEDDED { std::ostream& operator<<(std::ostream& os, const CallICState& s); -class BinaryOpICState FINAL BASE_EMBEDDED { +class BinaryOpICState final BASE_EMBEDDED { public: BinaryOpICState(Isolate* isolate, ExtraICState extra_ic_state); - - BinaryOpICState(Isolate* isolate, Token::Value op) + BinaryOpICState(Isolate* isolate, Token::Value op, LanguageMode language_mode) : op_(op), + strong_(is_strong(language_mode)), left_kind_(NONE), right_kind_(NONE), result_kind_(NONE), @@ -106,6 +106,10 @@ class BinaryOpICState FINAL BASE_EMBEDDED { return Max(left_kind_, right_kind_) == GENERIC; } + LanguageMode language_mode() const { + return strong_ ? LanguageMode::STRONG : LanguageMode::SLOPPY; + } + // Returns true if the IC should enable the inline smi code (i.e. if either // parameter may be a smi). bool UseInlinedSmiCode() const { @@ -144,13 +148,15 @@ class BinaryOpICState FINAL BASE_EMBEDDED { class OpField : public BitField<int, 0, 4> {}; class ResultKindField : public BitField<Kind, 4, 3> {}; class LeftKindField : public BitField<Kind, 7, 3> {}; + class StrongField : public BitField<bool, 10, 1> {}; // When fixed right arg is set, we don't need to store the right kind. // Thus the two fields can overlap. - class HasFixedRightArgField : public BitField<bool, 10, 1> {}; - class FixedRightArgValueField : public BitField<int, 11, 4> {}; - class RightKindField : public BitField<Kind, 11, 3> {}; + class HasFixedRightArgField : public BitField<bool, 11, 1> {}; + class FixedRightArgValueField : public BitField<int, 12, 4> {}; + class RightKindField : public BitField<Kind, 12, 3> {}; Token::Value op_; + bool strong_; Kind left_kind_; Kind right_kind_; Kind result_kind_; @@ -195,7 +201,7 @@ class CompareICState { }; -class LoadICState FINAL BASE_EMBEDDED { +class LoadICState final BASE_EMBEDDED { public: explicit LoadICState(ExtraICState extra_ic_state) : state_(extra_ic_state) {} diff --git a/deps/v8/src/ic/ic.cc b/deps/v8/src/ic/ic.cc index 0ba80d3590..daf7704c71 100644 --- a/deps/v8/src/ic/ic.cc +++ b/deps/v8/src/ic/ic.cc @@ -16,6 +16,7 @@ #include "src/ic/ic-inl.h" #include "src/ic/ic-compiler.h" #include "src/ic/stub-cache.h" +#include "src/messages.h" #include "src/prototype.h" #include "src/runtime/runtime.h" @@ -369,10 +370,10 @@ MaybeHandle<Object> IC::TypeError(const char* type, Handle<Object> object, } -MaybeHandle<Object> IC::ReferenceError(const char* type, Handle<Name> name) { +MaybeHandle<Object> IC::ReferenceError(Handle<Name> name) { HandleScope scope(isolate()); - THROW_NEW_ERROR(isolate(), NewReferenceError(type, HandleVector(&name, 1)), - Object); + THROW_NEW_ERROR( + isolate(), NewReferenceError(MessageTemplate::kNotDefined, name), Object); } @@ -737,7 +738,7 @@ MaybeHandle<Object> LoadIC::Load(Handle<Object> object, Handle<Name> name) { if (*result == *isolate()->factory()->the_hole_value()) { // Do not install stubs and stay pre-monomorphic for // uninitialized accesses. - return ReferenceError("not_defined", name); + return ReferenceError(name); } if (use_ic && LoadScriptContextFieldStub::Accepted(&lookup_result)) { @@ -767,7 +768,7 @@ MaybeHandle<Object> LoadIC::Load(Handle<Object> object, Handle<Name> name) { return result; } } - return ReferenceError("not_defined", name); + return ReferenceError(name); } @@ -1005,7 +1006,7 @@ Handle<Code> KeyedLoadIC::initialize_stub(Isolate* isolate) { Handle<Code> KeyedLoadIC::initialize_stub_in_optimized_code( Isolate* isolate, State initialization_state) { - if (FLAG_vector_ics) { + if (FLAG_vector_ics && initialization_state != MEGAMORPHIC) { return VectorRawKeyedLoadStub(isolate).GetCode(); } switch (initialization_state) { @@ -1219,16 +1220,19 @@ Handle<Code> LoadIC::CompileHandler(LookupIterator* lookup, case LookupIterator::ACCESSOR: { // Use simple field loads for some well-known callback properties. - if (receiver_is_holder) { - DCHECK(receiver->IsJSObject()); - Handle<JSObject> js_receiver = Handle<JSObject>::cast(receiver); - int object_offset; - if (Accessors::IsJSObjectFieldAccessor(map, lookup->name(), - &object_offset)) { - FieldIndex index = - FieldIndex::ForInObjectOffset(object_offset, js_receiver->map()); - return SimpleFieldLoad(index); - } + // The method will only return true for absolute truths based on the + // receiver maps. + int object_offset; + if (Accessors::IsJSObjectFieldAccessor(map, lookup->name(), + &object_offset)) { + FieldIndex index = FieldIndex::ForInObjectOffset(object_offset, *map); + return SimpleFieldLoad(index); + } + if (Accessors::IsJSArrayBufferViewFieldAccessor(map, lookup->name(), + &object_offset)) { + FieldIndex index = FieldIndex::ForInObjectOffset(object_offset, *map); + ArrayBufferViewLoadFieldStub stub(isolate(), index); + return stub.GetCode(); } Handle<Object> accessors = lookup->GetAccessors(); @@ -1563,7 +1567,7 @@ MaybeHandle<Object> StoreIC::Store(Handle<Object> object, Handle<Name> name, if (*previous_value == *isolate()->factory()->the_hole_value()) { // Do not install stubs and stay pre-monomorphic for // uninitialized accesses. - return ReferenceError("not_defined", name); + return ReferenceError(name); } if (FLAG_use_ic && @@ -1717,7 +1721,11 @@ void StoreIC::UpdateCaches(LookupIterator* lookup, Handle<Object> value, static Handle<Code> PropertyCellStoreHandler( Isolate* isolate, Handle<JSObject> receiver, Handle<GlobalObject> holder, Handle<Name> name, Handle<PropertyCell> cell, PropertyCellType type) { - StoreGlobalStub stub(isolate, type == PropertyCellType::kConstant, + auto constant_type = Nothing<PropertyCellConstantType>(); + if (type == PropertyCellType::kConstantType) { + constant_type = Just(cell->GetConstantType()); + } + StoreGlobalStub stub(isolate, type, constant_type, receiver->IsJSGlobalProxy()); auto code = stub.GetCodeCopyFromTemplate(holder, cell); // TODO(verwaest): Move caching of these NORMAL stubs outside as well. @@ -1818,11 +1826,12 @@ Handle<Code> StoreIC::CompileHandler(LookupIterator* lookup, DCHECK(holder.is_identical_to(receiver) || receiver->map()->prototype() == *holder); auto cell = lookup->GetPropertyCell(); - auto union_type = PropertyCell::UpdatedType( + auto updated_type = PropertyCell::UpdatedType( cell, value, lookup->property_details()); - return PropertyCellStoreHandler(isolate(), receiver, - Handle<GlobalObject>::cast(holder), - lookup->name(), cell, union_type); + auto code = PropertyCellStoreHandler( + isolate(), receiver, Handle<GlobalObject>::cast(holder), + lookup->name(), cell, updated_type); + return code; } DCHECK(holder.is_identical_to(receiver)); return isolate()->builtins()->StoreIC_Normal(); @@ -2571,7 +2580,7 @@ MaybeHandle<Object> BinaryOpIC::Transition( // Compute the actual result using the builtin for the binary operation. Object* builtin = isolate()->js_builtins_object()->javascript_builtin( - TokenToJSBuiltin(state.op())); + TokenToJSBuiltin(state.op(), state.language_mode())); Handle<JSFunction> function = handle(JSFunction::cast(builtin), isolate()); Handle<Object> result; ASSIGN_RETURN_ON_EXCEPTION( @@ -2808,43 +2817,38 @@ RUNTIME_FUNCTION(Unreachable) { } -Builtins::JavaScript BinaryOpIC::TokenToJSBuiltin(Token::Value op) { - switch (op) { - default: - UNREACHABLE(); - case Token::ADD: - return Builtins::ADD; - break; - case Token::SUB: - return Builtins::SUB; - break; - case Token::MUL: - return Builtins::MUL; - break; - case Token::DIV: - return Builtins::DIV; - break; - case Token::MOD: - return Builtins::MOD; - break; - case Token::BIT_OR: - return Builtins::BIT_OR; - break; - case Token::BIT_AND: - return Builtins::BIT_AND; - break; - case Token::BIT_XOR: - return Builtins::BIT_XOR; - break; - case Token::SAR: - return Builtins::SAR; - break; - case Token::SHR: - return Builtins::SHR; - break; - case Token::SHL: - return Builtins::SHL; - break; +Builtins::JavaScript BinaryOpIC::TokenToJSBuiltin(Token::Value op, + LanguageMode language_mode) { + if (is_strong(language_mode)) { + switch (op) { + default: UNREACHABLE(); + case Token::ADD: return Builtins::ADD_STRONG; + case Token::SUB: return Builtins::SUB_STRONG; + case Token::MUL: return Builtins::MUL_STRONG; + case Token::DIV: return Builtins::DIV_STRONG; + case Token::MOD: return Builtins::MOD_STRONG; + case Token::BIT_OR: return Builtins::BIT_OR_STRONG; + case Token::BIT_AND: return Builtins::BIT_AND_STRONG; + case Token::BIT_XOR: return Builtins::BIT_XOR_STRONG; + case Token::SAR: return Builtins::SAR_STRONG; + case Token::SHR: return Builtins::SHR_STRONG; + case Token::SHL: return Builtins::SHL_STRONG; + } + } else { + switch (op) { + default: UNREACHABLE(); + case Token::ADD: return Builtins::ADD; + case Token::SUB: return Builtins::SUB; + case Token::MUL: return Builtins::MUL; + case Token::DIV: return Builtins::DIV; + case Token::MOD: return Builtins::MOD; + case Token::BIT_OR: return Builtins::BIT_OR; + case Token::BIT_AND: return Builtins::BIT_AND; + case Token::BIT_XOR: return Builtins::BIT_XOR; + case Token::SAR: return Builtins::SAR; + case Token::SHR: return Builtins::SHR; + case Token::SHL: return Builtins::SHL; + } } } @@ -2934,7 +2938,7 @@ static Object* ThrowReferenceError(Isolate* isolate, Name* name) { // Throw a reference error. Handle<Name> name_handle(name); THROW_NEW_ERROR_RETURN_FAILURE( - isolate, NewReferenceError("not_defined", HandleVector(&name_handle, 1))); + isolate, NewReferenceError(MessageTemplate::kNotDefined, name_handle)); } diff --git a/deps/v8/src/ic/ic.h b/deps/v8/src/ic/ic.h index 4da6e7cecc..d51309cffe 100644 --- a/deps/v8/src/ic/ic.h +++ b/deps/v8/src/ic/ic.h @@ -164,7 +164,7 @@ class IC { MaybeHandle<Object> TypeError(const char* type, Handle<Object> object, Handle<Object> key); - MaybeHandle<Object> ReferenceError(const char* type, Handle<Name> name); + MaybeHandle<Object> ReferenceError(Handle<Name> name); // Access the target code for the given IC address. static inline Code* GetTargetAtAddress(Address address, @@ -418,7 +418,7 @@ class LoadIC : public IC { } } - Handle<Code> megamorphic_stub() OVERRIDE; + Handle<Code> megamorphic_stub() override; // Update the inline cache and the global stub cache based on the // lookup result. @@ -426,7 +426,7 @@ class LoadIC : public IC { virtual Handle<Code> CompileHandler(LookupIterator* lookup, Handle<Object> unused, - CacheHolderFlag cache_holder) OVERRIDE; + CacheHolderFlag cache_holder) override; private: virtual Handle<Code> pre_monomorphic_stub() const; @@ -556,7 +556,7 @@ class StoreIC : public IC { protected: // Stub accessors. - Handle<Code> megamorphic_stub() OVERRIDE; + Handle<Code> megamorphic_stub() override; Handle<Code> slow_stub() const; virtual Handle<Code> pre_monomorphic_stub() const { @@ -572,7 +572,7 @@ class StoreIC : public IC { JSReceiver::StoreFromKeyed store_mode); virtual Handle<Code> CompileHandler(LookupIterator* lookup, Handle<Object> value, - CacheHolderFlag cache_holder) OVERRIDE; + CacheHolderFlag cache_holder) override; private: inline void set_target(Code* code); @@ -682,7 +682,8 @@ class BinaryOpIC : public IC { public: explicit BinaryOpIC(Isolate* isolate) : IC(EXTRA_CALL_FRAME, isolate) {} - static Builtins::JavaScript TokenToJSBuiltin(Token::Value op); + static Builtins::JavaScript TokenToJSBuiltin(Token::Value op, + LanguageMode language_mode); MaybeHandle<Object> Transition(Handle<AllocationSite> allocation_site, Handle<Object> left, diff --git a/deps/v8/src/ic/mips/handler-compiler-mips.cc b/deps/v8/src/ic/mips/handler-compiler-mips.cc index 83f57bc0ca..60df292f41 100644 --- a/deps/v8/src/ic/mips/handler-compiler-mips.cc +++ b/deps/v8/src/ic/mips/handler-compiler-mips.cc @@ -401,8 +401,8 @@ void NamedStoreHandlerCompiler::GenerateFieldTypeChecks(HeapType* 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, PrototypeCheckType check, + ReturnHolder return_what) { Handle<Map> receiver_map = map(); // Make sure there's no overlap between holder and object registers. @@ -410,6 +410,30 @@ Register PropertyHandlerCompiler::CheckPrototypes( DCHECK(!scratch2.is(object_reg) && !scratch2.is(holder_reg) && !scratch2.is(scratch1)); + if (FLAG_eliminate_prototype_chain_checks) { + Handle<Cell> validity_cell = + Map::GetOrCreatePrototypeChainValidityCell(receiver_map, isolate()); + if (!validity_cell.is_null()) { + DCHECK_EQ(Smi::FromInt(Map::kPrototypeChainValid), + validity_cell->value()); + __ li(scratch1, Operand(validity_cell)); + __ lw(scratch1, FieldMemOperand(scratch1, Cell::kValueOffset)); + __ Branch(miss, ne, scratch1, + 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; @@ -454,30 +478,36 @@ Register PropertyHandlerCompiler::CheckPrototypes( current->property_dictionary()->FindEntry(name) == NameDictionary::kNotFound); + if (FLAG_eliminate_prototype_chain_checks && depth > 1) { + // TODO(jkummerow): Cache and re-use weak cell. + __ LoadWeakValue(reg, isolate()->factory()->NewWeakCell(current), miss); + } GenerateDictionaryNegativeLookup(masm(), miss, reg, name, scratch1, scratch2); - - __ lw(scratch1, FieldMemOperand(reg, HeapObject::kMapOffset)); - reg = holder_reg; // From now on the object will be in holder_reg. - __ lw(reg, FieldMemOperand(scratch1, Map::kPrototypeOffset)); + if (!FLAG_eliminate_prototype_chain_checks) { + __ lw(scratch1, FieldMemOperand(reg, HeapObject::kMapOffset)); + __ lw(holder_reg, FieldMemOperand(scratch1, Map::kPrototypeOffset)); + } } else { Register map_reg = scratch1; - __ lw(map_reg, FieldMemOperand(reg, HeapObject::kMapOffset)); - + if (!FLAG_eliminate_prototype_chain_checks) { + __ lw(map_reg, FieldMemOperand(reg, HeapObject::kMapOffset)); + } if (current_map->IsJSGlobalObjectMap()) { GenerateCheckPropertyCell(masm(), Handle<JSGlobalObject>::cast(current), name, scratch2, miss); - } else if (depth != 1 || check == CHECK_ALL_MAPS) { + } else if (!FLAG_eliminate_prototype_chain_checks && + (depth != 1 || check == CHECK_ALL_MAPS)) { Handle<WeakCell> cell = Map::WeakCellForMap(current_map); __ GetWeakValue(scratch2, cell); __ Branch(miss, ne, scratch2, Operand(map_reg)); } - - reg = holder_reg; // From now on the object will be in holder_reg. - - __ lw(reg, FieldMemOperand(map_reg, Map::kPrototypeOffset)); + if (!FLAG_eliminate_prototype_chain_checks) { + __ lw(holder_reg, FieldMemOperand(map_reg, Map::kPrototypeOffset)); + } } + 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_map = handle(current->map()); @@ -488,7 +518,8 @@ Register PropertyHandlerCompiler::CheckPrototypes( // Log the check depth. LOG(isolate(), IntEvent("check-maps-depth", depth + 1)); - if (depth != 0 || check == CHECK_ALL_MAPS) { + if (!FLAG_eliminate_prototype_chain_checks && + (depth != 0 || check == CHECK_ALL_MAPS)) { // Check the holder map. __ lw(scratch1, FieldMemOperand(reg, HeapObject::kMapOffset)); Handle<WeakCell> cell = Map::WeakCellForMap(current_map); @@ -496,8 +527,13 @@ Register PropertyHandlerCompiler::CheckPrototypes( __ Branch(miss, ne, scratch2, Operand(scratch1)); } + bool return_holder = return_what == RETURN_HOLDER; + if (FLAG_eliminate_prototype_chain_checks && return_holder && depth != 0) { + __ LoadWeakValue(reg, isolate()->factory()->NewWeakCell(current), miss); + } + // Return the register containing the holder. - return reg; + return return_holder ? reg : no_reg; } @@ -712,7 +748,7 @@ Handle<Code> NamedLoadHandlerCompiler::CompileLoadGlobal( PushVectorAndSlot(); } - FrontendHeader(receiver(), name, &miss); + FrontendHeader(receiver(), name, &miss, DONT_RETURN_ANYTHING); // Get the value from the cell. Register result = StoreDescriptor::ValueRegister(); diff --git a/deps/v8/src/ic/mips64/handler-compiler-mips64.cc b/deps/v8/src/ic/mips64/handler-compiler-mips64.cc index 90eecaaf0e..f60e8c6a43 100644 --- a/deps/v8/src/ic/mips64/handler-compiler-mips64.cc +++ b/deps/v8/src/ic/mips64/handler-compiler-mips64.cc @@ -402,8 +402,8 @@ void NamedStoreHandlerCompiler::GenerateFieldTypeChecks(HeapType* 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, PrototypeCheckType check, + ReturnHolder return_what) { Handle<Map> receiver_map = map(); // Make sure there's no overlap between holder and object registers. @@ -411,6 +411,30 @@ Register PropertyHandlerCompiler::CheckPrototypes( DCHECK(!scratch2.is(object_reg) && !scratch2.is(holder_reg) && !scratch2.is(scratch1)); + if (FLAG_eliminate_prototype_chain_checks) { + Handle<Cell> validity_cell = + Map::GetOrCreatePrototypeChainValidityCell(receiver_map, isolate()); + if (!validity_cell.is_null()) { + DCHECK_EQ(Smi::FromInt(Map::kPrototypeChainValid), + validity_cell->value()); + __ li(scratch1, Operand(validity_cell)); + __ ld(scratch1, FieldMemOperand(scratch1, Cell::kValueOffset)); + __ Branch(miss, ne, scratch1, + 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; @@ -455,30 +479,36 @@ Register PropertyHandlerCompiler::CheckPrototypes( current->property_dictionary()->FindEntry(name) == NameDictionary::kNotFound); + if (FLAG_eliminate_prototype_chain_checks && depth > 1) { + // TODO(jkummerow): Cache and re-use weak cell. + __ LoadWeakValue(reg, isolate()->factory()->NewWeakCell(current), miss); + } GenerateDictionaryNegativeLookup(masm(), miss, reg, name, scratch1, scratch2); - - __ ld(scratch1, FieldMemOperand(reg, HeapObject::kMapOffset)); - reg = holder_reg; // From now on the object will be in holder_reg. - __ ld(reg, FieldMemOperand(scratch1, Map::kPrototypeOffset)); + if (!FLAG_eliminate_prototype_chain_checks) { + __ ld(scratch1, FieldMemOperand(reg, HeapObject::kMapOffset)); + __ ld(holder_reg, FieldMemOperand(scratch1, Map::kPrototypeOffset)); + } } else { Register map_reg = scratch1; - __ ld(map_reg, FieldMemOperand(reg, HeapObject::kMapOffset)); - + if (!FLAG_eliminate_prototype_chain_checks) { + __ ld(map_reg, FieldMemOperand(reg, HeapObject::kMapOffset)); + } if (current_map->IsJSGlobalObjectMap()) { GenerateCheckPropertyCell(masm(), Handle<JSGlobalObject>::cast(current), name, scratch2, miss); - } else if (depth != 1 || check == CHECK_ALL_MAPS) { + } else if (!FLAG_eliminate_prototype_chain_checks && + (depth != 1 || check == CHECK_ALL_MAPS)) { Handle<WeakCell> cell = Map::WeakCellForMap(current_map); __ GetWeakValue(scratch2, cell); __ Branch(miss, ne, scratch2, Operand(map_reg)); } - - reg = holder_reg; // From now on the object will be in holder_reg. - - __ ld(reg, FieldMemOperand(map_reg, Map::kPrototypeOffset)); + if (!FLAG_eliminate_prototype_chain_checks) { + __ ld(holder_reg, FieldMemOperand(map_reg, Map::kPrototypeOffset)); + } } + 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_map = handle(current->map()); @@ -489,7 +519,8 @@ Register PropertyHandlerCompiler::CheckPrototypes( // Log the check depth. LOG(isolate(), IntEvent("check-maps-depth", depth + 1)); - if (depth != 0 || check == CHECK_ALL_MAPS) { + if (!FLAG_eliminate_prototype_chain_checks && + (depth != 0 || check == CHECK_ALL_MAPS)) { // Check the holder map. __ ld(scratch1, FieldMemOperand(reg, HeapObject::kMapOffset)); Handle<WeakCell> cell = Map::WeakCellForMap(current_map); @@ -497,8 +528,13 @@ Register PropertyHandlerCompiler::CheckPrototypes( __ Branch(miss, ne, scratch2, Operand(scratch1)); } + bool return_holder = return_what == RETURN_HOLDER; + if (FLAG_eliminate_prototype_chain_checks && return_holder && depth != 0) { + __ LoadWeakValue(reg, isolate()->factory()->NewWeakCell(current), miss); + } + // Return the register containing the holder. - return reg; + return return_holder ? reg : no_reg; } @@ -713,7 +749,7 @@ Handle<Code> NamedLoadHandlerCompiler::CompileLoadGlobal( PushVectorAndSlot(); } - FrontendHeader(receiver(), name, &miss); + FrontendHeader(receiver(), name, &miss, DONT_RETURN_ANYTHING); // Get the value from the cell. Register result = StoreDescriptor::ValueRegister(); diff --git a/deps/v8/src/ic/ppc/OWNERS b/deps/v8/src/ic/ppc/OWNERS index beecb3d0b1..a04d29a94f 100644 --- a/deps/v8/src/ic/ppc/OWNERS +++ b/deps/v8/src/ic/ppc/OWNERS @@ -1,3 +1,4 @@ +dstence@us.ibm.com joransiu@ca.ibm.com mbrandy@us.ibm.com michael_dawson@ca.ibm.com diff --git a/deps/v8/src/ic/ppc/handler-compiler-ppc.cc b/deps/v8/src/ic/ppc/handler-compiler-ppc.cc index d7a70d7446..5cb6f226bf 100644 --- a/deps/v8/src/ic/ppc/handler-compiler-ppc.cc +++ b/deps/v8/src/ic/ppc/handler-compiler-ppc.cc @@ -410,8 +410,8 @@ void NamedStoreHandlerCompiler::GenerateFieldTypeChecks(HeapType* 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, PrototypeCheckType check, + ReturnHolder return_what) { Handle<Map> receiver_map = map(); // Make sure there's no overlap between holder and object registers. @@ -419,6 +419,30 @@ Register PropertyHandlerCompiler::CheckPrototypes( DCHECK(!scratch2.is(object_reg) && !scratch2.is(holder_reg) && !scratch2.is(scratch1)); + if (FLAG_eliminate_prototype_chain_checks) { + Handle<Cell> validity_cell = + Map::GetOrCreatePrototypeChainValidityCell(receiver_map, isolate()); + if (!validity_cell.is_null()) { + DCHECK_EQ(Smi::FromInt(Map::kPrototypeChainValid), + validity_cell->value()); + __ mov(scratch1, Operand(validity_cell)); + __ LoadP(scratch1, FieldMemOperand(scratch1, Cell::kValueOffset)); + __ CmpSmiLiteral(scratch1, Smi::FromInt(Map::kPrototypeChainValid), r0); + __ 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; @@ -462,39 +486,48 @@ Register PropertyHandlerCompiler::CheckPrototypes( current->property_dictionary()->FindEntry(name) == NameDictionary::kNotFound); + if (FLAG_eliminate_prototype_chain_checks && depth > 1) { + // TODO(jkummerow): Cache and re-use weak cell. + __ LoadWeakValue(reg, isolate()->factory()->NewWeakCell(current), miss); + } GenerateDictionaryNegativeLookup(masm(), miss, reg, name, scratch1, scratch2); - - __ LoadP(scratch1, FieldMemOperand(reg, HeapObject::kMapOffset)); - reg = holder_reg; // From now on the object will be in holder_reg. - __ LoadP(reg, FieldMemOperand(scratch1, Map::kPrototypeOffset)); + if (!FLAG_eliminate_prototype_chain_checks) { + __ LoadP(scratch1, FieldMemOperand(reg, HeapObject::kMapOffset)); + __ LoadP(holder_reg, FieldMemOperand(scratch1, Map::kPrototypeOffset)); + } } else { Register map_reg = scratch1; - __ LoadP(map_reg, FieldMemOperand(reg, HeapObject::kMapOffset)); - + if (!FLAG_eliminate_prototype_chain_checks) { + __ LoadP(map_reg, FieldMemOperand(reg, HeapObject::kMapOffset)); + } if (current_map->IsJSGlobalObjectMap()) { GenerateCheckPropertyCell(masm(), Handle<JSGlobalObject>::cast(current), name, scratch2, miss); - } else if (depth != 1 || check == CHECK_ALL_MAPS) { + } else if (!FLAG_eliminate_prototype_chain_checks && + (depth != 1 || check == CHECK_ALL_MAPS)) { Handle<WeakCell> cell = Map::WeakCellForMap(current_map); __ CmpWeakValue(map_reg, cell, scratch2); __ bne(miss); } - - reg = holder_reg; // From now on the object will be in holder_reg. - - __ LoadP(reg, FieldMemOperand(map_reg, Map::kPrototypeOffset)); + if (!FLAG_eliminate_prototype_chain_checks) { + __ LoadP(holder_reg, FieldMemOperand(map_reg, Map::kPrototypeOffset)); + } } + 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_map = handle(current->map()); } + DCHECK(!current_map->IsJSGlobalProxyMap()); + // Log the check depth. LOG(isolate(), IntEvent("check-maps-depth", depth + 1)); - if (depth != 0 || check == CHECK_ALL_MAPS) { + if (!FLAG_eliminate_prototype_chain_checks && + (depth != 0 || check == CHECK_ALL_MAPS)) { // Check the holder map. __ LoadP(scratch1, FieldMemOperand(reg, HeapObject::kMapOffset)); Handle<WeakCell> cell = Map::WeakCellForMap(current_map); @@ -502,8 +535,13 @@ Register PropertyHandlerCompiler::CheckPrototypes( __ bne(miss); } + bool return_holder = return_what == RETURN_HOLDER; + if (FLAG_eliminate_prototype_chain_checks && return_holder && depth != 0) { + __ LoadWeakValue(reg, isolate()->factory()->NewWeakCell(current), miss); + } + // Return the register containing the holder. - return reg; + return return_holder ? reg : no_reg; } @@ -716,7 +754,7 @@ Handle<Code> NamedLoadHandlerCompiler::CompileLoadGlobal( if (IC::ICUseVector(kind())) { PushVectorAndSlot(); } - FrontendHeader(receiver(), name, &miss); + FrontendHeader(receiver(), name, &miss, DONT_RETURN_ANYTHING); // Get the value from the cell. Register result = StoreDescriptor::ValueRegister(); diff --git a/deps/v8/src/ic/x64/handler-compiler-x64.cc b/deps/v8/src/ic/x64/handler-compiler-x64.cc index b6add9d2bc..8288d8943d 100644 --- a/deps/v8/src/ic/x64/handler-compiler-x64.cc +++ b/deps/v8/src/ic/x64/handler-compiler-x64.cc @@ -413,8 +413,8 @@ void NamedStoreHandlerCompiler::GenerateFieldTypeChecks(HeapType* 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, PrototypeCheckType check, + ReturnHolder return_what) { Handle<Map> receiver_map = map(); // Make sure there's no overlap between holder and object registers. @@ -422,6 +422,31 @@ Register PropertyHandlerCompiler::CheckPrototypes( DCHECK(!scratch2.is(object_reg) && !scratch2.is(holder_reg) && !scratch2.is(scratch1)); + if (FLAG_eliminate_prototype_chain_checks) { + Handle<Cell> validity_cell = + Map::GetOrCreatePrototypeChainValidityCell(receiver_map, isolate()); + if (!validity_cell.is_null()) { + DCHECK_EQ(Smi::FromInt(Map::kPrototypeChainValid), + validity_cell->value()); + __ Move(scratch1, validity_cell, RelocInfo::CELL); + // Move(..., CELL) loads the payload's address! + __ SmiCompare(Operand(scratch1, 0), + Smi::FromInt(Map::kPrototypeChainValid)); + __ 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. @@ -468,30 +493,37 @@ Register PropertyHandlerCompiler::CheckPrototypes( current->property_dictionary()->FindEntry(name) == NameDictionary::kNotFound); + if (FLAG_eliminate_prototype_chain_checks && depth > 1) { + // TODO(jkummerow): Cache and re-use weak cell. + __ LoadWeakValue(reg, isolate()->factory()->NewWeakCell(current), miss); + } GenerateDictionaryNegativeLookup(masm(), miss, reg, name, scratch1, scratch2); - __ movp(scratch1, FieldOperand(reg, HeapObject::kMapOffset)); - reg = holder_reg; // From now on the object will be in holder_reg. - __ movp(reg, FieldOperand(scratch1, Map::kPrototypeOffset)); + if (!FLAG_eliminate_prototype_chain_checks) { + __ movp(scratch1, FieldOperand(reg, HeapObject::kMapOffset)); + __ movp(holder_reg, FieldOperand(scratch1, Map::kPrototypeOffset)); + } } else { Register map_reg = scratch1; - __ movp(map_reg, FieldOperand(reg, HeapObject::kMapOffset)); - + if (!FLAG_eliminate_prototype_chain_checks) { + __ movp(map_reg, FieldOperand(reg, HeapObject::kMapOffset)); + } if (current_map->IsJSGlobalObjectMap()) { GenerateCheckPropertyCell(masm(), Handle<JSGlobalObject>::cast(current), name, scratch2, miss); - } else if (depth != 1 || check == CHECK_ALL_MAPS) { + } else if (!FLAG_eliminate_prototype_chain_checks && + (depth != 1 || check == CHECK_ALL_MAPS)) { Handle<WeakCell> cell = Map::WeakCellForMap(current_map); __ CmpWeakValue(map_reg, cell, scratch2); __ j(not_equal, miss); } - - reg = holder_reg; // From now on the object will be in holder_reg. - - __ movp(reg, FieldOperand(map_reg, Map::kPrototypeOffset)); + if (!FLAG_eliminate_prototype_chain_checks) { + __ movp(holder_reg, FieldOperand(map_reg, Map::kPrototypeOffset)); + } } + 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_map = handle(current->map()); @@ -502,15 +534,22 @@ Register PropertyHandlerCompiler::CheckPrototypes( // Log the check depth. LOG(isolate(), IntEvent("check-maps-depth", depth + 1)); - if (depth != 0 || check == CHECK_ALL_MAPS) { + if (!FLAG_eliminate_prototype_chain_checks && + (depth != 0 || check == CHECK_ALL_MAPS)) { + // Check the holder map. __ movp(scratch1, FieldOperand(reg, HeapObject::kMapOffset)); Handle<WeakCell> cell = Map::WeakCellForMap(current_map); __ CmpWeakValue(scratch1, cell, scratch2); __ j(not_equal, miss); } + bool return_holder = return_what == RETURN_HOLDER; + if (FLAG_eliminate_prototype_chain_checks && return_holder && depth != 0) { + __ LoadWeakValue(reg, isolate()->factory()->NewWeakCell(current), miss); + } + // Return the register containing the holder. - return reg; + return return_holder ? reg : no_reg; } @@ -732,7 +771,7 @@ Handle<Code> NamedLoadHandlerCompiler::CompileLoadGlobal( if (IC::ICUseVector(kind())) { PushVectorAndSlot(); } - FrontendHeader(receiver(), name, &miss); + FrontendHeader(receiver(), name, &miss, DONT_RETURN_ANYTHING); // Get the value from the cell. Register result = StoreDescriptor::ValueRegister(); diff --git a/deps/v8/src/ic/x87/handler-compiler-x87.cc b/deps/v8/src/ic/x87/handler-compiler-x87.cc index ce902757f1..e9c8e4f713 100644 --- a/deps/v8/src/ic/x87/handler-compiler-x87.cc +++ b/deps/v8/src/ic/x87/handler-compiler-x87.cc @@ -414,8 +414,8 @@ void NamedStoreHandlerCompiler::GenerateFieldTypeChecks(HeapType* 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, PrototypeCheckType check, + ReturnHolder return_what) { Handle<Map> receiver_map = map(); // Make sure there's no overlap between holder and object registers. @@ -423,6 +423,30 @@ Register PropertyHandlerCompiler::CheckPrototypes( DCHECK(!scratch2.is(object_reg) && !scratch2.is(holder_reg) && !scratch2.is(scratch1)); + if (FLAG_eliminate_prototype_chain_checks) { + Handle<Cell> validity_cell = + Map::GetOrCreatePrototypeChainValidityCell(receiver_map, isolate()); + if (!validity_cell.is_null()) { + DCHECK_EQ(Smi::FromInt(Map::kPrototypeChainValid), + validity_cell->value()); + // Operand::ForCell(...) points to the cell's payload! + __ cmp(Operand::ForCell(validity_cell), + Immediate(Smi::FromInt(Map::kPrototypeChainValid))); + __ 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; @@ -467,28 +491,37 @@ Register PropertyHandlerCompiler::CheckPrototypes( current->property_dictionary()->FindEntry(name) == NameDictionary::kNotFound); + if (FLAG_eliminate_prototype_chain_checks && depth > 1) { + // TODO(jkummerow): Cache and re-use weak cell. + __ LoadWeakValue(reg, isolate()->factory()->NewWeakCell(current), miss); + } GenerateDictionaryNegativeLookup(masm(), miss, reg, name, scratch1, scratch2); - __ mov(scratch1, FieldOperand(reg, HeapObject::kMapOffset)); - reg = holder_reg; // From now on the object will be in holder_reg. - __ mov(reg, FieldOperand(scratch1, Map::kPrototypeOffset)); + if (!FLAG_eliminate_prototype_chain_checks) { + __ mov(scratch1, FieldOperand(reg, HeapObject::kMapOffset)); + __ mov(holder_reg, FieldOperand(scratch1, Map::kPrototypeOffset)); + } } else { Register map_reg = scratch1; - __ mov(map_reg, FieldOperand(reg, HeapObject::kMapOffset)); + if (!FLAG_eliminate_prototype_chain_checks) { + __ mov(map_reg, FieldOperand(reg, HeapObject::kMapOffset)); + } if (current_map->IsJSGlobalObjectMap()) { GenerateCheckPropertyCell(masm(), Handle<JSGlobalObject>::cast(current), name, scratch2, miss); - } else if (depth != 1 || check == CHECK_ALL_MAPS) { + } else if (!FLAG_eliminate_prototype_chain_checks && + (depth != 1 || check == CHECK_ALL_MAPS)) { Handle<WeakCell> cell = Map::WeakCellForMap(current_map); __ CmpWeakValue(map_reg, cell, scratch2); __ j(not_equal, miss); } - - reg = holder_reg; // From now on the object will be in holder_reg. - __ mov(reg, FieldOperand(map_reg, Map::kPrototypeOffset)); + if (!FLAG_eliminate_prototype_chain_checks) { + __ mov(holder_reg, FieldOperand(map_reg, Map::kPrototypeOffset)); + } } + 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_map = handle(current->map()); @@ -499,7 +532,8 @@ Register PropertyHandlerCompiler::CheckPrototypes( // Log the check depth. LOG(isolate(), IntEvent("check-maps-depth", depth + 1)); - if (depth != 0 || check == CHECK_ALL_MAPS) { + if (!FLAG_eliminate_prototype_chain_checks && + (depth != 0 || check == CHECK_ALL_MAPS)) { // Check the holder map. __ mov(scratch1, FieldOperand(reg, HeapObject::kMapOffset)); Handle<WeakCell> cell = Map::WeakCellForMap(current_map); @@ -507,8 +541,13 @@ Register PropertyHandlerCompiler::CheckPrototypes( __ j(not_equal, miss); } + bool return_holder = return_what == RETURN_HOLDER; + if (FLAG_eliminate_prototype_chain_checks && return_holder && depth != 0) { + __ LoadWeakValue(reg, isolate()->factory()->NewWeakCell(current), miss); + } + // Return the register containing the holder. - return reg; + return return_holder ? reg : no_reg; } @@ -738,7 +777,7 @@ Handle<Code> NamedLoadHandlerCompiler::CompileLoadGlobal( if (IC::ICUseVector(kind())) { PushVectorAndSlot(); } - FrontendHeader(receiver(), name, &miss); + FrontendHeader(receiver(), name, &miss, DONT_RETURN_ANYTHING); // Get the value from the cell. Register result = StoreDescriptor::ValueRegister(); Handle<WeakCell> weak_cell = factory()->NewWeakCell(cell); |