summaryrefslogtreecommitdiff
path: root/deps/v8/src/ic
diff options
context:
space:
mode:
authorBen Noordhuis <info@bnoordhuis.nl>2015-06-19 13:23:56 +0200
committerRod Vagg <rod@vagg.org>2015-08-04 11:56:14 -0700
commit70d1f32f5605465a1a630a64f6f0d35f96c7709d (patch)
tree0a349040a686eafcb0a09943ebc733477dce2781 /deps/v8/src/ic
parent4643b8b6671607a7aff60cbbd0b384dcf2f6959e (diff)
downloadandroid-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/OWNERS1
-rw-r--r--deps/v8/src/ic/arm/handler-compiler-arm.cc68
-rw-r--r--deps/v8/src/ic/arm64/handler-compiler-arm64.cc68
-rw-r--r--deps/v8/src/ic/handler-compiler.cc37
-rw-r--r--deps/v8/src/ic/handler-compiler.h9
-rw-r--r--deps/v8/src/ic/ia32/handler-compiler-ia32.cc65
-rw-r--r--deps/v8/src/ic/ic-compiler.cc13
-rw-r--r--deps/v8/src/ic/ic-state.cc20
-rw-r--r--deps/v8/src/ic/ic-state.h22
-rw-r--r--deps/v8/src/ic/ic.cc126
-rw-r--r--deps/v8/src/ic/ic.h13
-rw-r--r--deps/v8/src/ic/mips/handler-compiler-mips.cc68
-rw-r--r--deps/v8/src/ic/mips64/handler-compiler-mips64.cc68
-rw-r--r--deps/v8/src/ic/ppc/OWNERS1
-rw-r--r--deps/v8/src/ic/ppc/handler-compiler-ppc.cc70
-rw-r--r--deps/v8/src/ic/x64/handler-compiler-x64.cc69
-rw-r--r--deps/v8/src/ic/x87/handler-compiler-x87.cc65
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);