summaryrefslogtreecommitdiff
path: root/deps/v8/src/ic
diff options
context:
space:
mode:
authorMichaël Zasso <targos@protonmail.com>2016-09-06 22:49:51 +0200
committerMichaël Zasso <targos@protonmail.com>2016-09-22 09:51:19 +0200
commitec02b811a8a5c999bab4de312be2d732b7d9d50b (patch)
treeca3068017254f238cf413a451c57a803572983a4 /deps/v8/src/ic
parentd2eb7ce0105369a9cad82787cb33a665e9bd00ad (diff)
downloadandroid-node-v8-ec02b811a8a5c999bab4de312be2d732b7d9d50b.tar.gz
android-node-v8-ec02b811a8a5c999bab4de312be2d732b7d9d50b.tar.bz2
android-node-v8-ec02b811a8a5c999bab4de312be2d732b7d9d50b.zip
deps: update V8 to 5.4.500.27
Pick up latest commit from the 5.4-lkgr branch. deps: edit V8 gitignore to allow trace event copy deps: update V8 trace event to 315bf1e2d45be7d53346c31cfcc37424a32c30c8 deps: edit V8 gitignore to allow gtest_prod.h copy deps: update V8 gtest to 6f8a66431cb592dad629028a50b3dd418a408c87 PR-URL: https://github.com/nodejs/node/pull/8317 Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl> Reviewed-By: Ali Ijaz Sheikh <ofrobots@google.com>
Diffstat (limited to 'deps/v8/src/ic')
-rw-r--r--deps/v8/src/ic/access-compiler.cc4
-rw-r--r--deps/v8/src/ic/access-compiler.h1
-rw-r--r--deps/v8/src/ic/arm/access-compiler-arm.cc8
-rw-r--r--deps/v8/src/ic/arm/handler-compiler-arm.cc163
-rw-r--r--deps/v8/src/ic/arm/ic-arm.cc55
-rw-r--r--deps/v8/src/ic/arm/stub-cache-arm.cc73
-rw-r--r--deps/v8/src/ic/arm64/access-compiler-arm64.cc8
-rw-r--r--deps/v8/src/ic/arm64/handler-compiler-arm64.cc163
-rw-r--r--deps/v8/src/ic/arm64/ic-arm64.cc55
-rw-r--r--deps/v8/src/ic/arm64/stub-cache-arm64.cc62
-rw-r--r--deps/v8/src/ic/call-optimization.cc17
-rw-r--r--deps/v8/src/ic/handler-compiler.cc173
-rw-r--r--deps/v8/src/ic/handler-compiler.h32
-rw-r--r--deps/v8/src/ic/handler-configuration.h45
-rw-r--r--deps/v8/src/ic/ia32/access-compiler-ia32.cc8
-rw-r--r--deps/v8/src/ic/ia32/handler-compiler-ia32.cc168
-rw-r--r--deps/v8/src/ic/ia32/ic-ia32.cc44
-rw-r--r--deps/v8/src/ic/ia32/stub-cache-ia32.cc53
-rw-r--r--deps/v8/src/ic/ic-compiler.cc199
-rw-r--r--deps/v8/src/ic/ic-compiler.h64
-rw-r--r--deps/v8/src/ic/ic-inl.h32
-rw-r--r--deps/v8/src/ic/ic-state.cc15
-rw-r--r--deps/v8/src/ic/ic-state.h41
-rw-r--r--deps/v8/src/ic/ic.cc1716
-rw-r--r--deps/v8/src/ic/ic.h267
-rw-r--r--deps/v8/src/ic/mips/access-compiler-mips.cc8
-rw-r--r--deps/v8/src/ic/mips/handler-compiler-mips.cc172
-rw-r--r--deps/v8/src/ic/mips/ic-mips.cc55
-rw-r--r--deps/v8/src/ic/mips/stub-cache-mips.cc65
-rw-r--r--deps/v8/src/ic/mips64/access-compiler-mips64.cc8
-rw-r--r--deps/v8/src/ic/mips64/handler-compiler-mips64.cc172
-rw-r--r--deps/v8/src/ic/mips64/ic-mips64.cc55
-rw-r--r--deps/v8/src/ic/mips64/stub-cache-mips64.cc70
-rw-r--r--deps/v8/src/ic/ppc/OWNERS1
-rw-r--r--deps/v8/src/ic/ppc/access-compiler-ppc.cc8
-rw-r--r--deps/v8/src/ic/ppc/handler-compiler-ppc.cc162
-rw-r--r--deps/v8/src/ic/ppc/ic-ppc.cc56
-rw-r--r--deps/v8/src/ic/ppc/stub-cache-ppc.cc54
-rw-r--r--deps/v8/src/ic/s390/OWNERS1
-rw-r--r--deps/v8/src/ic/s390/access-compiler-s390.cc8
-rw-r--r--deps/v8/src/ic/s390/handler-compiler-s390.cc160
-rw-r--r--deps/v8/src/ic/s390/ic-s390.cc54
-rw-r--r--deps/v8/src/ic/s390/stub-cache-s390.cc50
-rw-r--r--deps/v8/src/ic/stub-cache.cc62
-rw-r--r--deps/v8/src/ic/stub-cache.h57
-rw-r--r--deps/v8/src/ic/x64/access-compiler-x64.cc8
-rw-r--r--deps/v8/src/ic/x64/handler-compiler-x64.cc170
-rw-r--r--deps/v8/src/ic/x64/ic-x64.cc45
-rw-r--r--deps/v8/src/ic/x64/stub-cache-x64.cc47
-rw-r--r--deps/v8/src/ic/x87/access-compiler-x87.cc8
-rw-r--r--deps/v8/src/ic/x87/handler-compiler-x87.cc168
-rw-r--r--deps/v8/src/ic/x87/ic-x87.cc44
-rw-r--r--deps/v8/src/ic/x87/stub-cache-x87.cc53
53 files changed, 1941 insertions, 3346 deletions
diff --git a/deps/v8/src/ic/access-compiler.cc b/deps/v8/src/ic/access-compiler.cc
index c99219201a..bb6b5e50d9 100644
--- a/deps/v8/src/ic/access-compiler.cc
+++ b/deps/v8/src/ic/access-compiler.cc
@@ -57,7 +57,7 @@ Register PropertyAccessCompiler::slot() const {
return LoadDescriptor::SlotRegister();
}
DCHECK(kind() == Code::STORE_IC || kind() == Code::KEYED_STORE_IC);
- return VectorStoreICDescriptor::SlotRegister();
+ return StoreWithVectorDescriptor::SlotRegister();
}
@@ -66,7 +66,7 @@ Register PropertyAccessCompiler::vector() const {
return LoadWithVectorDescriptor::VectorRegister();
}
DCHECK(kind() == Code::STORE_IC || kind() == Code::KEYED_STORE_IC);
- return VectorStoreICDescriptor::VectorRegister();
+ return StoreWithVectorDescriptor::VectorRegister();
}
} // namespace internal
} // namespace v8
diff --git a/deps/v8/src/ic/access-compiler.h b/deps/v8/src/ic/access-compiler.h
index 50c2cc7303..ecc5c08a59 100644
--- a/deps/v8/src/ic/access-compiler.h
+++ b/deps/v8/src/ic/access-compiler.h
@@ -58,7 +58,6 @@ class PropertyAccessCompiler BASE_EMBEDDED {
Register vector() const;
Register scratch1() const { return registers_[2]; }
Register scratch2() const { return registers_[3]; }
- Register scratch3() const { return registers_[4]; }
static Register* GetCallingConvention(Code::Kind);
static Register* load_calling_convention();
diff --git a/deps/v8/src/ic/arm/access-compiler-arm.cc b/deps/v8/src/ic/arm/access-compiler-arm.cc
index d360f5a62b..9ce485ed46 100644
--- a/deps/v8/src/ic/arm/access-compiler-arm.cc
+++ b/deps/v8/src/ic/arm/access-compiler-arm.cc
@@ -19,19 +19,19 @@ void PropertyAccessCompiler::GenerateTailCall(MacroAssembler* masm,
Register* PropertyAccessCompiler::load_calling_convention() {
- // receiver, name, scratch1, scratch2, scratch3, scratch4.
+ // receiver, name, scratch1, scratch2, scratch3.
Register receiver = LoadDescriptor::ReceiverRegister();
Register name = LoadDescriptor::NameRegister();
- static Register registers[] = {receiver, name, r3, r0, r4, r5};
+ static Register registers[] = {receiver, name, r3, r0, r4};
return registers;
}
Register* PropertyAccessCompiler::store_calling_convention() {
- // receiver, name, scratch1, scratch2, scratch3.
+ // receiver, name, scratch1, scratch2.
Register receiver = StoreDescriptor::ReceiverRegister();
Register name = StoreDescriptor::NameRegister();
- static Register registers[] = {receiver, name, r3, r4, r5};
+ static Register registers[] = {receiver, name, r3, r4};
return registers;
}
diff --git a/deps/v8/src/ic/arm/handler-compiler-arm.cc b/deps/v8/src/ic/arm/handler-compiler-arm.cc
index a3f23d3f22..4ed765e73f 100644
--- a/deps/v8/src/ic/arm/handler-compiler-arm.cc
+++ b/deps/v8/src/ic/arm/handler-compiler-arm.cc
@@ -203,9 +203,11 @@ void NamedLoadHandlerCompiler::GenerateLoadFunctionPrototype(
void PropertyHandlerCompiler::GenerateCheckPropertyCell(
MacroAssembler* masm, Handle<JSGlobalObject> global, Handle<Name> name,
Register scratch, Label* miss) {
- Handle<PropertyCell> cell = JSGlobalObject::EnsurePropertyCell(global, name);
- DCHECK(cell->value()->IsTheHole());
- Handle<WeakCell> weak_cell = masm->isolate()->factory()->NewWeakCell(cell);
+ Handle<PropertyCell> cell = JSGlobalObject::EnsureEmptyPropertyCell(
+ global, name, PropertyCellType::kInvalidated);
+ Isolate* isolate = masm->isolate();
+ DCHECK(cell->value()->IsTheHole(isolate));
+ Handle<WeakCell> weak_cell = isolate->factory()->NewWeakCell(cell);
__ LoadWeakValue(scratch, weak_cell, miss);
__ ldr(scratch, FieldMemOperand(scratch, PropertyCell::kValueOffset));
__ LoadRoot(ip, Heap::kTheHoleValueRootIndex);
@@ -290,7 +292,7 @@ void PropertyHandlerCompiler::GenerateApiAccessorCall(
Handle<CallHandlerInfo> api_call_info = optimization.api_call_info();
bool call_data_undefined = false;
// Put call data in place.
- if (api_call_info->data()->IsUndefined()) {
+ if (api_call_info->data()->IsUndefined(isolate)) {
call_data_undefined = true;
__ LoadRoot(data, Heap::kUndefinedValueRootIndex);
} else {
@@ -332,17 +334,8 @@ void PropertyHandlerCompiler::GenerateApiAccessorCall(
static void StoreIC_PushArgs(MacroAssembler* masm) {
__ Push(StoreDescriptor::ReceiverRegister(), StoreDescriptor::NameRegister(),
StoreDescriptor::ValueRegister(),
- VectorStoreICDescriptor::SlotRegister(),
- VectorStoreICDescriptor::VectorRegister());
-}
-
-
-void NamedStoreHandlerCompiler::GenerateSlow(MacroAssembler* masm) {
- StoreIC_PushArgs(masm);
-
- // The slow case calls into the runtime to complete the store without causing
- // an IC miss that would otherwise cause a transition to the generic stub.
- __ TailCallRuntime(Runtime::kStoreIC_Slow);
+ StoreWithVectorDescriptor::SlotRegister(),
+ StoreWithVectorDescriptor::VectorRegister());
}
@@ -437,28 +430,25 @@ 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);
- }
+ 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);
- }
+ // 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.
@@ -494,8 +484,10 @@ Register PropertyHandlerCompiler::CheckPrototypes(
!current_map->is_access_check_needed());
prototype = handle(JSObject::cast(current_map->prototype()));
- if (current_map->is_dictionary_map() &&
- !current_map->IsJSGlobalObjectMap()) {
+ if (current_map->IsJSGlobalObjectMap()) {
+ GenerateCheckPropertyCell(masm(), Handle<JSGlobalObject>::cast(current),
+ name, scratch2, miss);
+ } else if (current_map->is_dictionary_map()) {
DCHECK(!current_map->IsJSGlobalProxyMap()); // Proxy maps are fast.
if (!name->IsUniqueName()) {
DCHECK(name->IsString());
@@ -505,33 +497,12 @@ Register PropertyHandlerCompiler::CheckPrototypes(
current->property_dictionary()->FindEntry(name) ==
NameDictionary::kNotFound);
- if (FLAG_eliminate_prototype_chain_checks && depth > 1) {
+ if (depth > 1) {
// TODO(jkummerow): Cache and re-use weak cell.
__ LoadWeakValue(reg, isolate()->factory()->NewWeakCell(current), miss);
}
GenerateDictionaryNegativeLookup(masm(), miss, reg, name, scratch1,
scratch2);
- if (!FLAG_eliminate_prototype_chain_checks) {
- __ ldr(scratch1, FieldMemOperand(reg, HeapObject::kMapOffset));
- __ ldr(holder_reg, FieldMemOperand(scratch1, Map::kPrototypeOffset));
- }
- } else {
- Register map_reg = scratch1;
- 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 (!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);
- }
- 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.
@@ -545,17 +516,8 @@ Register PropertyHandlerCompiler::CheckPrototypes(
// Log the check depth.
LOG(isolate(), IntEvent("check-maps-depth", depth + 1));
- 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);
- __ CmpWeakValue(scratch1, cell, scratch2);
- __ b(ne, miss);
- }
-
bool return_holder = return_what == RETURN_HOLDER;
- if (FLAG_eliminate_prototype_chain_checks && return_holder && depth != 0) {
+ if (return_holder && depth != 0) {
__ LoadWeakValue(reg, isolate()->factory()->NewWeakCell(current), miss);
}
@@ -597,61 +559,10 @@ void NamedLoadHandlerCompiler::GenerateLoadConstant(Handle<Object> value) {
__ Ret();
}
-
-void NamedLoadHandlerCompiler::GenerateLoadCallback(
- Register reg, Handle<AccessorInfo> callback) {
- DCHECK(!AreAliased(scratch2(), scratch3(), scratch4(), receiver()));
- DCHECK(!AreAliased(scratch2(), scratch3(), scratch4(), reg));
-
- // Build v8::PropertyCallbackInfo::args_ array on the stack and push property
- // name below the exit frame to make GC aware of them.
- STATIC_ASSERT(PropertyCallbackArguments::kShouldThrowOnErrorIndex == 0);
- STATIC_ASSERT(PropertyCallbackArguments::kHolderIndex == 1);
- STATIC_ASSERT(PropertyCallbackArguments::kIsolateIndex == 2);
- STATIC_ASSERT(PropertyCallbackArguments::kReturnValueDefaultValueIndex == 3);
- STATIC_ASSERT(PropertyCallbackArguments::kReturnValueOffset == 4);
- STATIC_ASSERT(PropertyCallbackArguments::kDataIndex == 5);
- STATIC_ASSERT(PropertyCallbackArguments::kThisIndex == 6);
- STATIC_ASSERT(PropertyCallbackArguments::kArgsLength == 7);
-
- __ push(receiver());
- // Push data from AccessorInfo.
- Handle<Object> data(callback->data(), isolate());
- if (data->IsUndefined() || data->IsSmi()) {
- __ Move(scratch2(), data);
- } else {
- Handle<WeakCell> cell =
- isolate()->factory()->NewWeakCell(Handle<HeapObject>::cast(data));
- // The callback is alive if this instruction is executed,
- // so the weak cell is not cleared and points to data.
- __ GetWeakValue(scratch2(), cell);
- }
- __ push(scratch2());
- __ LoadRoot(scratch2(), Heap::kUndefinedValueRootIndex);
- __ Push(scratch2(), scratch2());
- __ mov(scratch2(), Operand(ExternalReference::isolate_address(isolate())));
- __ Push(scratch2(), reg);
- __ Push(Smi::FromInt(0)); // should_throw_on_error -> false
- __ push(name());
-
- // Abi for CallApiGetter
- Register getter_address_reg = ApiGetterDescriptor::function_address();
-
- Address getter_address = v8::ToCData<Address>(callback->getter());
- ApiFunction fun(getter_address);
- ExternalReference::Type type = ExternalReference::DIRECT_GETTER_CALL;
- ExternalReference ref = ExternalReference(&fun, type, isolate());
- __ mov(getter_address_reg, Operand(ref));
-
- CallApiGetterStub stub(isolate());
- __ TailCallStub(&stub);
-}
-
-
void NamedLoadHandlerCompiler::GenerateLoadInterceptorWithFollowup(
LookupIterator* it, Register holder_reg) {
DCHECK(holder()->HasNamedInterceptor());
- DCHECK(!holder()->GetNamedInterceptor()->getter()->IsUndefined());
+ DCHECK(!holder()->GetNamedInterceptor()->getter()->IsUndefined(isolate()));
// Compile the interceptor call, followed by inline code to load the
// property from further up the prototype chain if the call fails.
@@ -711,7 +622,7 @@ void NamedLoadHandlerCompiler::GenerateLoadInterceptorWithFollowup(
void NamedLoadHandlerCompiler::GenerateLoadInterceptor(Register holder_reg) {
// Call the runtime system to load the interceptor.
DCHECK(holder()->HasNamedInterceptor());
- DCHECK(!holder()->GetNamedInterceptor()->getter()->IsUndefined());
+ DCHECK(!holder()->GetNamedInterceptor()->getter()->IsUndefined(isolate()));
PushInterceptorArguments(masm(), receiver(), holder_reg, this->name(),
holder());
@@ -729,7 +640,7 @@ Handle<Code> NamedStoreHandlerCompiler::CompileStoreCallback(
// If the callback cannot leak, then push the callback directly,
// otherwise wrap it in a weak cell.
- if (callback->data()->IsUndefined() || callback->data()->IsSmi()) {
+ if (callback->data()->IsUndefined(isolate()) || callback->data()->IsSmi()) {
__ mov(ip, Operand(callback));
} else {
Handle<WeakCell> cell = isolate()->factory()->NewWeakCell(callback);
@@ -744,7 +655,7 @@ Handle<Code> NamedStoreHandlerCompiler::CompileStoreCallback(
__ TailCallRuntime(Runtime::kStoreCallbackProperty);
// Return the generated code.
- return GetCode(kind(), Code::FAST, name);
+ return GetCode(kind(), name);
}
@@ -784,7 +695,7 @@ Handle<Code> NamedLoadHandlerCompiler::CompileLoadGlobal(
FrontendFooter(name, &miss);
// Return the generated code.
- return GetCode(kind(), Code::NORMAL, name);
+ return GetCode(kind(), name);
}
diff --git a/deps/v8/src/ic/arm/ic-arm.cc b/deps/v8/src/ic/arm/ic-arm.cc
index 14ed8b41a5..fee6ebf259 100644
--- a/deps/v8/src/ic/arm/ic-arm.cc
+++ b/deps/v8/src/ic/arm/ic-arm.cc
@@ -415,10 +415,8 @@ void KeyedLoadIC::GenerateMegamorphic(MacroAssembler* masm) {
__ LoadRoot(vector, Heap::kDummyVectorRootIndex);
__ mov(slot, Operand(Smi::FromInt(slot_index)));
- Code::Flags flags = Code::RemoveTypeAndHolderFromFlags(
- Code::ComputeHandlerFlags(Code::LOAD_IC));
- masm->isolate()->stub_cache()->GenerateProbe(masm, Code::KEYED_LOAD_IC, flags,
- receiver, key, r4, r5, r6, r9);
+ masm->isolate()->load_stub_cache()->GenerateProbe(masm, receiver, key, r4, r5,
+ r6, r9);
// Cache miss.
GenerateMiss(masm);
@@ -445,8 +443,8 @@ void KeyedLoadIC::GenerateMegamorphic(MacroAssembler* masm) {
static void StoreIC_PushArgs(MacroAssembler* masm) {
__ Push(StoreDescriptor::ReceiverRegister(), StoreDescriptor::NameRegister(),
StoreDescriptor::ValueRegister(),
- VectorStoreICDescriptor::SlotRegister(),
- VectorStoreICDescriptor::VectorRegister());
+ StoreWithVectorDescriptor::SlotRegister(),
+ StoreWithVectorDescriptor::VectorRegister());
}
@@ -626,10 +624,10 @@ void KeyedStoreIC::GenerateMegamorphic(MacroAssembler* masm,
__ JumpIfSmi(receiver, &slow);
// Get the map of the object.
__ ldr(receiver_map, FieldMemOperand(receiver, HeapObject::kMapOffset));
- // Check that the receiver does not require access checks and is not observed.
- // The generic stub does not perform map checks or handle observed objects.
+ // Check that the receiver does not require access checks.
+ // The generic stub does not perform map checks.
__ ldrb(ip, FieldMemOperand(receiver_map, Map::kBitFieldOffset));
- __ tst(ip, Operand(1 << Map::kIsAccessCheckNeeded | 1 << Map::kIsObserved));
+ __ tst(ip, Operand(1 << Map::kIsAccessCheckNeeded));
__ b(ne, &slow);
// Check if the object is a JS array or not.
__ ldrb(r4, FieldMemOperand(receiver_map, Map::kInstanceTypeOffset));
@@ -671,8 +669,8 @@ void KeyedStoreIC::GenerateMegamorphic(MacroAssembler* masm,
Register temporary2 = r8;
// The handlers in the stub cache expect a vector and slot. Since we won't
// change the IC from any downstream misses, a dummy vector can be used.
- Register vector = VectorStoreICDescriptor::VectorRegister();
- Register slot = VectorStoreICDescriptor::SlotRegister();
+ Register vector = StoreWithVectorDescriptor::VectorRegister();
+ Register slot = StoreWithVectorDescriptor::SlotRegister();
DCHECK(!AreAliased(vector, slot, r5, temporary2, r6, r9));
Handle<TypeFeedbackVector> dummy_vector =
@@ -682,10 +680,8 @@ void KeyedStoreIC::GenerateMegamorphic(MacroAssembler* masm,
__ LoadRoot(vector, Heap::kDummyVectorRootIndex);
__ mov(slot, Operand(Smi::FromInt(slot_index)));
- Code::Flags flags = Code::RemoveTypeAndHolderFromFlags(
- Code::ComputeHandlerFlags(Code::STORE_IC));
- masm->isolate()->stub_cache()->GenerateProbe(
- masm, Code::STORE_IC, flags, receiver, key, r5, temporary2, r6, r9);
+ masm->isolate()->store_stub_cache()->GenerateProbe(masm, receiver, key, r5,
+ temporary2, r6, r9);
// Cache miss.
__ b(&miss);
@@ -734,26 +730,6 @@ void KeyedStoreIC::GenerateMegamorphic(MacroAssembler* masm,
GenerateMiss(masm);
}
-
-void StoreIC::GenerateMegamorphic(MacroAssembler* masm) {
- Register receiver = StoreDescriptor::ReceiverRegister();
- Register name = StoreDescriptor::NameRegister();
- DCHECK(receiver.is(r1));
- DCHECK(name.is(r2));
- DCHECK(StoreDescriptor::ValueRegister().is(r0));
-
- // Get the receiver from the stack and probe the stub cache.
- Code::Flags flags = Code::RemoveTypeAndHolderFromFlags(
- Code::ComputeHandlerFlags(Code::STORE_IC));
-
- masm->isolate()->stub_cache()->GenerateProbe(masm, Code::STORE_IC, flags,
- receiver, name, r3, r4, r5, r6);
-
- // Cache miss: Jump to runtime.
- GenerateMiss(masm);
-}
-
-
void StoreIC::GenerateMiss(MacroAssembler* masm) {
StoreIC_PushArgs(masm);
@@ -771,8 +747,8 @@ void StoreIC::GenerateNormal(MacroAssembler* masm) {
DCHECK(receiver.is(r1));
DCHECK(name.is(r2));
DCHECK(value.is(r0));
- DCHECK(VectorStoreICDescriptor::VectorRegister().is(r3));
- DCHECK(VectorStoreICDescriptor::SlotRegister().is(r4));
+ DCHECK(StoreWithVectorDescriptor::VectorRegister().is(r3));
+ DCHECK(StoreWithVectorDescriptor::SlotRegister().is(r4));
__ ldr(dictionary, FieldMemOperand(receiver, JSObject::kPropertiesOffset));
@@ -845,8 +821,9 @@ void PatchInlinedSmiCode(Isolate* isolate, Address address,
}
if (FLAG_trace_ic) {
- PrintF("[ patching ic at %p, cmp=%p, delta=%d\n", address,
- cmp_instruction_address, delta);
+ PrintF("[ patching ic at %p, cmp=%p, delta=%d\n",
+ static_cast<void*>(address),
+ static_cast<void*>(cmp_instruction_address), delta);
}
Address patch_address =
diff --git a/deps/v8/src/ic/arm/stub-cache-arm.cc b/deps/v8/src/ic/arm/stub-cache-arm.cc
index 86710eb29a..b0f93e32dc 100644
--- a/deps/v8/src/ic/arm/stub-cache-arm.cc
+++ b/deps/v8/src/ic/arm/stub-cache-arm.cc
@@ -14,16 +14,15 @@ namespace internal {
#define __ ACCESS_MASM(masm)
-
-static void ProbeTable(Isolate* isolate, MacroAssembler* masm,
- Code::Kind ic_kind, Code::Flags flags,
+static void ProbeTable(StubCache* stub_cache, MacroAssembler* masm,
StubCache::Table table, Register receiver, Register name,
- // Number of the cache entry, not scaled.
+ // The offset is scaled by 4, based on
+ // kCacheIndexShift, which is two bits
Register offset, Register scratch, Register scratch2,
Register offset_scratch) {
- ExternalReference key_offset(isolate->stub_cache()->key_reference(table));
- ExternalReference value_offset(isolate->stub_cache()->value_reference(table));
- ExternalReference map_offset(isolate->stub_cache()->map_reference(table));
+ ExternalReference key_offset(stub_cache->key_reference(table));
+ ExternalReference value_offset(stub_cache->value_reference(table));
+ ExternalReference map_offset(stub_cache->map_reference(table));
uint32_t key_off_addr = reinterpret_cast<uint32_t>(key_offset.address());
uint32_t value_off_addr = reinterpret_cast<uint32_t>(value_offset.address());
@@ -45,8 +44,7 @@ static void ProbeTable(Isolate* isolate, MacroAssembler* masm,
__ add(offset_scratch, offset, Operand(offset, LSL, 1));
// Calculate the base address of the entry.
- __ mov(base_addr, Operand(key_offset));
- __ add(base_addr, base_addr, Operand(offset_scratch, LSL, kPointerSizeLog2));
+ __ add(base_addr, offset_scratch, Operand(key_offset));
// Check that the key in the entry matches the name.
__ ldr(ip, MemOperand(base_addr, 0));
@@ -64,18 +62,6 @@ static void ProbeTable(Isolate* isolate, MacroAssembler* masm,
scratch2 = no_reg;
__ ldr(code, MemOperand(base_addr, value_off_addr - key_off_addr));
- // Check that the flags match what we're looking for.
- Register flags_reg = base_addr;
- base_addr = no_reg;
- __ ldr(flags_reg, FieldMemOperand(code, Code::kFlagsOffset));
- // It's a nice optimization if this constant is encodable in the bic insn.
-
- uint32_t mask = Code::kFlagsNotUsedInLookup;
- DCHECK(__ ImmediateFitsAddrMode1Instruction(mask));
- __ bic(flags_reg, flags_reg, Operand(mask));
- __ cmp(flags_reg, Operand(flags));
- __ b(ne, &miss);
-
#ifdef DEBUG
if (FLAG_test_secondary_stub_cache && table == StubCache::kPrimary) {
__ jmp(&miss);
@@ -91,21 +77,15 @@ static void ProbeTable(Isolate* isolate, MacroAssembler* masm,
__ bind(&miss);
}
-
-void StubCache::GenerateProbe(MacroAssembler* masm, Code::Kind ic_kind,
- Code::Flags flags, Register receiver,
+void StubCache::GenerateProbe(MacroAssembler* masm, Register receiver,
Register name, Register scratch, Register extra,
Register extra2, Register extra3) {
- Isolate* isolate = masm->isolate();
Label miss;
// Make sure that code is valid. The multiplying code relies on the
// entry size being 12.
DCHECK(sizeof(Entry) == 12);
- // Make sure the flags does not name a specific type.
- DCHECK(Code::ExtractTypeFromFlags(flags) == 0);
-
// Make sure that there are no register conflicts.
DCHECK(!AreAliased(receiver, name, scratch, extra, extra2, extra3));
@@ -119,12 +99,13 @@ void StubCache::GenerateProbe(MacroAssembler* masm, Code::Kind ic_kind,
// If vector-based ics are in use, ensure that scratch, extra, extra2 and
// extra3 don't conflict with the vector and slot registers, which need
// to be preserved for a handler call or miss.
- if (IC::ICUseVector(ic_kind)) {
+ if (IC::ICUseVector(ic_kind_)) {
Register vector, slot;
- if (ic_kind == Code::STORE_IC || ic_kind == Code::KEYED_STORE_IC) {
- vector = VectorStoreICDescriptor::VectorRegister();
- slot = VectorStoreICDescriptor::SlotRegister();
+ if (ic_kind_ == Code::STORE_IC || ic_kind_ == Code::KEYED_STORE_IC) {
+ vector = StoreWithVectorDescriptor::VectorRegister();
+ slot = StoreWithVectorDescriptor::SlotRegister();
} else {
+ DCHECK(ic_kind_ == Code::LOAD_IC || ic_kind_ == Code::KEYED_LOAD_IC);
vector = LoadWithVectorDescriptor::VectorRegister();
slot = LoadWithVectorDescriptor::SlotRegister();
}
@@ -143,29 +124,23 @@ void StubCache::GenerateProbe(MacroAssembler* masm, Code::Kind ic_kind,
__ ldr(scratch, FieldMemOperand(name, Name::kHashFieldOffset));
__ ldr(ip, FieldMemOperand(receiver, HeapObject::kMapOffset));
__ add(scratch, scratch, Operand(ip));
- uint32_t mask = kPrimaryTableSize - 1;
- // We shift out the last two bits because they are not part of the hash and
- // they are always 01 for maps.
- __ mov(scratch, Operand(scratch, LSR, kCacheIndexShift));
- // Mask down the eor argument to the minimum to keep the immediate
- // ARM-encodable.
- __ eor(scratch, scratch, Operand((flags >> kCacheIndexShift) & mask));
- // Prefer and_ to ubfx here because ubfx takes 2 cycles.
- __ and_(scratch, scratch, Operand(mask));
+ __ eor(scratch, scratch, Operand(kPrimaryMagic));
+ __ mov(ip, Operand(kPrimaryTableSize - 1));
+ __ and_(scratch, scratch, Operand(ip, LSL, kCacheIndexShift));
// Probe the primary table.
- ProbeTable(isolate, masm, ic_kind, flags, kPrimary, receiver, name, scratch,
- extra, extra2, extra3);
+ ProbeTable(this, masm, kPrimary, receiver, name, scratch, extra, extra2,
+ extra3);
// Primary miss: Compute hash for secondary probe.
- __ sub(scratch, scratch, Operand(name, LSR, kCacheIndexShift));
- uint32_t mask2 = kSecondaryTableSize - 1;
- __ add(scratch, scratch, Operand((flags >> kCacheIndexShift) & mask2));
- __ and_(scratch, scratch, Operand(mask2));
+ __ sub(scratch, scratch, Operand(name));
+ __ add(scratch, scratch, Operand(kSecondaryMagic));
+ __ mov(ip, Operand(kSecondaryTableSize - 1));
+ __ and_(scratch, scratch, Operand(ip, LSL, kCacheIndexShift));
// Probe the secondary table.
- ProbeTable(isolate, masm, ic_kind, flags, kSecondary, receiver, name, scratch,
- extra, extra2, extra3);
+ ProbeTable(this, masm, kSecondary, receiver, name, scratch, extra, extra2,
+ extra3);
// Cache miss: Fall-through and let caller handle the miss by
// entering the runtime system.
diff --git a/deps/v8/src/ic/arm64/access-compiler-arm64.cc b/deps/v8/src/ic/arm64/access-compiler-arm64.cc
index 892ce85dfb..6273633822 100644
--- a/deps/v8/src/ic/arm64/access-compiler-arm64.cc
+++ b/deps/v8/src/ic/arm64/access-compiler-arm64.cc
@@ -26,19 +26,19 @@ void PropertyAccessCompiler::GenerateTailCall(MacroAssembler* masm,
// we use the same assignments as ARM to remain on the safe side.
Register* PropertyAccessCompiler::load_calling_convention() {
- // receiver, name, scratch1, scratch2, scratch3, scratch4.
+ // receiver, name, scratch1, scratch2, scratch3.
Register receiver = LoadDescriptor::ReceiverRegister();
Register name = LoadDescriptor::NameRegister();
- static Register registers[] = {receiver, name, x3, x0, x4, x5};
+ static Register registers[] = {receiver, name, x3, x0, x4};
return registers;
}
Register* PropertyAccessCompiler::store_calling_convention() {
- // receiver, value, scratch1, scratch2, scratch3.
+ // receiver, value, scratch1, scratch2.
Register receiver = StoreDescriptor::ReceiverRegister();
Register name = StoreDescriptor::NameRegister();
- static Register registers[] = {receiver, name, x3, x4, x5};
+ static Register registers[] = {receiver, name, x3, x4};
return registers;
}
diff --git a/deps/v8/src/ic/arm64/handler-compiler-arm64.cc b/deps/v8/src/ic/arm64/handler-compiler-arm64.cc
index a704492550..277b4e7117 100644
--- a/deps/v8/src/ic/arm64/handler-compiler-arm64.cc
+++ b/deps/v8/src/ic/arm64/handler-compiler-arm64.cc
@@ -109,9 +109,11 @@ void NamedLoadHandlerCompiler::GenerateLoadFunctionPrototype(
void PropertyHandlerCompiler::GenerateCheckPropertyCell(
MacroAssembler* masm, Handle<JSGlobalObject> global, Handle<Name> name,
Register scratch, Label* miss) {
- Handle<PropertyCell> cell = JSGlobalObject::EnsurePropertyCell(global, name);
- DCHECK(cell->value()->IsTheHole());
- Handle<WeakCell> weak_cell = masm->isolate()->factory()->NewWeakCell(cell);
+ Handle<PropertyCell> cell = JSGlobalObject::EnsureEmptyPropertyCell(
+ global, name, PropertyCellType::kInvalidated);
+ Isolate* isolate = masm->isolate();
+ DCHECK(cell->value()->IsTheHole(isolate));
+ Handle<WeakCell> weak_cell = isolate->factory()->NewWeakCell(cell);
__ LoadWeakValue(scratch, weak_cell, miss);
__ Ldr(scratch, FieldMemOperand(scratch, PropertyCell::kValueOffset));
__ JumpIfNotRoot(scratch, Heap::kTheHoleValueRootIndex, miss);
@@ -197,7 +199,7 @@ void PropertyHandlerCompiler::GenerateApiAccessorCall(
Handle<CallHandlerInfo> api_call_info = optimization.api_call_info();
bool call_data_undefined = false;
// Put call data in place.
- if (api_call_info->data()->IsUndefined()) {
+ if (api_call_info->data()->IsUndefined(isolate)) {
call_data_undefined = true;
__ LoadRoot(data, Heap::kUndefinedValueRootIndex);
} else {
@@ -325,17 +327,8 @@ void NamedLoadHandlerCompiler::GenerateLoadViaGetter(
static void StoreIC_PushArgs(MacroAssembler* masm) {
__ Push(StoreDescriptor::ReceiverRegister(), StoreDescriptor::NameRegister(),
StoreDescriptor::ValueRegister(),
- VectorStoreICDescriptor::SlotRegister(),
- VectorStoreICDescriptor::VectorRegister());
-}
-
-
-void NamedStoreHandlerCompiler::GenerateSlow(MacroAssembler* masm) {
- StoreIC_PushArgs(masm);
-
- // The slow case calls into the runtime to complete the store without causing
- // an IC miss that would otherwise cause a transition to the generic stub.
- __ TailCallRuntime(Runtime::kStoreIC_Slow);
+ StoreWithVectorDescriptor::SlotRegister(),
+ StoreWithVectorDescriptor::VectorRegister());
}
@@ -382,7 +375,7 @@ Handle<Code> NamedLoadHandlerCompiler::CompileLoadGlobal(
FrontendFooter(name, &miss);
// Return the generated code.
- return GetCode(kind(), Code::NORMAL, name);
+ return GetCode(kind(), name);
}
@@ -467,28 +460,25 @@ Register PropertyHandlerCompiler::CheckPrototypes(
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);
- }
+ 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);
- }
+ // 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.
@@ -525,8 +515,10 @@ Register PropertyHandlerCompiler::CheckPrototypes(
!current_map->is_access_check_needed());
prototype = handle(JSObject::cast(current_map->prototype()));
- if (current_map->is_dictionary_map() &&
- !current_map->IsJSGlobalObjectMap()) {
+ if (current_map->IsJSGlobalObjectMap()) {
+ GenerateCheckPropertyCell(masm(), Handle<JSGlobalObject>::cast(current),
+ name, scratch2, miss);
+ } else if (current_map->is_dictionary_map()) {
DCHECK(!current_map->IsJSGlobalProxyMap()); // Proxy maps are fast.
if (!name->IsUniqueName()) {
DCHECK(name->IsString());
@@ -535,34 +527,12 @@ Register PropertyHandlerCompiler::CheckPrototypes(
DCHECK(current.is_null() || (current->property_dictionary()->FindEntry(
name) == NameDictionary::kNotFound));
- if (FLAG_eliminate_prototype_chain_checks && depth > 1) {
+ if (depth > 1) {
// TODO(jkummerow): Cache and re-use weak cell.
__ LoadWeakValue(reg, isolate()->factory()->NewWeakCell(current), miss);
}
GenerateDictionaryNegativeLookup(masm(), miss, reg, name, scratch1,
scratch2);
-
- if (!FLAG_eliminate_prototype_chain_checks) {
- __ Ldr(scratch1, FieldMemOperand(reg, HeapObject::kMapOffset));
- __ Ldr(holder_reg, FieldMemOperand(scratch1, Map::kPrototypeOffset));
- }
- } else {
- Register map_reg = scratch1;
- 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 (!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);
- }
- 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.
@@ -576,17 +546,8 @@ Register PropertyHandlerCompiler::CheckPrototypes(
// Log the check depth.
LOG(isolate(), IntEvent("check-maps-depth", depth + 1));
- 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);
- __ CmpWeakValue(scratch1, cell, scratch2);
- __ B(ne, miss);
- }
-
bool return_holder = return_what == RETURN_HOLDER;
- if (FLAG_eliminate_prototype_chain_checks && return_holder && depth != 0) {
+ if (return_holder && depth != 0) {
__ LoadWeakValue(reg, isolate()->factory()->NewWeakCell(current), miss);
}
@@ -632,62 +593,12 @@ void NamedLoadHandlerCompiler::GenerateLoadConstant(Handle<Object> value) {
__ Ret();
}
-
-void NamedLoadHandlerCompiler::GenerateLoadCallback(
- Register reg, Handle<AccessorInfo> callback) {
- DCHECK(!AreAliased(scratch2(), scratch3(), scratch4(), receiver()));
- DCHECK(!AreAliased(scratch2(), scratch3(), scratch4(), reg));
-
- // Build v8::PropertyCallbackInfo::args_ array on the stack and push property
- // name below the exit frame to make GC aware of them.
- STATIC_ASSERT(PropertyCallbackArguments::kShouldThrowOnErrorIndex == 0);
- STATIC_ASSERT(PropertyCallbackArguments::kHolderIndex == 1);
- STATIC_ASSERT(PropertyCallbackArguments::kIsolateIndex == 2);
- STATIC_ASSERT(PropertyCallbackArguments::kReturnValueDefaultValueIndex == 3);
- STATIC_ASSERT(PropertyCallbackArguments::kReturnValueOffset == 4);
- STATIC_ASSERT(PropertyCallbackArguments::kDataIndex == 5);
- STATIC_ASSERT(PropertyCallbackArguments::kThisIndex == 6);
- STATIC_ASSERT(PropertyCallbackArguments::kArgsLength == 7);
-
- __ Push(receiver());
-
- Handle<Object> data(callback->data(), isolate());
- if (data->IsUndefined() || data->IsSmi()) {
- __ Mov(scratch3(), Operand(data));
- } else {
- Handle<WeakCell> cell =
- isolate()->factory()->NewWeakCell(Handle<HeapObject>::cast(data));
- // The callback is alive if this instruction is executed,
- // so the weak cell is not cleared and points to data.
- __ GetWeakValue(scratch3(), cell);
- }
- __ LoadRoot(scratch4(), Heap::kUndefinedValueRootIndex);
- __ Mov(scratch2(), Operand(ExternalReference::isolate_address(isolate())));
- __ Push(scratch3(), scratch4(), scratch4(), scratch2(), reg);
- __ Push(Smi::FromInt(0)); // should_throw_on_error -> false
- __ Push(name());
-
- // Abi for CallApiGetter.
- Register getter_address_reg = x2;
-
- // Set up the call.
- Address getter_address = v8::ToCData<Address>(callback->getter());
- ApiFunction fun(getter_address);
- ExternalReference::Type type = ExternalReference::DIRECT_GETTER_CALL;
- ExternalReference ref = ExternalReference(&fun, type, isolate());
- __ Mov(getter_address_reg, ref);
-
- CallApiGetterStub stub(isolate());
- __ TailCallStub(&stub);
-}
-
-
void NamedLoadHandlerCompiler::GenerateLoadInterceptorWithFollowup(
LookupIterator* it, Register holder_reg) {
DCHECK(!AreAliased(receiver(), this->name(), scratch1(), scratch2(),
scratch3()));
DCHECK(holder()->HasNamedInterceptor());
- DCHECK(!holder()->GetNamedInterceptor()->getter()->IsUndefined());
+ DCHECK(!holder()->GetNamedInterceptor()->getter()->IsUndefined(isolate()));
// Compile the interceptor call, followed by inline code to load the
// property from further up the prototype chain if the call fails.
@@ -746,7 +657,7 @@ void NamedLoadHandlerCompiler::GenerateLoadInterceptorWithFollowup(
void NamedLoadHandlerCompiler::GenerateLoadInterceptor(Register holder_reg) {
// Call the runtime system to load the interceptor.
DCHECK(holder()->HasNamedInterceptor());
- DCHECK(!holder()->GetNamedInterceptor()->getter()->IsUndefined());
+ DCHECK(!holder()->GetNamedInterceptor()->getter()->IsUndefined(isolate()));
PushInterceptorArguments(masm(), receiver(), holder_reg, this->name(),
holder());
@@ -768,7 +679,7 @@ Handle<Code> NamedStoreHandlerCompiler::CompileStoreCallback(
DCHECK(!AreAliased(holder_reg, scratch1(), scratch2(), value()));
// If the callback cannot leak, then push the callback directly,
// otherwise wrap it in a weak cell.
- if (callback->data()->IsUndefined() || callback->data()->IsSmi()) {
+ if (callback->data()->IsUndefined(isolate()) || callback->data()->IsSmi()) {
__ Mov(scratch1(), Operand(callback));
} else {
Handle<WeakCell> cell = isolate()->factory()->NewWeakCell(callback);
@@ -782,7 +693,7 @@ Handle<Code> NamedStoreHandlerCompiler::CompileStoreCallback(
__ TailCallRuntime(Runtime::kStoreCallbackProperty);
// Return the generated code.
- return GetCode(kind(), Code::FAST, name);
+ return GetCode(kind(), name);
}
diff --git a/deps/v8/src/ic/arm64/ic-arm64.cc b/deps/v8/src/ic/arm64/ic-arm64.cc
index 726a68e45f..9d66eb2495 100644
--- a/deps/v8/src/ic/arm64/ic-arm64.cc
+++ b/deps/v8/src/ic/arm64/ic-arm64.cc
@@ -394,11 +394,8 @@ static void GenerateKeyedLoadWithNameKey(MacroAssembler* masm, Register key,
__ LoadRoot(vector, Heap::kDummyVectorRootIndex);
__ Mov(slot, Operand(Smi::FromInt(slot_index)));
- Code::Flags flags = Code::RemoveTypeAndHolderFromFlags(
- Code::ComputeHandlerFlags(Code::LOAD_IC));
- masm->isolate()->stub_cache()->GenerateProbe(masm, Code::KEYED_LOAD_IC, flags,
- receiver, key, scratch1,
- scratch2, scratch3, scratch4);
+ masm->isolate()->load_stub_cache()->GenerateProbe(
+ masm, receiver, key, scratch1, scratch2, scratch3, scratch4);
// Cache miss.
KeyedLoadIC::GenerateMiss(masm);
@@ -450,8 +447,8 @@ void KeyedLoadIC::GenerateMegamorphic(MacroAssembler* masm) {
static void StoreIC_PushArgs(MacroAssembler* masm) {
__ Push(StoreDescriptor::ReceiverRegister(), StoreDescriptor::NameRegister(),
StoreDescriptor::ValueRegister(),
- VectorStoreICDescriptor::SlotRegister(),
- VectorStoreICDescriptor::VectorRegister());
+ StoreWithVectorDescriptor::SlotRegister(),
+ StoreWithVectorDescriptor::VectorRegister());
}
@@ -622,11 +619,10 @@ void KeyedStoreIC::GenerateMegamorphic(MacroAssembler* masm,
__ JumpIfSmi(receiver, &slow);
__ Ldr(receiver_map, FieldMemOperand(receiver, HeapObject::kMapOffset));
- // Check that the receiver does not require access checks and is not observed.
- // The generic stub does not perform map checks or handle observed objects.
+ // Check that the receiver does not require access checks.
+ // The generic stub does not perform map checks.
__ Ldrb(x10, FieldMemOperand(receiver_map, Map::kBitFieldOffset));
- __ TestAndBranchIfAnySet(
- x10, (1 << Map::kIsAccessCheckNeeded) | (1 << Map::kIsObserved), &slow);
+ __ TestAndBranchIfAnySet(x10, (1 << Map::kIsAccessCheckNeeded), &slow);
// Check if the object is a JS array or not.
Register instance_type = x10;
@@ -663,8 +659,8 @@ void KeyedStoreIC::GenerateMegamorphic(MacroAssembler* masm,
// The handlers in the stub cache expect a vector and slot. Since we won't
// change the IC from any downstream misses, a dummy vector can be used.
- Register vector = VectorStoreICDescriptor::VectorRegister();
- Register slot = VectorStoreICDescriptor::SlotRegister();
+ Register vector = StoreWithVectorDescriptor::VectorRegister();
+ Register slot = StoreWithVectorDescriptor::SlotRegister();
DCHECK(!AreAliased(vector, slot, x5, x6, x7, x8));
Handle<TypeFeedbackVector> dummy_vector =
TypeFeedbackVector::DummyVector(masm->isolate());
@@ -673,10 +669,8 @@ void KeyedStoreIC::GenerateMegamorphic(MacroAssembler* masm,
__ LoadRoot(vector, Heap::kDummyVectorRootIndex);
__ Mov(slot, Operand(Smi::FromInt(slot_index)));
- Code::Flags flags = Code::RemoveTypeAndHolderFromFlags(
- Code::ComputeHandlerFlags(Code::STORE_IC));
- masm->isolate()->stub_cache()->GenerateProbe(masm, Code::STORE_IC, flags,
- receiver, key, x5, x6, x7, x8);
+ masm->isolate()->store_stub_cache()->GenerateProbe(masm, receiver, key, x5,
+ x6, x7, x8);
// Cache miss.
__ B(&miss);
@@ -725,24 +719,6 @@ void KeyedStoreIC::GenerateMegamorphic(MacroAssembler* masm,
GenerateMiss(masm);
}
-
-void StoreIC::GenerateMegamorphic(MacroAssembler* masm) {
- Register receiver = StoreDescriptor::ReceiverRegister();
- Register name = StoreDescriptor::NameRegister();
- DCHECK(!AreAliased(receiver, name, StoreDescriptor::ValueRegister(), x3, x4,
- x5, x6));
-
- // Probe the stub cache.
- Code::Flags flags = Code::RemoveTypeAndHolderFromFlags(
- Code::ComputeHandlerFlags(Code::STORE_IC));
- masm->isolate()->stub_cache()->GenerateProbe(masm, Code::STORE_IC, flags,
- receiver, name, x3, x4, x5, x6);
-
- // Cache miss: Jump to runtime.
- GenerateMiss(masm);
-}
-
-
void StoreIC::GenerateMiss(MacroAssembler* masm) {
StoreIC_PushArgs(masm);
@@ -758,8 +734,8 @@ void StoreIC::GenerateNormal(MacroAssembler* masm) {
Register name = StoreDescriptor::NameRegister();
Register dictionary = x5;
DCHECK(!AreAliased(value, receiver, name,
- VectorStoreICDescriptor::SlotRegister(),
- VectorStoreICDescriptor::VectorRegister(), x5, x6, x7));
+ StoreWithVectorDescriptor::SlotRegister(),
+ StoreWithVectorDescriptor::VectorRegister(), x5, x6, x7));
__ Ldr(dictionary, FieldMemOperand(receiver, JSObject::kPropertiesOffset));
@@ -822,8 +798,9 @@ void PatchInlinedSmiCode(Isolate* isolate, Address address,
}
if (FLAG_trace_ic) {
- PrintF("[ Patching ic at %p, marker=%p, SMI check=%p\n", address,
- info_address, reinterpret_cast<void*>(info.SmiCheck()));
+ PrintF("[ Patching ic at %p, marker=%p, SMI check=%p\n",
+ static_cast<void*>(address), static_cast<void*>(info_address),
+ static_cast<void*>(info.SmiCheck()));
}
// Patch and activate code generated by JumpPatchSite::EmitJumpIfNotSmi()
diff --git a/deps/v8/src/ic/arm64/stub-cache-arm64.cc b/deps/v8/src/ic/arm64/stub-cache-arm64.cc
index eb82f2af86..81c820725a 100644
--- a/deps/v8/src/ic/arm64/stub-cache-arm64.cc
+++ b/deps/v8/src/ic/arm64/stub-cache-arm64.cc
@@ -22,18 +22,19 @@ namespace internal {
// If there is a miss the code fall trough.
//
// 'receiver', 'name' and 'offset' registers are preserved on miss.
-static void ProbeTable(Isolate* isolate, MacroAssembler* masm,
- Code::Kind ic_kind, Code::Flags flags,
+static void ProbeTable(StubCache* stub_cache, MacroAssembler* masm,
StubCache::Table table, Register receiver, Register name,
+ // The offset is scaled by 4, based on
+ // kCacheIndexShift, which is two bits
Register offset, Register scratch, Register scratch2,
Register scratch3) {
// Some code below relies on the fact that the Entry struct contains
// 3 pointers (name, code, map).
STATIC_ASSERT(sizeof(StubCache::Entry) == (3 * kPointerSize));
- ExternalReference key_offset(isolate->stub_cache()->key_reference(table));
- ExternalReference value_offset(isolate->stub_cache()->value_reference(table));
- ExternalReference map_offset(isolate->stub_cache()->map_reference(table));
+ ExternalReference key_offset(stub_cache->key_reference(table));
+ ExternalReference value_offset(stub_cache->value_reference(table));
+ ExternalReference map_offset(stub_cache->map_reference(table));
uintptr_t key_off_addr = reinterpret_cast<uintptr_t>(key_offset.address());
uintptr_t value_off_addr =
@@ -49,7 +50,9 @@ static void ProbeTable(Isolate* isolate, MacroAssembler* masm,
// Calculate the base address of the entry.
__ Mov(scratch, key_offset);
- __ Add(scratch, scratch, Operand(scratch3, LSL, kPointerSizeLog2));
+ __ Add(
+ scratch, scratch,
+ Operand(scratch3, LSL, kPointerSizeLog2 - StubCache::kCacheIndexShift));
// Check that the key in the entry matches the name.
__ Ldr(scratch2, MemOperand(scratch));
@@ -65,12 +68,6 @@ static void ProbeTable(Isolate* isolate, MacroAssembler* masm,
// Get the code entry from the cache.
__ Ldr(scratch, MemOperand(scratch, value_off_addr - key_off_addr));
- // Check that the flags match what we're looking for.
- __ Ldr(scratch2.W(), FieldMemOperand(scratch, Code::kFlagsOffset));
- __ Bic(scratch2.W(), scratch2.W(), Code::kFlagsNotUsedInLookup);
- __ Cmp(scratch2.W(), flags);
- __ B(ne, &miss);
-
#ifdef DEBUG
if (FLAG_test_secondary_stub_cache && table == StubCache::kPrimary) {
__ B(&miss);
@@ -87,17 +84,11 @@ static void ProbeTable(Isolate* isolate, MacroAssembler* masm,
__ Bind(&miss);
}
-
-void StubCache::GenerateProbe(MacroAssembler* masm, Code::Kind ic_kind,
- Code::Flags flags, Register receiver,
+void StubCache::GenerateProbe(MacroAssembler* masm, Register receiver,
Register name, Register scratch, Register extra,
Register extra2, Register extra3) {
- Isolate* isolate = masm->isolate();
Label miss;
- // Make sure the flags does not name a specific type.
- DCHECK(Code::ExtractTypeFromFlags(flags) == 0);
-
// Make sure that there are no register conflicts.
DCHECK(!AreAliased(receiver, name, scratch, extra, extra2, extra3));
@@ -110,12 +101,13 @@ void StubCache::GenerateProbe(MacroAssembler* masm, Code::Kind ic_kind,
// If vector-based ics are in use, ensure that scratch, extra, extra2 and
// extra3 don't conflict with the vector and slot registers, which need
// to be preserved for a handler call or miss.
- if (IC::ICUseVector(ic_kind)) {
+ if (IC::ICUseVector(ic_kind_)) {
Register vector, slot;
- if (ic_kind == Code::STORE_IC || ic_kind == Code::KEYED_STORE_IC) {
- vector = VectorStoreICDescriptor::VectorRegister();
- slot = VectorStoreICDescriptor::SlotRegister();
+ if (ic_kind_ == Code::STORE_IC || ic_kind_ == Code::KEYED_STORE_IC) {
+ vector = StoreWithVectorDescriptor::VectorRegister();
+ slot = StoreWithVectorDescriptor::SlotRegister();
} else {
+ DCHECK(ic_kind_ == Code::LOAD_IC || ic_kind_ == Code::KEYED_LOAD_IC);
vector = LoadWithVectorDescriptor::VectorRegister();
slot = LoadWithVectorDescriptor::SlotRegister();
}
@@ -131,26 +123,26 @@ void StubCache::GenerateProbe(MacroAssembler* masm, Code::Kind ic_kind,
__ JumpIfSmi(receiver, &miss);
// Compute the hash for primary table.
- __ Ldr(scratch, FieldMemOperand(name, Name::kHashFieldOffset));
+ __ Ldr(scratch.W(), FieldMemOperand(name, Name::kHashFieldOffset));
__ Ldr(extra, FieldMemOperand(receiver, HeapObject::kMapOffset));
__ Add(scratch, scratch, extra);
- __ Eor(scratch, scratch, flags);
- // We shift out the last two bits because they are not part of the hash.
- __ Ubfx(scratch, scratch, kCacheIndexShift,
- CountTrailingZeros(kPrimaryTableSize, 64));
+ __ Eor(scratch, scratch, kPrimaryMagic);
+ __ And(scratch, scratch,
+ Operand((kPrimaryTableSize - 1) << kCacheIndexShift));
// Probe the primary table.
- ProbeTable(isolate, masm, ic_kind, flags, kPrimary, receiver, name, scratch,
- extra, extra2, extra3);
+ ProbeTable(this, masm, kPrimary, receiver, name, scratch, extra, extra2,
+ extra3);
// Primary miss: Compute hash for secondary table.
- __ Sub(scratch, scratch, Operand(name, LSR, kCacheIndexShift));
- __ Add(scratch, scratch, flags >> kCacheIndexShift);
- __ And(scratch, scratch, kSecondaryTableSize - 1);
+ __ Sub(scratch, scratch, Operand(name));
+ __ Add(scratch, scratch, Operand(kSecondaryMagic));
+ __ And(scratch, scratch,
+ Operand((kSecondaryTableSize - 1) << kCacheIndexShift));
// Probe the secondary table.
- ProbeTable(isolate, masm, ic_kind, flags, kSecondary, receiver, name, scratch,
- extra, extra2, extra3);
+ ProbeTable(this, masm, kSecondary, receiver, name, scratch, extra, extra2,
+ extra3);
// Cache miss: Fall-through and let caller handle the miss by
// entering the runtime system.
diff --git a/deps/v8/src/ic/call-optimization.cc b/deps/v8/src/ic/call-optimization.cc
index 571b614dde..f7a1f6982f 100644
--- a/deps/v8/src/ic/call-optimization.cc
+++ b/deps/v8/src/ic/call-optimization.cc
@@ -89,11 +89,12 @@ bool CallOptimization::IsCompatibleReceiverMap(Handle<Map> map,
void CallOptimization::Initialize(
Handle<FunctionTemplateInfo> function_template_info) {
- if (function_template_info->call_code()->IsUndefined()) return;
+ Isolate* isolate = function_template_info->GetIsolate();
+ if (function_template_info->call_code()->IsUndefined(isolate)) return;
api_call_info_ =
handle(CallHandlerInfo::cast(function_template_info->call_code()));
- if (!function_template_info->signature()->IsUndefined()) {
+ if (!function_template_info->signature()->IsUndefined(isolate)) {
expected_receiver_type_ =
handle(FunctionTemplateInfo::cast(function_template_info->signature()));
}
@@ -110,15 +111,17 @@ void CallOptimization::Initialize(Handle<JSFunction> function) {
void CallOptimization::AnalyzePossibleApiFunction(Handle<JSFunction> function) {
if (!function->shared()->IsApiFunction()) return;
- Handle<FunctionTemplateInfo> info(function->shared()->get_api_func_data());
+ Isolate* isolate = function->GetIsolate();
+ Handle<FunctionTemplateInfo> info(function->shared()->get_api_func_data(),
+ isolate);
// Require a C++ callback.
- if (info->call_code()->IsUndefined()) return;
- api_call_info_ = handle(CallHandlerInfo::cast(info->call_code()));
+ if (info->call_code()->IsUndefined(isolate)) return;
+ api_call_info_ = handle(CallHandlerInfo::cast(info->call_code()), isolate);
- if (!info->signature()->IsUndefined()) {
+ if (!info->signature()->IsUndefined(isolate)) {
expected_receiver_type_ =
- handle(FunctionTemplateInfo::cast(info->signature()));
+ handle(FunctionTemplateInfo::cast(info->signature()), isolate);
}
is_simple_api_call_ = true;
diff --git a/deps/v8/src/ic/handler-compiler.cc b/deps/v8/src/ic/handler-compiler.cc
index 714888c8b3..b6b81def54 100644
--- a/deps/v8/src/ic/handler-compiler.cc
+++ b/deps/v8/src/ic/handler-compiler.cc
@@ -6,31 +6,29 @@
#include "src/field-type.h"
#include "src/ic/call-optimization.h"
+#include "src/ic/handler-configuration.h"
#include "src/ic/ic-inl.h"
#include "src/ic/ic.h"
#include "src/isolate-inl.h"
-#include "src/profiler/cpu-profiler.h"
namespace v8 {
namespace internal {
-
Handle<Code> PropertyHandlerCompiler::Find(Handle<Name> name,
Handle<Map> stub_holder,
Code::Kind kind,
- CacheHolderFlag cache_holder,
- Code::StubType type) {
- Code::Flags flags = Code::ComputeHandlerFlags(kind, type, cache_holder);
- Object* probe = stub_holder->FindInCodeCache(*name, flags);
- if (probe->IsCode()) return handle(Code::cast(probe));
- return Handle<Code>::null();
+ CacheHolderFlag cache_holder) {
+ Code::Flags flags = Code::ComputeHandlerFlags(kind, cache_holder);
+ Code* code = stub_holder->LookupInCodeCache(*name, flags);
+ if (code == nullptr) return Handle<Code>();
+ return handle(code);
}
Handle<Code> NamedLoadHandlerCompiler::ComputeLoadNonexistent(
Handle<Name> name, Handle<Map> receiver_map) {
Isolate* isolate = name->GetIsolate();
- if (receiver_map->prototype()->IsNull()) {
+ if (receiver_map->prototype()->IsNull(isolate)) {
// TODO(jkummerow/verwaest): If there is no prototype and the property
// is nonexistent, introduce a builtin to handle this (fast properties
// -> return undefined, dictionary properties -> do negative lookup).
@@ -53,7 +51,7 @@ Handle<Code> NamedLoadHandlerCompiler::ComputeLoadNonexistent(
Handle<JSObject> last(JSObject::cast(receiver_map->prototype()));
while (true) {
if (current_map->is_dictionary_map()) cache_name = name;
- if (current_map->prototype()->IsNull()) break;
+ if (current_map->prototype()->IsNull(isolate)) break;
if (name->IsPrivate()) {
// TODO(verwaest): Use nonexistent_private_symbol.
cache_name = name;
@@ -66,9 +64,10 @@ Handle<Code> NamedLoadHandlerCompiler::ComputeLoadNonexistent(
// Compile the stub that is either shared for all names or
// name specific if there are global objects involved.
Handle<Code> handler = PropertyHandlerCompiler::Find(
- cache_name, stub_holder_map, Code::LOAD_IC, flag, Code::FAST);
+ cache_name, stub_holder_map, Code::LOAD_IC, flag);
if (!handler.is_null()) return handler;
+ TRACE_HANDLER_STATS(isolate, LoadIC_LoadNonexistent);
NamedLoadHandlerCompiler compiler(isolate, receiver_map, last, flag);
handler = compiler.CompileLoadNonexistent(cache_name);
Map::UpdateCodeCache(stub_holder_map, cache_name, handler);
@@ -77,11 +76,10 @@ Handle<Code> NamedLoadHandlerCompiler::ComputeLoadNonexistent(
Handle<Code> PropertyHandlerCompiler::GetCode(Code::Kind kind,
- Code::StubType type,
Handle<Name> name) {
- Code::Flags flags = Code::ComputeHandlerFlags(kind, type, cache_holder());
+ Code::Flags flags = Code::ComputeHandlerFlags(kind, cache_holder());
Handle<Code> code = GetCodeWithFlags(flags, name);
- PROFILE(isolate(), CodeCreateEvent(Logger::HANDLER_TAG,
+ PROFILE(isolate(), CodeCreateEvent(CodeEventListener::HANDLER_TAG,
AbstractCode::cast(*code), *name));
#ifdef DEBUG
code->VerifyEmbeddedObjects();
@@ -194,7 +192,7 @@ Handle<Code> NamedLoadHandlerCompiler::CompileLoadField(Handle<Name> name,
__ Move(receiver(), reg);
LoadFieldStub stub(isolate(), field);
GenerateTailCall(masm(), stub.GetCode());
- return GetCode(kind(), Code::FAST, name);
+ return GetCode(kind(), name);
}
@@ -204,7 +202,7 @@ Handle<Code> NamedLoadHandlerCompiler::CompileLoadConstant(Handle<Name> name,
__ Move(receiver(), reg);
LoadConstantStub stub(isolate(), constant_index);
GenerateTailCall(masm(), stub.GetCode());
- return GetCode(kind(), Code::FAST, name);
+ return GetCode(kind(), name);
}
@@ -221,26 +219,30 @@ Handle<Code> NamedLoadHandlerCompiler::CompileLoadNonexistent(
}
GenerateLoadConstant(isolate()->factory()->undefined_value());
FrontendFooter(name, &miss);
- return GetCode(kind(), Code::FAST, name);
+ return GetCode(kind(), name);
}
-
Handle<Code> NamedLoadHandlerCompiler::CompileLoadCallback(
- Handle<Name> name, Handle<AccessorInfo> callback) {
+ Handle<Name> name, Handle<AccessorInfo> callback, Handle<Code> slow_stub) {
+ if (FLAG_runtime_call_stats) {
+ GenerateTailCall(masm(), slow_stub);
+ }
Register reg = Frontend(name);
GenerateLoadCallback(reg, callback);
- return GetCode(kind(), Code::FAST, name);
+ return GetCode(kind(), name);
}
-
Handle<Code> NamedLoadHandlerCompiler::CompileLoadCallback(
Handle<Name> name, const CallOptimization& call_optimization,
- int accessor_index) {
+ int accessor_index, Handle<Code> slow_stub) {
DCHECK(call_optimization.is_simple_api_call());
+ if (FLAG_runtime_call_stats) {
+ GenerateTailCall(masm(), slow_stub);
+ }
Register holder = Frontend(name);
GenerateApiAccessorCall(masm(), call_optimization, map(), receiver(),
scratch2(), false, no_reg, holder, accessor_index);
- return GetCode(kind(), Code::FAST, name);
+ return GetCode(kind(), name);
}
@@ -358,9 +360,21 @@ Handle<Code> NamedLoadHandlerCompiler::CompileLoadInterceptor(
} else {
GenerateLoadInterceptor(reg);
}
- return GetCode(kind(), Code::FAST, it->name());
+ return GetCode(kind(), it->name());
}
+void NamedLoadHandlerCompiler::GenerateLoadCallback(
+ Register reg, Handle<AccessorInfo> callback) {
+ DCHECK(receiver().is(ApiGetterDescriptor::ReceiverRegister()));
+ __ Move(ApiGetterDescriptor::HolderRegister(), reg);
+ // The callback is alive if this instruction is executed,
+ // so the weak cell is not cleared and points to data.
+ Handle<WeakCell> cell = isolate()->factory()->NewWeakCell(callback);
+ __ GetWeakValue(ApiGetterDescriptor::CallbackRegister(), cell);
+
+ CallApiGetterStub stub(isolate());
+ __ TailCallStub(&stub);
+}
void NamedLoadHandlerCompiler::GenerateLoadPostInterceptor(
LookupIterator* it, Register interceptor_reg) {
@@ -410,13 +424,12 @@ void NamedLoadHandlerCompiler::GenerateLoadPostInterceptor(
}
}
-
Handle<Code> NamedLoadHandlerCompiler::CompileLoadViaGetter(
Handle<Name> name, int accessor_index, int expected_arguments) {
Register holder = Frontend(name);
GenerateLoadViaGetter(masm(), map(), receiver(), holder, accessor_index,
expected_arguments, scratch2());
- return GetCode(kind(), Code::FAST, name);
+ return GetCode(kind(), name);
}
@@ -435,8 +448,7 @@ Handle<Code> NamedStoreHandlerCompiler::CompileStoreTransition(
PrototypeIterator::WhereToEnd end =
name->IsPrivate() ? PrototypeIterator::END_AT_NON_HIDDEN
: PrototypeIterator::END_AT_NULL;
- PrototypeIterator iter(isolate(), holder(),
- PrototypeIterator::START_AT_PROTOTYPE, end);
+ PrototypeIterator iter(isolate(), holder(), kStartAtPrototype, end);
while (!iter.IsAtEnd()) {
last = PrototypeIterator::GetCurrent<JSObject>(iter);
iter.Advance();
@@ -464,7 +476,7 @@ Handle<Code> NamedStoreHandlerCompiler::CompileStoreTransition(
if (details.type() == DATA_CONSTANT) {
DCHECK(descriptors->GetValue(descriptor)->IsJSFunction());
Register tmp =
- virtual_args ? VectorStoreICDescriptor::VectorRegister() : map_reg;
+ virtual_args ? StoreWithVectorDescriptor::VectorRegister() : map_reg;
GenerateRestoreMap(transition, tmp, scratch2(), &miss);
GenerateConstantCheck(tmp, descriptor, value(), scratch2(), &miss);
if (virtual_args) {
@@ -488,7 +500,7 @@ Handle<Code> NamedStoreHandlerCompiler::CompileStoreTransition(
: StoreTransitionStub::StoreMapAndValue;
Register tmp =
- virtual_args ? VectorStoreICDescriptor::VectorRegister() : map_reg;
+ virtual_args ? StoreWithVectorDescriptor::VectorRegister() : map_reg;
GenerateRestoreMap(transition, tmp, scratch2(), &miss);
if (virtual_args) {
RearrangeVectorAndSlot(tmp, map_reg);
@@ -506,7 +518,7 @@ Handle<Code> NamedStoreHandlerCompiler::CompileStoreTransition(
PopVectorAndSlot();
TailCallBuiltin(masm(), MissBuiltin(kind()));
- return GetCode(kind(), Code::FAST, name);
+ return GetCode(kind(), name);
}
bool NamedStoreHandlerCompiler::RequiresFieldTypeChecks(
@@ -534,7 +546,7 @@ Handle<Code> NamedStoreHandlerCompiler::CompileStoreField(LookupIterator* it) {
__ bind(&miss);
if (need_save_restore) PopVectorAndSlot();
TailCallBuiltin(masm(), MissBuiltin(kind()));
- return GetCode(kind(), Code::FAST, it->name());
+ return GetCode(kind(), it->name());
}
@@ -545,61 +557,78 @@ Handle<Code> NamedStoreHandlerCompiler::CompileStoreViaSetter(
GenerateStoreViaSetter(masm(), map(), receiver(), holder, accessor_index,
expected_arguments, scratch2());
- return GetCode(kind(), Code::FAST, name);
+ return GetCode(kind(), name);
}
-
Handle<Code> NamedStoreHandlerCompiler::CompileStoreCallback(
Handle<JSObject> object, Handle<Name> name,
- const CallOptimization& call_optimization, int accessor_index) {
+ const CallOptimization& call_optimization, int accessor_index,
+ Handle<Code> slow_stub) {
+ if (FLAG_runtime_call_stats) {
+ GenerateTailCall(masm(), slow_stub);
+ }
Register holder = Frontend(name);
GenerateApiAccessorCall(masm(), call_optimization, handle(object->map()),
receiver(), scratch2(), true, value(), holder,
accessor_index);
- return GetCode(kind(), Code::FAST, name);
+ return GetCode(kind(), name);
}
#undef __
-void ElementHandlerCompiler::CompileElementHandlers(
- MapHandleList* receiver_maps, CodeHandleList* handlers) {
- for (int i = 0; i < receiver_maps->length(); ++i) {
- Handle<Map> receiver_map = receiver_maps->at(i);
- Handle<Code> cached_stub;
+// static
+Handle<Object> ElementHandlerCompiler::GetKeyedLoadHandler(
+ Handle<Map> receiver_map, Isolate* isolate) {
+ if (receiver_map->has_indexed_interceptor() &&
+ !receiver_map->GetIndexedInterceptor()->getter()->IsUndefined(isolate) &&
+ !receiver_map->GetIndexedInterceptor()->non_masking()) {
+ TRACE_HANDLER_STATS(isolate, KeyedLoadIC_LoadIndexedInterceptorStub);
+ return LoadIndexedInterceptorStub(isolate).GetCode();
+ }
+ if (receiver_map->IsStringMap()) {
+ TRACE_HANDLER_STATS(isolate, KeyedLoadIC_LoadIndexedStringStub);
+ return LoadIndexedStringStub(isolate).GetCode();
+ }
+ InstanceType instance_type = receiver_map->instance_type();
+ if (instance_type < FIRST_JS_RECEIVER_TYPE) {
+ TRACE_HANDLER_STATS(isolate, KeyedLoadIC_SlowStub);
+ return isolate->builtins()->KeyedLoadIC_Slow();
+ }
- if (receiver_map->IsStringMap()) {
- cached_stub = LoadIndexedStringStub(isolate()).GetCode();
- } else if (receiver_map->instance_type() < FIRST_JS_RECEIVER_TYPE) {
- cached_stub = isolate()->builtins()->KeyedLoadIC_Slow();
- } 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() &&
- !receiver_map->GetIndexedInterceptor()->getter()->IsUndefined() &&
- !receiver_map->GetIndexedInterceptor()->non_masking()) {
- cached_stub = LoadIndexedInterceptorStub(isolate()).GetCode();
- } else if (IsSloppyArgumentsElements(elements_kind)) {
- cached_stub = KeyedLoadSloppyArgumentsStub(isolate()).GetCode();
- } else if (IsFastElementsKind(elements_kind) ||
- IsFixedTypedArrayElementsKind(elements_kind)) {
- cached_stub = LoadFastElementStub(isolate(), is_js_array, elements_kind,
- convert_hole_to_undefined).GetCode();
- } else {
- DCHECK(elements_kind == DICTIONARY_ELEMENTS);
- LoadICState state = LoadICState(kNoExtraICState);
- cached_stub = LoadDictionaryElementStub(isolate(), state).GetCode();
- }
- }
+ ElementsKind elements_kind = receiver_map->elements_kind();
+ if (IsSloppyArgumentsElements(elements_kind)) {
+ TRACE_HANDLER_STATS(isolate, KeyedLoadIC_KeyedLoadSloppyArgumentsStub);
+ return KeyedLoadSloppyArgumentsStub(isolate).GetCode();
+ }
+ if (elements_kind == DICTIONARY_ELEMENTS) {
+ TRACE_HANDLER_STATS(isolate, KeyedLoadIC_LoadDictionaryElementStub);
+ return LoadDictionaryElementStub(isolate).GetCode();
+ }
+ DCHECK(IsFastElementsKind(elements_kind) ||
+ IsFixedTypedArrayElementsKind(elements_kind));
+ bool is_js_array = instance_type == JS_ARRAY_TYPE;
+ bool convert_hole_to_undefined =
+ is_js_array && elements_kind == FAST_HOLEY_ELEMENTS &&
+ *receiver_map == isolate->get_initial_js_array_map(elements_kind);
+ if (FLAG_tf_load_ic_stub) {
+ int config = KeyedLoadElementsKind::encode(elements_kind) |
+ KeyedLoadConvertHole::encode(convert_hole_to_undefined) |
+ KeyedLoadIsJsArray::encode(is_js_array) |
+ LoadHandlerTypeBit::encode(kLoadICHandlerForElements);
+ return handle(Smi::FromInt(config), isolate);
+ } else {
+ TRACE_HANDLER_STATS(isolate, KeyedLoadIC_LoadFastElementStub);
+ return LoadFastElementStub(isolate, is_js_array, elements_kind,
+ convert_hole_to_undefined)
+ .GetCode();
+ }
+}
- handlers->Add(cached_stub);
+void ElementHandlerCompiler::CompileElementHandlers(
+ MapHandleList* receiver_maps, List<Handle<Object>>* handlers) {
+ for (int i = 0; i < receiver_maps->length(); ++i) {
+ handlers->Add(GetKeyedLoadHandler(receiver_maps->at(i), isolate()));
}
}
} // namespace internal
diff --git a/deps/v8/src/ic/handler-compiler.h b/deps/v8/src/ic/handler-compiler.h
index 76036a260f..525889b80b 100644
--- a/deps/v8/src/ic/handler-compiler.h
+++ b/deps/v8/src/ic/handler-compiler.h
@@ -19,7 +19,7 @@ enum ReturnHolder { RETURN_HOLDER, DONT_RETURN_ANYTHING };
class PropertyHandlerCompiler : public PropertyAccessCompiler {
public:
static Handle<Code> Find(Handle<Name> name, Handle<Map> map, Code::Kind kind,
- CacheHolderFlag cache_holder, Code::StubType type);
+ CacheHolderFlag cache_holder);
protected:
PropertyHandlerCompiler(Isolate* isolate, Code::Kind kind, Handle<Map> map,
@@ -98,7 +98,7 @@ class PropertyHandlerCompiler : public PropertyAccessCompiler {
Handle<Name> name, Label* miss,
PrototypeCheckType check, ReturnHolder return_what);
- Handle<Code> GetCode(Code::Kind kind, Code::StubType type, Handle<Name> name);
+ Handle<Code> GetCode(Code::Kind kind, Handle<Name> name);
void set_holder(Handle<JSObject> holder) { holder_ = holder; }
Handle<Map> map() const { return map_; }
void set_map(Handle<Map> map) { map_ = map; }
@@ -123,11 +123,12 @@ class NamedLoadHandlerCompiler : public PropertyHandlerCompiler {
Handle<Code> CompileLoadField(Handle<Name> name, FieldIndex index);
Handle<Code> CompileLoadCallback(Handle<Name> name,
- Handle<AccessorInfo> callback);
+ Handle<AccessorInfo> callback,
+ Handle<Code> slow_stub);
Handle<Code> CompileLoadCallback(Handle<Name> name,
const CallOptimization& call_optimization,
- int accessor_index);
+ int accessor_index, Handle<Code> slow_stub);
Handle<Code> CompileLoadConstant(Handle<Name> name, int constant_index);
@@ -205,8 +206,7 @@ class NamedLoadHandlerCompiler : public PropertyHandlerCompiler {
Register prototype,
Label* miss);
-
- Register scratch4() { return registers_[5]; }
+ Register scratch3() { return registers_[4]; }
};
@@ -227,7 +227,7 @@ class NamedStoreHandlerCompiler : public PropertyHandlerCompiler {
LanguageMode language_mode);
Handle<Code> CompileStoreCallback(Handle<JSObject> object, Handle<Name> name,
const CallOptimization& call_optimization,
- int accessor_index);
+ int accessor_index, Handle<Code> slow_stub);
Handle<Code> CompileStoreViaSetter(Handle<JSObject> object, Handle<Name> name,
int accessor_index,
int expected_arguments);
@@ -242,8 +242,6 @@ class NamedStoreHandlerCompiler : public PropertyHandlerCompiler {
no_reg);
}
- static void GenerateSlow(MacroAssembler* masm);
-
protected:
virtual Register FrontendHeader(Register object_reg, Handle<Name> name,
Label* miss, ReturnHolder return_what);
@@ -268,18 +266,6 @@ class NamedStoreHandlerCompiler : public PropertyHandlerCompiler {
void GenerateFieldTypeChecks(FieldType* field_type, Register value_reg,
Label* miss_label);
- static Builtins::Name SlowBuiltin(Code::Kind kind) {
- switch (kind) {
- case Code::STORE_IC:
- return Builtins::kStoreIC_Slow;
- case Code::KEYED_STORE_IC:
- return Builtins::kKeyedStoreIC_Slow;
- default:
- UNREACHABLE();
- }
- return Builtins::kStoreIC_Slow;
- }
-
static Register value();
};
@@ -293,8 +279,10 @@ class ElementHandlerCompiler : public PropertyHandlerCompiler {
virtual ~ElementHandlerCompiler() {}
+ static Handle<Object> GetKeyedLoadHandler(Handle<Map> receiver_map,
+ Isolate* isolate);
void CompileElementHandlers(MapHandleList* receiver_maps,
- CodeHandleList* handlers);
+ List<Handle<Object>>* handlers);
static void GenerateStoreSlow(MacroAssembler* masm);
};
diff --git a/deps/v8/src/ic/handler-configuration.h b/deps/v8/src/ic/handler-configuration.h
new file mode 100644
index 0000000000..bf7c4770b9
--- /dev/null
+++ b/deps/v8/src/ic/handler-configuration.h
@@ -0,0 +1,45 @@
+// Copyright 2016 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef V8_IC_HANDLER_CONFIGURATION_H_
+#define V8_IC_HANDLER_CONFIGURATION_H_
+
+#include "src/elements-kind.h"
+#include "src/globals.h"
+#include "src/utils.h"
+
+namespace v8 {
+namespace internal {
+
+enum LoadHandlerType {
+ kLoadICHandlerForElements = 0,
+ kLoadICHandlerForProperties = 1
+};
+
+class LoadHandlerTypeBit : public BitField<bool, 0, 1> {};
+
+// Encoding for configuration Smis for property loads:
+class FieldOffsetIsInobject
+ : public BitField<bool, LoadHandlerTypeBit::kNext, 1> {};
+class FieldOffsetIsDouble
+ : public BitField<bool, FieldOffsetIsInobject::kNext, 1> {};
+class FieldOffsetOffset : public BitField<int, FieldOffsetIsDouble::kNext, 27> {
+};
+// Make sure we don't overflow into the sign bit.
+STATIC_ASSERT(FieldOffsetOffset::kNext <= kSmiValueSize - 1);
+
+// Encoding for configuration Smis for elements loads:
+class KeyedLoadIsJsArray : public BitField<bool, LoadHandlerTypeBit::kNext, 1> {
+};
+class KeyedLoadConvertHole
+ : public BitField<bool, KeyedLoadIsJsArray::kNext, 1> {};
+class KeyedLoadElementsKind
+ : public BitField<ElementsKind, KeyedLoadConvertHole::kNext, 8> {};
+// Make sure we don't overflow into the sign bit.
+STATIC_ASSERT(KeyedLoadElementsKind::kNext <= kSmiValueSize - 1);
+
+} // namespace internal
+} // namespace v8
+
+#endif // V8_IC_HANDLER_CONFIGURATION_H_
diff --git a/deps/v8/src/ic/ia32/access-compiler-ia32.cc b/deps/v8/src/ic/ia32/access-compiler-ia32.cc
index 1825202366..3219f3d1cb 100644
--- a/deps/v8/src/ic/ia32/access-compiler-ia32.cc
+++ b/deps/v8/src/ic/ia32/access-compiler-ia32.cc
@@ -18,19 +18,19 @@ void PropertyAccessCompiler::GenerateTailCall(MacroAssembler* masm,
Register* PropertyAccessCompiler::load_calling_convention() {
- // receiver, name, scratch1, scratch2, scratch3, scratch4.
+ // receiver, name, scratch1, scratch2, scratch3.
Register receiver = LoadDescriptor::ReceiverRegister();
Register name = LoadDescriptor::NameRegister();
- static Register registers[] = {receiver, name, ebx, eax, edi, no_reg};
+ static Register registers[] = {receiver, name, ebx, eax, edi};
return registers;
}
Register* PropertyAccessCompiler::store_calling_convention() {
- // receiver, name, scratch1, scratch2, scratch3.
+ // receiver, name, scratch1, scratch2.
Register receiver = StoreDescriptor::ReceiverRegister();
Register name = StoreDescriptor::NameRegister();
- static Register registers[] = {receiver, name, ebx, edi, no_reg};
+ static Register registers[] = {receiver, name, ebx, edi};
return registers;
}
diff --git a/deps/v8/src/ic/ia32/handler-compiler-ia32.cc b/deps/v8/src/ic/ia32/handler-compiler-ia32.cc
index 132090dc8e..b332f117b8 100644
--- a/deps/v8/src/ic/ia32/handler-compiler-ia32.cc
+++ b/deps/v8/src/ic/ia32/handler-compiler-ia32.cc
@@ -199,7 +199,7 @@ void PropertyHandlerCompiler::GenerateApiAccessorCall(
Handle<CallHandlerInfo> api_call_info = optimization.api_call_info();
bool call_data_undefined = false;
// Put call data in place.
- if (api_call_info->data()->IsUndefined()) {
+ if (api_call_info->data()->IsUndefined(isolate)) {
call_data_undefined = true;
__ mov(data, Immediate(isolate->factory()->undefined_value()));
} else {
@@ -236,13 +236,14 @@ void PropertyHandlerCompiler::GenerateApiAccessorCall(
void PropertyHandlerCompiler::GenerateCheckPropertyCell(
MacroAssembler* masm, Handle<JSGlobalObject> global, Handle<Name> name,
Register scratch, Label* miss) {
- Handle<PropertyCell> cell = JSGlobalObject::EnsurePropertyCell(global, name);
- DCHECK(cell->value()->IsTheHole());
- Factory* factory = masm->isolate()->factory();
- Handle<WeakCell> weak_cell = factory->NewWeakCell(cell);
+ Handle<PropertyCell> cell = JSGlobalObject::EnsureEmptyPropertyCell(
+ global, name, PropertyCellType::kInvalidated);
+ Isolate* isolate = masm->isolate();
+ DCHECK(cell->value()->IsTheHole(isolate));
+ Handle<WeakCell> weak_cell = isolate->factory()->NewWeakCell(cell);
__ LoadWeakValue(scratch, weak_cell, miss);
__ cmp(FieldOperand(scratch, PropertyCell::kValueOffset),
- Immediate(factory->the_hole_value()));
+ Immediate(isolate->factory()->the_hole_value()));
__ j(not_equal, miss);
}
@@ -320,8 +321,8 @@ static void StoreIC_PushArgs(MacroAssembler* masm) {
Register receiver = StoreDescriptor::ReceiverRegister();
Register name = StoreDescriptor::NameRegister();
Register value = StoreDescriptor::ValueRegister();
- Register slot = VectorStoreICDescriptor::SlotRegister();
- Register vector = VectorStoreICDescriptor::VectorRegister();
+ Register slot = StoreWithVectorDescriptor::SlotRegister();
+ Register vector = StoreWithVectorDescriptor::VectorRegister();
__ xchg(receiver, Operand(esp, 0));
__ push(name);
@@ -332,15 +333,6 @@ static void StoreIC_PushArgs(MacroAssembler* masm) {
}
-void NamedStoreHandlerCompiler::GenerateSlow(MacroAssembler* masm) {
- // Return address is on the stack.
- StoreIC_PushArgs(masm);
-
- // Do tail-call to runtime routine.
- __ TailCallRuntime(Runtime::kStoreIC_Slow);
-}
-
-
void ElementHandlerCompiler::GenerateStoreSlow(MacroAssembler* masm) {
// Return address is on the stack.
StoreIC_PushArgs(masm);
@@ -439,28 +431,25 @@ 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);
- }
+ 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);
- }
+ // 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.
@@ -496,8 +485,10 @@ Register PropertyHandlerCompiler::CheckPrototypes(
!current_map->is_access_check_needed());
prototype = handle(JSObject::cast(current_map->prototype()));
- if (current_map->is_dictionary_map() &&
- !current_map->IsJSGlobalObjectMap()) {
+ if (current_map->IsJSGlobalObjectMap()) {
+ GenerateCheckPropertyCell(masm(), Handle<JSGlobalObject>::cast(current),
+ name, scratch2, miss);
+ } else if (current_map->is_dictionary_map()) {
DCHECK(!current_map->IsJSGlobalProxyMap()); // Proxy maps are fast.
if (!name->IsUniqueName()) {
DCHECK(name->IsString());
@@ -507,34 +498,12 @@ Register PropertyHandlerCompiler::CheckPrototypes(
current->property_dictionary()->FindEntry(name) ==
NameDictionary::kNotFound);
- if (FLAG_eliminate_prototype_chain_checks && depth > 1) {
+ if (depth > 1) {
// TODO(jkummerow): Cache and re-use weak cell.
__ LoadWeakValue(reg, isolate()->factory()->NewWeakCell(current), miss);
}
GenerateDictionaryNegativeLookup(masm(), miss, reg, name, scratch1,
scratch2);
-
- if (!FLAG_eliminate_prototype_chain_checks) {
- __ mov(scratch1, FieldOperand(reg, HeapObject::kMapOffset));
- __ mov(holder_reg, FieldOperand(scratch1, Map::kPrototypeOffset));
- }
- } else {
- Register map_reg = scratch1;
- 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 (!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);
- }
- 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.
@@ -548,17 +517,8 @@ Register PropertyHandlerCompiler::CheckPrototypes(
// Log the check depth.
LOG(isolate(), IntEvent("check-maps-depth", depth + 1));
- 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);
- __ 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) {
+ if (return_holder && depth != 0) {
__ LoadWeakValue(reg, isolate()->factory()->NewWeakCell(current), miss);
}
@@ -594,58 +554,6 @@ void NamedStoreHandlerCompiler::FrontendFooter(Handle<Name> name, Label* miss) {
}
-void NamedLoadHandlerCompiler::GenerateLoadCallback(
- Register reg, Handle<AccessorInfo> callback) {
- DCHECK(!AreAliased(scratch2(), scratch3(), receiver()));
- DCHECK(!AreAliased(scratch2(), scratch3(), reg));
-
- // Insert additional parameters into the stack frame above return address.
- __ pop(scratch3()); // Get return address to place it below.
-
- // Build v8::PropertyCallbackInfo::args_ array on the stack and push property
- // name below the exit frame to make GC aware of them.
- STATIC_ASSERT(PropertyCallbackArguments::kShouldThrowOnErrorIndex == 0);
- STATIC_ASSERT(PropertyCallbackArguments::kHolderIndex == 1);
- STATIC_ASSERT(PropertyCallbackArguments::kIsolateIndex == 2);
- STATIC_ASSERT(PropertyCallbackArguments::kReturnValueDefaultValueIndex == 3);
- STATIC_ASSERT(PropertyCallbackArguments::kReturnValueOffset == 4);
- STATIC_ASSERT(PropertyCallbackArguments::kDataIndex == 5);
- STATIC_ASSERT(PropertyCallbackArguments::kThisIndex == 6);
- STATIC_ASSERT(PropertyCallbackArguments::kArgsLength == 7);
-
- __ push(receiver()); // receiver
- // Push data from AccessorInfo.
- Handle<Object> data(callback->data(), isolate());
- if (data->IsUndefined() || data->IsSmi()) {
- __ push(Immediate(data));
- } else {
- Handle<WeakCell> cell =
- isolate()->factory()->NewWeakCell(Handle<HeapObject>::cast(data));
- // The callback is alive if this instruction is executed,
- // so the weak cell is not cleared and points to data.
- __ GetWeakValue(scratch2(), cell);
- __ push(scratch2());
- }
- __ push(Immediate(isolate()->factory()->undefined_value())); // ReturnValue
- // ReturnValue default value
- __ push(Immediate(isolate()->factory()->undefined_value()));
- __ push(Immediate(reinterpret_cast<int>(isolate())));
- __ push(reg); // holder
- __ push(Immediate(Smi::FromInt(0))); // should_throw_on_error -> false
-
- __ push(name()); // name
- __ push(scratch3()); // Restore return address.
-
- // Abi for CallApiGetter
- Register getter_address = ApiGetterDescriptor::function_address();
- Address function_address = v8::ToCData<Address>(callback->getter());
- __ mov(getter_address, Immediate(function_address));
-
- CallApiGetterStub stub(isolate());
- __ TailCallStub(&stub);
-}
-
-
void NamedLoadHandlerCompiler::GenerateLoadConstant(Handle<Object> value) {
// Return the constant value.
__ LoadObject(eax, value);
@@ -656,7 +564,7 @@ void NamedLoadHandlerCompiler::GenerateLoadConstant(Handle<Object> value) {
void NamedLoadHandlerCompiler::GenerateLoadInterceptorWithFollowup(
LookupIterator* it, Register holder_reg) {
DCHECK(holder()->HasNamedInterceptor());
- DCHECK(!holder()->GetNamedInterceptor()->getter()->IsUndefined());
+ DCHECK(!holder()->GetNamedInterceptor()->getter()->IsUndefined(isolate()));
// Compile the interceptor call, followed by inline code to load the
// property from further up the prototype chain if the call fails.
@@ -723,7 +631,7 @@ void NamedLoadHandlerCompiler::GenerateLoadInterceptorWithFollowup(
void NamedLoadHandlerCompiler::GenerateLoadInterceptor(Register holder_reg) {
DCHECK(holder()->HasNamedInterceptor());
- DCHECK(!holder()->GetNamedInterceptor()->getter()->IsUndefined());
+ DCHECK(!holder()->GetNamedInterceptor()->getter()->IsUndefined(isolate()));
// Call the runtime system to load the interceptor.
__ pop(scratch2()); // save old return address
PushInterceptorArguments(masm(), receiver(), holder_reg, this->name(),
@@ -744,7 +652,7 @@ Handle<Code> NamedStoreHandlerCompiler::CompileStoreCallback(
__ push(holder_reg);
// If the callback cannot leak, then push the callback directly,
// otherwise wrap it in a weak cell.
- if (callback->data()->IsUndefined() || callback->data()->IsSmi()) {
+ if (callback->data()->IsUndefined(isolate()) || callback->data()->IsSmi()) {
__ Push(callback);
} else {
Handle<WeakCell> cell = isolate()->factory()->NewWeakCell(callback);
@@ -759,7 +667,7 @@ Handle<Code> NamedStoreHandlerCompiler::CompileStoreCallback(
__ TailCallRuntime(Runtime::kStoreCallbackProperty);
// Return the generated code.
- return GetCode(kind(), Code::FAST, name);
+ return GetCode(kind(), name);
}
@@ -801,7 +709,7 @@ Handle<Code> NamedLoadHandlerCompiler::CompileLoadGlobal(
FrontendFooter(name, &miss);
// Return the generated code.
- return GetCode(kind(), Code::NORMAL, name);
+ return GetCode(kind(), name);
}
diff --git a/deps/v8/src/ic/ia32/ic-ia32.cc b/deps/v8/src/ic/ia32/ic-ia32.cc
index e66716f6cb..0550d92e91 100644
--- a/deps/v8/src/ic/ia32/ic-ia32.cc
+++ b/deps/v8/src/ic/ia32/ic-ia32.cc
@@ -336,10 +336,8 @@ void KeyedLoadIC::GenerateMegamorphic(MacroAssembler* masm) {
__ push(Immediate(Smi::FromInt(slot)));
__ push(Immediate(dummy_vector));
- Code::Flags flags = Code::RemoveTypeAndHolderFromFlags(
- Code::ComputeHandlerFlags(Code::LOAD_IC));
- masm->isolate()->stub_cache()->GenerateProbe(masm, Code::KEYED_LOAD_IC, flags,
- receiver, key, ebx, edi);
+ masm->isolate()->load_stub_cache()->GenerateProbe(masm, receiver, key, ebx,
+ edi);
__ pop(LoadWithVectorDescriptor::VectorRegister());
__ pop(LoadDescriptor::SlotRegister());
@@ -519,10 +517,10 @@ void KeyedStoreIC::GenerateMegamorphic(MacroAssembler* masm,
__ JumpIfSmi(receiver, &slow);
// Get the map from the receiver.
__ mov(edi, FieldOperand(receiver, HeapObject::kMapOffset));
- // Check that the receiver does not require access checks and is not observed.
- // The generic stub does not perform map checks or handle observed objects.
+ // Check that the receiver does not require access checks.
+ // The generic stub does not perform map checks.
__ test_b(FieldOperand(edi, Map::kBitFieldOffset),
- Immediate(1 << Map::kIsAccessCheckNeeded | 1 << Map::kIsObserved));
+ Immediate(1 << Map::kIsAccessCheckNeeded));
__ j(not_zero, &slow);
// Check that the key is a smi.
__ JumpIfNotSmi(key, &maybe_name_key);
@@ -563,13 +561,11 @@ void KeyedStoreIC::GenerateMegamorphic(MacroAssembler* masm,
__ push(Immediate(Smi::FromInt(slot)));
__ push(Immediate(dummy_vector));
- Code::Flags flags = Code::RemoveTypeAndHolderFromFlags(
- Code::ComputeHandlerFlags(Code::STORE_IC));
- masm->isolate()->stub_cache()->GenerateProbe(masm, Code::STORE_IC, flags,
- receiver, key, edi, no_reg);
+ masm->isolate()->store_stub_cache()->GenerateProbe(masm, receiver, key, edi,
+ no_reg);
- __ pop(VectorStoreICDescriptor::VectorRegister());
- __ pop(VectorStoreICDescriptor::SlotRegister());
+ __ pop(StoreWithVectorDescriptor::VectorRegister());
+ __ pop(StoreWithVectorDescriptor::SlotRegister());
// Cache miss.
__ jmp(&miss);
@@ -708,21 +704,12 @@ void KeyedLoadIC::GenerateRuntimeGetProperty(MacroAssembler* masm) {
__ TailCallRuntime(Runtime::kKeyedGetProperty);
}
-
-void StoreIC::GenerateMegamorphic(MacroAssembler* masm) {
- // This shouldn't be called.
- // TODO(mvstanton): remove this method.
- __ int3();
- return;
-}
-
-
static void StoreIC_PushArgs(MacroAssembler* masm) {
Register receiver = StoreDescriptor::ReceiverRegister();
Register name = StoreDescriptor::NameRegister();
Register value = StoreDescriptor::ValueRegister();
- Register slot = VectorStoreICDescriptor::SlotRegister();
- Register vector = VectorStoreICDescriptor::VectorRegister();
+ Register slot = StoreWithVectorDescriptor::SlotRegister();
+ Register vector = StoreWithVectorDescriptor::VectorRegister();
__ xchg(receiver, Operand(esp, 0));
__ push(name);
@@ -747,8 +734,8 @@ void StoreIC::GenerateNormal(MacroAssembler* masm) {
Register receiver = StoreDescriptor::ReceiverRegister();
Register name = StoreDescriptor::NameRegister();
Register value = StoreDescriptor::ValueRegister();
- Register vector = VectorStoreICDescriptor::VectorRegister();
- Register slot = VectorStoreICDescriptor::SlotRegister();
+ Register vector = StoreWithVectorDescriptor::VectorRegister();
+ Register slot = StoreWithVectorDescriptor::SlotRegister();
// A lot of registers are needed for storing to slow case
// objects. Push and restore receiver but rely on
@@ -836,8 +823,9 @@ void PatchInlinedSmiCode(Isolate* isolate, Address address,
// condition code uses at the patched jump.
uint8_t delta = *reinterpret_cast<uint8_t*>(delta_address);
if (FLAG_trace_ic) {
- PrintF("[ patching ic at %p, test=%p, delta=%d\n", address,
- test_instruction_address, delta);
+ PrintF("[ patching ic at %p, test=%p, delta=%d\n",
+ static_cast<void*>(address),
+ static_cast<void*>(test_instruction_address), delta);
}
// Patch with a short conditional jump. Enabling means switching from a short
diff --git a/deps/v8/src/ic/ia32/stub-cache-ia32.cc b/deps/v8/src/ic/ia32/stub-cache-ia32.cc
index fcfae4bc0c..939e7fc0fd 100644
--- a/deps/v8/src/ic/ia32/stub-cache-ia32.cc
+++ b/deps/v8/src/ic/ia32/stub-cache-ia32.cc
@@ -14,19 +14,19 @@ namespace internal {
#define __ ACCESS_MASM(masm)
-
-static void ProbeTable(Isolate* isolate, MacroAssembler* masm,
- Code::Kind ic_kind, Code::Flags flags,
+static void ProbeTable(StubCache* stub_cache, MacroAssembler* masm,
StubCache::Table table, Register name, Register receiver,
- // Number of the cache entry pointer-size scaled.
+ // The offset is scaled by 4, based on
+ // kCacheIndexShift, which is two bits
Register offset, Register extra) {
- ExternalReference key_offset(isolate->stub_cache()->key_reference(table));
- ExternalReference value_offset(isolate->stub_cache()->value_reference(table));
- ExternalReference map_offset(isolate->stub_cache()->map_reference(table));
+ ExternalReference key_offset(stub_cache->key_reference(table));
+ ExternalReference value_offset(stub_cache->value_reference(table));
+ ExternalReference map_offset(stub_cache->map_reference(table));
ExternalReference virtual_register =
ExternalReference::virtual_handler_register(masm->isolate());
Label miss;
+ Code::Kind ic_kind = stub_cache->ic_kind();
bool is_vector_store =
IC::ICUseVector(ic_kind) &&
(ic_kind == Code::STORE_IC || ic_kind == Code::KEYED_STORE_IC);
@@ -47,12 +47,6 @@ static void ProbeTable(Isolate* isolate, MacroAssembler* masm,
__ cmp(offset, FieldOperand(receiver, HeapObject::kMapOffset));
__ j(not_equal, &miss);
- // Check that the flags match what we're looking for.
- __ mov(offset, FieldOperand(extra, Code::kFlagsOffset));
- __ and_(offset, ~Code::kFlagsNotUsedInLookup);
- __ cmp(offset, flags);
- __ j(not_equal, &miss);
-
#ifdef DEBUG
if (FLAG_test_secondary_stub_cache && table == StubCache::kPrimary) {
__ jmp(&miss);
@@ -65,8 +59,8 @@ static void ProbeTable(Isolate* isolate, MacroAssembler* masm,
// probe, and need to be dropped before calling the handler.
if (is_vector_store) {
// The overlap here is rather embarrassing. One does what one must.
- Register vector = VectorStoreICDescriptor::VectorRegister();
- DCHECK(extra.is(VectorStoreICDescriptor::SlotRegister()));
+ Register vector = StoreWithVectorDescriptor::VectorRegister();
+ DCHECK(extra.is(StoreWithVectorDescriptor::SlotRegister()));
__ add(extra, Immediate(Code::kHeaderSize - kHeapObjectTag));
__ pop(vector);
__ mov(Operand::StaticVariable(virtual_register), extra);
@@ -102,12 +96,6 @@ static void ProbeTable(Isolate* isolate, MacroAssembler* masm,
// Get the code entry from the cache.
__ mov(offset, Operand::StaticArray(offset, times_1, value_offset));
- // Check that the flags match what we're looking for.
- __ mov(offset, FieldOperand(offset, Code::kFlagsOffset));
- __ and_(offset, ~Code::kFlagsNotUsedInLookup);
- __ cmp(offset, flags);
- __ j(not_equal, &miss);
-
#ifdef DEBUG
if (FLAG_test_secondary_stub_cache && table == StubCache::kPrimary) {
__ jmp(&miss);
@@ -124,8 +112,8 @@ static void ProbeTable(Isolate* isolate, MacroAssembler* masm,
if (is_vector_store) {
// The vector and slot were pushed onto the stack before starting the
// probe, and need to be dropped before calling the handler.
- Register vector = VectorStoreICDescriptor::VectorRegister();
- DCHECK(offset.is(VectorStoreICDescriptor::SlotRegister()));
+ Register vector = StoreWithVectorDescriptor::VectorRegister();
+ DCHECK(offset.is(StoreWithVectorDescriptor::SlotRegister()));
__ add(offset, Immediate(Code::kHeaderSize - kHeapObjectTag));
__ mov(Operand::StaticVariable(virtual_register), offset);
__ pop(vector);
@@ -142,9 +130,7 @@ static void ProbeTable(Isolate* isolate, MacroAssembler* masm,
}
}
-
-void StubCache::GenerateProbe(MacroAssembler* masm, Code::Kind ic_kind,
- Code::Flags flags, Register receiver,
+void StubCache::GenerateProbe(MacroAssembler* masm, Register receiver,
Register name, Register scratch, Register extra,
Register extra2, Register extra3) {
Label miss;
@@ -153,9 +139,6 @@ void StubCache::GenerateProbe(MacroAssembler* masm, Code::Kind ic_kind,
// being 12.
DCHECK(sizeof(Entry) == 12);
- // Assert the flags do not name a specific type.
- DCHECK(Code::ExtractTypeFromFlags(flags) == 0);
-
// Assert that there are no register conflicts.
DCHECK(!scratch.is(receiver));
DCHECK(!scratch.is(name));
@@ -180,7 +163,7 @@ void StubCache::GenerateProbe(MacroAssembler* masm, Code::Kind ic_kind,
// Get the map of the receiver and compute the hash.
__ mov(offset, FieldOperand(name, Name::kHashFieldOffset));
__ add(offset, FieldOperand(receiver, HeapObject::kMapOffset));
- __ xor_(offset, flags);
+ __ xor_(offset, kPrimaryMagic);
// We mask out the last two bits because they are not part of the hash and
// they are always 01 for maps. Also in the two 'and' instructions below.
__ and_(offset, (kPrimaryTableSize - 1) << kCacheIndexShift);
@@ -189,21 +172,19 @@ void StubCache::GenerateProbe(MacroAssembler* masm, Code::Kind ic_kind,
DCHECK(kCacheIndexShift == kPointerSizeLog2);
// Probe the primary table.
- ProbeTable(isolate(), masm, ic_kind, flags, kPrimary, name, receiver, offset,
- extra);
+ ProbeTable(this, masm, kPrimary, name, receiver, offset, extra);
// Primary miss: Compute hash for secondary probe.
__ mov(offset, FieldOperand(name, Name::kHashFieldOffset));
__ add(offset, FieldOperand(receiver, HeapObject::kMapOffset));
- __ xor_(offset, flags);
+ __ xor_(offset, kPrimaryMagic);
__ and_(offset, (kPrimaryTableSize - 1) << kCacheIndexShift);
__ sub(offset, name);
- __ add(offset, Immediate(flags));
+ __ add(offset, Immediate(kSecondaryMagic));
__ and_(offset, (kSecondaryTableSize - 1) << kCacheIndexShift);
// Probe the secondary table.
- ProbeTable(isolate(), masm, ic_kind, flags, kSecondary, name, receiver,
- offset, extra);
+ ProbeTable(this, masm, kSecondary, name, receiver, offset, extra);
// Cache miss: Fall-through and let caller handle the miss by
// entering the runtime system.
diff --git a/deps/v8/src/ic/ic-compiler.cc b/deps/v8/src/ic/ic-compiler.cc
index d1e9416d41..2f0633e0d8 100644
--- a/deps/v8/src/ic/ic-compiler.cc
+++ b/deps/v8/src/ic/ic-compiler.cc
@@ -6,211 +6,39 @@
#include "src/ic/handler-compiler.h"
#include "src/ic/ic-inl.h"
-#include "src/profiler/cpu-profiler.h"
-
namespace v8 {
namespace internal {
-
-Handle<Code> PropertyICCompiler::Find(Handle<Name> name,
- Handle<Map> stub_holder, Code::Kind kind,
- ExtraICState extra_state,
- CacheHolderFlag cache_holder) {
- Code::Flags flags =
- Code::ComputeMonomorphicFlags(kind, extra_state, cache_holder);
- Object* probe = stub_holder->FindInCodeCache(*name, flags);
- if (probe->IsCode()) return handle(Code::cast(probe));
- return Handle<Code>::null();
-}
-
-
-bool PropertyICCompiler::IncludesNumberMap(MapHandleList* maps) {
- for (int i = 0; i < maps->length(); ++i) {
- if (maps->at(i)->instance_type() == HEAP_NUMBER_TYPE) return true;
- }
- return false;
-}
-
-
-Handle<Code> PropertyICCompiler::ComputeKeyedLoadMonomorphicHandler(
- Handle<Map> receiver_map, ExtraICState extra_ic_state) {
- 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();
- } else if (receiver_map->IsStringMap()) {
- stub = LoadIndexedStringStub(isolate).GetCode();
- } else if (receiver_map->has_sloppy_arguments_elements()) {
- stub = KeyedLoadSloppyArgumentsStub(isolate).GetCode();
- } else if (receiver_map->has_fast_elements() ||
- receiver_map->has_fixed_typed_array_elements()) {
- stub = LoadFastElementStub(isolate, is_js_array, elements_kind,
- convert_hole_to_undefined).GetCode();
- } else {
- DCHECK(receiver_map->has_dictionary_elements());
- stub = LoadDictionaryElementStub(isolate, LoadICState(extra_ic_state))
- .GetCode();
- }
- return stub;
-}
-
-
Handle<Code> PropertyICCompiler::ComputeKeyedStoreMonomorphicHandler(
- Handle<Map> receiver_map, LanguageMode language_mode,
- KeyedAccessStoreMode store_mode) {
+ Handle<Map> receiver_map, KeyedAccessStoreMode store_mode) {
Isolate* isolate = receiver_map->GetIsolate();
- ExtraICState extra_state =
- KeyedStoreIC::ComputeExtraICState(language_mode, store_mode);
DCHECK(store_mode == STANDARD_STORE ||
store_mode == STORE_AND_GROW_NO_TRANSITION ||
store_mode == STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS ||
store_mode == STORE_NO_TRANSITION_HANDLE_COW);
- PropertyICCompiler compiler(isolate, Code::KEYED_STORE_IC, extra_state);
+ PropertyICCompiler compiler(isolate);
Handle<Code> code =
compiler.CompileKeyedStoreMonomorphicHandler(receiver_map, store_mode);
return code;
}
-
-Code* PropertyICCompiler::FindPreMonomorphic(Isolate* isolate, Code::Kind kind,
- ExtraICState state) {
- Code::Flags flags = Code::ComputeFlags(kind, PREMONOMORPHIC, state);
- UnseededNumberDictionary* dictionary =
- isolate->heap()->non_monomorphic_cache();
- int entry = dictionary->FindEntry(isolate, flags);
- DCHECK(entry != -1);
- Object* code = dictionary->ValueAt(entry);
- // This might be called during the marking phase of the collector
- // hence the unchecked cast.
- return reinterpret_cast<Code*>(code);
-}
-
-
-static void FillCache(Isolate* isolate, Handle<Code> code) {
- Handle<UnseededNumberDictionary> dictionary = UnseededNumberDictionary::Set(
- isolate->factory()->non_monomorphic_cache(), code->flags(), code);
- isolate->heap()->SetRootNonMonomorphicCache(*dictionary);
-}
-
-
-Handle<Code> PropertyICCompiler::ComputeStore(Isolate* isolate,
- InlineCacheState ic_state,
- ExtraICState extra_state) {
- Code::Flags flags = Code::ComputeFlags(Code::STORE_IC, ic_state, extra_state);
- Handle<UnseededNumberDictionary> cache =
- isolate->factory()->non_monomorphic_cache();
- int entry = cache->FindEntry(isolate, flags);
- if (entry != -1) return Handle<Code>(Code::cast(cache->ValueAt(entry)));
-
- PropertyICCompiler compiler(isolate, Code::STORE_IC);
- Handle<Code> code;
- if (ic_state == UNINITIALIZED) {
- code = compiler.CompileStoreInitialize(flags);
- } else if (ic_state == PREMONOMORPHIC) {
- code = compiler.CompileStorePreMonomorphic(flags);
- } else if (ic_state == GENERIC) {
- code = compiler.CompileStoreGeneric(flags);
- } else if (ic_state == MEGAMORPHIC) {
- code = compiler.CompileStoreMegamorphic(flags);
- } else {
- UNREACHABLE();
- }
-
- FillCache(isolate, code);
- return code;
-}
-
-
void PropertyICCompiler::ComputeKeyedStorePolymorphicHandlers(
MapHandleList* receiver_maps, MapHandleList* transitioned_maps,
- CodeHandleList* handlers, KeyedAccessStoreMode store_mode,
- LanguageMode language_mode) {
+ CodeHandleList* handlers, KeyedAccessStoreMode store_mode) {
Isolate* isolate = receiver_maps->at(0)->GetIsolate();
DCHECK(store_mode == STANDARD_STORE ||
store_mode == STORE_AND_GROW_NO_TRANSITION ||
store_mode == STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS ||
store_mode == STORE_NO_TRANSITION_HANDLE_COW);
- ExtraICState extra_state =
- KeyedStoreIC::ComputeExtraICState(language_mode, store_mode);
- PropertyICCompiler compiler(isolate, Code::KEYED_STORE_IC, extra_state);
+ PropertyICCompiler compiler(isolate);
compiler.CompileKeyedStorePolymorphicHandlers(
receiver_maps, transitioned_maps, handlers, store_mode);
}
-Handle<Code> PropertyICCompiler::CompileLoadInitialize(Code::Flags flags) {
- LoadIC::GenerateInitialize(masm());
- Handle<Code> code = GetCodeWithFlags(flags, "CompileLoadInitialize");
- PROFILE(isolate(), CodeCreateEvent(Logger::LOAD_INITIALIZE_TAG,
- AbstractCode::cast(*code), 0));
- return code;
-}
-
-
-Handle<Code> PropertyICCompiler::CompileStoreInitialize(Code::Flags flags) {
- StoreIC::GenerateInitialize(masm());
- Handle<Code> code = GetCodeWithFlags(flags, "CompileStoreInitialize");
- PROFILE(isolate(), CodeCreateEvent(Logger::STORE_INITIALIZE_TAG,
- AbstractCode::cast(*code), 0));
- return code;
-}
-
-
-Handle<Code> PropertyICCompiler::CompileStorePreMonomorphic(Code::Flags flags) {
- StoreIC::GeneratePreMonomorphic(masm());
- Handle<Code> code = GetCodeWithFlags(flags, "CompileStorePreMonomorphic");
- PROFILE(isolate(), CodeCreateEvent(Logger::STORE_PREMONOMORPHIC_TAG,
- AbstractCode::cast(*code), 0));
- return code;
-}
-
-
-Handle<Code> PropertyICCompiler::CompileStoreGeneric(Code::Flags flags) {
- ExtraICState extra_state = Code::ExtractExtraICStateFromFlags(flags);
- LanguageMode language_mode = StoreICState::GetLanguageMode(extra_state);
- GenerateRuntimeSetProperty(masm(), language_mode);
- Handle<Code> code = GetCodeWithFlags(flags, "CompileStoreGeneric");
- PROFILE(isolate(), CodeCreateEvent(Logger::STORE_GENERIC_TAG,
- AbstractCode::cast(*code), 0));
- return code;
-}
-
-
-Handle<Code> PropertyICCompiler::CompileStoreMegamorphic(Code::Flags flags) {
- StoreIC::GenerateMegamorphic(masm());
- Handle<Code> code = GetCodeWithFlags(flags, "CompileStoreMegamorphic");
- PROFILE(isolate(), CodeCreateEvent(Logger::STORE_MEGAMORPHIC_TAG,
- AbstractCode::cast(*code), 0));
- return code;
-}
-
-
-Handle<Code> PropertyICCompiler::GetCode(Code::Kind kind, Code::StubType type,
- Handle<Name> name,
- InlineCacheState state) {
- Code::Flags flags =
- Code::ComputeFlags(kind, state, extra_ic_state_, type, cache_holder());
- Handle<Code> code = GetCodeWithFlags(flags, name);
- PROFILE(isolate(),
- CodeCreateEvent(log_kind(code), AbstractCode::cast(*code), *name));
-#ifdef DEBUG
- code->VerifyEmbeddedObjects();
-#endif
- return code;
-}
-
-
void PropertyICCompiler::CompileKeyedStorePolymorphicHandlers(
MapHandleList* receiver_maps, MapHandleList* transitioned_maps,
CodeHandleList* handlers, KeyedAccessStoreMode store_mode) {
@@ -268,34 +96,21 @@ Handle<Code> PropertyICCompiler::CompileKeyedStoreMonomorphicHandler(
bool is_jsarray = receiver_map->instance_type() == JS_ARRAY_TYPE;
Handle<Code> stub;
if (receiver_map->has_sloppy_arguments_elements()) {
+ TRACE_HANDLER_STATS(isolate(), KeyedStoreIC_KeyedStoreSloppyArgumentsStub);
stub = KeyedStoreSloppyArgumentsStub(isolate(), store_mode).GetCode();
} else if (receiver_map->has_fast_elements() ||
receiver_map->has_fixed_typed_array_elements()) {
+ TRACE_HANDLER_STATS(isolate(), KeyedStoreIC_StoreFastElementStub);
stub = StoreFastElementStub(isolate(), is_jsarray, elements_kind,
store_mode).GetCode();
} else {
+ TRACE_HANDLER_STATS(isolate(), KeyedStoreIC_StoreElementStub);
stub = StoreElementStub(isolate(), elements_kind, store_mode).GetCode();
}
return stub;
}
-Handle<Code> PropertyICCompiler::CompileKeyedStoreMonomorphic(
- Handle<Map> receiver_map, KeyedAccessStoreMode store_mode) {
- Handle<Code> stub =
- CompileKeyedStoreMonomorphicHandler(receiver_map, store_mode);
-
- Handle<WeakCell> cell = Map::WeakCellForMap(receiver_map);
-
- __ DispatchWeakMap(receiver(), scratch1(), scratch2(), cell, stub,
- DO_SMI_CHECK);
-
- TailCallBuiltin(masm(), Builtins::kKeyedStoreIC_Miss);
-
- return GetCode(kind(), Code::NORMAL, factory()->empty_string());
-}
-
-
#undef __
} // namespace internal
} // namespace v8
diff --git a/deps/v8/src/ic/ic-compiler.h b/deps/v8/src/ic/ic-compiler.h
index 3a5aecccbb..fa3ba15af2 100644
--- a/deps/v8/src/ic/ic-compiler.h
+++ b/deps/v8/src/ic/ic-compiler.h
@@ -13,25 +13,12 @@ namespace internal {
class PropertyICCompiler : public PropertyAccessCompiler {
public:
- // Finds the Code object stored in the Heap::non_monomorphic_cache().
- static Code* FindPreMonomorphic(Isolate* isolate, Code::Kind kind,
- ExtraICState extra_ic_state);
-
- // Named
- static Handle<Code> ComputeStore(Isolate* isolate, InlineCacheState ic_state,
- ExtraICState extra_state);
-
// Keyed
- static Handle<Code> ComputeKeyedLoadMonomorphicHandler(
- Handle<Map> receiver_map, ExtraICState extra_ic_state);
-
static Handle<Code> ComputeKeyedStoreMonomorphicHandler(
- Handle<Map> receiver_map, LanguageMode language_mode,
- KeyedAccessStoreMode store_mode);
+ Handle<Map> receiver_map, KeyedAccessStoreMode store_mode);
static void ComputeKeyedStorePolymorphicHandlers(
MapHandleList* receiver_maps, MapHandleList* transitioned_maps,
- CodeHandleList* handlers, KeyedAccessStoreMode store_mode,
- LanguageMode language_mode);
+ CodeHandleList* handlers, KeyedAccessStoreMode store_mode);
// Helpers
// TODO(verwaest): Move all uses of these helpers to the PropertyICCompiler
@@ -41,57 +28,16 @@ class PropertyICCompiler : public PropertyAccessCompiler {
private:
- PropertyICCompiler(Isolate* isolate, Code::Kind kind,
- ExtraICState extra_ic_state = kNoExtraICState,
- CacheHolderFlag cache_holder = kCacheOnReceiver)
- : PropertyAccessCompiler(isolate, kind, cache_holder),
- extra_ic_state_(extra_ic_state) {}
-
- static Handle<Code> Find(Handle<Name> name, Handle<Map> stub_holder_map,
- Code::Kind kind,
- ExtraICState extra_ic_state = kNoExtraICState,
- CacheHolderFlag cache_holder = kCacheOnReceiver);
-
- Handle<Code> CompileLoadInitialize(Code::Flags flags);
- Handle<Code> CompileStoreInitialize(Code::Flags flags);
- Handle<Code> CompileStorePreMonomorphic(Code::Flags flags);
- Handle<Code> CompileStoreGeneric(Code::Flags flags);
- Handle<Code> CompileStoreMegamorphic(Code::Flags flags);
+ explicit PropertyICCompiler(Isolate* isolate)
+ : PropertyAccessCompiler(isolate, Code::KEYED_STORE_IC,
+ kCacheOnReceiver) {}
Handle<Code> CompileKeyedStoreMonomorphicHandler(
Handle<Map> receiver_map, KeyedAccessStoreMode store_mode);
- Handle<Code> CompileKeyedStoreMonomorphic(Handle<Map> receiver_map,
- KeyedAccessStoreMode store_mode);
void CompileKeyedStorePolymorphicHandlers(MapHandleList* receiver_maps,
MapHandleList* transitioned_maps,
CodeHandleList* handlers,
KeyedAccessStoreMode store_mode);
-
- bool IncludesNumberMap(MapHandleList* maps);
-
- Handle<Code> GetCode(Code::Kind kind, Code::StubType type, Handle<Name> name,
- InlineCacheState state = MONOMORPHIC);
-
- Logger::LogEventsAndTags log_kind(Handle<Code> code) {
- if (kind() == Code::LOAD_IC) {
- return code->ic_state() == MONOMORPHIC ? Logger::LOAD_IC_TAG
- : Logger::LOAD_POLYMORPHIC_IC_TAG;
- } else if (kind() == Code::KEYED_LOAD_IC) {
- return code->ic_state() == MONOMORPHIC
- ? Logger::KEYED_LOAD_IC_TAG
- : Logger::KEYED_LOAD_POLYMORPHIC_IC_TAG;
- } else if (kind() == Code::STORE_IC) {
- return code->ic_state() == MONOMORPHIC ? Logger::STORE_IC_TAG
- : Logger::STORE_POLYMORPHIC_IC_TAG;
- } else {
- DCHECK_EQ(Code::KEYED_STORE_IC, kind());
- return code->ic_state() == MONOMORPHIC
- ? Logger::KEYED_STORE_IC_TAG
- : Logger::KEYED_STORE_POLYMORPHIC_IC_TAG;
- }
- }
-
- const ExtraICState extra_ic_state_;
};
diff --git a/deps/v8/src/ic/ic-inl.h b/deps/v8/src/ic/ic-inl.h
index 998bd8cf12..f77c40a396 100644
--- a/deps/v8/src/ic/ic-inl.h
+++ b/deps/v8/src/ic/ic-inl.h
@@ -87,42 +87,12 @@ void IC::SetTargetAtAddress(Address address, Code* target,
void IC::set_target(Code* code) {
SetTargetAtAddress(address(), code, constant_pool());
- target_set_ = true;
}
-
-void LoadIC::set_target(Code* code) {
- // The contextual mode must be preserved across IC patching.
- DCHECK(LoadICState::GetTypeofMode(code->extra_ic_state()) ==
- LoadICState::GetTypeofMode(target()->extra_ic_state()));
-
- IC::set_target(code);
-}
-
-
-void StoreIC::set_target(Code* code) {
- // Language mode must be preserved across IC patching.
- DCHECK(StoreICState::GetLanguageMode(code->extra_ic_state()) ==
- StoreICState::GetLanguageMode(target()->extra_ic_state()));
- IC::set_target(code);
-}
-
-
-void KeyedStoreIC::set_target(Code* code) {
- // Language mode must be preserved across IC patching.
- DCHECK(StoreICState::GetLanguageMode(code->extra_ic_state()) ==
- language_mode());
- IC::set_target(code);
-}
-
-
-Code* IC::raw_target() const {
+Code* IC::target() const {
return GetTargetAtAddress(address(), constant_pool());
}
-void IC::UpdateTarget() { target_ = handle(raw_target(), isolate_); }
-
-
Handle<Map> IC::GetHandlerCacheHolder(Handle<Map> receiver_map,
bool receiver_is_holder, Isolate* isolate,
CacheHolderFlag* flag) {
diff --git a/deps/v8/src/ic/ic-state.cc b/deps/v8/src/ic/ic-state.cc
index bf1e45fb50..d157c926dd 100644
--- a/deps/v8/src/ic/ic-state.cc
+++ b/deps/v8/src/ic/ic-state.cc
@@ -257,10 +257,10 @@ void BinaryOpICState::Update(Handle<Object> left, Handle<Object> right,
if (old_extra_ic_state == GetExtraICState()) {
// Tagged operations can lead to non-truncating HChanges
- if (left->IsUndefined() || left->IsBoolean()) {
+ if (left->IsUndefined(isolate_) || left->IsBoolean()) {
left_kind_ = GENERIC;
} else {
- DCHECK(right->IsUndefined() || right->IsBoolean());
+ DCHECK(right->IsUndefined(isolate_) || right->IsBoolean());
right_kind_ = GENERIC;
}
}
@@ -274,7 +274,7 @@ BinaryOpICState::Kind BinaryOpICState::UpdateKind(Handle<Object> object,
if (object->IsBoolean() && is_truncating) {
// Booleans will be automatically truncated by HChange.
new_kind = INT32;
- } else if (object->IsUndefined()) {
+ } else if (object->IsUndefined(isolate_)) {
// Undefined will be automatically truncated by HChange.
new_kind = is_truncating ? INT32 : NUMBER;
} else if (object->IsSmi()) {
@@ -446,8 +446,9 @@ CompareICState::State CompareICState::NewInputState(State old_state,
// static
CompareICState::State CompareICState::TargetState(
- State old_state, State old_left, State old_right, Token::Value op,
- bool has_inlined_smi_code, Handle<Object> x, Handle<Object> y) {
+ Isolate* isolate, State old_state, State old_left, State old_right,
+ Token::Value op, bool has_inlined_smi_code, Handle<Object> x,
+ Handle<Object> y) {
switch (old_state) {
case UNINITIALIZED:
if (x->IsBoolean() && y->IsBoolean()) return BOOLEAN;
@@ -456,8 +457,8 @@ CompareICState::State CompareICState::TargetState(
if (Token::IsOrderedRelationalCompareOp(op)) {
// Ordered comparisons treat undefined as NaN, so the
// NUMBER stub will do the right thing.
- if ((x->IsNumber() && y->IsUndefined()) ||
- (y->IsNumber() && x->IsUndefined())) {
+ if ((x->IsNumber() && y->IsUndefined(isolate)) ||
+ (y->IsNumber() && x->IsUndefined(isolate))) {
return NUMBER;
}
}
diff --git a/deps/v8/src/ic/ic-state.h b/deps/v8/src/ic/ic-state.h
index e1d33f8678..6888a7ab5c 100644
--- a/deps/v8/src/ic/ic-state.h
+++ b/deps/v8/src/ic/ic-state.h
@@ -128,11 +128,15 @@ class BinaryOpICState final BASE_EMBEDDED {
Isolate* isolate() const { return isolate_; }
+ enum Kind { NONE, SMI, INT32, NUMBER, STRING, GENERIC };
+ Kind kind() const {
+ return KindGeneralize(KindGeneralize(left_kind_, right_kind_),
+ result_kind_);
+ }
+
private:
friend std::ostream& operator<<(std::ostream& os, const BinaryOpICState& s);
- enum Kind { NONE, SMI, INT32, NUMBER, STRING, GENERIC };
-
Kind UpdateKind(Handle<Object> object, Kind kind) const;
static const char* KindToString(Kind kind);
@@ -140,6 +144,18 @@ class BinaryOpICState final BASE_EMBEDDED {
static bool KindMaybeSmi(Kind kind) {
return (kind >= SMI && kind <= NUMBER) || kind == GENERIC;
}
+ static bool KindLessGeneralThan(Kind kind1, Kind kind2) {
+ if (kind1 == NONE) return true;
+ if (kind1 == kind2) return true;
+ if (kind2 == GENERIC) return true;
+ if (kind2 == STRING) return false;
+ return kind1 <= kind2;
+ }
+ static Kind KindGeneralize(Kind kind1, Kind kind2) {
+ if (KindLessGeneralThan(kind1, kind2)) return kind2;
+ if (KindLessGeneralThan(kind2, kind1)) return kind1;
+ return GENERIC;
+ }
// We truncate the last bit of the token.
STATIC_ASSERT(LAST_TOKEN - FIRST_TOKEN < (1 << 4));
@@ -193,13 +209,13 @@ class CompareICState {
static const char* GetStateName(CompareICState::State state);
- static State TargetState(State old_state, State old_left, State old_right,
- Token::Value op, bool has_inlined_smi_code,
- Handle<Object> x, Handle<Object> y);
+ static State TargetState(Isolate* isolate, State old_state, State old_left,
+ State old_right, Token::Value op,
+ bool has_inlined_smi_code, Handle<Object> x,
+ Handle<Object> y);
};
-
-class LoadICState final BASE_EMBEDDED {
+class LoadGlobalICState final BASE_EMBEDDED {
private:
class TypeofModeBits : public BitField<TypeofMode, 0, 1> {};
STATIC_ASSERT(static_cast<int>(INSIDE_TYPEOF) == 0);
@@ -208,9 +224,10 @@ class LoadICState final BASE_EMBEDDED {
public:
static const uint32_t kNextBitFieldOffset = TypeofModeBits::kNext;
- explicit LoadICState(ExtraICState extra_ic_state) : state_(extra_ic_state) {}
+ explicit LoadGlobalICState(ExtraICState extra_ic_state)
+ : state_(extra_ic_state) {}
- explicit LoadICState(TypeofMode typeof_mode)
+ explicit LoadGlobalICState(TypeofMode typeof_mode)
: state_(TypeofModeBits::encode(typeof_mode)) {}
ExtraICState GetExtraICState() const { return state_; }
@@ -218,7 +235,7 @@ class LoadICState final BASE_EMBEDDED {
TypeofMode typeof_mode() const { return TypeofModeBits::decode(state_); }
static TypeofMode GetTypeofMode(ExtraICState state) {
- return LoadICState(state).typeof_mode();
+ return LoadGlobalICState(state).typeof_mode();
}
};
@@ -240,8 +257,8 @@ class StoreICState final BASE_EMBEDDED {
return StoreICState(state).language_mode();
}
- class LanguageModeState : public BitField<LanguageMode, 1, 2> {};
- STATIC_ASSERT(i::LANGUAGE_END == 3);
+ class LanguageModeState : public BitField<LanguageMode, 1, 1> {};
+ STATIC_ASSERT(i::LANGUAGE_END == 2);
// For convenience, a statically declared encoding of strict mode extra
// IC state.
diff --git a/deps/v8/src/ic/ic.cc b/deps/v8/src/ic/ic.cc
index 49bbc6ed8d..b72791aa9e 100644
--- a/deps/v8/src/ic/ic.cc
+++ b/deps/v8/src/ic/ic.cc
@@ -5,11 +5,10 @@
#include "src/ic/ic.h"
#include "src/accessors.h"
+#include "src/api-arguments-inl.h"
#include "src/api.h"
-#include "src/api-arguments.h"
#include "src/arguments.h"
#include "src/base/bits.h"
-#include "src/code-factory.h"
#include "src/codegen.h"
#include "src/conversions.h"
#include "src/execution.h"
@@ -17,14 +16,15 @@
#include "src/frames-inl.h"
#include "src/ic/call-optimization.h"
#include "src/ic/handler-compiler.h"
-#include "src/ic/ic-inl.h"
#include "src/ic/ic-compiler.h"
+#include "src/ic/ic-inl.h"
#include "src/ic/stub-cache.h"
#include "src/isolate-inl.h"
#include "src/macro-assembler.h"
#include "src/prototype.h"
-#include "src/runtime/runtime.h"
+#include "src/runtime-profiler.h"
#include "src/runtime/runtime-utils.h"
+#include "src/runtime/runtime.h"
#include "src/tracing/trace-event.h"
namespace v8 {
@@ -38,7 +38,7 @@ char IC::TransitionMarkFromState(IC::State state) {
return '.';
case MONOMORPHIC:
return '1';
- case PROTOTYPE_FAILURE:
+ case RECOMPUTE_HANDLER:
return '^';
case POLYMORPHIC:
return 'P';
@@ -46,12 +46,6 @@ char IC::TransitionMarkFromState(IC::State state) {
return 'N';
case GENERIC:
return 'G';
-
- // We never see the debugger states here, because the state is
- // computed from the original code - not the patched code. Let
- // these cases fall through to the unreachable code below.
- case DEBUG_STUB:
- break;
}
UNREACHABLE();
return 0;
@@ -95,8 +89,8 @@ const char* GetTransitionMarkModifier(KeyedAccessStoreMode mode) {
void IC::TraceIC(const char* type, Handle<Object> name) {
if (FLAG_trace_ic) {
if (AddressIsDeoptimizedCode()) return;
- State new_state =
- UseVector() ? nexus()->StateFromFeedback() : raw_target()->ic_state();
+ DCHECK(UseVector());
+ State new_state = nexus()->StateFromFeedback();
TraceIC(type, name, state(), new_state);
}
}
@@ -105,8 +99,7 @@ void IC::TraceIC(const char* type, Handle<Object> name) {
void IC::TraceIC(const char* type, Handle<Object> name, State old_state,
State new_state) {
if (FLAG_trace_ic) {
- Code* new_target = raw_target();
- PrintF("[%s%s in ", new_target->is_keyed_stub() ? "Keyed" : "", type);
+ PrintF("[%s%s in ", is_keyed() ? "Keyed" : "", type);
// TODO(jkummerow): Add support for "apply". The logic is roughly:
// marker = [fp_ + kMarkerOffset];
@@ -123,19 +116,18 @@ void IC::TraceIC(const char* type, Handle<Object> name, State old_state,
}
const char* modifier = "";
- if (new_target->kind() == Code::KEYED_STORE_IC) {
+ if (kind() == Code::KEYED_STORE_IC) {
KeyedAccessStoreMode mode =
casted_nexus<KeyedStoreICNexus>()->GetKeyedAccessStoreMode();
modifier = GetTransitionMarkModifier(mode);
}
- PrintF(" (%c->%c%s) ", TransitionMarkFromState(old_state),
- TransitionMarkFromState(new_state), modifier);
-#ifdef OBJECT_PRINT
- OFStream os(stdout);
- name->Print(os);
-#else
+ void* map = nullptr;
+ if (!receiver_map().is_null()) {
+ map = reinterpret_cast<void*>(*receiver_map());
+ }
+ PrintF(" (%c->%c%s) map=%p ", TransitionMarkFromState(old_state),
+ TransitionMarkFromState(new_state), modifier, map);
name->ShortPrint(stdout);
-#endif
PrintF("]\n");
}
}
@@ -146,7 +138,6 @@ void IC::TraceIC(const char* type, Handle<Object> name, State old_state,
IC::IC(FrameDepth depth, Isolate* isolate, FeedbackNexus* nexus)
: isolate_(isolate),
- target_set_(false),
vector_set_(false),
target_maps_set_(false),
nexus_(nexus) {
@@ -185,13 +176,34 @@ IC::IC(FrameDepth depth, Isolate* isolate, FeedbackNexus* nexus)
constant_pool_address_ = constant_pool;
}
pc_address_ = StackFrame::ResolveReturnAddressLocation(pc_address);
- target_ = handle(raw_target(), isolate);
- kind_ = target_->kind();
- state_ = UseVector() ? nexus->StateFromFeedback() : target_->ic_state();
+ Code* target = this->target();
+ kind_ = target->kind();
+ state_ = UseVector() ? nexus->StateFromFeedback() : StateFromCode(target);
old_state_ = state_;
- extra_ic_state_ = target_->extra_ic_state();
+ extra_ic_state_ = target->extra_ic_state();
}
+InlineCacheState IC::StateFromCode(Code* code) {
+ Isolate* isolate = code->GetIsolate();
+ switch (code->kind()) {
+ case Code::BINARY_OP_IC: {
+ BinaryOpICState state(isolate, code->extra_ic_state());
+ return state.GetICState();
+ }
+ case Code::COMPARE_IC: {
+ CompareICStub stub(isolate, code->extra_ic_state());
+ return stub.GetICState();
+ }
+ case Code::TO_BOOLEAN_IC: {
+ ToBooleanICStub stub(isolate, code->extra_ic_state());
+ return stub.GetICState();
+ }
+ default:
+ if (code->is_debug_stub()) return UNINITIALIZED;
+ UNREACHABLE();
+ return UNINITIALIZED;
+ }
+}
SharedFunctionInfo* IC::GetSharedFunctionInfo() const {
// Compute the JavaScript frame for the frame pointer of this IC
@@ -226,7 +238,6 @@ bool IC::AddressIsOptimizedCode() const {
return host->kind() == Code::OPTIMIZED_FUNCTION;
}
-
static void LookupForRead(LookupIterator* it) {
for (; it->IsFound(); it->Next()) {
switch (it->state()) {
@@ -238,7 +249,8 @@ static void LookupForRead(LookupIterator* it) {
case LookupIterator::INTERCEPTOR: {
// If there is a getter, return; otherwise loop to perform the lookup.
Handle<JSObject> holder = it->GetHolder<JSObject>();
- if (!holder->GetNamedInterceptor()->getter()->IsUndefined()) {
+ if (!holder->GetNamedInterceptor()->getter()->IsUndefined(
+ it->isolate())) {
return;
}
break;
@@ -258,15 +270,15 @@ static void LookupForRead(LookupIterator* it) {
}
}
+bool IC::ShouldRecomputeHandler(Handle<Object> receiver, Handle<String> name) {
+ if (!RecomputeHandlerForName(name)) return false;
-bool IC::TryRemoveInvalidPrototypeDependentStub(Handle<Object> receiver,
- Handle<String> name) {
- if (!IsNameCompatibleWithPrototypeFailure(name)) return false;
- if (UseVector()) {
- maybe_handler_ = nexus()->FindHandlerForMap(receiver_map());
- } else {
- maybe_handler_ = target()->FindHandlerForMap(*receiver_map());
- }
+ DCHECK(UseVector());
+ maybe_handler_ = nexus()->FindHandlerForMap(receiver_map());
+
+ // This is a contextual access, always just update the handler and stay
+ // monomorphic.
+ if (kind() == Code::LOAD_GLOBAL_IC) return true;
// The current map wasn't handled yet. There's no reason to stay monomorphic,
// *unless* we're moving from a deprecated map to its replacement, or
@@ -283,38 +295,15 @@ bool IC::TryRemoveInvalidPrototypeDependentStub(Handle<Object> receiver,
receiver_map()->elements_kind());
}
- CacheHolderFlag flag;
- Handle<Map> ic_holder_map(GetICCacheHolder(receiver_map(), isolate(), &flag));
-
- DCHECK(flag != kCacheOnReceiver || receiver->IsJSObject());
- DCHECK(flag != kCacheOnPrototype || !receiver->IsJSReceiver());
- DCHECK(flag != kCacheOnPrototypeReceiverIsDictionary);
-
- if (state() == MONOMORPHIC) {
- int index = ic_holder_map->IndexInCodeCache(*name, *target());
- if (index >= 0) {
- ic_holder_map->RemoveFromCodeCache(*name, *target(), index);
- }
- }
-
- if (receiver->IsJSGlobalObject()) {
- Handle<JSGlobalObject> global = Handle<JSGlobalObject>::cast(receiver);
- LookupIterator it(global, name, LookupIterator::OWN_SKIP_INTERCEPTOR);
- if (it.state() == LookupIterator::ACCESS_CHECK) return false;
- if (!it.IsFound()) return false;
- return it.property_details().cell_type() == PropertyCellType::kConstant;
- }
-
return true;
}
-
-bool IC::IsNameCompatibleWithPrototypeFailure(Handle<Object> name) {
- if (target()->is_keyed_stub()) {
+bool IC::RecomputeHandlerForName(Handle<Object> name) {
+ if (is_keyed()) {
// Determine whether the failure is due to a name failure.
if (!name->IsName()) return false;
- Name* stub_name =
- UseVector() ? nexus()->FindFirstName() : target()->FindFirstName();
+ DCHECK(UseVector());
+ Name* stub_name = nexus()->FindFirstName();
if (*name != stub_name) return false;
}
@@ -326,15 +315,13 @@ void IC::UpdateState(Handle<Object> receiver, Handle<Object> name) {
update_receiver_map(receiver);
if (!name->IsString()) return;
if (state() != MONOMORPHIC && state() != POLYMORPHIC) return;
- if (receiver->IsUndefined() || receiver->IsNull()) return;
+ if (receiver->IsUndefined(isolate()) || receiver->IsNull(isolate())) return;
// Remove the target from the code cache if it became invalid
// because of changes in the prototype chain to avoid hitting it
// again.
- if (TryRemoveInvalidPrototypeDependentStub(receiver,
- Handle<String>::cast(name))) {
- MarkPrototypeFailure(name);
- return;
+ if (ShouldRecomputeHandler(receiver, Handle<String>::cast(name))) {
+ MarkRecomputeHandler(name);
}
}
@@ -382,43 +369,11 @@ static void ComputeTypeInfoCountDelta(IC::State old_state, IC::State new_state,
*polymorphic_delta = 1;
}
break;
- case PROTOTYPE_FAILURE:
- case DEBUG_STUB:
+ case RECOMPUTE_HANDLER:
UNREACHABLE();
}
}
-
-void IC::OnTypeFeedbackChanged(Isolate* isolate, Address address,
- State old_state, State new_state,
- bool target_remains_ic_stub) {
- Code* host =
- isolate->inner_pointer_to_code_cache()->GetCacheEntry(address)->code;
- if (host->kind() != Code::FUNCTION) return;
-
- if (FLAG_type_info_threshold > 0 && target_remains_ic_stub &&
- // Not all Code objects have TypeFeedbackInfo.
- host->type_feedback_info()->IsTypeFeedbackInfo()) {
- int polymorphic_delta = 0; // "Polymorphic" here includes monomorphic.
- int generic_delta = 0; // "Generic" here includes megamorphic.
- ComputeTypeInfoCountDelta(old_state, new_state, &polymorphic_delta,
- &generic_delta);
- TypeFeedbackInfo* info = TypeFeedbackInfo::cast(host->type_feedback_info());
- info->change_ic_with_type_info_count(polymorphic_delta);
- info->change_ic_generic_count(generic_delta);
- }
- if (host->type_feedback_info()->IsTypeFeedbackInfo()) {
- TypeFeedbackInfo* info = TypeFeedbackInfo::cast(host->type_feedback_info());
- info->change_own_type_change_checksum();
- }
- host->set_profiler_ticks(0);
- isolate->runtime_profiler()->NotifyICChanged();
- // TODO(2029): When an optimized function is patched, it would
- // be nice to propagate the corresponding type information to its
- // unoptimized version for the benefit of later inlining.
-}
-
-
// static
void IC::OnTypeFeedbackChanged(Isolate* isolate, Code* host) {
if (host->kind() != Code::FUNCTION) return;
@@ -432,26 +387,42 @@ void IC::OnTypeFeedbackChanged(Isolate* isolate, Code* host) {
// unoptimized version for the benefit of later inlining.
}
-
void IC::PostPatching(Address address, Code* target, Code* old_target) {
// Type vector based ICs update these statistics at a different time because
// they don't always patch on state change.
if (ICUseVector(target->kind())) return;
- Isolate* isolate = target->GetHeap()->isolate();
- State old_state = UNINITIALIZED;
- State new_state = UNINITIALIZED;
- bool target_remains_ic_stub = false;
- if (old_target->is_inline_cache_stub() && target->is_inline_cache_stub()) {
- old_state = old_target->ic_state();
- new_state = target->ic_state();
- target_remains_ic_stub = true;
- }
+ DCHECK(old_target->is_inline_cache_stub());
+ DCHECK(target->is_inline_cache_stub());
+ State old_state = StateFromCode(old_target);
+ State new_state = StateFromCode(target);
- OnTypeFeedbackChanged(isolate, address, old_state, new_state,
- target_remains_ic_stub);
-}
+ Isolate* isolate = target->GetIsolate();
+ Code* host =
+ isolate->inner_pointer_to_code_cache()->GetCacheEntry(address)->code;
+ if (host->kind() != Code::FUNCTION) return;
+ // Not all Code objects have TypeFeedbackInfo.
+ if (host->type_feedback_info()->IsTypeFeedbackInfo()) {
+ if (FLAG_type_info_threshold > 0) {
+ int polymorphic_delta = 0; // "Polymorphic" here includes monomorphic.
+ int generic_delta = 0; // "Generic" here includes megamorphic.
+ ComputeTypeInfoCountDelta(old_state, new_state, &polymorphic_delta,
+ &generic_delta);
+ TypeFeedbackInfo* info =
+ TypeFeedbackInfo::cast(host->type_feedback_info());
+ info->change_ic_with_type_info_count(polymorphic_delta);
+ info->change_ic_generic_count(generic_delta);
+ }
+ TypeFeedbackInfo* info = TypeFeedbackInfo::cast(host->type_feedback_info());
+ info->change_own_type_change_checksum();
+ }
+ host->set_profiler_ticks(0);
+ isolate->runtime_profiler()->NotifyICChanged();
+ // TODO(2029): When an optimized function is patched, it would
+ // be nice to propagate the corresponding type information to its
+ // unoptimized version for the benefit of later inlining.
+}
void IC::Clear(Isolate* isolate, Address address, Address constant_pool) {
Code* target = GetTargetAtAddress(address, constant_pool);
@@ -459,22 +430,8 @@ void IC::Clear(Isolate* isolate, Address address, Address constant_pool) {
// Don't clear debug break inline cache as it will remove the break point.
if (target->is_debug_stub()) return;
- switch (target->kind()) {
- case Code::LOAD_IC:
- case Code::KEYED_LOAD_IC:
- case Code::STORE_IC:
- case Code::KEYED_STORE_IC:
- return;
- case Code::COMPARE_IC:
- return CompareIC::Clear(isolate, address, target, constant_pool);
- case Code::CALL_IC: // CallICs are vector-based and cleared differently.
- case Code::BINARY_OP_IC:
- case Code::TO_BOOLEAN_IC:
- // Clearing these is tricky and does not
- // make any performance difference.
- return;
- default:
- UNREACHABLE();
+ if (target->kind() == Code::COMPARE_IC) {
+ CompareIC::Clear(isolate, address, target, constant_pool);
}
}
@@ -508,16 +465,13 @@ void LoadIC::Clear(Isolate* isolate, Code* host, LoadICNexus* nexus) {
OnTypeFeedbackChanged(isolate, host);
}
-
-void StoreIC::Clear(Isolate* isolate, Address address, Code* target,
- Address constant_pool) {
- if (IsCleared(target)) return;
- Code* code = PropertyICCompiler::FindPreMonomorphic(isolate, Code::STORE_IC,
- target->extra_ic_state());
- SetTargetAtAddress(address, code, constant_pool);
+void LoadGlobalIC::Clear(Isolate* isolate, Code* host,
+ LoadGlobalICNexus* nexus) {
+ if (IsCleared(nexus)) return;
+ nexus->ConfigureUninitialized();
+ OnTypeFeedbackChanged(isolate, host);
}
-
void StoreIC::Clear(Isolate* isolate, Code* host, StoreICNexus* nexus) {
if (IsCleared(nexus)) return;
nexus->ConfigurePremonomorphic();
@@ -525,15 +479,6 @@ void StoreIC::Clear(Isolate* isolate, Code* host, StoreICNexus* nexus) {
}
-void KeyedStoreIC::Clear(Isolate* isolate, Address address, Code* target,
- Address constant_pool) {
- if (IsCleared(target)) return;
- Handle<Code> code = pre_monomorphic_stub(
- isolate, StoreICState::GetLanguageMode(target->extra_ic_state()));
- SetTargetAtAddress(address, *code, constant_pool);
-}
-
-
void KeyedStoreIC::Clear(Isolate* isolate, Code* host,
KeyedStoreICNexus* nexus) {
if (IsCleared(nexus)) return;
@@ -557,8 +502,9 @@ void CompareIC::Clear(Isolate* isolate, Address address, Code* target,
// static
Handle<Code> KeyedLoadIC::ChooseMegamorphicStub(Isolate* isolate,
ExtraICState extra_state) {
+ // TODO(ishell): remove extra_ic_state
if (FLAG_compiled_keyed_generic_loads) {
- return KeyedLoadGenericStub(isolate, LoadICState(extra_state)).GetCode();
+ return KeyedLoadGenericStub(isolate).GetCode();
} else {
return isolate->builtins()->KeyedLoadIC_Megamorphic();
}
@@ -596,32 +542,33 @@ void IC::ConfigureVectorState(IC::State new_state, Handle<Object> key) {
OnTypeFeedbackChanged(isolate(), get_host());
}
-
void IC::ConfigureVectorState(Handle<Name> name, Handle<Map> map,
- Handle<Code> handler) {
+ Handle<Object> handler) {
DCHECK(UseVector());
if (kind() == Code::LOAD_IC) {
LoadICNexus* nexus = casted_nexus<LoadICNexus>();
nexus->ConfigureMonomorphic(map, handler);
+ } else if (kind() == Code::LOAD_GLOBAL_IC) {
+ LoadGlobalICNexus* nexus = casted_nexus<LoadGlobalICNexus>();
+ nexus->ConfigureHandlerMode(Handle<Code>::cast(handler));
} else if (kind() == Code::KEYED_LOAD_IC) {
KeyedLoadICNexus* nexus = casted_nexus<KeyedLoadICNexus>();
nexus->ConfigureMonomorphic(name, map, handler);
} else if (kind() == Code::STORE_IC) {
StoreICNexus* nexus = casted_nexus<StoreICNexus>();
- nexus->ConfigureMonomorphic(map, handler);
+ nexus->ConfigureMonomorphic(map, Handle<Code>::cast(handler));
} else {
DCHECK(kind() == Code::KEYED_STORE_IC);
KeyedStoreICNexus* nexus = casted_nexus<KeyedStoreICNexus>();
- nexus->ConfigureMonomorphic(name, map, handler);
+ nexus->ConfigureMonomorphic(name, map, Handle<Code>::cast(handler));
}
vector_set_ = true;
OnTypeFeedbackChanged(isolate(), get_host());
}
-
void IC::ConfigureVectorState(Handle<Name> name, MapHandleList* maps,
- CodeHandleList* handlers) {
+ List<Handle<Object>>* handlers) {
DCHECK(UseVector());
if (kind() == Code::LOAD_IC) {
LoadICNexus* nexus = casted_nexus<LoadICNexus>();
@@ -659,34 +606,45 @@ void IC::ConfigureVectorState(MapHandleList* maps,
MaybeHandle<Object> LoadIC::Load(Handle<Object> object, Handle<Name> name) {
// If the object is undefined or null it's illegal to try to get any
// of its properties; throw a TypeError in that case.
- if (object->IsUndefined() || object->IsNull()) {
+ if (object->IsUndefined(isolate()) || object->IsNull(isolate())) {
return TypeError(MessageTemplate::kNonObjectPropertyLoad, object, name);
}
- // Check if the name is trivially convertible to an index and get
- // the element or char if so.
- uint32_t index;
- if (kind() == Code::KEYED_LOAD_IC && name->AsArrayIndex(&index)) {
- // Rewrite to the generic keyed load stub.
- if (FLAG_use_ic) {
- DCHECK(UseVector());
- ConfigureVectorState(MEGAMORPHIC, name);
- TRACE_IC("LoadIC", name);
- TRACE_GENERIC_IC(isolate(), "LoadIC", "name as array index");
- }
+ bool use_ic = MigrateDeprecated(object) ? false : FLAG_use_ic;
+
+ if (state() != UNINITIALIZED) {
+ JSObject::MakePrototypesFast(object, kStartAtReceiver, isolate());
+ update_receiver_map(object);
+ }
+ // Named lookup in the object.
+ LookupIterator it(object, name);
+ LookupForRead(&it);
+
+ if (it.IsFound() || !ShouldThrowReferenceError()) {
+ // Update inline cache and stub cache.
+ if (use_ic) UpdateCaches(&it);
+
+ // Get the property.
Handle<Object> result;
- ASSIGN_RETURN_ON_EXCEPTION(isolate(), result,
- Object::GetElement(isolate(), object, index),
+
+ ASSIGN_RETURN_ON_EXCEPTION(isolate(), result, Object::GetProperty(&it),
Object);
- return result;
+ if (it.IsFound()) {
+ return result;
+ } else if (!ShouldThrowReferenceError()) {
+ LOG(isolate(), SuspectReadEvent(*name, *object));
+ return result;
+ }
}
+ return ReferenceError(name);
+}
- bool use_ic = MigrateDeprecated(object) ? false : FLAG_use_ic;
+MaybeHandle<Object> LoadGlobalIC::Load(Handle<Name> name) {
+ Handle<JSGlobalObject> global = isolate()->global_object();
- if (object->IsJSGlobalObject() && name->IsString()) {
+ if (name->IsString()) {
// Look up in script context table.
Handle<String> str_name = Handle<String>::cast(name);
- Handle<JSGlobalObject> global = Handle<JSGlobalObject>::cast(object);
Handle<ScriptContextTable> script_contexts(
global->native_context()->script_context_table());
@@ -696,44 +654,24 @@ MaybeHandle<Object> LoadIC::Load(Handle<Object> object, Handle<Name> name) {
FixedArray::get(*ScriptContextTable::GetContext(
script_contexts, lookup_result.context_index),
lookup_result.slot_index, isolate());
- if (*result == *isolate()->factory()->the_hole_value()) {
+ if (result->IsTheHole(isolate())) {
// Do not install stubs and stay pre-monomorphic for
// uninitialized accesses.
return ReferenceError(name);
}
- if (use_ic && LoadScriptContextFieldStub::Accepted(&lookup_result)) {
+ if (FLAG_use_ic && LoadScriptContextFieldStub::Accepted(&lookup_result)) {
+ TRACE_HANDLER_STATS(isolate(), LoadIC_LoadScriptContextFieldStub);
LoadScriptContextFieldStub stub(isolate(), &lookup_result);
PatchCache(name, stub.GetCode());
+ TRACE_IC("LoadGlobalIC", name);
}
return result;
}
}
-
- // Named lookup in the object.
- LookupIterator it(object, name);
- LookupForRead(&it);
-
- if (it.IsFound() || !ShouldThrowReferenceError(object)) {
- // Update inline cache and stub cache.
- if (use_ic) UpdateCaches(&it);
-
- // Get the property.
- Handle<Object> result;
-
- ASSIGN_RETURN_ON_EXCEPTION(isolate(), result, Object::GetProperty(&it),
- Object);
- if (it.IsFound()) {
- return result;
- } else if (!ShouldThrowReferenceError(object)) {
- LOG(isolate(), SuspectReadEvent(*name, *object));
- return result;
- }
- }
- return ReferenceError(name);
+ return LoadIC::Load(global, name);
}
-
static bool AddOneReceiverMapIfMissing(MapHandleList* receiver_maps,
Handle<Map> new_receiver_map) {
DCHECK(!new_receiver_map.is_null());
@@ -747,13 +685,15 @@ static bool AddOneReceiverMapIfMissing(MapHandleList* receiver_maps,
return true;
}
-
-bool IC::UpdatePolymorphicIC(Handle<Name> name, Handle<Code> code) {
- if (!code->is_handler()) return false;
- if (target()->is_keyed_stub() && state() != PROTOTYPE_FAILURE) return false;
+bool IC::UpdatePolymorphicIC(Handle<Name> name, Handle<Object> code) {
+ DCHECK(code->IsSmi() || code->IsCode());
+ if (!code->IsSmi() && !Code::cast(*code)->is_handler()) {
+ return false;
+ }
+ if (is_keyed() && state() != RECOMPUTE_HANDLER) return false;
Handle<Map> map = receiver_map();
MapHandleList maps;
- CodeHandleList handlers;
+ List<Handle<Object>> handlers;
TargetMaps(&maps);
int number_of_maps = maps.length();
@@ -783,14 +723,11 @@ bool IC::UpdatePolymorphicIC(Handle<Name> name, Handle<Code> code) {
if (number_of_maps == 0 && state() != MONOMORPHIC && state() != POLYMORPHIC) {
return false;
}
- if (UseVector()) {
- if (!nexus()->FindHandlers(&handlers, maps.length())) return false;
- } else {
- if (!target()->FindHandlers(&handlers, maps.length())) return false;
- }
+ DCHECK(UseVector());
+ if (!nexus()->FindHandlers(&handlers, maps.length())) return false;
number_of_valid_maps++;
- if (number_of_valid_maps > 1 && target()->is_keyed_stub()) return false;
+ if (number_of_valid_maps > 1 && is_keyed()) return false;
Handle<Code> ic;
if (number_of_valid_maps == 1) {
ConfigureVectorState(name, receiver_map(), code);
@@ -808,22 +745,21 @@ bool IC::UpdatePolymorphicIC(Handle<Name> name, Handle<Code> code) {
ConfigureVectorState(name, &maps, &handlers);
}
- if (!UseVector()) set_target(*ic);
return true;
}
-
-void IC::UpdateMonomorphicIC(Handle<Code> handler, Handle<Name> name) {
- DCHECK(handler->is_handler());
+void IC::UpdateMonomorphicIC(Handle<Object> handler, Handle<Name> name) {
+ DCHECK(handler->IsSmi() ||
+ (handler->IsCode() && Handle<Code>::cast(handler)->is_handler()));
ConfigureVectorState(name, receiver_map(), handler);
}
void IC::CopyICToMegamorphicCache(Handle<Name> name) {
MapHandleList maps;
- CodeHandleList handlers;
+ List<Handle<Object>> handlers;
TargetMaps(&maps);
- if (!target()->FindHandlers(&handlers, maps.length())) return;
+ if (!nexus()->FindHandlers(&handlers, maps.length())) return;
for (int i = 0; i < maps.length(); i++) {
UpdateMegamorphicCache(*maps.at(i), *name, *handlers.at(i));
}
@@ -845,38 +781,36 @@ bool IC::IsTransitionOfMonomorphicTarget(Map* source_map, Map* target_map) {
return transitioned_map == target_map;
}
-
-void IC::PatchCache(Handle<Name> name, Handle<Code> code) {
+void IC::PatchCache(Handle<Name> name, Handle<Object> code) {
+ DCHECK(code->IsCode() || (code->IsSmi() && (kind() == Code::LOAD_IC ||
+ kind() == Code::KEYED_LOAD_IC)));
switch (state()) {
case UNINITIALIZED:
case PREMONOMORPHIC:
UpdateMonomorphicIC(code, name);
break;
- case PROTOTYPE_FAILURE:
+ case RECOMPUTE_HANDLER:
case MONOMORPHIC:
+ if (kind() == Code::LOAD_GLOBAL_IC) {
+ UpdateMonomorphicIC(code, name);
+ break;
+ }
+ // Fall through.
case POLYMORPHIC:
- if (!target()->is_keyed_stub() || state() == PROTOTYPE_FAILURE) {
+ if (!is_keyed() || state() == RECOMPUTE_HANDLER) {
if (UpdatePolymorphicIC(name, code)) break;
// For keyed stubs, we can't know whether old handlers were for the
// same key.
CopyICToMegamorphicCache(name);
}
- if (UseVector()) {
- ConfigureVectorState(MEGAMORPHIC, name);
- } else {
- set_target(*megamorphic_stub());
- }
+ DCHECK(UseVector());
+ ConfigureVectorState(MEGAMORPHIC, name);
// Fall through.
case MEGAMORPHIC:
UpdateMegamorphicCache(*receiver_map(), *name, *code);
// Indicate that we've handled this case.
- if (UseVector()) {
- vector_set_ = true;
- } else {
- target_set_ = true;
- }
- break;
- case DEBUG_STUB:
+ DCHECK(UseVector());
+ vector_set_ = true;
break;
case GENERIC:
UNREACHABLE();
@@ -884,96 +818,19 @@ void IC::PatchCache(Handle<Name> name, Handle<Code> code) {
}
}
-
-Handle<Code> LoadIC::initialize_stub(Isolate* isolate,
- ExtraICState extra_state) {
- return LoadICTrampolineStub(isolate, LoadICState(extra_state)).GetCode();
-}
-
-
-Handle<Code> LoadIC::initialize_stub_in_optimized_code(
- Isolate* isolate, ExtraICState extra_state, State initialization_state) {
- return LoadICStub(isolate, LoadICState(extra_state)).GetCode();
-}
-
-
-Handle<Code> KeyedLoadIC::initialize_stub(Isolate* isolate,
- ExtraICState extra_state) {
- return KeyedLoadICTrampolineStub(isolate, LoadICState(extra_state)).GetCode();
-}
-
-
-Handle<Code> KeyedLoadIC::initialize_stub_in_optimized_code(
- Isolate* isolate, State initialization_state, ExtraICState extra_state) {
- if (initialization_state != MEGAMORPHIC) {
- return KeyedLoadICStub(isolate, LoadICState(extra_state)).GetCode();
- }
- return isolate->builtins()->KeyedLoadIC_Megamorphic();
-}
-
-
-static Handle<Code> KeyedStoreICInitializeStubHelper(
- Isolate* isolate, LanguageMode language_mode,
- InlineCacheState initialization_state) {
- switch (initialization_state) {
- case UNINITIALIZED:
- return is_strict(language_mode)
- ? isolate->builtins()->KeyedStoreIC_Initialize_Strict()
- : isolate->builtins()->KeyedStoreIC_Initialize();
- case PREMONOMORPHIC:
- return is_strict(language_mode)
- ? isolate->builtins()->KeyedStoreIC_PreMonomorphic_Strict()
- : isolate->builtins()->KeyedStoreIC_PreMonomorphic();
- case MEGAMORPHIC:
- return is_strict(language_mode)
- ? isolate->builtins()->KeyedStoreIC_Megamorphic_Strict()
- : isolate->builtins()->KeyedStoreIC_Megamorphic();
- default:
- UNREACHABLE();
- }
- return Handle<Code>();
-}
-
-
-Handle<Code> KeyedStoreIC::initialize_stub(Isolate* isolate,
- LanguageMode language_mode,
- State initialization_state) {
- if (initialization_state != MEGAMORPHIC) {
- VectorKeyedStoreICTrampolineStub stub(isolate, StoreICState(language_mode));
- return stub.GetCode();
- }
-
- return KeyedStoreICInitializeStubHelper(isolate, language_mode,
- initialization_state);
-}
-
-
-Handle<Code> KeyedStoreIC::initialize_stub_in_optimized_code(
- Isolate* isolate, LanguageMode language_mode, State initialization_state) {
- if (initialization_state != MEGAMORPHIC) {
- VectorKeyedStoreICStub stub(isolate, StoreICState(language_mode));
- return stub.GetCode();
- }
-
- return KeyedStoreICInitializeStubHelper(isolate, language_mode,
- initialization_state);
-}
-
-
Handle<Code> KeyedStoreIC::ChooseMegamorphicStub(Isolate* isolate,
ExtraICState extra_state) {
LanguageMode mode = StoreICState::GetLanguageMode(extra_state);
- return KeyedStoreICInitializeStubHelper(isolate, mode, MEGAMORPHIC);
-}
-
-
-Handle<Code> LoadIC::megamorphic_stub() {
- DCHECK_EQ(Code::KEYED_LOAD_IC, kind());
- return KeyedLoadIC::ChooseMegamorphicStub(isolate(), extra_ic_state());
+ return is_strict(mode)
+ ? isolate->builtins()->KeyedStoreIC_Megamorphic_Strict()
+ : isolate->builtins()->KeyedStoreIC_Megamorphic();
}
-
-Handle<Code> LoadIC::SimpleFieldLoad(FieldIndex index) {
+Handle<Object> LoadIC::SimpleFieldLoad(FieldIndex index) {
+ if (FLAG_tf_load_ic_stub) {
+ return handle(Smi::FromInt(index.GetLoadByFieldOffset()), isolate());
+ }
+ TRACE_HANDLER_STATS(isolate(), LoadIC_LoadFieldStub);
LoadFieldStub stub(isolate(), index);
return stub.GetCode();
}
@@ -992,8 +849,9 @@ bool IsCompatibleReceiver(LookupIterator* lookup, Handle<Map> receiver_map) {
} else if (accessors->IsAccessorPair()) {
Handle<Object> getter(Handle<AccessorPair>::cast(accessors)->getter(),
isolate);
- if (!getter->IsJSFunction() && !getter->IsFunctionTemplateInfo())
+ if (!getter->IsJSFunction() && !getter->IsFunctionTemplateInfo()) {
return false;
+ }
Handle<JSObject> holder = lookup->GetHolder<JSObject>();
Handle<Object> receiver = lookup->GetReceiver();
if (holder->HasFastProperties()) {
@@ -1018,7 +876,7 @@ bool IsCompatibleReceiver(LookupIterator* lookup, Handle<Map> receiver_map) {
void LoadIC::UpdateCaches(LookupIterator* lookup) {
- if (state() == UNINITIALIZED) {
+ if (state() == UNINITIALIZED && kind() != Code::LOAD_GLOBAL_IC) {
// This is the first time we execute this inline cache. Set the target to
// the pre monomorphic stub to delay setting the monomorphic state.
ConfigureVectorState(PREMONOMORPHIC, Handle<Object>());
@@ -1026,12 +884,12 @@ void LoadIC::UpdateCaches(LookupIterator* lookup) {
return;
}
- Handle<Code> code;
+ Handle<Object> code;
if (lookup->state() == LookupIterator::JSPROXY ||
lookup->state() == LookupIterator::ACCESS_CHECK) {
code = slow_stub();
} else if (!lookup->IsFound()) {
- if (kind() == Code::LOAD_IC) {
+ if (kind() == Code::LOAD_IC || kind() == Code::LOAD_GLOBAL_IC) {
code = NamedLoadHandlerCompiler::ComputeLoadNonexistent(lookup->name(),
receiver_map());
// TODO(jkummerow/verwaest): Introduce a builtin that handles this case.
@@ -1040,21 +898,41 @@ void LoadIC::UpdateCaches(LookupIterator* lookup) {
code = slow_stub();
}
} else {
- if (lookup->state() == LookupIterator::ACCESSOR) {
+ if (kind() == Code::LOAD_GLOBAL_IC &&
+ lookup->state() == LookupIterator::DATA &&
+ lookup->GetHolder<Object>()->IsJSGlobalObject()) {
+#if DEBUG
+ Handle<Object> holder = lookup->GetHolder<Object>();
+ Handle<Object> receiver = lookup->GetReceiver();
+ DCHECK_EQ(*receiver, *holder);
+#endif
+ // Now update the cell in the feedback vector.
+ LoadGlobalICNexus* nexus = casted_nexus<LoadGlobalICNexus>();
+ nexus->ConfigurePropertyCellMode(lookup->GetPropertyCell());
+ TRACE_IC("LoadGlobalIC", lookup->name());
+ return;
+ } else if (lookup->state() == LookupIterator::ACCESSOR) {
if (!IsCompatibleReceiver(lookup, receiver_map())) {
TRACE_GENERIC_IC(isolate(), "LoadIC", "incompatible receiver type");
code = slow_stub();
}
} else if (lookup->state() == LookupIterator::INTERCEPTOR) {
- // Perform a lookup behind the interceptor. Copy the LookupIterator since
- // the original iterator will be used to fetch the value.
- LookupIterator it = *lookup;
- it.Next();
- LookupForRead(&it);
- if (it.state() == LookupIterator::ACCESSOR &&
- !IsCompatibleReceiver(&it, receiver_map())) {
- TRACE_GENERIC_IC(isolate(), "LoadIC", "incompatible receiver type");
+ if (kind() == Code::LOAD_GLOBAL_IC) {
+ // The interceptor handler requires name but it is not passed explicitly
+ // to LoadGlobalIC and the LoadGlobalIC dispatcher also does not load
+ // it so we will just use slow stub.
code = slow_stub();
+ } else {
+ // Perform a lookup behind the interceptor. Copy the LookupIterator
+ // since the original iterator will be used to fetch the value.
+ LookupIterator it = *lookup;
+ it.Next();
+ LookupForRead(&it);
+ if (it.state() == LookupIterator::ACCESSOR &&
+ !IsCompatibleReceiver(&it, receiver_map())) {
+ TRACE_GENERIC_IC(isolate(), "LoadIC", "incompatible receiver type");
+ code = slow_stub();
+ }
}
}
if (code.is_null()) code = ComputeHandler(lookup);
@@ -1064,39 +942,90 @@ void LoadIC::UpdateCaches(LookupIterator* lookup) {
TRACE_IC("LoadIC", lookup->name());
}
+StubCache* IC::stub_cache() {
+ switch (kind()) {
+ case Code::LOAD_IC:
+ case Code::KEYED_LOAD_IC:
+ return isolate()->load_stub_cache();
+
+ case Code::STORE_IC:
+ case Code::KEYED_STORE_IC:
+ return isolate()->store_stub_cache();
-void IC::UpdateMegamorphicCache(Map* map, Name* name, Code* code) {
- isolate()->stub_cache()->Set(name, map, code);
+ default:
+ break;
+ }
+ UNREACHABLE();
+ return nullptr;
+}
+
+void IC::UpdateMegamorphicCache(Map* map, Name* name, Object* code) {
+ if (code->IsSmi()) {
+ // TODO(jkummerow): Support Smis in the code cache.
+ Handle<Map> map_handle(map, isolate());
+ Handle<Name> name_handle(name, isolate());
+ FieldIndex index =
+ FieldIndex::ForLoadByFieldOffset(map, Smi::cast(code)->value());
+ TRACE_HANDLER_STATS(isolate(), LoadIC_LoadFieldStub);
+ LoadFieldStub stub(isolate(), index);
+ Code* handler = *stub.GetCode();
+ stub_cache()->Set(*name_handle, *map_handle, handler);
+ return;
+ }
+ DCHECK(code->IsCode());
+ stub_cache()->Set(name, map, Code::cast(code));
}
+Handle<Object> IC::ComputeHandler(LookupIterator* lookup,
+ Handle<Object> value) {
+ // Try to find a globally shared handler stub.
+ Handle<Object> handler_or_index = GetMapIndependentHandler(lookup);
+ if (!handler_or_index.is_null()) {
+ DCHECK(handler_or_index->IsCode() || handler_or_index->IsSmi());
+ return handler_or_index;
+ }
-Handle<Code> IC::ComputeHandler(LookupIterator* lookup, Handle<Object> value) {
+ // Otherwise check the map's handler cache for a map-specific handler, and
+ // compile one if the cache comes up empty.
bool receiver_is_holder =
lookup->GetReceiver().is_identical_to(lookup->GetHolder<JSObject>());
CacheHolderFlag flag;
- Handle<Map> stub_holder_map = IC::GetHandlerCacheHolder(
- receiver_map(), receiver_is_holder, isolate(), &flag);
+ Handle<Map> stub_holder_map;
+ if (kind() == Code::LOAD_IC || kind() == Code::LOAD_GLOBAL_IC ||
+ kind() == Code::KEYED_LOAD_IC) {
+ stub_holder_map = IC::GetHandlerCacheHolder(
+ receiver_map(), receiver_is_holder, isolate(), &flag);
+ } else {
+ DCHECK(kind() == Code::STORE_IC || kind() == Code::KEYED_STORE_IC);
+ // Store handlers cannot be cached on prototypes.
+ flag = kCacheOnReceiver;
+ stub_holder_map = receiver_map();
+ }
Handle<Code> code = PropertyHandlerCompiler::Find(
- lookup->name(), stub_holder_map, kind(), flag,
- lookup->is_dictionary_holder() ? Code::NORMAL : Code::FAST);
+ lookup->name(), stub_holder_map, kind(), flag);
// Use the cached value if it exists, and if it is different from the
// handler that just missed.
if (!code.is_null()) {
- if (!maybe_handler_.is_null() &&
- !maybe_handler_.ToHandleChecked().is_identical_to(code)) {
- return code;
- }
- if (maybe_handler_.is_null()) {
+ Handle<Object> handler;
+ if (maybe_handler_.ToHandle(&handler)) {
+ if (!handler.is_identical_to(code)) {
+ TRACE_HANDLER_STATS(isolate(), IC_HandlerCacheHit);
+ return code;
+ }
+ } else {
// maybe_handler_ is only populated for MONOMORPHIC and POLYMORPHIC ICs.
// In MEGAMORPHIC case, check if the handler in the megamorphic stub
// cache (which just missed) is different from the cached handler.
if (state() == MEGAMORPHIC && lookup->GetReceiver()->IsHeapObject()) {
Map* map = Handle<HeapObject>::cast(lookup->GetReceiver())->map();
- Code* megamorphic_cached_code =
- isolate()->stub_cache()->Get(*lookup->name(), map, code->flags());
- if (megamorphic_cached_code != *code) return code;
+ Code* megamorphic_cached_code = stub_cache()->Get(*lookup->name(), map);
+ if (megamorphic_cached_code != *code) {
+ TRACE_HANDLER_STATS(isolate(), IC_HandlerCacheHit);
+ return code;
+ }
} else {
+ TRACE_HANDLER_STATS(isolate(), IC_HandlerCacheHit);
return code;
}
}
@@ -1104,24 +1033,13 @@ Handle<Code> IC::ComputeHandler(LookupIterator* lookup, Handle<Object> value) {
code = CompileHandler(lookup, value, flag);
DCHECK(code->is_handler());
-
- // TODO(mvstanton): we'd only like to cache code on the map when it's custom
- // code compiled for this map, otherwise it's already cached in the global
- // code cache. We are also guarding against installing code with flags that
- // don't match the desired CacheHolderFlag computed above, which would lead to
- // invalid lookups later.
- if (code->type() != Code::NORMAL &&
- Code::ExtractCacheHolderFromFlags(code->flags()) == flag) {
- Map::UpdateCodeCache(stub_holder_map, lookup->name(), code);
- }
+ DCHECK(Code::ExtractCacheHolderFromFlags(code->flags()) == flag);
+ Map::UpdateCodeCache(stub_holder_map, lookup->name(), code);
return code;
}
-
-Handle<Code> LoadIC::CompileHandler(LookupIterator* lookup,
- Handle<Object> unused,
- CacheHolderFlag cache_holder) {
+Handle<Object> LoadIC::GetMapIndependentHandler(LookupIterator* lookup) {
Handle<Object> receiver = lookup->GetReceiver();
if (receiver->IsString() &&
Name::Equals(isolate()->factory()->length_string(), lookup->name())) {
@@ -1131,6 +1049,7 @@ Handle<Code> LoadIC::CompileHandler(LookupIterator* lookup,
if (receiver->IsStringWrapper() &&
Name::Equals(isolate()->factory()->length_string(), lookup->name())) {
+ TRACE_HANDLER_STATS(isolate(), LoadIC_StringLengthStub);
StringLengthStub string_length_stub(isolate());
return string_length_stub.GetCode();
}
@@ -1143,6 +1062,7 @@ Handle<Code> LoadIC::CompileHandler(LookupIterator* lookup,
->map()
->has_non_instance_prototype()) {
Handle<Code> stub;
+ TRACE_HANDLER_STATS(isolate(), LoadIC_FunctionPrototypeStub);
FunctionPrototypeStub function_prototype_stub(isolate());
return function_prototype_stub.GetCode();
}
@@ -1151,16 +1071,8 @@ Handle<Code> LoadIC::CompileHandler(LookupIterator* lookup,
Handle<JSObject> holder = lookup->GetHolder<JSObject>();
bool receiver_is_holder = receiver.is_identical_to(holder);
switch (lookup->state()) {
- case LookupIterator::INTERCEPTOR: {
- DCHECK(!holder->GetNamedInterceptor()->getter()->IsUndefined());
- NamedLoadHandlerCompiler compiler(isolate(), map, holder, cache_holder);
- // Perform a lookup behind the interceptor. Copy the LookupIterator since
- // the original iterator will be used to fetch the value.
- LookupIterator it = *lookup;
- it.Next();
- LookupForRead(&it);
- return compiler.CompileLoadInterceptor(&it);
- }
+ case LookupIterator::INTERCEPTOR:
+ break; // Custom-compiled handler.
case LookupIterator::ACCESSOR: {
// Use simple field loads for some well-known callback properties.
@@ -1172,72 +1084,64 @@ Handle<Code> LoadIC::CompileHandler(LookupIterator* lookup,
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();
- }
if (IsCompatibleReceiver(lookup, map)) {
Handle<Object> accessors = lookup->GetAccessors();
if (accessors->IsAccessorPair()) {
- if (!holder->HasFastProperties()) break;
+ if (!holder->HasFastProperties()) {
+ TRACE_HANDLER_STATS(isolate(), LoadIC_SlowStub);
+ return slow_stub();
+ }
// When debugging we need to go the slow path to flood the accessor.
- if (GetSharedFunctionInfo()->HasDebugInfo()) break;
- Handle<Object> getter(Handle<AccessorPair>::cast(accessors)->getter(),
- isolate());
- CallOptimization call_optimization(getter);
- NamedLoadHandlerCompiler compiler(isolate(), map, holder,
- cache_holder);
- if (call_optimization.is_simple_api_call()) {
- return compiler.CompileLoadCallback(
- lookup->name(), call_optimization, lookup->GetAccessorIndex());
+ if (GetSharedFunctionInfo()->HasDebugInfo()) {
+ TRACE_HANDLER_STATS(isolate(), LoadIC_SlowStub);
+ return slow_stub();
}
- int expected_arguments = Handle<JSFunction>::cast(getter)
- ->shared()
- ->internal_formal_parameter_count();
- return compiler.CompileLoadViaGetter(
- lookup->name(), lookup->GetAccessorIndex(), expected_arguments);
+ break; // Custom-compiled handler.
} else if (accessors->IsAccessorInfo()) {
Handle<AccessorInfo> info = Handle<AccessorInfo>::cast(accessors);
- if (v8::ToCData<Address>(info->getter()) == 0) break;
- if (!AccessorInfo::IsCompatibleReceiverMap(isolate(), info, map)) {
- // This case should be already handled in LoadIC::UpdateCaches.
- UNREACHABLE();
- break;
+ if (v8::ToCData<Address>(info->getter()) == nullptr) {
+ TRACE_HANDLER_STATS(isolate(), LoadIC_SlowStub);
+ return slow_stub();
+ }
+ // Ruled out by IsCompatibleReceiver() above.
+ DCHECK(AccessorInfo::IsCompatibleReceiverMap(isolate(), info, map));
+ if (!holder->HasFastProperties()) return slow_stub();
+ if (receiver_is_holder) {
+ TRACE_HANDLER_STATS(isolate(), LoadIC_LoadApiGetterStub);
+ int index = lookup->GetAccessorIndex();
+ LoadApiGetterStub stub(isolate(), true, index);
+ return stub.GetCode();
}
- if (!holder->HasFastProperties()) break;
- if (info->is_sloppy() && !receiver->IsJSReceiver()) break;
- NamedLoadHandlerCompiler compiler(isolate(), map, holder,
- cache_holder);
- return compiler.CompileLoadCallback(lookup->name(), info);
+ if (info->is_sloppy() && !receiver->IsJSReceiver()) {
+ TRACE_HANDLER_STATS(isolate(), LoadIC_SlowStub);
+ return slow_stub();
+ }
+ break; // Custom-compiled handler.
}
}
- break;
+ TRACE_HANDLER_STATS(isolate(), LoadIC_SlowStub);
+ return slow_stub();
}
case LookupIterator::DATA: {
if (lookup->is_dictionary_holder()) {
- if (kind() != Code::LOAD_IC) break;
+ if (kind() != Code::LOAD_IC && kind() != Code::LOAD_GLOBAL_IC) {
+ TRACE_HANDLER_STATS(isolate(), LoadIC_SlowStub);
+ return slow_stub();
+ }
if (holder->IsJSGlobalObject()) {
- NamedLoadHandlerCompiler compiler(isolate(), map, holder,
- cache_holder);
- Handle<PropertyCell> cell = lookup->GetPropertyCell();
- Handle<Code> code = compiler.CompileLoadGlobal(
- cell, lookup->name(), lookup->IsConfigurable());
- // TODO(verwaest): Move caching of these NORMAL stubs outside as well.
- CacheHolderFlag flag;
- Handle<Map> stub_holder_map =
- GetHandlerCacheHolder(map, receiver_is_holder, isolate(), &flag);
- Map::UpdateCodeCache(stub_holder_map, lookup->name(), code);
- return code;
+ break; // Custom-compiled handler.
}
// There is only one shared stub for loading normalized
// properties. It does not traverse the prototype chain, so the
// property must be found in the object for the stub to be
// applicable.
- if (!receiver_is_holder) break;
+ if (!receiver_is_holder) {
+ TRACE_HANDLER_STATS(isolate(), LoadIC_SlowStub);
+ return slow_stub();
+ }
+ TRACE_HANDLER_STATS(isolate(), LoadIC_LoadNormal);
return isolate()->builtins()->LoadIC_Normal();
}
@@ -1247,30 +1151,153 @@ Handle<Code> LoadIC::CompileHandler(LookupIterator* lookup,
if (receiver_is_holder) {
return SimpleFieldLoad(field);
}
- NamedLoadHandlerCompiler compiler(isolate(), map, holder, cache_holder);
- return compiler.CompileLoadField(lookup->name(), field);
+ break; // Custom-compiled handler.
}
// -------------- Constant properties --------------
DCHECK(lookup->property_details().type() == DATA_CONSTANT);
if (receiver_is_holder) {
+ TRACE_HANDLER_STATS(isolate(), LoadIC_LoadConstantStub);
LoadConstantStub stub(isolate(), lookup->GetConstantIndex());
return stub.GetCode();
}
+ break; // Custom-compiled handler.
+ }
+
+ case LookupIterator::INTEGER_INDEXED_EXOTIC:
+ TRACE_HANDLER_STATS(isolate(), LoadIC_SlowStub);
+ return slow_stub();
+ case LookupIterator::ACCESS_CHECK:
+ case LookupIterator::JSPROXY:
+ case LookupIterator::NOT_FOUND:
+ case LookupIterator::TRANSITION:
+ UNREACHABLE();
+ }
+
+ return Handle<Code>::null();
+}
+
+Handle<Code> LoadIC::CompileHandler(LookupIterator* lookup,
+ Handle<Object> unused,
+ CacheHolderFlag cache_holder) {
+ Handle<JSObject> holder = lookup->GetHolder<JSObject>();
+#ifdef DEBUG
+ // Only used by DCHECKs below.
+ Handle<Object> receiver = lookup->GetReceiver();
+ bool receiver_is_holder = receiver.is_identical_to(holder);
+#endif
+ // Non-map-specific handler stubs have already been selected.
+ DCHECK(!receiver->IsString() ||
+ !Name::Equals(isolate()->factory()->length_string(), lookup->name()));
+ DCHECK(!receiver->IsStringWrapper() ||
+ !Name::Equals(isolate()->factory()->length_string(), lookup->name()));
+
+ DCHECK(!(
+ receiver->IsJSFunction() &&
+ Name::Equals(isolate()->factory()->prototype_string(), lookup->name()) &&
+ receiver->IsConstructor() &&
+ !Handle<JSFunction>::cast(receiver)
+ ->map()
+ ->has_non_instance_prototype()));
+
+ Handle<Map> map = receiver_map();
+ switch (lookup->state()) {
+ case LookupIterator::INTERCEPTOR: {
+ DCHECK(!holder->GetNamedInterceptor()->getter()->IsUndefined(isolate()));
+ TRACE_HANDLER_STATS(isolate(), LoadIC_LoadInterceptor);
+ NamedLoadHandlerCompiler compiler(isolate(), map, holder, cache_holder);
+ // Perform a lookup behind the interceptor. Copy the LookupIterator since
+ // the original iterator will be used to fetch the value.
+ LookupIterator it = *lookup;
+ it.Next();
+ LookupForRead(&it);
+ return compiler.CompileLoadInterceptor(&it);
+ }
+
+ case LookupIterator::ACCESSOR: {
+#ifdef DEBUG
+ int object_offset;
+ DCHECK(!Accessors::IsJSObjectFieldAccessor(map, lookup->name(),
+ &object_offset));
+#endif
+
+ DCHECK(IsCompatibleReceiver(lookup, map));
+ Handle<Object> accessors = lookup->GetAccessors();
+ if (accessors->IsAccessorPair()) {
+ DCHECK(holder->HasFastProperties());
+ DCHECK(!GetSharedFunctionInfo()->HasDebugInfo());
+ Handle<Object> getter(Handle<AccessorPair>::cast(accessors)->getter(),
+ isolate());
+ CallOptimization call_optimization(getter);
+ NamedLoadHandlerCompiler compiler(isolate(), map, holder, cache_holder);
+ if (call_optimization.is_simple_api_call()) {
+ TRACE_HANDLER_STATS(isolate(), LoadIC_LoadCallback);
+ int index = lookup->GetAccessorIndex();
+ Handle<Code> code = compiler.CompileLoadCallback(
+ lookup->name(), call_optimization, index, slow_stub());
+ return code;
+ }
+ TRACE_HANDLER_STATS(isolate(), LoadIC_LoadViaGetter);
+ int expected_arguments = Handle<JSFunction>::cast(getter)
+ ->shared()
+ ->internal_formal_parameter_count();
+ return compiler.CompileLoadViaGetter(
+ lookup->name(), lookup->GetAccessorIndex(), expected_arguments);
+ } else {
+ DCHECK(accessors->IsAccessorInfo());
+ Handle<AccessorInfo> info = Handle<AccessorInfo>::cast(accessors);
+ DCHECK(v8::ToCData<Address>(info->getter()) != nullptr);
+ DCHECK(AccessorInfo::IsCompatibleReceiverMap(isolate(), info, map));
+ DCHECK(holder->HasFastProperties());
+ DCHECK(!receiver_is_holder);
+ DCHECK(!info->is_sloppy() || receiver->IsJSReceiver());
+ TRACE_HANDLER_STATS(isolate(), LoadIC_LoadCallback);
+ NamedLoadHandlerCompiler compiler(isolate(), map, holder, cache_holder);
+ Handle<Code> code =
+ compiler.CompileLoadCallback(lookup->name(), info, slow_stub());
+ return code;
+ }
+ UNREACHABLE();
+ }
+
+ case LookupIterator::DATA: {
+ if (lookup->is_dictionary_holder()) {
+ DCHECK(kind() == Code::LOAD_IC || kind() == Code::LOAD_GLOBAL_IC);
+ DCHECK(holder->IsJSGlobalObject());
+ TRACE_HANDLER_STATS(isolate(), LoadIC_LoadGlobal);
+ NamedLoadHandlerCompiler compiler(isolate(), map, holder, cache_holder);
+ Handle<PropertyCell> cell = lookup->GetPropertyCell();
+ Handle<Code> code = compiler.CompileLoadGlobal(
+ cell, lookup->name(), lookup->IsConfigurable());
+ return code;
+ }
+
+ // -------------- Fields --------------
+ if (lookup->property_details().type() == DATA) {
+ FieldIndex field = lookup->GetFieldIndex();
+ DCHECK(!receiver_is_holder);
+ TRACE_HANDLER_STATS(isolate(), LoadIC_LoadField);
+ NamedLoadHandlerCompiler compiler(isolate(), map, holder, cache_holder);
+ return compiler.CompileLoadField(lookup->name(), field);
+ }
+
+ // -------------- Constant properties --------------
+ DCHECK(lookup->property_details().type() == DATA_CONSTANT);
+ DCHECK(!receiver_is_holder);
+ TRACE_HANDLER_STATS(isolate(), LoadIC_LoadConstant);
NamedLoadHandlerCompiler compiler(isolate(), map, holder, cache_holder);
return compiler.CompileLoadConstant(lookup->name(),
lookup->GetConstantIndex());
}
case LookupIterator::INTEGER_INDEXED_EXOTIC:
- return slow_stub();
case LookupIterator::ACCESS_CHECK:
case LookupIterator::JSPROXY:
case LookupIterator::NOT_FOUND:
case LookupIterator::TRANSITION:
UNREACHABLE();
}
-
+ UNREACHABLE();
return slow_stub();
}
@@ -1288,33 +1315,35 @@ static Handle<Object> TryConvertKey(Handle<Object> key, Isolate* isolate) {
key = handle(Smi::FromInt(int_value), isolate);
}
}
- } else if (key->IsUndefined()) {
+ } else if (key->IsUndefined(isolate)) {
key = isolate->factory()->undefined_string();
}
return key;
}
-
-Handle<Code> KeyedLoadIC::LoadElementStub(Handle<HeapObject> receiver) {
- Handle<Code> null_handle;
+void KeyedLoadIC::UpdateLoadElement(Handle<HeapObject> receiver) {
Handle<Map> receiver_map(receiver->map(), isolate());
- DCHECK(receiver_map->instance_type() != JS_VALUE_TYPE); // Checked by caller.
+ DCHECK(receiver_map->instance_type() != JS_VALUE_TYPE &&
+ receiver_map->instance_type() != JS_PROXY_TYPE); // Checked by caller.
MapHandleList target_receiver_maps;
TargetMaps(&target_receiver_maps);
if (target_receiver_maps.length() == 0) {
- Handle<Code> handler =
- PropertyICCompiler::ComputeKeyedLoadMonomorphicHandler(
- receiver_map, extra_ic_state());
- ConfigureVectorState(Handle<Name>::null(), receiver_map, handler);
- return null_handle;
+ Handle<Object> handler =
+ ElementHandlerCompiler::GetKeyedLoadHandler(receiver_map, isolate());
+ return ConfigureVectorState(Handle<Name>(), receiver_map, handler);
}
for (int i = 0; i < target_receiver_maps.length(); i++) {
- if (!target_receiver_maps.at(i).is_null() &&
- target_receiver_maps.at(i)->instance_type() == JS_VALUE_TYPE) {
+ Handle<Map> map = target_receiver_maps.at(i);
+ if (map.is_null()) continue;
+ if (map->instance_type() == JS_VALUE_TYPE) {
TRACE_GENERIC_IC(isolate(), "KeyedLoadIC", "JSValue");
- return megamorphic_stub();
+ return;
+ }
+ if (map->instance_type() == JS_PROXY_TYPE) {
+ TRACE_GENERIC_IC(isolate(), "KeyedLoadIC", "JSProxy");
+ return;
}
}
@@ -1329,11 +1358,9 @@ Handle<Code> KeyedLoadIC::LoadElementStub(Handle<HeapObject> receiver) {
IsMoreGeneralElementsKindTransition(
target_receiver_maps.at(0)->elements_kind(),
Handle<JSObject>::cast(receiver)->GetElementsKind())) {
- Handle<Code> handler =
- PropertyICCompiler::ComputeKeyedLoadMonomorphicHandler(
- receiver_map, extra_ic_state());
- ConfigureVectorState(Handle<Name>::null(), receiver_map, handler);
- return null_handle;
+ Handle<Object> handler =
+ ElementHandlerCompiler::GetKeyedLoadHandler(receiver_map, isolate());
+ return ConfigureVectorState(Handle<Name>(), receiver_map, handler);
}
DCHECK(state() != GENERIC);
@@ -1344,21 +1371,20 @@ Handle<Code> KeyedLoadIC::LoadElementStub(Handle<HeapObject> receiver) {
// If the miss wasn't due to an unseen map, a polymorphic stub
// won't help, use the generic stub.
TRACE_GENERIC_IC(isolate(), "KeyedLoadIC", "same map added twice");
- return megamorphic_stub();
+ return;
}
// If the maximum number of receiver maps has been exceeded, use the generic
// version of the IC.
if (target_receiver_maps.length() > kMaxKeyedPolymorphism) {
TRACE_GENERIC_IC(isolate(), "KeyedLoadIC", "max polymorph exceeded");
- return megamorphic_stub();
+ return;
}
- CodeHandleList handlers(target_receiver_maps.length());
+ List<Handle<Object>> handlers(target_receiver_maps.length());
ElementHandlerCompiler compiler(isolate());
compiler.CompileElementHandlers(&target_receiver_maps, &handlers);
- ConfigureVectorState(Handle<Name>::null(), &target_receiver_maps, &handlers);
- return null_handle;
+ ConfigureVectorState(Handle<Name>(), &target_receiver_maps, &handlers);
}
@@ -1373,13 +1399,15 @@ MaybeHandle<Object> KeyedLoadIC::Load(Handle<Object> object,
}
Handle<Object> load_handle;
- Handle<Code> stub = megamorphic_stub();
// Check for non-string values that can be converted into an
// internalized string directly or is representable as a smi.
key = TryConvertKey(key, isolate());
- if (key->IsInternalizedString() || key->IsSymbol()) {
+ uint32_t index;
+ if ((key->IsInternalizedString() &&
+ !String::cast(*key)->AsArrayIndex(&index)) ||
+ key->IsSymbol()) {
ASSIGN_RETURN_ON_EXCEPTION(isolate(), load_handle,
LoadIC::Load(object, Handle<Name>::cast(key)),
Object);
@@ -1387,20 +1415,15 @@ MaybeHandle<Object> KeyedLoadIC::Load(Handle<Object> object,
!object->IsJSValue()) {
if (object->IsJSObject() || (object->IsString() && key->IsNumber())) {
Handle<HeapObject> receiver = Handle<HeapObject>::cast(object);
- if (object->IsString() || key->IsSmi()) stub = LoadElementStub(receiver);
+ if (object->IsString() || key->IsSmi()) UpdateLoadElement(receiver);
}
}
- DCHECK(UseVector());
- if (!is_vector_set() || stub.is_null()) {
- Code* generic = *megamorphic_stub();
- if (!stub.is_null() && *stub == generic) {
- ConfigureVectorState(MEGAMORPHIC, key);
- TRACE_GENERIC_IC(isolate(), "KeyedLoadIC", "set generic");
- }
-
- TRACE_IC("LoadIC", key);
+ if (!is_vector_set()) {
+ ConfigureVectorState(MEGAMORPHIC, key);
+ TRACE_GENERIC_IC(isolate(), "KeyedLoadIC", "set generic");
}
+ TRACE_IC("LoadIC", key);
if (!load_handle.is_null()) return load_handle;
@@ -1432,9 +1455,9 @@ bool StoreIC::LookupForWrite(LookupIterator* it, Handle<Object> value,
InterceptorInfo* info = holder->GetNamedInterceptor();
if (it->HolderIsReceiverOrHiddenPrototype()) {
return !info->non_masking() && receiver.is_identical_to(holder) &&
- !info->setter()->IsUndefined();
- } else if (!info->getter()->IsUndefined() ||
- !info->query()->IsUndefined()) {
+ !info->setter()->IsUndefined(it->isolate());
+ } else if (!info->getter()->IsUndefined(it->isolate()) ||
+ !info->query()->IsUndefined(it->isolate())) {
return false;
}
break;
@@ -1483,27 +1506,6 @@ bool StoreIC::LookupForWrite(LookupIterator* it, Handle<Object> value,
MaybeHandle<Object> StoreIC::Store(Handle<Object> object, Handle<Name> name,
Handle<Object> value,
JSReceiver::StoreFromKeyed store_mode) {
- // Check if the name is trivially convertible to an index and set the element.
- uint32_t index;
- if (kind() == Code::KEYED_STORE_IC && name->AsArrayIndex(&index)) {
- // Rewrite to the generic keyed store stub.
- if (FLAG_use_ic) {
- if (UseVector()) {
- ConfigureVectorState(MEGAMORPHIC, name);
- } else if (!AddressIsDeoptimizedCode()) {
- set_target(*megamorphic_stub());
- }
- TRACE_IC("StoreIC", name);
- TRACE_GENERIC_IC(isolate(), "StoreIC", "name as array index");
- }
- Handle<Object> result;
- ASSIGN_RETURN_ON_EXCEPTION(
- isolate(), result,
- Object::SetElement(isolate(), object, index, value, language_mode()),
- Object);
- return result;
- }
-
if (object->IsJSGlobalObject() && name->IsString()) {
// Look up in script context table.
Handle<String> str_name = Handle<String>::cast(name);
@@ -1522,7 +1524,7 @@ MaybeHandle<Object> StoreIC::Store(Handle<Object> object, Handle<Name> name,
Handle<Object> previous_value =
FixedArray::get(*script_context, lookup_result.slot_index, isolate());
- if (*previous_value == *isolate()->factory()->the_hole_value()) {
+ if (previous_value->IsTheHole(isolate())) {
// Do not install stubs and stay pre-monomorphic for
// uninitialized accesses.
return ReferenceError(name);
@@ -1530,6 +1532,7 @@ MaybeHandle<Object> StoreIC::Store(Handle<Object> object, Handle<Name> name,
if (FLAG_use_ic &&
StoreScriptContextFieldStub::Accepted(&lookup_result)) {
+ TRACE_HANDLER_STATS(isolate(), StoreIC_StoreScriptContextFieldStub);
StoreScriptContextFieldStub stub(isolate(), &lookup_result);
PatchCache(name, stub.GetCode());
}
@@ -1551,21 +1554,13 @@ MaybeHandle<Object> StoreIC::Store(Handle<Object> object, Handle<Name> name,
// If the object is undefined or null it's illegal to try to set any
// properties on it; throw a TypeError in that case.
- if (object->IsUndefined() || object->IsNull()) {
+ if (object->IsUndefined(isolate()) || object->IsNull(isolate())) {
return TypeError(MessageTemplate::kNonObjectPropertyStore, object, name);
}
- // Observed objects are always modified through the runtime.
- if (object->IsHeapObject() &&
- Handle<HeapObject>::cast(object)->map()->is_observed()) {
- Handle<Object> result;
- ASSIGN_RETURN_ON_EXCEPTION(
- isolate(), result,
- Object::SetProperty(object, name, value, language_mode(), store_mode),
- Object);
- return result;
+ if (state() != UNINITIALIZED) {
+ JSObject::MakePrototypesFast(object, kStartAtPrototype, isolate());
}
-
LookupIterator it(object, name);
if (FLAG_use_ic) UpdateCaches(&it, value, store_mode);
@@ -1574,90 +1569,6 @@ MaybeHandle<Object> StoreIC::Store(Handle<Object> object, Handle<Name> name,
return value;
}
-Handle<Code> CallIC::initialize_stub(Isolate* isolate, int argc,
- ConvertReceiverMode mode,
- TailCallMode tail_call_mode) {
- CallICTrampolineStub stub(isolate, CallICState(argc, mode, tail_call_mode));
- Handle<Code> code = stub.GetCode();
- return code;
-}
-
-Handle<Code> CallIC::initialize_stub_in_optimized_code(
- Isolate* isolate, int argc, ConvertReceiverMode mode,
- TailCallMode tail_call_mode) {
- CallICStub stub(isolate, CallICState(argc, mode, tail_call_mode));
- Handle<Code> code = stub.GetCode();
- return code;
-}
-
-
-static Handle<Code> StoreICInitializeStubHelper(
- Isolate* isolate, ExtraICState extra_state,
- InlineCacheState initialization_state) {
- Handle<Code> ic = PropertyICCompiler::ComputeStore(
- isolate, initialization_state, extra_state);
- return ic;
-}
-
-
-Handle<Code> StoreIC::initialize_stub(Isolate* isolate,
- LanguageMode language_mode,
- State initialization_state) {
- DCHECK(initialization_state == UNINITIALIZED ||
- initialization_state == PREMONOMORPHIC ||
- initialization_state == MEGAMORPHIC);
- VectorStoreICTrampolineStub stub(isolate, StoreICState(language_mode));
- return stub.GetCode();
-}
-
-
-Handle<Code> StoreIC::initialize_stub_in_optimized_code(
- Isolate* isolate, LanguageMode language_mode, State initialization_state) {
- DCHECK(initialization_state == UNINITIALIZED ||
- initialization_state == PREMONOMORPHIC ||
- initialization_state == MEGAMORPHIC);
- if (initialization_state != MEGAMORPHIC) {
- VectorStoreICStub stub(isolate, StoreICState(language_mode));
- return stub.GetCode();
- }
-
- return StoreICInitializeStubHelper(
- isolate, ComputeExtraICState(language_mode), initialization_state);
-}
-
-
-Handle<Code> StoreIC::megamorphic_stub() {
- if (kind() == Code::STORE_IC) {
- return PropertyICCompiler::ComputeStore(isolate(), MEGAMORPHIC,
- extra_ic_state());
- } else {
- DCHECK(kind() == Code::KEYED_STORE_IC);
- if (is_strict(language_mode())) {
- return isolate()->builtins()->KeyedStoreIC_Megamorphic_Strict();
- } else {
- return isolate()->builtins()->KeyedStoreIC_Megamorphic();
- }
- }
-}
-
-
-Handle<Code> StoreIC::slow_stub() const {
- if (kind() == Code::STORE_IC) {
- return isolate()->builtins()->StoreIC_Slow();
- } else {
- DCHECK(kind() == Code::KEYED_STORE_IC);
- return isolate()->builtins()->KeyedStoreIC_Slow();
- }
-}
-
-
-Handle<Code> StoreIC::pre_monomorphic_stub(Isolate* isolate,
- LanguageMode language_mode) {
- ExtraICState state = ComputeExtraICState(language_mode);
- return PropertyICCompiler::ComputeStore(isolate, PREMONOMORPHIC, state);
-}
-
-
void StoreIC::UpdateCaches(LookupIterator* lookup, Handle<Object> value,
JSReceiver::StoreFromKeyed store_mode) {
if (state() == UNINITIALIZED) {
@@ -1672,7 +1583,8 @@ void StoreIC::UpdateCaches(LookupIterator* lookup, Handle<Object> value,
if (!use_ic) {
TRACE_GENERIC_IC(isolate(), "StoreIC", "LookupForWrite said 'false'");
}
- Handle<Code> code = use_ic ? ComputeHandler(lookup, value) : slow_stub();
+ Handle<Code> code =
+ use_ic ? Handle<Code>::cast(ComputeHandler(lookup, value)) : slow_stub();
PatchCache(lookup->name(), code);
TRACE_IC("StoreIC", lookup->name());
@@ -1694,10 +1606,7 @@ static Handle<Code> PropertyCellStoreHandler(
return code;
}
-
-Handle<Code> StoreIC::CompileHandler(LookupIterator* lookup,
- Handle<Object> value,
- CacheHolderFlag cache_holder) {
+Handle<Object> StoreIC::GetMapIndependentHandler(LookupIterator* lookup) {
DCHECK_NE(LookupIterator::JSPROXY, lookup->state());
// This is currently guaranteed by checks in StoreIC::Store.
@@ -1709,97 +1618,87 @@ Handle<Code> StoreIC::CompileHandler(LookupIterator* lookup,
case LookupIterator::TRANSITION: {
auto store_target = lookup->GetStoreTarget();
if (store_target->IsJSGlobalObject()) {
- // TODO(dcarney): this currently just deopts. Use the transition cell.
- auto cell = isolate()->factory()->NewPropertyCell();
- cell->set_value(*value);
- auto code = PropertyCellStoreHandler(
- isolate(), store_target, Handle<JSGlobalObject>::cast(store_target),
- lookup->name(), cell, PropertyCellType::kConstant);
- cell->set_value(isolate()->heap()->the_hole_value());
- return code;
+ break; // Custom-compiled handler.
}
- Handle<Map> transition = lookup->transition_map();
// Currently not handled by CompileStoreTransition.
if (!holder->HasFastProperties()) {
TRACE_GENERIC_IC(isolate(), "StoreIC", "transition from slow");
- break;
+ TRACE_HANDLER_STATS(isolate(), StoreIC_SlowStub);
+ return slow_stub();
}
DCHECK(lookup->IsCacheableTransition());
- NamedStoreHandlerCompiler compiler(isolate(), receiver_map(), holder);
- return compiler.CompileStoreTransition(transition, lookup->name());
+ break; // Custom-compiled handler.
}
case LookupIterator::INTERCEPTOR: {
- DCHECK(!holder->GetNamedInterceptor()->setter()->IsUndefined());
- return CodeFactory::StoreInterceptor(isolate()).code();
+ DCHECK(!holder->GetNamedInterceptor()->setter()->IsUndefined(isolate()));
+ TRACE_HANDLER_STATS(isolate(), StoreIC_StoreInterceptorStub);
+ StoreInterceptorStub stub(isolate());
+ return stub.GetCode();
}
case LookupIterator::ACCESSOR: {
if (!holder->HasFastProperties()) {
TRACE_GENERIC_IC(isolate(), "StoreIC", "accessor on slow map");
- break;
+ TRACE_HANDLER_STATS(isolate(), StoreIC_SlowStub);
+ return slow_stub();
}
Handle<Object> accessors = lookup->GetAccessors();
if (accessors->IsAccessorInfo()) {
Handle<AccessorInfo> info = Handle<AccessorInfo>::cast(accessors);
- if (v8::ToCData<Address>(info->setter()) == 0) {
- TRACE_GENERIC_IC(isolate(), "StoreIC", "setter == 0");
- break;
+ if (v8::ToCData<Address>(info->setter()) == nullptr) {
+ TRACE_GENERIC_IC(isolate(), "StoreIC", "setter == nullptr");
+ TRACE_HANDLER_STATS(isolate(), StoreIC_SlowStub);
+ return slow_stub();
}
if (AccessorInfo::cast(*accessors)->is_special_data_property() &&
!lookup->HolderIsReceiverOrHiddenPrototype()) {
TRACE_GENERIC_IC(isolate(), "StoreIC",
"special data property in prototype chain");
- break;
+ TRACE_HANDLER_STATS(isolate(), StoreIC_SlowStub);
+ return slow_stub();
}
if (!AccessorInfo::IsCompatibleReceiverMap(isolate(), info,
receiver_map())) {
TRACE_GENERIC_IC(isolate(), "StoreIC", "incompatible receiver type");
- break;
+ TRACE_HANDLER_STATS(isolate(), StoreIC_SlowStub);
+ return slow_stub();
}
- if (info->is_sloppy() && !receiver->IsJSReceiver()) break;
- NamedStoreHandlerCompiler compiler(isolate(), receiver_map(), holder);
- return compiler.CompileStoreCallback(receiver, lookup->name(), info,
- language_mode());
+ if (info->is_sloppy() && !receiver->IsJSReceiver()) {
+ TRACE_HANDLER_STATS(isolate(), StoreIC_SlowStub);
+ return slow_stub();
+ }
+ break; // Custom-compiled handler.
} else if (accessors->IsAccessorPair()) {
Handle<Object> setter(Handle<AccessorPair>::cast(accessors)->setter(),
isolate());
- if (!setter->IsJSFunction()) {
+ if (!setter->IsJSFunction() && !setter->IsFunctionTemplateInfo()) {
TRACE_GENERIC_IC(isolate(), "StoreIC", "setter not a function");
- break;
+ TRACE_HANDLER_STATS(isolate(), StoreIC_SlowStub);
+ return slow_stub();
}
- Handle<JSFunction> function = Handle<JSFunction>::cast(setter);
- CallOptimization call_optimization(function);
- NamedStoreHandlerCompiler compiler(isolate(), receiver_map(), holder);
- if (call_optimization.is_simple_api_call() &&
- call_optimization.IsCompatibleReceiver(receiver, holder)) {
- return compiler.CompileStoreCallback(receiver, lookup->name(),
- call_optimization,
- lookup->GetAccessorIndex());
+ CallOptimization call_optimization(setter);
+ if (call_optimization.is_simple_api_call()) {
+ if (call_optimization.IsCompatibleReceiver(receiver, holder)) {
+ break; // Custom-compiled handler.
+ }
+ TRACE_GENERIC_IC(isolate(), "StoreIC", "incompatible receiver");
+ TRACE_HANDLER_STATS(isolate(), StoreIC_SlowStub);
+ return slow_stub();
}
- int expected_arguments =
- function->shared()->internal_formal_parameter_count();
- return compiler.CompileStoreViaSetter(receiver, lookup->name(),
- lookup->GetAccessorIndex(),
- expected_arguments);
+ break; // Custom-compiled handler.
}
- break;
+ TRACE_HANDLER_STATS(isolate(), StoreIC_SlowStub);
+ return slow_stub();
}
case LookupIterator::DATA: {
if (lookup->is_dictionary_holder()) {
if (holder->IsJSGlobalObject()) {
- DCHECK(holder.is_identical_to(receiver) ||
- receiver->map()->prototype() == *holder);
- auto cell = lookup->GetPropertyCell();
- auto updated_type = PropertyCell::UpdatedType(
- cell, value, lookup->property_details());
- auto code = PropertyCellStoreHandler(
- isolate(), receiver, Handle<JSGlobalObject>::cast(holder),
- lookup->name(), cell, updated_type);
- return code;
+ break; // Custom-compiled handler.
}
+ TRACE_HANDLER_STATS(isolate(), StoreIC_StoreNormal);
DCHECK(holder.is_identical_to(receiver));
return isolate()->builtins()->StoreIC_Normal();
}
@@ -1813,18 +1712,19 @@ Handle<Code> StoreIC::CompileHandler(LookupIterator* lookup,
use_stub = !field_type->IsClass();
}
if (use_stub) {
+ TRACE_HANDLER_STATS(isolate(), StoreIC_StoreFieldStub);
StoreFieldStub stub(isolate(), lookup->GetFieldIndex(),
lookup->representation());
return stub.GetCode();
}
- NamedStoreHandlerCompiler compiler(isolate(), receiver_map(), holder);
- return compiler.CompileStoreField(lookup);
+ break; // Custom-compiled handler.
}
// -------------- Constant properties --------------
DCHECK(lookup->property_details().type() == DATA_CONSTANT);
TRACE_GENERIC_IC(isolate(), "StoreIC", "constant property");
- break;
+ TRACE_HANDLER_STATS(isolate(), StoreIC_SlowStub);
+ return slow_stub();
}
case LookupIterator::INTEGER_INDEXED_EXOTIC:
@@ -1833,22 +1733,134 @@ Handle<Code> StoreIC::CompileHandler(LookupIterator* lookup,
case LookupIterator::NOT_FOUND:
UNREACHABLE();
}
- return slow_stub();
+ return Handle<Code>::null();
}
+Handle<Code> StoreIC::CompileHandler(LookupIterator* lookup,
+ Handle<Object> value,
+ CacheHolderFlag cache_holder) {
+ DCHECK_NE(LookupIterator::JSPROXY, lookup->state());
+
+ // This is currently guaranteed by checks in StoreIC::Store.
+ Handle<JSObject> receiver = Handle<JSObject>::cast(lookup->GetReceiver());
+ Handle<JSObject> holder = lookup->GetHolder<JSObject>();
+ DCHECK(!receiver->IsAccessCheckNeeded() || lookup->name()->IsPrivate());
+
+ switch (lookup->state()) {
+ case LookupIterator::TRANSITION: {
+ auto store_target = lookup->GetStoreTarget();
+ if (store_target->IsJSGlobalObject()) {
+ TRACE_HANDLER_STATS(isolate(), StoreIC_StoreGlobalTransition);
+ Handle<PropertyCell> cell = lookup->transition_cell();
+ cell->set_value(*value);
+ Handle<Code> code = PropertyCellStoreHandler(
+ isolate(), store_target, Handle<JSGlobalObject>::cast(store_target),
+ lookup->name(), cell, PropertyCellType::kConstant);
+ cell->set_value(isolate()->heap()->the_hole_value());
+ return code;
+ }
+ Handle<Map> transition = lookup->transition_map();
+ // Currently not handled by CompileStoreTransition.
+ DCHECK(holder->HasFastProperties());
+
+ DCHECK(lookup->IsCacheableTransition());
+ TRACE_HANDLER_STATS(isolate(), StoreIC_StoreTransition);
+ NamedStoreHandlerCompiler compiler(isolate(), receiver_map(), holder);
+ return compiler.CompileStoreTransition(transition, lookup->name());
+ }
+
+ case LookupIterator::INTERCEPTOR:
+ UNREACHABLE();
+
+ case LookupIterator::ACCESSOR: {
+ DCHECK(holder->HasFastProperties());
+ Handle<Object> accessors = lookup->GetAccessors();
+ if (accessors->IsAccessorInfo()) {
+ Handle<AccessorInfo> info = Handle<AccessorInfo>::cast(accessors);
+ DCHECK(v8::ToCData<Address>(info->setter()) != 0);
+ DCHECK(!AccessorInfo::cast(*accessors)->is_special_data_property() ||
+ lookup->HolderIsReceiverOrHiddenPrototype());
+ DCHECK(AccessorInfo::IsCompatibleReceiverMap(isolate(), info,
+ receiver_map()));
+ DCHECK(!info->is_sloppy() || receiver->IsJSReceiver());
+ TRACE_HANDLER_STATS(isolate(), StoreIC_StoreCallback);
+ NamedStoreHandlerCompiler compiler(isolate(), receiver_map(), holder);
+ Handle<Code> code = compiler.CompileStoreCallback(
+ receiver, lookup->name(), info, language_mode());
+ return code;
+ } else {
+ DCHECK(accessors->IsAccessorPair());
+ Handle<Object> setter(Handle<AccessorPair>::cast(accessors)->setter(),
+ isolate());
+ DCHECK(setter->IsJSFunction() || setter->IsFunctionTemplateInfo());
+ CallOptimization call_optimization(setter);
+ NamedStoreHandlerCompiler compiler(isolate(), receiver_map(), holder);
+ if (call_optimization.is_simple_api_call()) {
+ DCHECK(call_optimization.IsCompatibleReceiver(receiver, holder));
+ TRACE_HANDLER_STATS(isolate(), StoreIC_StoreCallback);
+ Handle<Code> code = compiler.CompileStoreCallback(
+ receiver, lookup->name(), call_optimization,
+ lookup->GetAccessorIndex(), slow_stub());
+ return code;
+ }
+ TRACE_HANDLER_STATS(isolate(), StoreIC_StoreViaSetter);
+ int expected_arguments = JSFunction::cast(*setter)
+ ->shared()
+ ->internal_formal_parameter_count();
+ return compiler.CompileStoreViaSetter(receiver, lookup->name(),
+ lookup->GetAccessorIndex(),
+ expected_arguments);
+ }
+ }
+
+ case LookupIterator::DATA: {
+ if (lookup->is_dictionary_holder()) {
+ DCHECK(holder->IsJSGlobalObject());
+ TRACE_HANDLER_STATS(isolate(), StoreIC_StoreGlobal);
+ DCHECK(holder.is_identical_to(receiver) ||
+ receiver->map()->prototype() == *holder);
+ auto cell = lookup->GetPropertyCell();
+ auto updated_type =
+ PropertyCell::UpdatedType(cell, value, lookup->property_details());
+ auto code = PropertyCellStoreHandler(
+ isolate(), receiver, Handle<JSGlobalObject>::cast(holder),
+ lookup->name(), cell, updated_type);
+ return code;
+ }
-Handle<Code> KeyedStoreIC::StoreElementStub(Handle<Map> receiver_map,
- KeyedAccessStoreMode store_mode) {
- Handle<Code> null_handle;
- // Don't handle megamorphic property accesses for INTERCEPTORS or
- // ACCESSOR_CONSTANT
- // via megamorphic stubs, since they don't have a map in their relocation info
- // and so the stubs can't be harvested for the object needed for a map check.
- if (target()->type() != Code::NORMAL) {
- TRACE_GENERIC_IC(isolate(), "KeyedStoreIC", "non-NORMAL target type");
- return megamorphic_stub();
+ // -------------- Fields --------------
+ if (lookup->property_details().type() == DATA) {
+#ifdef DEBUG
+ bool use_stub = true;
+ if (lookup->representation().IsHeapObject()) {
+ // Only use a generic stub if no types need to be tracked.
+ Handle<FieldType> field_type = lookup->GetFieldType();
+ use_stub = !field_type->IsClass();
+ }
+ DCHECK(!use_stub);
+#endif
+ TRACE_HANDLER_STATS(isolate(), StoreIC_StoreField);
+ NamedStoreHandlerCompiler compiler(isolate(), receiver_map(), holder);
+ return compiler.CompileStoreField(lookup);
+ }
+
+ // -------------- Constant properties --------------
+ DCHECK(lookup->property_details().type() == DATA_CONSTANT);
+ UNREACHABLE();
+ }
+
+ case LookupIterator::INTEGER_INDEXED_EXOTIC:
+ case LookupIterator::ACCESS_CHECK:
+ case LookupIterator::JSPROXY:
+ case LookupIterator::NOT_FOUND:
+ UNREACHABLE();
}
+ UNREACHABLE();
+ return slow_stub();
+}
+void KeyedStoreIC::UpdateStoreElement(Handle<Map> receiver_map,
+ KeyedAccessStoreMode store_mode) {
MapHandleList target_receiver_maps;
TargetMaps(&target_receiver_maps);
if (target_receiver_maps.length() == 0) {
@@ -1856,10 +1868,17 @@ Handle<Code> KeyedStoreIC::StoreElementStub(Handle<Map> receiver_map,
ComputeTransitionedMap(receiver_map, store_mode);
store_mode = GetNonTransitioningStoreMode(store_mode);
Handle<Code> handler =
- PropertyICCompiler::ComputeKeyedStoreMonomorphicHandler(
- monomorphic_map, language_mode(), store_mode);
- ConfigureVectorState(Handle<Name>::null(), monomorphic_map, handler);
- return null_handle;
+ PropertyICCompiler::ComputeKeyedStoreMonomorphicHandler(monomorphic_map,
+ store_mode);
+ return ConfigureVectorState(Handle<Name>(), monomorphic_map, handler);
+ }
+
+ for (int i = 0; i < target_receiver_maps.length(); i++) {
+ if (!target_receiver_maps.at(i).is_null() &&
+ target_receiver_maps.at(i)->instance_type() == JS_VALUE_TYPE) {
+ TRACE_GENERIC_IC(isolate(), "KeyedStoreIC", "JSValue");
+ return;
+ }
}
// There are several special cases where an IC that is MONOMORPHIC can still
@@ -1884,23 +1903,22 @@ Handle<Code> KeyedStoreIC::StoreElementStub(Handle<Map> receiver_map,
store_mode = GetNonTransitioningStoreMode(store_mode);
Handle<Code> handler =
PropertyICCompiler::ComputeKeyedStoreMonomorphicHandler(
- transitioned_receiver_map, language_mode(), store_mode);
- ConfigureVectorState(Handle<Name>::null(), transitioned_receiver_map,
- handler);
- return null_handle;
- } else if (receiver_map.is_identical_to(previous_receiver_map) &&
- old_store_mode == STANDARD_STORE &&
- (store_mode == STORE_AND_GROW_NO_TRANSITION ||
- store_mode == STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS ||
- store_mode == STORE_NO_TRANSITION_HANDLE_COW)) {
+ transitioned_receiver_map, store_mode);
+ ConfigureVectorState(Handle<Name>(), transitioned_receiver_map, handler);
+ return;
+ }
+ if (receiver_map.is_identical_to(previous_receiver_map) &&
+ old_store_mode == STANDARD_STORE &&
+ (store_mode == STORE_AND_GROW_NO_TRANSITION ||
+ store_mode == STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS ||
+ store_mode == STORE_NO_TRANSITION_HANDLE_COW)) {
// A "normal" IC that handles stores can switch to a version that can
// grow at the end of the array, handle OOB accesses or copy COW arrays
// and still stay MONOMORPHIC.
Handle<Code> handler =
- PropertyICCompiler::ComputeKeyedStoreMonomorphicHandler(
- receiver_map, language_mode(), store_mode);
- ConfigureVectorState(Handle<Name>::null(), receiver_map, handler);
- return null_handle;
+ PropertyICCompiler::ComputeKeyedStoreMonomorphicHandler(receiver_map,
+ store_mode);
+ return ConfigureVectorState(Handle<Name>(), receiver_map, handler);
}
}
@@ -1920,14 +1938,12 @@ Handle<Code> KeyedStoreIC::StoreElementStub(Handle<Map> receiver_map,
// If the miss wasn't due to an unseen map, a polymorphic stub
// won't help, use the megamorphic stub which can handle everything.
TRACE_GENERIC_IC(isolate(), "KeyedStoreIC", "same map added twice");
- return megamorphic_stub();
+ return;
}
// If the maximum number of receiver maps has been exceeded, use the
// megamorphic version of the IC.
- if (target_receiver_maps.length() > kMaxKeyedPolymorphism) {
- return megamorphic_stub();
- }
+ if (target_receiver_maps.length() > kMaxKeyedPolymorphism) return;
// Make sure all polymorphic handlers have the same store mode, otherwise the
// megamorphic stub must be used.
@@ -1937,7 +1953,7 @@ Handle<Code> KeyedStoreIC::StoreElementStub(Handle<Map> receiver_map,
store_mode = old_store_mode;
} else if (store_mode != old_store_mode) {
TRACE_GENERIC_IC(isolate(), "KeyedStoreIC", "store mode mismatch");
- return megamorphic_stub();
+ return;
}
}
@@ -1955,17 +1971,16 @@ Handle<Code> KeyedStoreIC::StoreElementStub(Handle<Map> receiver_map,
external_arrays != target_receiver_maps.length()) {
TRACE_GENERIC_IC(isolate(), "KeyedStoreIC",
"unsupported combination of external and normal arrays");
- return megamorphic_stub();
+ return;
}
}
+ TRACE_HANDLER_STATS(isolate(), KeyedStoreIC_Polymorphic);
MapHandleList transitioned_maps(target_receiver_maps.length());
CodeHandleList handlers(target_receiver_maps.length());
PropertyICCompiler::ComputeKeyedStorePolymorphicHandlers(
- &target_receiver_maps, &transitioned_maps, &handlers, store_mode,
- language_mode());
+ &target_receiver_maps, &transitioned_maps, &handlers, store_mode);
ConfigureVectorState(&target_receiver_maps, &transitioned_maps, &handlers);
- return null_handle;
}
@@ -2078,7 +2093,6 @@ MaybeHandle<Object> KeyedStoreIC::Store(Handle<Object> object,
key = TryConvertKey(key, isolate());
Handle<Object> store_handle;
- Handle<Code> stub = megamorphic_stub();
uint32_t index;
if ((key->IsInternalizedString() &&
@@ -2098,10 +2112,8 @@ MaybeHandle<Object> KeyedStoreIC::Store(Handle<Object> object,
return store_handle;
}
- bool use_ic =
- FLAG_use_ic && !object->IsStringWrapper() &&
- !object->IsAccessCheckNeeded() && !object->IsJSGlobalProxy() &&
- !(object->IsJSObject() && JSObject::cast(*object)->map()->is_observed());
+ bool use_ic = FLAG_use_ic && !object->IsStringWrapper() &&
+ !object->IsAccessCheckNeeded() && !object->IsJSGlobalProxy();
if (use_ic && !object->IsSmi()) {
// Don't use ICs for maps of the objects in Array's prototype chain. We
// expect to be able to trap element sets to objects with those maps in
@@ -2149,7 +2161,7 @@ MaybeHandle<Object> KeyedStoreIC::Store(Handle<Object> object,
// other non-dictionary receivers in the polymorphic case benefit
// from fast path keyed stores.
if (!old_receiver_map->DictionaryElementsInPrototypeChainOnly()) {
- stub = StoreElementStub(old_receiver_map, store_mode);
+ UpdateStoreElement(old_receiver_map, store_mode);
} else {
TRACE_GENERIC_IC(isolate(), "KeyedStoreIC",
"dictionary or proxy prototype");
@@ -2162,13 +2174,9 @@ MaybeHandle<Object> KeyedStoreIC::Store(Handle<Object> object,
}
}
- if (!is_vector_set() || stub.is_null()) {
- Code* megamorphic = *megamorphic_stub();
- if (!stub.is_null() && (*stub == megamorphic || *stub == *slow_stub())) {
- ConfigureVectorState(MEGAMORPHIC, key);
- TRACE_GENERIC_IC(isolate(), "KeyedStoreIC",
- *stub == megamorphic ? "set generic" : "slow stub");
- }
+ if (!is_vector_set()) {
+ ConfigureVectorState(MEGAMORPHIC, key);
+ TRACE_GENERIC_IC(isolate(), "KeyedStoreIC", "set generic");
}
TRACE_IC("StoreIC", key);
@@ -2228,7 +2236,6 @@ void CallIC::HandleMiss(Handle<Object> function) {
// Used from ic-<arch>.cc.
RUNTIME_FUNCTION(Runtime_CallIC_Miss) {
TimerEventScope<TimerEventIcMiss> timer(isolate);
- TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8"), "V8.IcMiss");
HandleScope scope(isolate);
DCHECK(args.length() == 3);
Handle<Object> function = args.at<Object>(0);
@@ -2245,44 +2252,120 @@ RUNTIME_FUNCTION(Runtime_CallIC_Miss) {
// Used from ic-<arch>.cc.
RUNTIME_FUNCTION(Runtime_LoadIC_Miss) {
TimerEventScope<TimerEventIcMiss> timer(isolate);
- TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8"), "V8.IcMiss");
HandleScope scope(isolate);
Handle<Object> receiver = args.at<Object>(0);
- Handle<Name> key = args.at<Name>(1);
- Handle<Object> result;
- DCHECK(args.length() == 4);
+ DCHECK_EQ(4, args.length());
Handle<Smi> slot = args.at<Smi>(2);
Handle<TypeFeedbackVector> vector = args.at<TypeFeedbackVector>(3);
FeedbackVectorSlot vector_slot = vector->ToSlot(slot->value());
// A monomorphic or polymorphic KeyedLoadIC with a string key can call the
// LoadIC miss handler if the handler misses. Since the vector Nexus is
// set up outside the IC, handle that here.
- if (vector->GetKind(vector_slot) == FeedbackVectorSlotKind::LOAD_IC) {
+ FeedbackVectorSlotKind kind = vector->GetKind(vector_slot);
+ if (kind == FeedbackVectorSlotKind::LOAD_IC) {
+ Handle<Name> key = args.at<Name>(1);
LoadICNexus nexus(vector, vector_slot);
LoadIC ic(IC::NO_EXTRA_FRAME, isolate, &nexus);
ic.UpdateState(receiver, key);
- ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result, ic.Load(receiver, key));
+ RETURN_RESULT_OR_FAILURE(isolate, ic.Load(receiver, key));
+
+ } else if (kind == FeedbackVectorSlotKind::LOAD_GLOBAL_IC) {
+ Handle<Name> key(vector->GetName(vector_slot), isolate);
+ DCHECK_NE(*key, *isolate->factory()->empty_string());
+ DCHECK_EQ(*isolate->global_object(), *receiver);
+ LoadGlobalICNexus nexus(vector, vector_slot);
+ LoadGlobalIC ic(IC::NO_EXTRA_FRAME, isolate, &nexus);
+ ic.UpdateState(receiver, key);
+ RETURN_RESULT_OR_FAILURE(isolate, ic.Load(key));
+
} else {
- DCHECK_EQ(FeedbackVectorSlotKind::KEYED_LOAD_IC,
- vector->GetKind(vector_slot));
+ Handle<Name> key = args.at<Name>(1);
+ DCHECK_EQ(FeedbackVectorSlotKind::KEYED_LOAD_IC, kind);
KeyedLoadICNexus nexus(vector, vector_slot);
KeyedLoadIC ic(IC::NO_EXTRA_FRAME, isolate, &nexus);
ic.UpdateState(receiver, key);
- ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result, ic.Load(receiver, key));
+ RETURN_RESULT_OR_FAILURE(isolate, ic.Load(receiver, key));
}
+}
+
+// Used from ic-<arch>.cc.
+RUNTIME_FUNCTION(Runtime_LoadGlobalIC_Miss) {
+ TimerEventScope<TimerEventIcMiss> timer(isolate);
+ HandleScope scope(isolate);
+ DCHECK_EQ(2, args.length());
+ Handle<JSGlobalObject> global = isolate->global_object();
+ Handle<Smi> slot = args.at<Smi>(0);
+ Handle<TypeFeedbackVector> vector = args.at<TypeFeedbackVector>(1);
+ FeedbackVectorSlot vector_slot = vector->ToSlot(slot->value());
+ DCHECK_EQ(FeedbackVectorSlotKind::LOAD_GLOBAL_IC,
+ vector->GetKind(vector_slot));
+ Handle<String> name(vector->GetName(vector_slot), isolate);
+ DCHECK_NE(*name, *isolate->factory()->empty_string());
+
+ LoadGlobalICNexus nexus(vector, vector_slot);
+ LoadGlobalIC ic(IC::NO_EXTRA_FRAME, isolate, &nexus);
+ ic.UpdateState(global, name);
+
+ Handle<Object> result;
+ ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result, ic.Load(name));
return *result;
}
+RUNTIME_FUNCTION(Runtime_LoadGlobalIC_Slow) {
+ HandleScope scope(isolate);
+ DCHECK_EQ(2, args.length());
+ CONVERT_SMI_ARG_CHECKED(slot, 0);
+ CONVERT_ARG_HANDLE_CHECKED(TypeFeedbackVector, vector, 1);
+
+ FeedbackVectorSlot vector_slot = vector->ToSlot(slot);
+ DCHECK_EQ(FeedbackVectorSlotKind::LOAD_GLOBAL_IC,
+ vector->GetKind(vector_slot));
+ Handle<String> name(vector->GetName(vector_slot), isolate);
+ DCHECK_NE(*name, *isolate->factory()->empty_string());
+
+ Handle<JSGlobalObject> global = isolate->global_object();
+
+ Handle<ScriptContextTable> script_contexts(
+ global->native_context()->script_context_table());
+
+ ScriptContextTable::LookupResult lookup_result;
+ if (ScriptContextTable::Lookup(script_contexts, name, &lookup_result)) {
+ Handle<Context> script_context = ScriptContextTable::GetContext(
+ script_contexts, lookup_result.context_index);
+ Handle<Object> result =
+ FixedArray::get(*script_context, lookup_result.slot_index, isolate);
+ if (*result == *isolate->factory()->the_hole_value()) {
+ THROW_NEW_ERROR_RETURN_FAILURE(
+ isolate, NewReferenceError(MessageTemplate::kNotDefined, name));
+ }
+ return *result;
+ }
+
+ Handle<Object> result;
+ bool is_found = false;
+ ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
+ isolate, result,
+ Runtime::GetObjectProperty(isolate, global, name, &is_found));
+ if (!is_found) {
+ LoadICNexus nexus(isolate);
+ LoadIC ic(IC::NO_EXTRA_FRAME, isolate, &nexus);
+ // It is actually a LoadGlobalICs here but the predicate handles this case
+ // properly.
+ if (ic.ShouldThrowReferenceError()) {
+ THROW_NEW_ERROR_RETURN_FAILURE(
+ isolate, NewReferenceError(MessageTemplate::kNotDefined, name));
+ }
+ }
+ return *result;
+}
// Used from ic-<arch>.cc
RUNTIME_FUNCTION(Runtime_KeyedLoadIC_Miss) {
TimerEventScope<TimerEventIcMiss> timer(isolate);
- TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8"), "V8.IcMiss");
HandleScope scope(isolate);
Handle<Object> receiver = args.at<Object>(0);
Handle<Object> key = args.at<Object>(1);
- Handle<Object> result;
DCHECK(args.length() == 4);
Handle<Smi> slot = args.at<Smi>(2);
@@ -2291,41 +2374,35 @@ RUNTIME_FUNCTION(Runtime_KeyedLoadIC_Miss) {
KeyedLoadICNexus nexus(vector, vector_slot);
KeyedLoadIC ic(IC::NO_EXTRA_FRAME, isolate, &nexus);
ic.UpdateState(receiver, key);
- ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result, ic.Load(receiver, key));
- return *result;
+ RETURN_RESULT_OR_FAILURE(isolate, ic.Load(receiver, key));
}
RUNTIME_FUNCTION(Runtime_KeyedLoadIC_MissFromStubFailure) {
TimerEventScope<TimerEventIcMiss> timer(isolate);
- TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8"), "V8.IcMiss");
HandleScope scope(isolate);
- Handle<Object> receiver = args.at<Object>(0);
- Handle<Object> key = args.at<Object>(1);
- Handle<Object> result;
-
- DCHECK(args.length() == 4);
- Handle<Smi> slot = args.at<Smi>(2);
- Handle<TypeFeedbackVector> vector = args.at<TypeFeedbackVector>(3);
+ DCHECK_EQ(4, args.length());
+ typedef LoadWithVectorDescriptor Descriptor;
+ Handle<Object> receiver = args.at<Object>(Descriptor::kReceiver);
+ Handle<Object> key = args.at<Object>(Descriptor::kName);
+ Handle<Smi> slot = args.at<Smi>(Descriptor::kSlot);
+ Handle<TypeFeedbackVector> vector =
+ args.at<TypeFeedbackVector>(Descriptor::kVector);
FeedbackVectorSlot vector_slot = vector->ToSlot(slot->value());
KeyedLoadICNexus nexus(vector, vector_slot);
KeyedLoadIC ic(IC::EXTRA_CALL_FRAME, isolate, &nexus);
ic.UpdateState(receiver, key);
- ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result, ic.Load(receiver, key));
-
- return *result;
+ RETURN_RESULT_OR_FAILURE(isolate, ic.Load(receiver, key));
}
// Used from ic-<arch>.cc.
RUNTIME_FUNCTION(Runtime_StoreIC_Miss) {
TimerEventScope<TimerEventIcMiss> timer(isolate);
- TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8"), "V8.IcMiss");
HandleScope scope(isolate);
Handle<Object> receiver = args.at<Object>(0);
Handle<Name> key = args.at<Name>(1);
Handle<Object> value = args.at<Object>(2);
- Handle<Object> result;
DCHECK(args.length() == 5 || args.length() == 6);
Handle<Smi> slot = args.at<Smi>(3);
@@ -2335,32 +2412,58 @@ RUNTIME_FUNCTION(Runtime_StoreIC_Miss) {
StoreICNexus nexus(vector, vector_slot);
StoreIC ic(IC::NO_EXTRA_FRAME, isolate, &nexus);
ic.UpdateState(receiver, key);
- ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result,
- ic.Store(receiver, key, value));
+ RETURN_RESULT_OR_FAILURE(isolate, ic.Store(receiver, key, value));
} else {
DCHECK_EQ(FeedbackVectorSlotKind::KEYED_STORE_IC,
vector->GetKind(vector_slot));
KeyedStoreICNexus nexus(vector, vector_slot);
KeyedStoreIC ic(IC::NO_EXTRA_FRAME, isolate, &nexus);
ic.UpdateState(receiver, key);
- ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result,
- ic.Store(receiver, key, value));
+ RETURN_RESULT_OR_FAILURE(isolate, ic.Store(receiver, key, value));
}
- return *result;
}
RUNTIME_FUNCTION(Runtime_StoreIC_MissFromStubFailure) {
TimerEventScope<TimerEventIcMiss> timer(isolate);
- TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8"), "V8.IcMiss");
+ HandleScope scope(isolate);
+ DCHECK_EQ(5, args.length());
+ typedef StoreWithVectorDescriptor Descriptor;
+ Handle<Object> receiver = args.at<Object>(Descriptor::kReceiver);
+ Handle<Name> key = args.at<Name>(Descriptor::kName);
+ Handle<Object> value = args.at<Object>(Descriptor::kValue);
+ Handle<Smi> slot = args.at<Smi>(Descriptor::kSlot);
+ Handle<TypeFeedbackVector> vector =
+ args.at<TypeFeedbackVector>(Descriptor::kVector);
+
+ FeedbackVectorSlot vector_slot = vector->ToSlot(slot->value());
+ if (vector->GetKind(vector_slot) == FeedbackVectorSlotKind::STORE_IC) {
+ StoreICNexus nexus(vector, vector_slot);
+ StoreIC ic(IC::EXTRA_CALL_FRAME, isolate, &nexus);
+ ic.UpdateState(receiver, key);
+ RETURN_RESULT_OR_FAILURE(isolate, ic.Store(receiver, key, value));
+ } else {
+ DCHECK_EQ(FeedbackVectorSlotKind::KEYED_STORE_IC,
+ vector->GetKind(vector_slot));
+ KeyedStoreICNexus nexus(vector, vector_slot);
+ KeyedStoreIC ic(IC::EXTRA_CALL_FRAME, isolate, &nexus);
+ ic.UpdateState(receiver, key);
+ RETURN_RESULT_OR_FAILURE(isolate, ic.Store(receiver, key, value));
+ }
+}
+
+RUNTIME_FUNCTION(Runtime_TransitionStoreIC_MissFromStubFailure) {
+ TimerEventScope<TimerEventIcMiss> timer(isolate);
HandleScope scope(isolate);
Handle<Object> receiver = args.at<Object>(0);
Handle<Name> key = args.at<Name>(1);
Handle<Object> value = args.at<Object>(2);
- Handle<Object> result;
int length = args.length();
DCHECK(length == 5 || length == 6);
+ // TODO(ishell): use VectorStoreTransitionDescriptor indices here and update
+ // this comment:
+ //
// We might have slot and vector, for a normal miss (slot(3), vector(4)).
// Or, map and vector for a transitioning store miss (map(3), vector(4)).
// In this case, we need to recover the slot from a virtual register.
@@ -2368,15 +2471,10 @@ RUNTIME_FUNCTION(Runtime_StoreIC_MissFromStubFailure) {
Handle<Smi> slot;
Handle<TypeFeedbackVector> vector;
if (length == 5) {
- if (args.at<Object>(3)->IsMap()) {
- vector = args.at<TypeFeedbackVector>(4);
- slot = handle(
- *reinterpret_cast<Smi**>(isolate->virtual_slot_register_address()),
- isolate);
- } else {
- vector = args.at<TypeFeedbackVector>(4);
- slot = args.at<Smi>(3);
- }
+ vector = args.at<TypeFeedbackVector>(4);
+ slot = handle(
+ *reinterpret_cast<Smi**>(isolate->virtual_slot_register_address()),
+ isolate);
} else {
vector = args.at<TypeFeedbackVector>(5);
slot = args.at<Smi>(4);
@@ -2387,87 +2485,57 @@ RUNTIME_FUNCTION(Runtime_StoreIC_MissFromStubFailure) {
StoreICNexus nexus(vector, vector_slot);
StoreIC ic(IC::EXTRA_CALL_FRAME, isolate, &nexus);
ic.UpdateState(receiver, key);
- ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result,
- ic.Store(receiver, key, value));
+ RETURN_RESULT_OR_FAILURE(isolate, ic.Store(receiver, key, value));
} else {
DCHECK_EQ(FeedbackVectorSlotKind::KEYED_STORE_IC,
vector->GetKind(vector_slot));
KeyedStoreICNexus nexus(vector, vector_slot);
KeyedStoreIC ic(IC::EXTRA_CALL_FRAME, isolate, &nexus);
ic.UpdateState(receiver, key);
- ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result,
- ic.Store(receiver, key, value));
+ RETURN_RESULT_OR_FAILURE(isolate, ic.Store(receiver, key, value));
}
- return *result;
}
-
// Used from ic-<arch>.cc.
RUNTIME_FUNCTION(Runtime_KeyedStoreIC_Miss) {
TimerEventScope<TimerEventIcMiss> timer(isolate);
- TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8"), "V8.IcMiss");
HandleScope scope(isolate);
+ DCHECK_EQ(5, args.length());
Handle<Object> receiver = args.at<Object>(0);
Handle<Object> key = args.at<Object>(1);
Handle<Object> value = args.at<Object>(2);
- Handle<Object> result;
-
- DCHECK(args.length() == 5);
Handle<Smi> slot = args.at<Smi>(3);
Handle<TypeFeedbackVector> vector = args.at<TypeFeedbackVector>(4);
FeedbackVectorSlot vector_slot = vector->ToSlot(slot->value());
KeyedStoreICNexus nexus(vector, vector_slot);
KeyedStoreIC ic(IC::NO_EXTRA_FRAME, isolate, &nexus);
ic.UpdateState(receiver, key);
- ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result,
- ic.Store(receiver, key, value));
- return *result;
+ RETURN_RESULT_OR_FAILURE(isolate, ic.Store(receiver, key, value));
}
RUNTIME_FUNCTION(Runtime_KeyedStoreIC_MissFromStubFailure) {
TimerEventScope<TimerEventIcMiss> timer(isolate);
- TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8"), "V8.IcMiss");
HandleScope scope(isolate);
- Handle<Object> receiver = args.at<Object>(0);
- Handle<Object> key = args.at<Object>(1);
- Handle<Object> value = args.at<Object>(2);
- Handle<Object> result;
-
- DCHECK(args.length() == 5);
- Handle<Smi> slot = args.at<Smi>(3);
- Handle<TypeFeedbackVector> vector = args.at<TypeFeedbackVector>(4);
+ DCHECK_EQ(5, args.length());
+ typedef StoreWithVectorDescriptor Descriptor;
+ Handle<Object> receiver = args.at<Object>(Descriptor::kReceiver);
+ Handle<Object> key = args.at<Object>(Descriptor::kName);
+ Handle<Object> value = args.at<Object>(Descriptor::kValue);
+ Handle<Smi> slot = args.at<Smi>(Descriptor::kSlot);
+ Handle<TypeFeedbackVector> vector =
+ args.at<TypeFeedbackVector>(Descriptor::kVector);
FeedbackVectorSlot vector_slot = vector->ToSlot(slot->value());
KeyedStoreICNexus nexus(vector, vector_slot);
KeyedStoreIC ic(IC::EXTRA_CALL_FRAME, isolate, &nexus);
ic.UpdateState(receiver, key);
- ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result,
- ic.Store(receiver, key, value));
- return *result;
-}
-
-
-RUNTIME_FUNCTION(Runtime_StoreIC_Slow) {
- HandleScope scope(isolate);
- DCHECK(args.length() == 5);
- Handle<Object> object = args.at<Object>(0);
- Handle<Object> key = args.at<Object>(1);
- Handle<Object> value = args.at<Object>(2);
- LanguageMode language_mode;
- StoreICNexus nexus(isolate);
- StoreIC ic(IC::NO_EXTRA_FRAME, isolate, &nexus);
- language_mode = ic.language_mode();
- Handle<Object> result;
- ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
- isolate, result,
- Runtime::SetObjectProperty(isolate, object, key, value, language_mode));
- return *result;
+ RETURN_RESULT_OR_FAILURE(isolate, ic.Store(receiver, key, value));
}
RUNTIME_FUNCTION(Runtime_KeyedStoreIC_Slow) {
HandleScope scope(isolate);
- DCHECK(args.length() == 5);
+ DCHECK_EQ(5, args.length());
Handle<Object> object = args.at<Object>(0);
Handle<Object> key = args.at<Object>(1);
Handle<Object> value = args.at<Object>(2);
@@ -2475,17 +2543,14 @@ RUNTIME_FUNCTION(Runtime_KeyedStoreIC_Slow) {
KeyedStoreICNexus nexus(isolate);
KeyedStoreIC ic(IC::NO_EXTRA_FRAME, isolate, &nexus);
language_mode = ic.language_mode();
- Handle<Object> result;
- ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
- isolate, result,
+ RETURN_RESULT_OR_FAILURE(
+ isolate,
Runtime::SetObjectProperty(isolate, object, key, value, language_mode));
- return *result;
}
RUNTIME_FUNCTION(Runtime_ElementsTransitionAndStoreIC_Miss) {
TimerEventScope<TimerEventIcMiss> timer(isolate);
- TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8"), "V8.IcMiss");
HandleScope scope(isolate);
// Length == 5 or 6, depending on whether the vector slot
// is passed in a virtual register or not.
@@ -2502,18 +2567,16 @@ RUNTIME_FUNCTION(Runtime_ElementsTransitionAndStoreIC_Miss) {
JSObject::TransitionElementsKind(Handle<JSObject>::cast(object),
map->elements_kind());
}
- Handle<Object> result;
- ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
- isolate, result,
+ RETURN_RESULT_OR_FAILURE(
+ isolate,
Runtime::SetObjectProperty(isolate, object, key, value, language_mode));
- return *result;
}
MaybeHandle<Object> BinaryOpIC::Transition(
Handle<AllocationSite> allocation_site, Handle<Object> left,
Handle<Object> right) {
- BinaryOpICState state(isolate(), target()->extra_ic_state());
+ BinaryOpICState state(isolate(), extra_ic_state());
// Compute the actual result using the builtin for the binary operation.
Handle<Object> result;
@@ -2577,16 +2640,12 @@ MaybeHandle<Object> BinaryOpIC::Transition(
return result;
}
- // Execution::Call can execute arbitrary JavaScript, hence potentially
- // update the state of this very IC, so we must update the stored state.
- UpdateTarget();
-
// Compute the new state.
BinaryOpICState old_state(isolate(), target()->extra_ic_state());
state.Update(left, right, result);
// Check if we have a string operation here.
- Handle<Code> target;
+ Handle<Code> new_target;
if (!allocation_site.is_null() || state.ShouldCreateAllocationMementos()) {
// Setup the allocation site on-demand.
if (allocation_site.is_null()) {
@@ -2595,24 +2654,24 @@ MaybeHandle<Object> BinaryOpIC::Transition(
// Install the stub with an allocation site.
BinaryOpICWithAllocationSiteStub stub(isolate(), state);
- target = stub.GetCodeCopyFromTemplate(allocation_site);
+ new_target = stub.GetCodeCopyFromTemplate(allocation_site);
// Sanity check the trampoline stub.
- DCHECK_EQ(*allocation_site, target->FindFirstAllocationSite());
+ DCHECK_EQ(*allocation_site, new_target->FindFirstAllocationSite());
} else {
// Install the generic stub.
BinaryOpICStub stub(isolate(), state);
- target = stub.GetCode();
+ new_target = stub.GetCode();
// Sanity check the generic stub.
- DCHECK_NULL(target->FindFirstAllocationSite());
+ DCHECK_NULL(new_target->FindFirstAllocationSite());
}
- set_target(*target);
+ set_target(*new_target);
if (FLAG_trace_ic) {
OFStream os(stdout);
os << "[BinaryOpIC" << old_state << " => " << state << " @ "
- << static_cast<void*>(*target) << " <- ";
+ << static_cast<void*>(*new_target) << " <- ";
JavaScriptFrame::PrintTop(isolate(), stdout, false, true);
if (!allocation_site.is_null()) {
os << " using allocation site " << static_cast<void*>(*allocation_site);
@@ -2633,35 +2692,29 @@ MaybeHandle<Object> BinaryOpIC::Transition(
RUNTIME_FUNCTION(Runtime_BinaryOpIC_Miss) {
TimerEventScope<TimerEventIcMiss> timer(isolate);
- TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8"), "V8.IcMiss");
HandleScope scope(isolate);
DCHECK_EQ(2, args.length());
- Handle<Object> left = args.at<Object>(BinaryOpICStub::kLeft);
- Handle<Object> right = args.at<Object>(BinaryOpICStub::kRight);
+ typedef BinaryOpDescriptor Descriptor;
+ Handle<Object> left = args.at<Object>(Descriptor::kLeft);
+ Handle<Object> right = args.at<Object>(Descriptor::kRight);
BinaryOpIC ic(isolate);
- Handle<Object> result;
- ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
- isolate, result,
- ic.Transition(Handle<AllocationSite>::null(), left, right));
- return *result;
+ RETURN_RESULT_OR_FAILURE(
+ isolate, ic.Transition(Handle<AllocationSite>::null(), left, right));
}
RUNTIME_FUNCTION(Runtime_BinaryOpIC_MissWithAllocationSite) {
TimerEventScope<TimerEventIcMiss> timer(isolate);
- TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8"), "V8.IcMiss");
HandleScope scope(isolate);
DCHECK_EQ(3, args.length());
+ typedef BinaryOpWithAllocationSiteDescriptor Descriptor;
Handle<AllocationSite> allocation_site =
- args.at<AllocationSite>(BinaryOpWithAllocationSiteStub::kAllocationSite);
- Handle<Object> left = args.at<Object>(BinaryOpWithAllocationSiteStub::kLeft);
- Handle<Object> right =
- args.at<Object>(BinaryOpWithAllocationSiteStub::kRight);
+ args.at<AllocationSite>(Descriptor::kAllocationSite);
+ Handle<Object> left = args.at<Object>(Descriptor::kLeft);
+ Handle<Object> right = args.at<Object>(Descriptor::kRight);
BinaryOpIC ic(isolate);
- Handle<Object> result;
- ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
- isolate, result, ic.Transition(allocation_site, left, right));
- return *result;
+ RETURN_RESULT_OR_FAILURE(isolate,
+ ic.Transition(allocation_site, left, right));
}
Code* CompareIC::GetRawUninitialized(Isolate* isolate, Token::Value op) {
@@ -2673,14 +2726,6 @@ Code* CompareIC::GetRawUninitialized(Isolate* isolate, Token::Value op) {
return code;
}
-Handle<Code> CompareIC::GetUninitialized(Isolate* isolate, Token::Value op) {
- CompareICStub stub(isolate, op, CompareICState::UNINITIALIZED,
- CompareICState::UNINITIALIZED,
- CompareICState::UNINITIALIZED);
- return stub.GetCode();
-}
-
-
Code* CompareIC::UpdateCaches(Handle<Object> x, Handle<Object> y) {
HandleScope scope(isolate());
CompareICStub old_stub(target()->stub_key(), isolate());
@@ -2689,7 +2734,7 @@ Code* CompareIC::UpdateCaches(Handle<Object> x, Handle<Object> y) {
CompareICState::State new_right =
CompareICState::NewInputState(old_stub.right(), y);
CompareICState::State state = CompareICState::TargetState(
- old_stub.state(), old_stub.left(), old_stub.right(), op_,
+ isolate(), old_stub.state(), old_stub.left(), old_stub.right(), op_,
HasInlinedSmiCode(address()), x, y);
CompareICStub stub(isolate(), op_, new_left, new_right, state);
if (state == CompareICState::KNOWN_RECEIVER) {
@@ -2724,7 +2769,6 @@ Code* CompareIC::UpdateCaches(Handle<Object> x, Handle<Object> y) {
// Used from CompareICStub::GenerateMiss in code-stubs-<arch>.cc.
RUNTIME_FUNCTION(Runtime_CompareIC_Miss) {
TimerEventScope<TimerEventIcMiss> timer(isolate);
- TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8"), "V8.IcMiss");
HandleScope scope(isolate);
DCHECK(args.length() == 3);
CompareIC ic(isolate, static_cast<Token::Value>(args.smi_at(2)));
@@ -2740,7 +2784,7 @@ RUNTIME_FUNCTION(Runtime_Unreachable) {
Handle<Object> ToBooleanIC::ToBoolean(Handle<Object> object) {
- ToBooleanICStub stub(isolate(), target()->extra_ic_state());
+ ToBooleanICStub stub(isolate(), extra_ic_state());
bool to_boolean_value = stub.UpdateStatus(object);
Handle<Code> code = stub.GetCode();
set_target(*code);
@@ -2750,7 +2794,6 @@ Handle<Object> ToBooleanIC::ToBoolean(Handle<Object> object) {
RUNTIME_FUNCTION(Runtime_ToBooleanIC_Miss) {
TimerEventScope<TimerEventIcMiss> timer(isolate);
- TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8"), "V8.IcMiss");
DCHECK(args.length() == 1);
HandleScope scope(isolate);
Handle<Object> object = args.at<Object>(0);
@@ -2768,6 +2811,12 @@ RUNTIME_FUNCTION(Runtime_StoreCallbackProperty) {
CONVERT_LANGUAGE_MODE_ARG_CHECKED(language_mode, 5);
HandleScope scope(isolate);
+ if (FLAG_runtime_call_stats) {
+ RETURN_RESULT_OR_FAILURE(
+ isolate, Runtime::SetObjectProperty(isolate, receiver, name, value,
+ language_mode));
+ }
+
Handle<AccessorInfo> callback(
callback_or_cell->IsWeakCell()
? AccessorInfo::cast(WeakCell::cast(*callback_or_cell)->value())
@@ -2873,15 +2922,15 @@ RUNTIME_FUNCTION(Runtime_LoadPropertyWithInterceptor) {
if (it.IsFound()) return *result;
+#ifdef DEBUG
LoadICNexus nexus(isolate);
LoadIC ic(IC::NO_EXTRA_FRAME, isolate, &nexus);
- if (!ic.ShouldThrowReferenceError(it.GetReceiver())) {
- return isolate->heap()->undefined_value();
- }
+ // It could actually be any kind of LoadICs here but the predicate handles
+ // all the cases properly.
+ DCHECK(!ic.ShouldThrowReferenceError());
+#endif
- // Throw a reference error.
- THROW_NEW_ERROR_RETURN_FAILURE(
- isolate, NewReferenceError(MessageTemplate::kNotDefined, it.name()));
+ return isolate->heap()->undefined_value();
}
@@ -2955,15 +3004,14 @@ RUNTIME_FUNCTION(Runtime_LoadElementWithInterceptor) {
RUNTIME_FUNCTION(Runtime_LoadIC_MissFromStubFailure) {
TimerEventScope<TimerEventIcMiss> timer(isolate);
- TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8"), "V8.IcMiss");
HandleScope scope(isolate);
- Handle<Object> receiver = args.at<Object>(0);
- Handle<Name> key = args.at<Name>(1);
- Handle<Object> result;
-
- DCHECK(args.length() == 4);
- Handle<Smi> slot = args.at<Smi>(2);
- Handle<TypeFeedbackVector> vector = args.at<TypeFeedbackVector>(3);
+ DCHECK_EQ(4, args.length());
+ typedef LoadWithVectorDescriptor Descriptor;
+ Handle<Object> receiver = args.at<Object>(Descriptor::kReceiver);
+ Handle<Name> key = args.at<Name>(Descriptor::kName);
+ Handle<Smi> slot = args.at<Smi>(Descriptor::kSlot);
+ Handle<TypeFeedbackVector> vector =
+ args.at<TypeFeedbackVector>(Descriptor::kVector);
FeedbackVectorSlot vector_slot = vector->ToSlot(slot->value());
// A monomorphic or polymorphic KeyedLoadIC with a string key can call the
// LoadIC miss handler if the handler misses. Since the vector Nexus is
@@ -2972,17 +3020,15 @@ RUNTIME_FUNCTION(Runtime_LoadIC_MissFromStubFailure) {
LoadICNexus nexus(vector, vector_slot);
LoadIC ic(IC::EXTRA_CALL_FRAME, isolate, &nexus);
ic.UpdateState(receiver, key);
- ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result, ic.Load(receiver, key));
+ RETURN_RESULT_OR_FAILURE(isolate, ic.Load(receiver, key));
} else {
DCHECK_EQ(FeedbackVectorSlotKind::KEYED_LOAD_IC,
vector->GetKind(vector_slot));
KeyedLoadICNexus nexus(vector, vector_slot);
KeyedLoadIC ic(IC::EXTRA_CALL_FRAME, isolate, &nexus);
ic.UpdateState(receiver, key);
- ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result, ic.Load(receiver, key));
+ RETURN_RESULT_OR_FAILURE(isolate, ic.Load(receiver, key));
}
-
- return *result;
}
} // namespace internal
} // namespace v8
diff --git a/deps/v8/src/ic/ic.h b/deps/v8/src/ic/ic.h
index 8bd2f447b8..35f3844464 100644
--- a/deps/v8/src/ic/ic.h
+++ b/deps/v8/src/ic/ic.h
@@ -35,11 +35,11 @@ class IC {
// Compute the current IC state based on the target stub, receiver and name.
void UpdateState(Handle<Object> receiver, Handle<Object> name);
- bool IsNameCompatibleWithPrototypeFailure(Handle<Object> name);
- void MarkPrototypeFailure(Handle<Object> name) {
- DCHECK(IsNameCompatibleWithPrototypeFailure(name));
+ bool RecomputeHandlerForName(Handle<Object> name);
+ void MarkRecomputeHandler(Handle<Object> name) {
+ DCHECK(RecomputeHandlerForName(name));
old_state_ = state_;
- state_ = PROTOTYPE_FAILURE;
+ state_ = RECOMPUTE_HANDLER;
}
// Clear the inline cache to initial state.
@@ -47,14 +47,13 @@ class IC {
#ifdef DEBUG
bool IsLoadStub() const {
- return target()->is_load_stub() || target()->is_keyed_load_stub();
+ return kind_ == Code::LOAD_IC || kind_ == Code::LOAD_GLOBAL_IC ||
+ kind_ == Code::KEYED_LOAD_IC;
}
-
bool IsStoreStub() const {
- return target()->is_store_stub() || target()->is_keyed_store_stub();
+ return kind_ == Code::STORE_IC || kind_ == Code::KEYED_STORE_IC;
}
-
- bool IsCallStub() const { return target()->is_call_stub(); }
+ bool IsCallStub() const { return kind_ == Code::CALL_IC; }
#endif
static inline Handle<Map> GetHandlerCacheHolder(Handle<Map> receiver_map,
@@ -65,26 +64,20 @@ class IC {
Isolate* isolate,
CacheHolderFlag* flag);
- static bool IsCleared(Code* code) {
- InlineCacheState state = code->ic_state();
- return !FLAG_use_ic || state == UNINITIALIZED || state == PREMONOMORPHIC;
- }
-
static bool IsCleared(FeedbackNexus* nexus) {
InlineCacheState state = nexus->StateFromFeedback();
return !FLAG_use_ic || state == UNINITIALIZED || state == PREMONOMORPHIC;
}
static bool ICUseVector(Code::Kind kind) {
- return kind == Code::LOAD_IC || kind == Code::KEYED_LOAD_IC ||
- kind == Code::CALL_IC || kind == Code::STORE_IC ||
- kind == Code::KEYED_STORE_IC;
+ return kind == Code::LOAD_IC || kind == Code::LOAD_GLOBAL_IC ||
+ kind == Code::KEYED_LOAD_IC || kind == Code::CALL_IC ||
+ kind == Code::STORE_IC || kind == Code::KEYED_STORE_IC;
}
- protected:
- // Get the call-site target; used for determining the state.
- Handle<Code> target() const { return target_; }
+ static InlineCacheState StateFromCode(Code* code);
+ protected:
Address fp() const { return fp_; }
Address pc() const { return *pc_address_; }
Isolate* isolate() const { return isolate_; }
@@ -101,13 +94,12 @@ class IC {
// Set the call-site target.
inline void set_target(Code* code);
- bool is_target_set() { return target_set_; }
bool is_vector_set() { return vector_set_; }
bool UseVector() const {
bool use = ICUseVector(kind());
// If we are supposed to use the nexus, verify the nexus is non-null.
- DCHECK(!use || nexus_ != NULL);
+ DCHECK(!use || nexus_ != nullptr);
return use;
}
@@ -115,10 +107,10 @@ class IC {
void ConfigureVectorState(IC::State new_state, Handle<Object> key);
// Configure the vector for MONOMORPHIC.
void ConfigureVectorState(Handle<Name> name, Handle<Map> map,
- Handle<Code> handler);
+ Handle<Object> handler);
// Configure the vector for POLYMORPHIC.
void ConfigureVectorState(Handle<Name> name, MapHandleList* maps,
- CodeHandleList* handlers);
+ List<Handle<Object>>* handlers);
// Configure the vector for POLYMORPHIC with transitions (only for element
// keyed stores).
void ConfigureVectorState(MapHandleList* maps,
@@ -139,16 +131,17 @@ class IC {
Address constant_pool);
static inline void SetTargetAtAddress(Address address, Code* target,
Address constant_pool);
- static void OnTypeFeedbackChanged(Isolate* isolate, Address address,
- State old_state, State new_state,
- bool target_remains_ic_stub);
// As a vector-based IC, type feedback must be updated differently.
static void OnTypeFeedbackChanged(Isolate* isolate, Code* host);
static void PostPatching(Address address, Code* target, Code* old_target);
// Compute the handler either by compiling or by retrieving a cached version.
- Handle<Code> ComputeHandler(LookupIterator* lookup,
- Handle<Object> value = Handle<Code>::null());
+ Handle<Object> ComputeHandler(LookupIterator* lookup,
+ Handle<Object> value = Handle<Code>::null());
+ virtual Handle<Object> GetMapIndependentHandler(LookupIterator* lookup) {
+ UNREACHABLE();
+ return Handle<Code>::null();
+ }
virtual Handle<Code> CompileHandler(LookupIterator* lookup,
Handle<Object> value,
CacheHolderFlag cache_holder) {
@@ -156,30 +149,28 @@ class IC {
return Handle<Code>::null();
}
- void UpdateMonomorphicIC(Handle<Code> handler, Handle<Name> name);
- bool UpdatePolymorphicIC(Handle<Name> name, Handle<Code> code);
- void UpdateMegamorphicCache(Map* map, Name* name, Code* code);
+ void UpdateMonomorphicIC(Handle<Object> handler, Handle<Name> name);
+ bool UpdatePolymorphicIC(Handle<Name> name, Handle<Object> code);
+ void UpdateMegamorphicCache(Map* map, Name* name, Object* code);
+
+ StubCache* stub_cache();
void CopyICToMegamorphicCache(Handle<Name> name);
bool IsTransitionOfMonomorphicTarget(Map* source_map, Map* target_map);
- void PatchCache(Handle<Name> name, Handle<Code> code);
+ void PatchCache(Handle<Name> name, Handle<Object> code);
Code::Kind kind() const { return kind_; }
+ bool is_keyed() const {
+ return kind_ == Code::KEYED_LOAD_IC || kind_ == Code::KEYED_STORE_IC;
+ }
Code::Kind handler_kind() const {
if (kind_ == Code::KEYED_LOAD_IC) return Code::LOAD_IC;
DCHECK(kind_ == Code::LOAD_IC || kind_ == Code::STORE_IC ||
kind_ == Code::KEYED_STORE_IC);
return kind_;
}
- virtual Handle<Code> megamorphic_stub() {
- UNREACHABLE();
- return Handle<Code>::null();
- }
-
- bool TryRemoveInvalidPrototypeDependentStub(Handle<Object> receiver,
- Handle<String> name);
+ bool ShouldRecomputeHandler(Handle<Object> receiver, Handle<String> name);
ExtraICState extra_ic_state() const { return extra_ic_state_; }
- void set_extra_ic_state(ExtraICState state) { extra_ic_state_ = state; }
Handle<Map> receiver_map() { return receiver_map_; }
void update_receiver_map(Handle<Object> receiver) {
@@ -202,12 +193,10 @@ class IC {
return target_maps_.length() > 0 ? *target_maps_.at(0) : NULL;
}
- inline void UpdateTarget();
-
Handle<TypeFeedbackVector> vector() const { return nexus()->vector_handle(); }
FeedbackVectorSlot slot() const { return nexus()->slot(); }
State saved_state() const {
- return state() == PROTOTYPE_FAILURE ? old_state_ : state();
+ return state() == RECOMPUTE_HANDLER ? old_state_ : state();
}
template <class NexusClass>
@@ -217,25 +206,17 @@ class IC {
FeedbackNexus* nexus() const { return nexus_; }
inline Code* get_host();
+ inline Code* target() const;
private:
- inline Code* raw_target() const;
inline Address constant_pool() const;
inline Address raw_constant_pool() const;
void FindTargetMaps() {
if (target_maps_set_) return;
target_maps_set_ = true;
- if (UseVector()) {
- nexus()->ExtractMaps(&target_maps_);
- } else {
- if (state_ == MONOMORPHIC) {
- Map* map = target_->FindFirstMap();
- if (map != NULL) target_maps_.Add(handle(map));
- } else if (state_ != UNINITIALIZED && state_ != PREMONOMORPHIC) {
- target_->FindAllMaps(&target_maps_);
- }
- }
+ DCHECK(UseVector());
+ nexus()->ExtractMaps(&target_maps_);
}
// Frame pointer for the frame that uses (calls) the IC.
@@ -253,15 +234,12 @@ class IC {
Isolate* isolate_;
- // The original code target that missed.
- Handle<Code> target_;
- bool target_set_;
bool vector_set_;
State old_state_; // For saving if we marked as prototype failure.
State state_;
Code::Kind kind_;
Handle<Map> receiver_map_;
- MaybeHandle<Code> maybe_handler_;
+ MaybeHandle<Object> maybe_handler_;
ExtraICState extra_ic_state_;
MapHandleList target_maps_;
@@ -282,81 +260,69 @@ class CallIC : public IC {
void HandleMiss(Handle<Object> function);
- // Code generator routines.
- static Handle<Code> initialize_stub(Isolate* isolate, int argc,
- ConvertReceiverMode mode,
- TailCallMode tail_call_mode);
- static Handle<Code> initialize_stub_in_optimized_code(
- Isolate* isolate, int argc, ConvertReceiverMode mode,
- TailCallMode tail_call_mode);
-
static void Clear(Isolate* isolate, Code* host, CallICNexus* nexus);
};
class LoadIC : public IC {
public:
- TypeofMode typeof_mode() const {
- return LoadICState::GetTypeofMode(extra_ic_state());
- }
-
LoadIC(FrameDepth depth, Isolate* isolate, FeedbackNexus* nexus = NULL)
: IC(depth, isolate, nexus) {
DCHECK(nexus != NULL);
DCHECK(IsLoadStub());
}
- bool ShouldThrowReferenceError(Handle<Object> receiver) {
- return receiver->IsJSGlobalObject() && typeof_mode() == NOT_INSIDE_TYPEOF;
+ bool ShouldThrowReferenceError() const {
+ return kind() == Code::LOAD_GLOBAL_IC &&
+ LoadGlobalICState::GetTypeofMode(extra_ic_state()) ==
+ NOT_INSIDE_TYPEOF;
}
// Code generator routines.
- static void GenerateInitialize(MacroAssembler* masm) { GenerateMiss(masm); }
static void GenerateMiss(MacroAssembler* masm);
static void GenerateRuntimeGetProperty(MacroAssembler* masm);
static void GenerateNormal(MacroAssembler* masm);
- static Handle<Code> initialize_stub(Isolate* isolate,
- ExtraICState extra_state);
- static Handle<Code> initialize_stub_in_optimized_code(
- Isolate* isolate, ExtraICState extra_state, State initialization_state);
-
MUST_USE_RESULT MaybeHandle<Object> Load(Handle<Object> object,
Handle<Name> name);
static void Clear(Isolate* isolate, Code* host, LoadICNexus* nexus);
protected:
- inline void set_target(Code* code);
-
- Handle<Code> slow_stub() const {
- if (kind() == Code::LOAD_IC) {
- return isolate()->builtins()->LoadIC_Slow();
- } else {
- DCHECK_EQ(Code::KEYED_LOAD_IC, kind());
- return isolate()->builtins()->KeyedLoadIC_Slow();
- }
+ virtual Handle<Code> slow_stub() const {
+ return isolate()->builtins()->LoadIC_Slow();
}
- Handle<Code> megamorphic_stub() override;
-
// Update the inline cache and the global stub cache based on the
// lookup result.
void UpdateCaches(LookupIterator* lookup);
+ Handle<Object> GetMapIndependentHandler(LookupIterator* lookup) override;
+
Handle<Code> CompileHandler(LookupIterator* lookup, Handle<Object> unused,
CacheHolderFlag cache_holder) override;
private:
- Handle<Code> SimpleFieldLoad(FieldIndex index);
-
- static void Clear(Isolate* isolate, Address address, Code* target,
- Address constant_pool);
+ Handle<Object> SimpleFieldLoad(FieldIndex index);
friend class IC;
};
+class LoadGlobalIC : public LoadIC {
+ public:
+ LoadGlobalIC(FrameDepth depth, Isolate* isolate, FeedbackNexus* nexus = NULL)
+ : LoadIC(depth, isolate, nexus) {}
+
+ MUST_USE_RESULT MaybeHandle<Object> Load(Handle<Name> name);
+
+ static void Clear(Isolate* isolate, Code* host, LoadGlobalICNexus* nexus);
+
+ protected:
+ Handle<Code> slow_stub() const override {
+ return isolate()->builtins()->LoadGlobalIC_Slow();
+ }
+};
class KeyedLoadIC : public LoadIC {
public:
@@ -364,7 +330,6 @@ class KeyedLoadIC : public LoadIC {
KeyedLoadICNexus* nexus = NULL)
: LoadIC(depth, isolate, nexus) {
DCHECK(nexus != NULL);
- DCHECK(target()->is_keyed_load_stub());
}
MUST_USE_RESULT MaybeHandle<Object> Load(Handle<Object> object,
@@ -373,20 +338,8 @@ class KeyedLoadIC : public LoadIC {
// Code generator routines.
static void GenerateMiss(MacroAssembler* masm);
static void GenerateRuntimeGetProperty(MacroAssembler* masm);
- static void GenerateInitialize(MacroAssembler* masm) { GenerateMiss(masm); }
static void GenerateMegamorphic(MacroAssembler* masm);
- // Bit mask to be tested against bit field for the cases when
- // generic stub should go into slow case.
- // Access check is necessary explicitly since generic stub does not perform
- // map checks.
- static const int kSlowCaseBitFieldMask =
- (1 << Map::kIsAccessCheckNeeded) | (1 << Map::kHasIndexedInterceptor);
-
- static Handle<Code> initialize_stub(Isolate* isolate,
- ExtraICState extra_state);
- static Handle<Code> initialize_stub_in_optimized_code(
- Isolate* isolate, State initialization_state, ExtraICState extra_state);
static Handle<Code> ChooseMegamorphicStub(Isolate* isolate,
ExtraICState extra_state);
@@ -394,22 +347,15 @@ class KeyedLoadIC : public LoadIC {
protected:
// receiver is HeapObject because it could be a String or a JSObject
- Handle<Code> LoadElementStub(Handle<HeapObject> receiver);
+ void UpdateLoadElement(Handle<HeapObject> receiver);
private:
- static void Clear(Isolate* isolate, Address address, Code* target,
- Address constant_pool);
-
friend class IC;
};
class StoreIC : public IC {
public:
- static ExtraICState ComputeExtraICState(LanguageMode flag) {
- return StoreICState(flag).GetExtraICState();
- }
-
StoreIC(FrameDepth depth, Isolate* isolate, FeedbackNexus* nexus = NULL)
: IC(depth, isolate, nexus) {
DCHECK(IsStoreStub());
@@ -421,21 +367,8 @@ class StoreIC : public IC {
// Code generators for stub routines. Only called once at startup.
static void GenerateSlow(MacroAssembler* masm);
- static void GenerateInitialize(MacroAssembler* masm) { GenerateMiss(masm); }
- static void GeneratePreMonomorphic(MacroAssembler* masm) {
- GenerateMiss(masm);
- }
static void GenerateMiss(MacroAssembler* masm);
- static void GenerateMegamorphic(MacroAssembler* masm);
static void GenerateNormal(MacroAssembler* masm);
- static void GenerateRuntimeSetProperty(MacroAssembler* masm,
- LanguageMode language_mode);
-
- static Handle<Code> initialize_stub(Isolate* isolate,
- LanguageMode language_mode,
- State initialization_state);
- static Handle<Code> initialize_stub_in_optimized_code(
- Isolate* isolate, LanguageMode language_mode, State initialization_state);
MUST_USE_RESULT MaybeHandle<Object> Store(
Handle<Object> object, Handle<Name> name, Handle<Object> value,
@@ -449,29 +382,27 @@ class StoreIC : public IC {
protected:
// Stub accessors.
- Handle<Code> megamorphic_stub() override;
- Handle<Code> slow_stub() const;
-
- virtual Handle<Code> pre_monomorphic_stub() const {
- return pre_monomorphic_stub(isolate(), language_mode());
+ Handle<Code> slow_stub() const {
+ switch (language_mode()) {
+ case SLOPPY:
+ return isolate()->builtins()->StoreIC_SlowSloppy();
+ case STRICT:
+ return isolate()->builtins()->StoreIC_SlowStrict();
+ default:
+ UNREACHABLE();
+ return Handle<Code>();
+ }
}
- static Handle<Code> pre_monomorphic_stub(Isolate* isolate,
- LanguageMode language_mode);
-
// Update the inline cache and the global stub cache based on the
// lookup result.
void UpdateCaches(LookupIterator* lookup, Handle<Object> value,
JSReceiver::StoreFromKeyed store_mode);
+ Handle<Object> GetMapIndependentHandler(LookupIterator* lookup) override;
Handle<Code> CompileHandler(LookupIterator* lookup, Handle<Object> value,
CacheHolderFlag cache_holder) override;
private:
- inline void set_target(Code* code);
-
- static void Clear(Isolate* isolate, Address address, Code* target,
- Address constant_pool);
-
friend class IC;
};
@@ -484,79 +415,34 @@ enum KeyedStoreIncrementLength { kDontIncrementLength, kIncrementLength };
class KeyedStoreIC : public StoreIC {
public:
- // ExtraICState bits (building on IC)
- // ExtraICState bits
- // When more language modes are added, these BitFields need to move too.
- STATIC_ASSERT(i::LANGUAGE_END == 3);
- class ExtraICStateKeyedAccessStoreMode
- : public BitField<KeyedAccessStoreMode, 3, 3> {}; // NOLINT
-
- class IcCheckTypeField : public BitField<IcCheckType, 6, 1> {};
-
- static ExtraICState ComputeExtraICState(LanguageMode flag,
- KeyedAccessStoreMode mode) {
- return StoreICState(flag).GetExtraICState() |
- ExtraICStateKeyedAccessStoreMode::encode(mode) |
- IcCheckTypeField::encode(ELEMENT);
- }
-
KeyedAccessStoreMode GetKeyedAccessStoreMode() {
return casted_nexus<KeyedStoreICNexus>()->GetKeyedAccessStoreMode();
}
KeyedStoreIC(FrameDepth depth, Isolate* isolate,
KeyedStoreICNexus* nexus = NULL)
- : StoreIC(depth, isolate, nexus) {
- DCHECK(target()->is_keyed_store_stub());
- }
+ : StoreIC(depth, isolate, nexus) {}
MUST_USE_RESULT MaybeHandle<Object> Store(Handle<Object> object,
Handle<Object> name,
Handle<Object> value);
// Code generators for stub routines. Only called once at startup.
- static void GenerateInitialize(MacroAssembler* masm) { GenerateMiss(masm); }
- static void GeneratePreMonomorphic(MacroAssembler* masm) {
- GenerateMiss(masm);
- }
static void GenerateMiss(MacroAssembler* masm);
static void GenerateSlow(MacroAssembler* masm);
static void GenerateMegamorphic(MacroAssembler* masm,
LanguageMode language_mode);
- static Handle<Code> initialize_stub(Isolate* isolate,
- LanguageMode language_mode,
- State initialization_state);
-
- static Handle<Code> initialize_stub_in_optimized_code(
- Isolate* isolate, LanguageMode language_mode, State initialization_state);
static Handle<Code> ChooseMegamorphicStub(Isolate* isolate,
ExtraICState extra_state);
static void Clear(Isolate* isolate, Code* host, KeyedStoreICNexus* nexus);
protected:
- virtual Handle<Code> pre_monomorphic_stub() const {
- return pre_monomorphic_stub(isolate(), language_mode());
- }
- static Handle<Code> pre_monomorphic_stub(Isolate* isolate,
- LanguageMode language_mode) {
- if (is_strict(language_mode)) {
- return isolate->builtins()->KeyedStoreIC_PreMonomorphic_Strict();
- } else {
- return isolate->builtins()->KeyedStoreIC_PreMonomorphic();
- }
- }
-
- Handle<Code> StoreElementStub(Handle<Map> receiver_map,
- KeyedAccessStoreMode store_mode);
+ void UpdateStoreElement(Handle<Map> receiver_map,
+ KeyedAccessStoreMode store_mode);
private:
- inline void set_target(Code* code);
-
- static void Clear(Isolate* isolate, Address address, Code* target,
- Address constant_pool);
-
Handle<Map> ComputeTransitionedMap(Handle<Map> map,
KeyedAccessStoreMode store_mode);
@@ -586,9 +472,6 @@ class CompareIC : public IC {
// Helper function for computing the condition for a compare operation.
static Condition ComputeCondition(Token::Value op);
- // Factory method for getting an uninitialized compare stub.
- static Handle<Code> GetUninitialized(Isolate* isolate, Token::Value op);
-
private:
static bool HasInlinedSmiCode(Address address);
diff --git a/deps/v8/src/ic/mips/access-compiler-mips.cc b/deps/v8/src/ic/mips/access-compiler-mips.cc
index b122946577..2aa0283485 100644
--- a/deps/v8/src/ic/mips/access-compiler-mips.cc
+++ b/deps/v8/src/ic/mips/access-compiler-mips.cc
@@ -19,19 +19,19 @@ void PropertyAccessCompiler::GenerateTailCall(MacroAssembler* masm,
Register* PropertyAccessCompiler::load_calling_convention() {
- // receiver, name, scratch1, scratch2, scratch3, scratch4.
+ // receiver, name, scratch1, scratch2, scratch3.
Register receiver = LoadDescriptor::ReceiverRegister();
Register name = LoadDescriptor::NameRegister();
- static Register registers[] = {receiver, name, a3, a0, t0, t1};
+ static Register registers[] = {receiver, name, a3, a0, t0};
return registers;
}
Register* PropertyAccessCompiler::store_calling_convention() {
- // receiver, name, scratch1, scratch2, scratch3.
+ // receiver, name, scratch1, scratch2.
Register receiver = StoreDescriptor::ReceiverRegister();
Register name = StoreDescriptor::NameRegister();
- static Register registers[] = {receiver, name, a3, t0, t1};
+ static Register registers[] = {receiver, name, a3, t0};
return registers;
}
diff --git a/deps/v8/src/ic/mips/handler-compiler-mips.cc b/deps/v8/src/ic/mips/handler-compiler-mips.cc
index b924bdad78..f4e0f0baba 100644
--- a/deps/v8/src/ic/mips/handler-compiler-mips.cc
+++ b/deps/v8/src/ic/mips/handler-compiler-mips.cc
@@ -195,9 +195,11 @@ void NamedLoadHandlerCompiler::GenerateLoadFunctionPrototype(
void PropertyHandlerCompiler::GenerateCheckPropertyCell(
MacroAssembler* masm, Handle<JSGlobalObject> global, Handle<Name> name,
Register scratch, Label* miss) {
- Handle<PropertyCell> cell = JSGlobalObject::EnsurePropertyCell(global, name);
- DCHECK(cell->value()->IsTheHole());
- Handle<WeakCell> weak_cell = masm->isolate()->factory()->NewWeakCell(cell);
+ Handle<PropertyCell> cell = JSGlobalObject::EnsureEmptyPropertyCell(
+ global, name, PropertyCellType::kInvalidated);
+ Isolate* isolate = masm->isolate();
+ DCHECK(cell->value()->IsTheHole(isolate));
+ Handle<WeakCell> weak_cell = isolate->factory()->NewWeakCell(cell);
__ LoadWeakValue(scratch, weak_cell, miss);
__ lw(scratch, FieldMemOperand(scratch, PropertyCell::kValueOffset));
__ LoadRoot(at, Heap::kTheHoleValueRootIndex);
@@ -279,7 +281,7 @@ void PropertyHandlerCompiler::GenerateApiAccessorCall(
Handle<CallHandlerInfo> api_call_info = optimization.api_call_info();
bool call_data_undefined = false;
// Put call data in place.
- if (api_call_info->data()->IsUndefined()) {
+ if (api_call_info->data()->IsUndefined(isolate)) {
call_data_undefined = true;
__ LoadRoot(data, Heap::kUndefinedValueRootIndex);
} else {
@@ -319,17 +321,8 @@ void PropertyHandlerCompiler::GenerateApiAccessorCall(
static void StoreIC_PushArgs(MacroAssembler* masm) {
__ Push(StoreDescriptor::ReceiverRegister(), StoreDescriptor::NameRegister(),
StoreDescriptor::ValueRegister(),
- VectorStoreICDescriptor::SlotRegister(),
- VectorStoreICDescriptor::VectorRegister());
-}
-
-
-void NamedStoreHandlerCompiler::GenerateSlow(MacroAssembler* masm) {
- StoreIC_PushArgs(masm);
-
- // The slow case calls into the runtime to complete the store without causing
- // an IC miss that would otherwise cause a transition to the generic stub.
- __ TailCallRuntime(Runtime::kStoreIC_Slow);
+ StoreWithVectorDescriptor::SlotRegister(),
+ StoreWithVectorDescriptor::VectorRegister());
}
@@ -423,28 +416,25 @@ 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)));
- }
+ 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));
- }
+ // 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.
@@ -480,8 +470,10 @@ Register PropertyHandlerCompiler::CheckPrototypes(
!current_map->is_access_check_needed());
prototype = handle(JSObject::cast(current_map->prototype()));
- if (current_map->is_dictionary_map() &&
- !current_map->IsJSGlobalObjectMap()) {
+ if (current_map->IsJSGlobalObjectMap()) {
+ GenerateCheckPropertyCell(masm(), Handle<JSGlobalObject>::cast(current),
+ name, scratch2, miss);
+ } else if (current_map->is_dictionary_map()) {
DCHECK(!current_map->IsJSGlobalProxyMap()); // Proxy maps are fast.
if (!name->IsUniqueName()) {
DCHECK(name->IsString());
@@ -491,33 +483,12 @@ Register PropertyHandlerCompiler::CheckPrototypes(
current->property_dictionary()->FindEntry(name) ==
NameDictionary::kNotFound);
- if (FLAG_eliminate_prototype_chain_checks && depth > 1) {
+ if (depth > 1) {
// TODO(jkummerow): Cache and re-use weak cell.
__ LoadWeakValue(reg, isolate()->factory()->NewWeakCell(current), miss);
}
GenerateDictionaryNegativeLookup(masm(), miss, reg, name, scratch1,
scratch2);
- if (!FLAG_eliminate_prototype_chain_checks) {
- __ lw(scratch1, FieldMemOperand(reg, HeapObject::kMapOffset));
- __ lw(holder_reg, FieldMemOperand(scratch1, Map::kPrototypeOffset));
- }
- } else {
- Register map_reg = scratch1;
- 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 (!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));
- }
- 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.
@@ -531,17 +502,8 @@ Register PropertyHandlerCompiler::CheckPrototypes(
// Log the check depth.
LOG(isolate(), IntEvent("check-maps-depth", depth + 1));
- 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);
- __ GetWeakValue(scratch2, cell);
- __ Branch(miss, ne, scratch2, Operand(scratch1));
- }
-
bool return_holder = return_what == RETURN_HOLDER;
- if (FLAG_eliminate_prototype_chain_checks && return_holder && depth != 0) {
+ if (return_holder && depth != 0) {
__ LoadWeakValue(reg, isolate()->factory()->NewWeakCell(current), miss);
}
@@ -584,70 +546,10 @@ void NamedLoadHandlerCompiler::GenerateLoadConstant(Handle<Object> value) {
}
-void NamedLoadHandlerCompiler::GenerateLoadCallback(
- Register reg, Handle<AccessorInfo> callback) {
- DCHECK(!AreAliased(scratch2(), scratch3(), scratch4(), receiver()));
- DCHECK(!AreAliased(scratch2(), scratch3(), scratch4(), reg));
-
- // Build v8::PropertyCallbackInfo::args_ array on the stack and push property
- // name below the exit frame to make GC aware of them.
- STATIC_ASSERT(PropertyCallbackArguments::kShouldThrowOnErrorIndex == 0);
- STATIC_ASSERT(PropertyCallbackArguments::kHolderIndex == 1);
- STATIC_ASSERT(PropertyCallbackArguments::kIsolateIndex == 2);
- STATIC_ASSERT(PropertyCallbackArguments::kReturnValueDefaultValueIndex == 3);
- STATIC_ASSERT(PropertyCallbackArguments::kReturnValueOffset == 4);
- STATIC_ASSERT(PropertyCallbackArguments::kDataIndex == 5);
- STATIC_ASSERT(PropertyCallbackArguments::kThisIndex == 6);
- STATIC_ASSERT(PropertyCallbackArguments::kArgsLength == 7);
-
- // Here and below +1 is for name() pushed after the args_ array.
- typedef PropertyCallbackArguments PCA;
- __ Subu(sp, sp, (PCA::kArgsLength + 1) * kPointerSize);
- __ sw(receiver(), MemOperand(sp, (PCA::kThisIndex + 1) * kPointerSize));
- Handle<Object> data(callback->data(), isolate());
- if (data->IsUndefined() || data->IsSmi()) {
- __ li(scratch2(), data);
- } else {
- Handle<WeakCell> cell =
- isolate()->factory()->NewWeakCell(Handle<HeapObject>::cast(data));
- // The callback is alive if this instruction is executed,
- // so the weak cell is not cleared and points to data.
- __ GetWeakValue(scratch2(), cell);
- }
- __ sw(scratch2(), MemOperand(sp, (PCA::kDataIndex + 1) * kPointerSize));
- __ LoadRoot(scratch2(), Heap::kUndefinedValueRootIndex);
- __ sw(scratch2(),
- MemOperand(sp, (PCA::kReturnValueOffset + 1) * kPointerSize));
- __ sw(scratch2(), MemOperand(sp, (PCA::kReturnValueDefaultValueIndex + 1) *
- kPointerSize));
- __ li(scratch2(), Operand(ExternalReference::isolate_address(isolate())));
- __ sw(scratch2(), MemOperand(sp, (PCA::kIsolateIndex + 1) * kPointerSize));
- __ sw(reg, MemOperand(sp, (PCA::kHolderIndex + 1) * kPointerSize));
- // should_throw_on_error -> false
- DCHECK(Smi::FromInt(0) == nullptr);
- __ sw(zero_reg,
- MemOperand(sp, (PCA::kShouldThrowOnErrorIndex + 1) * kPointerSize));
-
- __ sw(name(), MemOperand(sp, 0 * kPointerSize));
-
- // Abi for CallApiGetter.
- Register getter_address_reg = ApiGetterDescriptor::function_address();
-
- Address getter_address = v8::ToCData<Address>(callback->getter());
- ApiFunction fun(getter_address);
- ExternalReference::Type type = ExternalReference::DIRECT_GETTER_CALL;
- ExternalReference ref = ExternalReference(&fun, type, isolate());
- __ li(getter_address_reg, Operand(ref));
-
- CallApiGetterStub stub(isolate());
- __ TailCallStub(&stub);
-}
-
-
void NamedLoadHandlerCompiler::GenerateLoadInterceptorWithFollowup(
LookupIterator* it, Register holder_reg) {
DCHECK(holder()->HasNamedInterceptor());
- DCHECK(!holder()->GetNamedInterceptor()->getter()->IsUndefined());
+ DCHECK(!holder()->GetNamedInterceptor()->getter()->IsUndefined(isolate()));
// Compile the interceptor call, followed by inline code to load the
// property from further up the prototype chain if the call fails.
@@ -706,7 +608,7 @@ void NamedLoadHandlerCompiler::GenerateLoadInterceptorWithFollowup(
void NamedLoadHandlerCompiler::GenerateLoadInterceptor(Register holder_reg) {
// Call the runtime system to load the interceptor.
DCHECK(holder()->HasNamedInterceptor());
- DCHECK(!holder()->GetNamedInterceptor()->getter()->IsUndefined());
+ DCHECK(!holder()->GetNamedInterceptor()->getter()->IsUndefined(isolate()));
PushInterceptorArguments(masm(), receiver(), holder_reg, this->name(),
holder());
@@ -722,7 +624,7 @@ Handle<Code> NamedStoreHandlerCompiler::CompileStoreCallback(
__ Push(receiver(), holder_reg); // Receiver.
// If the callback cannot leak, then push the callback directly,
// otherwise wrap it in a weak cell.
- if (callback->data()->IsUndefined() || callback->data()->IsSmi()) {
+ if (callback->data()->IsUndefined(isolate()) || callback->data()->IsSmi()) {
__ li(at, Operand(callback));
} else {
Handle<WeakCell> cell = isolate()->factory()->NewWeakCell(callback);
@@ -737,7 +639,7 @@ Handle<Code> NamedStoreHandlerCompiler::CompileStoreCallback(
__ TailCallRuntime(Runtime::kStoreCallbackProperty);
// Return the generated code.
- return GetCode(kind(), Code::FAST, name);
+ return GetCode(kind(), name);
}
@@ -778,7 +680,7 @@ Handle<Code> NamedLoadHandlerCompiler::CompileLoadGlobal(
FrontendFooter(name, &miss);
// Return the generated code.
- return GetCode(kind(), Code::NORMAL, name);
+ return GetCode(kind(), name);
}
diff --git a/deps/v8/src/ic/mips/ic-mips.cc b/deps/v8/src/ic/mips/ic-mips.cc
index ae3615e3bb..3a28b13bd8 100644
--- a/deps/v8/src/ic/mips/ic-mips.cc
+++ b/deps/v8/src/ic/mips/ic-mips.cc
@@ -419,10 +419,8 @@ void KeyedLoadIC::GenerateMegamorphic(MacroAssembler* masm) {
__ LoadRoot(vector, Heap::kDummyVectorRootIndex);
__ li(slot, Operand(Smi::FromInt(slot_index)));
- Code::Flags flags = Code::RemoveTypeAndHolderFromFlags(
- Code::ComputeHandlerFlags(Code::LOAD_IC));
- masm->isolate()->stub_cache()->GenerateProbe(masm, Code::LOAD_IC, flags,
- receiver, key, t0, t1, t2, t5);
+ masm->isolate()->load_stub_cache()->GenerateProbe(masm, receiver, key, t0, t1,
+ t2, t5);
// Cache miss.
GenerateMiss(masm);
@@ -616,11 +614,10 @@ void KeyedStoreIC::GenerateMegamorphic(MacroAssembler* masm,
__ JumpIfSmi(receiver, &slow);
// Get the map of the object.
__ lw(receiver_map, FieldMemOperand(receiver, HeapObject::kMapOffset));
- // Check that the receiver does not require access checks and is not observed.
- // The generic stub does not perform map checks or handle observed objects.
+ // Check that the receiver does not require access checks.
+ // The generic stub does not perform map checks.
__ lbu(t0, FieldMemOperand(receiver_map, Map::kBitFieldOffset));
- __ And(t0, t0,
- Operand(1 << Map::kIsAccessCheckNeeded | 1 << Map::kIsObserved));
+ __ And(t0, t0, Operand(1 << Map::kIsAccessCheckNeeded));
__ Branch(&slow, ne, t0, Operand(zero_reg));
// Check if the object is a JS array or not.
__ lbu(t0, FieldMemOperand(receiver_map, Map::kInstanceTypeOffset));
@@ -653,8 +650,8 @@ void KeyedStoreIC::GenerateMegamorphic(MacroAssembler* masm,
// The handlers in the stub cache expect a vector and slot. Since we won't
// change the IC from any downstream misses, a dummy vector can be used.
- Register vector = VectorStoreICDescriptor::VectorRegister();
- Register slot = VectorStoreICDescriptor::SlotRegister();
+ Register vector = StoreWithVectorDescriptor::VectorRegister();
+ Register slot = StoreWithVectorDescriptor::SlotRegister();
DCHECK(!AreAliased(vector, slot, t1, t2, t4, t5));
Handle<TypeFeedbackVector> dummy_vector =
TypeFeedbackVector::DummyVector(masm->isolate());
@@ -663,10 +660,8 @@ void KeyedStoreIC::GenerateMegamorphic(MacroAssembler* masm,
__ LoadRoot(vector, Heap::kDummyVectorRootIndex);
__ li(slot, Operand(Smi::FromInt(slot_index)));
- Code::Flags flags = Code::RemoveTypeAndHolderFromFlags(
- Code::ComputeHandlerFlags(Code::STORE_IC));
- masm->isolate()->stub_cache()->GenerateProbe(masm, Code::STORE_IC, flags,
- receiver, key, t1, t2, t4, t5);
+ masm->isolate()->store_stub_cache()->GenerateProbe(masm, receiver, key, t1,
+ t2, t4, t5);
// Cache miss.
__ Branch(&miss);
@@ -717,8 +712,8 @@ void KeyedStoreIC::GenerateMegamorphic(MacroAssembler* masm,
static void StoreIC_PushArgs(MacroAssembler* masm) {
__ Push(StoreDescriptor::ReceiverRegister(), StoreDescriptor::NameRegister(),
StoreDescriptor::ValueRegister(),
- VectorStoreICDescriptor::SlotRegister(),
- VectorStoreICDescriptor::VectorRegister());
+ StoreWithVectorDescriptor::SlotRegister(),
+ StoreWithVectorDescriptor::VectorRegister());
}
@@ -728,25 +723,6 @@ void KeyedStoreIC::GenerateMiss(MacroAssembler* masm) {
__ TailCallRuntime(Runtime::kKeyedStoreIC_Miss);
}
-
-void StoreIC::GenerateMegamorphic(MacroAssembler* masm) {
- Register receiver = StoreDescriptor::ReceiverRegister();
- Register name = StoreDescriptor::NameRegister();
- DCHECK(receiver.is(a1));
- DCHECK(name.is(a2));
- DCHECK(StoreDescriptor::ValueRegister().is(a0));
-
- // Get the receiver from the stack and probe the stub cache.
- Code::Flags flags = Code::RemoveTypeAndHolderFromFlags(
- Code::ComputeHandlerFlags(Code::STORE_IC));
- masm->isolate()->stub_cache()->GenerateProbe(masm, Code::STORE_IC, flags,
- receiver, name, a3, t0, t1, t2);
-
- // Cache miss: Jump to runtime.
- GenerateMiss(masm);
-}
-
-
void StoreIC::GenerateMiss(MacroAssembler* masm) {
StoreIC_PushArgs(masm);
@@ -764,8 +740,8 @@ void StoreIC::GenerateNormal(MacroAssembler* masm) {
DCHECK(receiver.is(a1));
DCHECK(name.is(a2));
DCHECK(value.is(a0));
- DCHECK(VectorStoreICDescriptor::VectorRegister().is(a3));
- DCHECK(VectorStoreICDescriptor::SlotRegister().is(t0));
+ DCHECK(StoreWithVectorDescriptor::VectorRegister().is(a3));
+ DCHECK(StoreWithVectorDescriptor::SlotRegister().is(t0));
__ lw(dictionary, FieldMemOperand(receiver, JSObject::kPropertiesOffset));
@@ -840,8 +816,9 @@ void PatchInlinedSmiCode(Isolate* isolate, Address address,
}
if (FLAG_trace_ic) {
- PrintF("[ patching ic at %p, andi=%p, delta=%d\n", address,
- andi_instruction_address, delta);
+ PrintF("[ patching ic at %p, andi=%p, delta=%d\n",
+ static_cast<void*>(address),
+ static_cast<void*>(andi_instruction_address), delta);
}
Address patch_address =
diff --git a/deps/v8/src/ic/mips/stub-cache-mips.cc b/deps/v8/src/ic/mips/stub-cache-mips.cc
index 039763c4cf..d476c1e63e 100644
--- a/deps/v8/src/ic/mips/stub-cache-mips.cc
+++ b/deps/v8/src/ic/mips/stub-cache-mips.cc
@@ -14,16 +14,15 @@ namespace internal {
#define __ ACCESS_MASM(masm)
-
-static void ProbeTable(Isolate* isolate, MacroAssembler* masm,
- Code::Kind ic_kind, Code::Flags flags,
+static void ProbeTable(StubCache* stub_cache, MacroAssembler* masm,
StubCache::Table table, Register receiver, Register name,
- // Number of the cache entry, not scaled.
+ // The offset is scaled by 4, based on
+ // kCacheIndexShift, which is two bits
Register offset, Register scratch, Register scratch2,
Register offset_scratch) {
- ExternalReference key_offset(isolate->stub_cache()->key_reference(table));
- ExternalReference value_offset(isolate->stub_cache()->value_reference(table));
- ExternalReference map_offset(isolate->stub_cache()->map_reference(table));
+ ExternalReference key_offset(stub_cache->key_reference(table));
+ ExternalReference value_offset(stub_cache->value_reference(table));
+ ExternalReference map_offset(stub_cache->map_reference(table));
uint32_t key_off_addr = reinterpret_cast<uint32_t>(key_offset.address());
uint32_t value_off_addr = reinterpret_cast<uint32_t>(value_offset.address());
@@ -46,7 +45,7 @@ static void ProbeTable(Isolate* isolate, MacroAssembler* masm,
// Calculate the base address of the entry.
__ li(base_addr, Operand(key_offset));
- __ Lsa(base_addr, base_addr, offset_scratch, kPointerSizeLog2);
+ __ Addu(base_addr, base_addr, offset_scratch);
// Check that the key in the entry matches the name.
__ lw(at, MemOperand(base_addr, 0));
@@ -62,13 +61,6 @@ static void ProbeTable(Isolate* isolate, MacroAssembler* masm,
scratch2 = no_reg;
__ lw(code, MemOperand(base_addr, value_off_addr - key_off_addr));
- // Check that the flags match what we're looking for.
- Register flags_reg = base_addr;
- base_addr = no_reg;
- __ lw(flags_reg, FieldMemOperand(code, Code::kFlagsOffset));
- __ And(flags_reg, flags_reg, Operand(~Code::kFlagsNotUsedInLookup));
- __ Branch(&miss, ne, flags_reg, Operand(flags));
-
#ifdef DEBUG
if (FLAG_test_secondary_stub_cache && table == StubCache::kPrimary) {
__ jmp(&miss);
@@ -85,21 +77,15 @@ static void ProbeTable(Isolate* isolate, MacroAssembler* masm,
__ bind(&miss);
}
-
-void StubCache::GenerateProbe(MacroAssembler* masm, Code::Kind ic_kind,
- Code::Flags flags, Register receiver,
+void StubCache::GenerateProbe(MacroAssembler* masm, Register receiver,
Register name, Register scratch, Register extra,
Register extra2, Register extra3) {
- Isolate* isolate = masm->isolate();
Label miss;
// Make sure that code is valid. The multiplying code relies on the
// entry size being 12.
DCHECK(sizeof(Entry) == 12);
- // Make sure the flags does not name a specific type.
- DCHECK(Code::ExtractTypeFromFlags(flags) == 0);
-
// Make sure that there are no register conflicts.
DCHECK(!AreAliased(receiver, name, scratch, extra, extra2, extra3));
@@ -113,12 +99,13 @@ void StubCache::GenerateProbe(MacroAssembler* masm, Code::Kind ic_kind,
// If vector-based ics are in use, ensure that scratch, extra, extra2 and
// extra3 don't conflict with the vector and slot registers, which need
// to be preserved for a handler call or miss.
- if (IC::ICUseVector(ic_kind)) {
+ if (IC::ICUseVector(ic_kind_)) {
Register vector, slot;
- if (ic_kind == Code::STORE_IC || ic_kind == Code::KEYED_STORE_IC) {
- vector = VectorStoreICDescriptor::VectorRegister();
- slot = VectorStoreICDescriptor::SlotRegister();
+ if (ic_kind_ == Code::STORE_IC || ic_kind_ == Code::KEYED_STORE_IC) {
+ vector = StoreWithVectorDescriptor::VectorRegister();
+ slot = StoreWithVectorDescriptor::SlotRegister();
} else {
+ DCHECK(ic_kind_ == Code::LOAD_IC || ic_kind_ == Code::KEYED_LOAD_IC);
vector = LoadWithVectorDescriptor::VectorRegister();
slot = LoadWithVectorDescriptor::SlotRegister();
}
@@ -137,27 +124,23 @@ void StubCache::GenerateProbe(MacroAssembler* masm, Code::Kind ic_kind,
__ lw(scratch, FieldMemOperand(name, Name::kHashFieldOffset));
__ lw(at, FieldMemOperand(receiver, HeapObject::kMapOffset));
__ Addu(scratch, scratch, at);
- uint32_t mask = kPrimaryTableSize - 1;
- // We shift out the last two bits because they are not part of the hash and
- // they are always 01 for maps.
- __ srl(scratch, scratch, kCacheIndexShift);
- __ Xor(scratch, scratch, Operand((flags >> kCacheIndexShift) & mask));
- __ And(scratch, scratch, Operand(mask));
+ __ Xor(scratch, scratch, Operand(kPrimaryMagic));
+ __ And(scratch, scratch,
+ Operand((kPrimaryTableSize - 1) << kCacheIndexShift));
// Probe the primary table.
- ProbeTable(isolate, masm, ic_kind, flags, kPrimary, receiver, name, scratch,
- extra, extra2, extra3);
+ ProbeTable(this, masm, kPrimary, receiver, name, scratch, extra, extra2,
+ extra3);
// Primary miss: Compute hash for secondary probe.
- __ srl(at, name, kCacheIndexShift);
- __ Subu(scratch, scratch, at);
- uint32_t mask2 = kSecondaryTableSize - 1;
- __ Addu(scratch, scratch, Operand((flags >> kCacheIndexShift) & mask2));
- __ And(scratch, scratch, Operand(mask2));
+ __ Subu(scratch, scratch, name);
+ __ Addu(scratch, scratch, Operand(kSecondaryMagic));
+ __ And(scratch, scratch,
+ Operand((kSecondaryTableSize - 1) << kCacheIndexShift));
// Probe the secondary table.
- ProbeTable(isolate, masm, ic_kind, flags, kSecondary, receiver, name, scratch,
- extra, extra2, extra3);
+ ProbeTable(this, masm, kSecondary, receiver, name, scratch, extra, extra2,
+ extra3);
// Cache miss: Fall-through and let caller handle the miss by
// entering the runtime system.
diff --git a/deps/v8/src/ic/mips64/access-compiler-mips64.cc b/deps/v8/src/ic/mips64/access-compiler-mips64.cc
index 96e921c7c6..bf6c73e86f 100644
--- a/deps/v8/src/ic/mips64/access-compiler-mips64.cc
+++ b/deps/v8/src/ic/mips64/access-compiler-mips64.cc
@@ -19,19 +19,19 @@ void PropertyAccessCompiler::GenerateTailCall(MacroAssembler* masm,
Register* PropertyAccessCompiler::load_calling_convention() {
- // receiver, name, scratch1, scratch2, scratch3, scratch4.
+ // receiver, name, scratch1, scratch2, scratch3.
Register receiver = LoadDescriptor::ReceiverRegister();
Register name = LoadDescriptor::NameRegister();
- static Register registers[] = {receiver, name, a3, a0, a4, a5};
+ static Register registers[] = {receiver, name, a3, a0, a4};
return registers;
}
Register* PropertyAccessCompiler::store_calling_convention() {
- // receiver, name, scratch1, scratch2, scratch3.
+ // receiver, name, scratch1, scratch2.
Register receiver = StoreDescriptor::ReceiverRegister();
Register name = StoreDescriptor::NameRegister();
- static Register registers[] = {receiver, name, a3, a4, a5};
+ static Register registers[] = {receiver, name, a3, a4};
return registers;
}
diff --git a/deps/v8/src/ic/mips64/handler-compiler-mips64.cc b/deps/v8/src/ic/mips64/handler-compiler-mips64.cc
index 52260ee754..53b097f8ce 100644
--- a/deps/v8/src/ic/mips64/handler-compiler-mips64.cc
+++ b/deps/v8/src/ic/mips64/handler-compiler-mips64.cc
@@ -195,9 +195,11 @@ void NamedLoadHandlerCompiler::GenerateLoadFunctionPrototype(
void PropertyHandlerCompiler::GenerateCheckPropertyCell(
MacroAssembler* masm, Handle<JSGlobalObject> global, Handle<Name> name,
Register scratch, Label* miss) {
- Handle<PropertyCell> cell = JSGlobalObject::EnsurePropertyCell(global, name);
- DCHECK(cell->value()->IsTheHole());
- Handle<WeakCell> weak_cell = masm->isolate()->factory()->NewWeakCell(cell);
+ Handle<PropertyCell> cell = JSGlobalObject::EnsureEmptyPropertyCell(
+ global, name, PropertyCellType::kInvalidated);
+ Isolate* isolate = masm->isolate();
+ DCHECK(cell->value()->IsTheHole(isolate));
+ Handle<WeakCell> weak_cell = isolate->factory()->NewWeakCell(cell);
__ LoadWeakValue(scratch, weak_cell, miss);
__ ld(scratch, FieldMemOperand(scratch, PropertyCell::kValueOffset));
__ LoadRoot(at, Heap::kTheHoleValueRootIndex);
@@ -279,7 +281,7 @@ void PropertyHandlerCompiler::GenerateApiAccessorCall(
Handle<CallHandlerInfo> api_call_info = optimization.api_call_info();
bool call_data_undefined = false;
// Put call data in place.
- if (api_call_info->data()->IsUndefined()) {
+ if (api_call_info->data()->IsUndefined(isolate)) {
call_data_undefined = true;
__ LoadRoot(data, Heap::kUndefinedValueRootIndex);
} else {
@@ -319,17 +321,8 @@ void PropertyHandlerCompiler::GenerateApiAccessorCall(
static void StoreIC_PushArgs(MacroAssembler* masm) {
__ Push(StoreDescriptor::ReceiverRegister(), StoreDescriptor::NameRegister(),
StoreDescriptor::ValueRegister(),
- VectorStoreICDescriptor::SlotRegister(),
- VectorStoreICDescriptor::VectorRegister());
-}
-
-
-void NamedStoreHandlerCompiler::GenerateSlow(MacroAssembler* masm) {
- StoreIC_PushArgs(masm);
-
- // The slow case calls into the runtime to complete the store without causing
- // an IC miss that would otherwise cause a transition to the generic stub.
- __ TailCallRuntime(Runtime::kStoreIC_Slow);
+ StoreWithVectorDescriptor::SlotRegister(),
+ StoreWithVectorDescriptor::VectorRegister());
}
@@ -423,28 +416,25 @@ 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)));
- }
+ 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));
- }
+ // 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.
@@ -480,8 +470,10 @@ Register PropertyHandlerCompiler::CheckPrototypes(
!current_map->is_access_check_needed());
prototype = handle(JSObject::cast(current_map->prototype()));
- if (current_map->is_dictionary_map() &&
- !current_map->IsJSGlobalObjectMap()) {
+ if (current_map->IsJSGlobalObjectMap()) {
+ GenerateCheckPropertyCell(masm(), Handle<JSGlobalObject>::cast(current),
+ name, scratch2, miss);
+ } else if (current_map->is_dictionary_map()) {
DCHECK(!current_map->IsJSGlobalProxyMap()); // Proxy maps are fast.
if (!name->IsUniqueName()) {
DCHECK(name->IsString());
@@ -491,33 +483,12 @@ Register PropertyHandlerCompiler::CheckPrototypes(
current->property_dictionary()->FindEntry(name) ==
NameDictionary::kNotFound);
- if (FLAG_eliminate_prototype_chain_checks && depth > 1) {
+ if (depth > 1) {
// TODO(jkummerow): Cache and re-use weak cell.
__ LoadWeakValue(reg, isolate()->factory()->NewWeakCell(current), miss);
}
GenerateDictionaryNegativeLookup(masm(), miss, reg, name, scratch1,
scratch2);
- if (!FLAG_eliminate_prototype_chain_checks) {
- __ ld(scratch1, FieldMemOperand(reg, HeapObject::kMapOffset));
- __ ld(holder_reg, FieldMemOperand(scratch1, Map::kPrototypeOffset));
- }
- } else {
- Register map_reg = scratch1;
- 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 (!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));
- }
- 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.
@@ -531,17 +502,8 @@ Register PropertyHandlerCompiler::CheckPrototypes(
// Log the check depth.
LOG(isolate(), IntEvent("check-maps-depth", depth + 1));
- 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);
- __ GetWeakValue(scratch2, cell);
- __ Branch(miss, ne, scratch2, Operand(scratch1));
- }
-
bool return_holder = return_what == RETURN_HOLDER;
- if (FLAG_eliminate_prototype_chain_checks && return_holder && depth != 0) {
+ if (return_holder && depth != 0) {
__ LoadWeakValue(reg, isolate()->factory()->NewWeakCell(current), miss);
}
@@ -584,70 +546,10 @@ void NamedLoadHandlerCompiler::GenerateLoadConstant(Handle<Object> value) {
}
-void NamedLoadHandlerCompiler::GenerateLoadCallback(
- Register reg, Handle<AccessorInfo> callback) {
- DCHECK(!AreAliased(scratch2(), scratch3(), scratch4(), receiver()));
- DCHECK(!AreAliased(scratch2(), scratch3(), scratch4(), reg));
-
- // Build v8::PropertyCallbackInfo::args_ array on the stack and push property
- // name below the exit frame to make GC aware of them.
- STATIC_ASSERT(PropertyCallbackArguments::kShouldThrowOnErrorIndex == 0);
- STATIC_ASSERT(PropertyCallbackArguments::kHolderIndex == 1);
- STATIC_ASSERT(PropertyCallbackArguments::kIsolateIndex == 2);
- STATIC_ASSERT(PropertyCallbackArguments::kReturnValueDefaultValueIndex == 3);
- STATIC_ASSERT(PropertyCallbackArguments::kReturnValueOffset == 4);
- STATIC_ASSERT(PropertyCallbackArguments::kDataIndex == 5);
- STATIC_ASSERT(PropertyCallbackArguments::kThisIndex == 6);
- STATIC_ASSERT(PropertyCallbackArguments::kArgsLength == 7);
-
- // Here and below +1 is for name() pushed after the args_ array.
- typedef PropertyCallbackArguments PCA;
- __ Dsubu(sp, sp, (PCA::kArgsLength + 1) * kPointerSize);
- __ sd(receiver(), MemOperand(sp, (PCA::kThisIndex + 1) * kPointerSize));
- Handle<Object> data(callback->data(), isolate());
- if (data->IsUndefined() || data->IsSmi()) {
- __ li(scratch2(), data);
- } else {
- Handle<WeakCell> cell =
- isolate()->factory()->NewWeakCell(Handle<HeapObject>::cast(data));
- // The callback is alive if this instruction is executed,
- // so the weak cell is not cleared and points to data.
- __ GetWeakValue(scratch2(), cell);
- }
- __ sd(scratch2(), MemOperand(sp, (PCA::kDataIndex + 1) * kPointerSize));
- __ LoadRoot(scratch2(), Heap::kUndefinedValueRootIndex);
- __ sd(scratch2(),
- MemOperand(sp, (PCA::kReturnValueOffset + 1) * kPointerSize));
- __ sd(scratch2(), MemOperand(sp, (PCA::kReturnValueDefaultValueIndex + 1) *
- kPointerSize));
- __ li(scratch2(), Operand(ExternalReference::isolate_address(isolate())));
- __ sd(scratch2(), MemOperand(sp, (PCA::kIsolateIndex + 1) * kPointerSize));
- __ sd(reg, MemOperand(sp, (PCA::kHolderIndex + 1) * kPointerSize));
- // should_throw_on_error -> false
- DCHECK(Smi::FromInt(0) == nullptr);
- __ sd(zero_reg,
- MemOperand(sp, (PCA::kShouldThrowOnErrorIndex + 1) * kPointerSize));
-
- __ sd(name(), MemOperand(sp, 0 * kPointerSize));
-
- // Abi for CallApiGetter.
- Register getter_address_reg = ApiGetterDescriptor::function_address();
-
- Address getter_address = v8::ToCData<Address>(callback->getter());
- ApiFunction fun(getter_address);
- ExternalReference::Type type = ExternalReference::DIRECT_GETTER_CALL;
- ExternalReference ref = ExternalReference(&fun, type, isolate());
- __ li(getter_address_reg, Operand(ref));
-
- CallApiGetterStub stub(isolate());
- __ TailCallStub(&stub);
-}
-
-
void NamedLoadHandlerCompiler::GenerateLoadInterceptorWithFollowup(
LookupIterator* it, Register holder_reg) {
DCHECK(holder()->HasNamedInterceptor());
- DCHECK(!holder()->GetNamedInterceptor()->getter()->IsUndefined());
+ DCHECK(!holder()->GetNamedInterceptor()->getter()->IsUndefined(isolate()));
// Compile the interceptor call, followed by inline code to load the
// property from further up the prototype chain if the call fails.
@@ -706,7 +608,7 @@ void NamedLoadHandlerCompiler::GenerateLoadInterceptorWithFollowup(
void NamedLoadHandlerCompiler::GenerateLoadInterceptor(Register holder_reg) {
// Call the runtime system to load the interceptor.
DCHECK(holder()->HasNamedInterceptor());
- DCHECK(!holder()->GetNamedInterceptor()->getter()->IsUndefined());
+ DCHECK(!holder()->GetNamedInterceptor()->getter()->IsUndefined(isolate()));
PushInterceptorArguments(masm(), receiver(), holder_reg, this->name(),
holder());
@@ -722,7 +624,7 @@ Handle<Code> NamedStoreHandlerCompiler::CompileStoreCallback(
__ Push(receiver(), holder_reg); // Receiver.
// If the callback cannot leak, then push the callback directly,
// otherwise wrap it in a weak cell.
- if (callback->data()->IsUndefined() || callback->data()->IsSmi()) {
+ if (callback->data()->IsUndefined(isolate()) || callback->data()->IsSmi()) {
__ li(at, Operand(callback));
} else {
Handle<WeakCell> cell = isolate()->factory()->NewWeakCell(callback);
@@ -737,7 +639,7 @@ Handle<Code> NamedStoreHandlerCompiler::CompileStoreCallback(
__ TailCallRuntime(Runtime::kStoreCallbackProperty);
// Return the generated code.
- return GetCode(kind(), Code::FAST, name);
+ return GetCode(kind(), name);
}
@@ -778,7 +680,7 @@ Handle<Code> NamedLoadHandlerCompiler::CompileLoadGlobal(
FrontendFooter(name, &miss);
// Return the generated code.
- return GetCode(kind(), Code::NORMAL, name);
+ return GetCode(kind(), name);
}
diff --git a/deps/v8/src/ic/mips64/ic-mips64.cc b/deps/v8/src/ic/mips64/ic-mips64.cc
index f46c9dcb26..b551bc70f6 100644
--- a/deps/v8/src/ic/mips64/ic-mips64.cc
+++ b/deps/v8/src/ic/mips64/ic-mips64.cc
@@ -418,10 +418,8 @@ void KeyedLoadIC::GenerateMegamorphic(MacroAssembler* masm) {
__ LoadRoot(vector, Heap::kDummyVectorRootIndex);
__ li(slot, Operand(Smi::FromInt(slot_index)));
- Code::Flags flags = Code::RemoveTypeAndHolderFromFlags(
- Code::ComputeHandlerFlags(Code::LOAD_IC));
- masm->isolate()->stub_cache()->GenerateProbe(masm, Code::LOAD_IC, flags,
- receiver, key, a4, a5, a6, t1);
+ masm->isolate()->load_stub_cache()->GenerateProbe(masm, receiver, key, a4, a5,
+ a6, t1);
// Cache miss.
GenerateMiss(masm);
@@ -622,11 +620,10 @@ void KeyedStoreIC::GenerateMegamorphic(MacroAssembler* masm,
__ JumpIfSmi(receiver, &slow);
// Get the map of the object.
__ ld(receiver_map, FieldMemOperand(receiver, HeapObject::kMapOffset));
- // Check that the receiver does not require access checks and is not observed.
- // The generic stub does not perform map checks or handle observed objects.
+ // Check that the receiver does not require access checks.
+ // The generic stub does not perform map checks.
__ lbu(a4, FieldMemOperand(receiver_map, Map::kBitFieldOffset));
- __ And(a4, a4,
- Operand(1 << Map::kIsAccessCheckNeeded | 1 << Map::kIsObserved));
+ __ And(a4, a4, Operand(1 << Map::kIsAccessCheckNeeded));
__ Branch(&slow, ne, a4, Operand(zero_reg));
// Check if the object is a JS array or not.
__ lbu(a4, FieldMemOperand(receiver_map, Map::kInstanceTypeOffset));
@@ -656,8 +653,8 @@ void KeyedStoreIC::GenerateMegamorphic(MacroAssembler* masm,
// The handlers in the stub cache expect a vector and slot. Since we won't
// change the IC from any downstream misses, a dummy vector can be used.
- Register vector = VectorStoreICDescriptor::VectorRegister();
- Register slot = VectorStoreICDescriptor::SlotRegister();
+ Register vector = StoreWithVectorDescriptor::VectorRegister();
+ Register slot = StoreWithVectorDescriptor::SlotRegister();
DCHECK(!AreAliased(vector, slot, a5, a6, a7, t0));
Handle<TypeFeedbackVector> dummy_vector =
@@ -667,10 +664,8 @@ void KeyedStoreIC::GenerateMegamorphic(MacroAssembler* masm,
__ LoadRoot(vector, Heap::kDummyVectorRootIndex);
__ li(slot, Operand(Smi::FromInt(slot_index)));
- Code::Flags flags = Code::RemoveTypeAndHolderFromFlags(
- Code::ComputeHandlerFlags(Code::STORE_IC));
- masm->isolate()->stub_cache()->GenerateProbe(masm, Code::STORE_IC, flags,
- receiver, key, a5, a6, a7, t0);
+ masm->isolate()->store_stub_cache()->GenerateProbe(masm, receiver, key, a5,
+ a6, a7, t0);
// Cache miss.
__ Branch(&miss);
@@ -721,8 +716,8 @@ void KeyedStoreIC::GenerateMegamorphic(MacroAssembler* masm,
static void StoreIC_PushArgs(MacroAssembler* masm) {
__ Push(StoreDescriptor::ReceiverRegister(), StoreDescriptor::NameRegister(),
StoreDescriptor::ValueRegister(),
- VectorStoreICDescriptor::SlotRegister(),
- VectorStoreICDescriptor::VectorRegister());
+ StoreWithVectorDescriptor::SlotRegister(),
+ StoreWithVectorDescriptor::VectorRegister());
}
@@ -732,25 +727,6 @@ void KeyedStoreIC::GenerateMiss(MacroAssembler* masm) {
__ TailCallRuntime(Runtime::kKeyedStoreIC_Miss);
}
-
-void StoreIC::GenerateMegamorphic(MacroAssembler* masm) {
- Register receiver = StoreDescriptor::ReceiverRegister();
- Register name = StoreDescriptor::NameRegister();
- DCHECK(receiver.is(a1));
- DCHECK(name.is(a2));
- DCHECK(StoreDescriptor::ValueRegister().is(a0));
-
- // Get the receiver from the stack and probe the stub cache.
- Code::Flags flags = Code::RemoveTypeAndHolderFromFlags(
- Code::ComputeHandlerFlags(Code::STORE_IC));
- masm->isolate()->stub_cache()->GenerateProbe(masm, Code::STORE_IC, flags,
- receiver, name, a3, a4, a5, a6);
-
- // Cache miss: Jump to runtime.
- GenerateMiss(masm);
-}
-
-
void StoreIC::GenerateMiss(MacroAssembler* masm) {
StoreIC_PushArgs(masm);
@@ -766,8 +742,8 @@ void StoreIC::GenerateNormal(MacroAssembler* masm) {
Register value = StoreDescriptor::ValueRegister();
Register dictionary = a5;
DCHECK(!AreAliased(
- value, receiver, name, VectorStoreICDescriptor::VectorRegister(),
- VectorStoreICDescriptor::SlotRegister(), dictionary, a6, a7));
+ value, receiver, name, StoreWithVectorDescriptor::VectorRegister(),
+ StoreWithVectorDescriptor::SlotRegister(), dictionary, a6, a7));
__ ld(dictionary, FieldMemOperand(receiver, JSObject::kPropertiesOffset));
@@ -842,8 +818,9 @@ void PatchInlinedSmiCode(Isolate* isolate, Address address,
}
if (FLAG_trace_ic) {
- PrintF("[ patching ic at %p, andi=%p, delta=%d\n", address,
- andi_instruction_address, delta);
+ PrintF("[ patching ic at %p, andi=%p, delta=%d\n",
+ static_cast<void*>(address),
+ static_cast<void*>(andi_instruction_address), delta);
}
Address patch_address =
diff --git a/deps/v8/src/ic/mips64/stub-cache-mips64.cc b/deps/v8/src/ic/mips64/stub-cache-mips64.cc
index 0bd7dd0f2d..6a87b7ba88 100644
--- a/deps/v8/src/ic/mips64/stub-cache-mips64.cc
+++ b/deps/v8/src/ic/mips64/stub-cache-mips64.cc
@@ -14,16 +14,15 @@ namespace internal {
#define __ ACCESS_MASM(masm)
-
-static void ProbeTable(Isolate* isolate, MacroAssembler* masm,
- Code::Kind ic_kind, Code::Flags flags,
+static void ProbeTable(StubCache* stub_cache, MacroAssembler* masm,
StubCache::Table table, Register receiver, Register name,
- // Number of the cache entry, not scaled.
+ // The offset is scaled by 4, based on
+ // kCacheIndexShift, which is two bits
Register offset, Register scratch, Register scratch2,
Register offset_scratch) {
- ExternalReference key_offset(isolate->stub_cache()->key_reference(table));
- ExternalReference value_offset(isolate->stub_cache()->value_reference(table));
- ExternalReference map_offset(isolate->stub_cache()->map_reference(table));
+ ExternalReference key_offset(stub_cache->key_reference(table));
+ ExternalReference value_offset(stub_cache->value_reference(table));
+ ExternalReference map_offset(stub_cache->map_reference(table));
uint64_t key_off_addr = reinterpret_cast<uint64_t>(key_offset.address());
uint64_t value_off_addr = reinterpret_cast<uint64_t>(value_offset.address());
@@ -46,7 +45,8 @@ static void ProbeTable(Isolate* isolate, MacroAssembler* masm,
// Calculate the base address of the entry.
__ li(base_addr, Operand(key_offset));
- __ Dlsa(base_addr, base_addr, offset_scratch, kPointerSizeLog2);
+ __ Dlsa(base_addr, base_addr, offset_scratch,
+ kPointerSizeLog2 - StubCache::kCacheIndexShift);
// Check that the key in the entry matches the name.
__ ld(at, MemOperand(base_addr, 0));
@@ -64,13 +64,6 @@ static void ProbeTable(Isolate* isolate, MacroAssembler* masm,
__ ld(code, MemOperand(base_addr,
static_cast<int32_t>(value_off_addr - key_off_addr)));
- // Check that the flags match what we're looking for.
- Register flags_reg = base_addr;
- base_addr = no_reg;
- __ lw(flags_reg, FieldMemOperand(code, Code::kFlagsOffset));
- __ And(flags_reg, flags_reg, Operand(~Code::kFlagsNotUsedInLookup));
- __ Branch(&miss, ne, flags_reg, Operand(flags));
-
#ifdef DEBUG
if (FLAG_test_secondary_stub_cache && table == StubCache::kPrimary) {
__ jmp(&miss);
@@ -87,12 +80,9 @@ static void ProbeTable(Isolate* isolate, MacroAssembler* masm,
__ bind(&miss);
}
-
-void StubCache::GenerateProbe(MacroAssembler* masm, Code::Kind ic_kind,
- Code::Flags flags, Register receiver,
+void StubCache::GenerateProbe(MacroAssembler* masm, Register receiver,
Register name, Register scratch, Register extra,
Register extra2, Register extra3) {
- Isolate* isolate = masm->isolate();
Label miss;
// Make sure that code is valid. The multiplying code relies on the
@@ -100,9 +90,6 @@ void StubCache::GenerateProbe(MacroAssembler* masm, Code::Kind ic_kind,
// DCHECK(sizeof(Entry) == 12);
// DCHECK(sizeof(Entry) == 3 * kPointerSize);
- // Make sure the flags does not name a specific type.
- DCHECK(Code::ExtractTypeFromFlags(flags) == 0);
-
// Make sure that there are no register conflicts.
DCHECK(!AreAliased(receiver, name, scratch, extra, extra2, extra3));
@@ -116,12 +103,13 @@ void StubCache::GenerateProbe(MacroAssembler* masm, Code::Kind ic_kind,
// If vector-based ics are in use, ensure that scratch, extra, extra2 and
// extra3 don't conflict with the vector and slot registers, which need
// to be preserved for a handler call or miss.
- if (IC::ICUseVector(ic_kind)) {
+ if (IC::ICUseVector(ic_kind_)) {
Register vector, slot;
- if (ic_kind == Code::STORE_IC || ic_kind == Code::KEYED_STORE_IC) {
- vector = VectorStoreICDescriptor::VectorRegister();
- slot = VectorStoreICDescriptor::SlotRegister();
+ if (ic_kind_ == Code::STORE_IC || ic_kind_ == Code::KEYED_STORE_IC) {
+ vector = StoreWithVectorDescriptor::VectorRegister();
+ slot = StoreWithVectorDescriptor::SlotRegister();
} else {
+ DCHECK(ic_kind_ == Code::LOAD_IC || ic_kind_ == Code::KEYED_LOAD_IC);
vector = LoadWithVectorDescriptor::VectorRegister();
slot = LoadWithVectorDescriptor::SlotRegister();
}
@@ -137,30 +125,26 @@ void StubCache::GenerateProbe(MacroAssembler* masm, Code::Kind ic_kind,
__ JumpIfSmi(receiver, &miss);
// Get the map of the receiver and compute the hash.
- __ ld(scratch, FieldMemOperand(name, Name::kHashFieldOffset));
+ __ lwu(scratch, FieldMemOperand(name, Name::kHashFieldOffset));
__ ld(at, FieldMemOperand(receiver, HeapObject::kMapOffset));
- __ Daddu(scratch, scratch, at);
- uint64_t mask = kPrimaryTableSize - 1;
- // We shift out the last two bits because they are not part of the hash and
- // they are always 01 for maps.
- __ dsrl(scratch, scratch, kCacheIndexShift);
- __ Xor(scratch, scratch, Operand((flags >> kCacheIndexShift) & mask));
- __ And(scratch, scratch, Operand(mask));
+ __ Addu(scratch, scratch, at);
+ __ Xor(scratch, scratch, Operand(kPrimaryMagic));
+ __ And(scratch, scratch,
+ Operand((kPrimaryTableSize - 1) << kCacheIndexShift));
// Probe the primary table.
- ProbeTable(isolate, masm, ic_kind, flags, kPrimary, receiver, name, scratch,
- extra, extra2, extra3);
+ ProbeTable(this, masm, kPrimary, receiver, name, scratch, extra, extra2,
+ extra3);
// Primary miss: Compute hash for secondary probe.
- __ dsrl(at, name, kCacheIndexShift);
- __ Dsubu(scratch, scratch, at);
- uint64_t mask2 = kSecondaryTableSize - 1;
- __ Daddu(scratch, scratch, Operand((flags >> kCacheIndexShift) & mask2));
- __ And(scratch, scratch, Operand(mask2));
+ __ Subu(scratch, scratch, name);
+ __ Addu(scratch, scratch, kSecondaryMagic);
+ __ And(scratch, scratch,
+ Operand((kSecondaryTableSize - 1) << kCacheIndexShift));
// Probe the secondary table.
- ProbeTable(isolate, masm, ic_kind, flags, kSecondary, receiver, name, scratch,
- extra, extra2, extra3);
+ ProbeTable(this, masm, kSecondary, receiver, name, scratch, extra, extra2,
+ extra3);
// Cache miss: Fall-through and let caller handle the miss by
// entering the runtime system.
diff --git a/deps/v8/src/ic/ppc/OWNERS b/deps/v8/src/ic/ppc/OWNERS
index eb007cb908..752e8e3d81 100644
--- a/deps/v8/src/ic/ppc/OWNERS
+++ b/deps/v8/src/ic/ppc/OWNERS
@@ -3,3 +3,4 @@ dstence@us.ibm.com
joransiu@ca.ibm.com
mbrandy@us.ibm.com
michael_dawson@ca.ibm.com
+bjaideep@ca.ibm.com
diff --git a/deps/v8/src/ic/ppc/access-compiler-ppc.cc b/deps/v8/src/ic/ppc/access-compiler-ppc.cc
index b1e06e16e1..6143b4ce47 100644
--- a/deps/v8/src/ic/ppc/access-compiler-ppc.cc
+++ b/deps/v8/src/ic/ppc/access-compiler-ppc.cc
@@ -19,19 +19,19 @@ void PropertyAccessCompiler::GenerateTailCall(MacroAssembler* masm,
Register* PropertyAccessCompiler::load_calling_convention() {
- // receiver, name, scratch1, scratch2, scratch3, scratch4.
+ // receiver, name, scratch1, scratch2, scratch3.
Register receiver = LoadDescriptor::ReceiverRegister();
Register name = LoadDescriptor::NameRegister();
- static Register registers[] = {receiver, name, r6, r3, r7, r8};
+ static Register registers[] = {receiver, name, r6, r3, r7};
return registers;
}
Register* PropertyAccessCompiler::store_calling_convention() {
- // receiver, name, scratch1, scratch2, scratch3.
+ // receiver, name, scratch1, scratch2.
Register receiver = StoreDescriptor::ReceiverRegister();
Register name = StoreDescriptor::NameRegister();
- static Register registers[] = {receiver, name, r6, r7, r8};
+ static Register registers[] = {receiver, name, r6, r7};
return registers;
}
diff --git a/deps/v8/src/ic/ppc/handler-compiler-ppc.cc b/deps/v8/src/ic/ppc/handler-compiler-ppc.cc
index 832c25ae48..22c0608c97 100644
--- a/deps/v8/src/ic/ppc/handler-compiler-ppc.cc
+++ b/deps/v8/src/ic/ppc/handler-compiler-ppc.cc
@@ -198,9 +198,11 @@ void NamedLoadHandlerCompiler::GenerateLoadFunctionPrototype(
void PropertyHandlerCompiler::GenerateCheckPropertyCell(
MacroAssembler* masm, Handle<JSGlobalObject> global, Handle<Name> name,
Register scratch, Label* miss) {
- Handle<PropertyCell> cell = JSGlobalObject::EnsurePropertyCell(global, name);
- DCHECK(cell->value()->IsTheHole());
- Handle<WeakCell> weak_cell = masm->isolate()->factory()->NewWeakCell(cell);
+ Handle<PropertyCell> cell = JSGlobalObject::EnsureEmptyPropertyCell(
+ global, name, PropertyCellType::kInvalidated);
+ Isolate* isolate = masm->isolate();
+ DCHECK(cell->value()->IsTheHole(isolate));
+ Handle<WeakCell> weak_cell = isolate->factory()->NewWeakCell(cell);
__ LoadWeakValue(scratch, weak_cell, miss);
__ LoadP(scratch, FieldMemOperand(scratch, PropertyCell::kValueOffset));
__ LoadRoot(ip, Heap::kTheHoleValueRootIndex);
@@ -285,7 +287,7 @@ void PropertyHandlerCompiler::GenerateApiAccessorCall(
Handle<CallHandlerInfo> api_call_info = optimization.api_call_info();
bool call_data_undefined = false;
// Put call data in place.
- if (api_call_info->data()->IsUndefined()) {
+ if (api_call_info->data()->IsUndefined(isolate)) {
call_data_undefined = true;
__ LoadRoot(data, Heap::kUndefinedValueRootIndex);
} else {
@@ -327,17 +329,8 @@ void PropertyHandlerCompiler::GenerateApiAccessorCall(
static void StoreIC_PushArgs(MacroAssembler* masm) {
__ Push(StoreDescriptor::ReceiverRegister(), StoreDescriptor::NameRegister(),
StoreDescriptor::ValueRegister(),
- VectorStoreICDescriptor::SlotRegister(),
- VectorStoreICDescriptor::VectorRegister());
-}
-
-
-void NamedStoreHandlerCompiler::GenerateSlow(MacroAssembler* masm) {
- StoreIC_PushArgs(masm);
-
- // The slow case calls into the runtime to complete the store without causing
- // an IC miss that would otherwise cause a transition to the generic stub.
- __ TailCallRuntime(Runtime::kStoreIC_Slow);
+ StoreWithVectorDescriptor::SlotRegister(),
+ StoreWithVectorDescriptor::VectorRegister());
}
@@ -432,28 +425,25 @@ 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);
- }
+ 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);
- }
+ // 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.
@@ -488,8 +478,10 @@ Register PropertyHandlerCompiler::CheckPrototypes(
!current_map->is_access_check_needed());
prototype = handle(JSObject::cast(current_map->prototype()));
- if (current_map->is_dictionary_map() &&
- !current_map->IsJSGlobalObjectMap()) {
+ if (current_map->IsJSGlobalObjectMap()) {
+ GenerateCheckPropertyCell(masm(), Handle<JSGlobalObject>::cast(current),
+ name, scratch2, miss);
+ } else if (current_map->is_dictionary_map()) {
DCHECK(!current_map->IsJSGlobalProxyMap()); // Proxy maps are fast.
if (!name->IsUniqueName()) {
DCHECK(name->IsString());
@@ -499,33 +491,12 @@ Register PropertyHandlerCompiler::CheckPrototypes(
current->property_dictionary()->FindEntry(name) ==
NameDictionary::kNotFound);
- if (FLAG_eliminate_prototype_chain_checks && depth > 1) {
+ if (depth > 1) {
// TODO(jkummerow): Cache and re-use weak cell.
__ LoadWeakValue(reg, isolate()->factory()->NewWeakCell(current), miss);
}
GenerateDictionaryNegativeLookup(masm(), miss, reg, name, scratch1,
scratch2);
- if (!FLAG_eliminate_prototype_chain_checks) {
- __ LoadP(scratch1, FieldMemOperand(reg, HeapObject::kMapOffset));
- __ LoadP(holder_reg, FieldMemOperand(scratch1, Map::kPrototypeOffset));
- }
- } else {
- Register map_reg = scratch1;
- 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 (!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);
- }
- 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.
@@ -539,17 +510,8 @@ Register PropertyHandlerCompiler::CheckPrototypes(
// Log the check depth.
LOG(isolate(), IntEvent("check-maps-depth", depth + 1));
- 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);
- __ CmpWeakValue(scratch1, cell, scratch2);
- __ bne(miss);
- }
-
bool return_holder = return_what == RETURN_HOLDER;
- if (FLAG_eliminate_prototype_chain_checks && return_holder && depth != 0) {
+ if (return_holder && depth != 0) {
__ LoadWeakValue(reg, isolate()->factory()->NewWeakCell(current), miss);
}
@@ -592,60 +554,10 @@ void NamedLoadHandlerCompiler::GenerateLoadConstant(Handle<Object> value) {
}
-void NamedLoadHandlerCompiler::GenerateLoadCallback(
- Register reg, Handle<AccessorInfo> callback) {
- DCHECK(!AreAliased(scratch2(), scratch3(), scratch4(), receiver()));
- DCHECK(!AreAliased(scratch2(), scratch3(), scratch4(), reg));
-
- // Build v8::PropertyCallbackInfo::args_ array on the stack and push property
- // name below the exit frame to make GC aware of them.
- STATIC_ASSERT(PropertyCallbackArguments::kShouldThrowOnErrorIndex == 0);
- STATIC_ASSERT(PropertyCallbackArguments::kHolderIndex == 1);
- STATIC_ASSERT(PropertyCallbackArguments::kIsolateIndex == 2);
- STATIC_ASSERT(PropertyCallbackArguments::kReturnValueDefaultValueIndex == 3);
- STATIC_ASSERT(PropertyCallbackArguments::kReturnValueOffset == 4);
- STATIC_ASSERT(PropertyCallbackArguments::kDataIndex == 5);
- STATIC_ASSERT(PropertyCallbackArguments::kThisIndex == 6);
- STATIC_ASSERT(PropertyCallbackArguments::kArgsLength == 7);
-
- __ push(receiver());
- // Push data from AccessorInfo.
- Handle<Object> data(callback->data(), isolate());
- if (data->IsUndefined() || data->IsSmi()) {
- __ Move(scratch2(), data);
- } else {
- Handle<WeakCell> cell =
- isolate()->factory()->NewWeakCell(Handle<HeapObject>::cast(data));
- // The callback is alive if this instruction is executed,
- // so the weak cell is not cleared and points to data.
- __ GetWeakValue(scratch2(), cell);
- }
- __ push(scratch2());
- __ LoadRoot(scratch2(), Heap::kUndefinedValueRootIndex);
- __ Push(scratch2(), scratch2());
- __ mov(scratch2(), Operand(ExternalReference::isolate_address(isolate())));
- // should_throw_on_error -> false
- __ mov(scratch3(), Operand(Smi::FromInt(0)));
- __ Push(scratch2(), reg, scratch3(), name());
-
- // Abi for CallApiGetter
- Register getter_address_reg = ApiGetterDescriptor::function_address();
-
- Address getter_address = v8::ToCData<Address>(callback->getter());
- ApiFunction fun(getter_address);
- ExternalReference::Type type = ExternalReference::DIRECT_GETTER_CALL;
- ExternalReference ref = ExternalReference(&fun, type, isolate());
- __ mov(getter_address_reg, Operand(ref));
-
- CallApiGetterStub stub(isolate());
- __ TailCallStub(&stub);
-}
-
-
void NamedLoadHandlerCompiler::GenerateLoadInterceptorWithFollowup(
LookupIterator* it, Register holder_reg) {
DCHECK(holder()->HasNamedInterceptor());
- DCHECK(!holder()->GetNamedInterceptor()->getter()->IsUndefined());
+ DCHECK(!holder()->GetNamedInterceptor()->getter()->IsUndefined(isolate()));
// Compile the interceptor call, followed by inline code to load the
// property from further up the prototype chain if the call fails.
@@ -705,7 +617,7 @@ void NamedLoadHandlerCompiler::GenerateLoadInterceptorWithFollowup(
void NamedLoadHandlerCompiler::GenerateLoadInterceptor(Register holder_reg) {
// Call the runtime system to load the interceptor.
DCHECK(holder()->HasNamedInterceptor());
- DCHECK(!holder()->GetNamedInterceptor()->getter()->IsUndefined());
+ DCHECK(!holder()->GetNamedInterceptor()->getter()->IsUndefined(isolate()));
PushInterceptorArguments(masm(), receiver(), holder_reg, this->name(),
holder());
@@ -722,7 +634,7 @@ Handle<Code> NamedStoreHandlerCompiler::CompileStoreCallback(
// If the callback cannot leak, then push the callback directly,
// otherwise wrap it in a weak cell.
- if (callback->data()->IsUndefined() || callback->data()->IsSmi()) {
+ if (callback->data()->IsUndefined(isolate()) || callback->data()->IsSmi()) {
__ mov(ip, Operand(callback));
} else {
Handle<WeakCell> cell = isolate()->factory()->NewWeakCell(callback);
@@ -737,7 +649,7 @@ Handle<Code> NamedStoreHandlerCompiler::CompileStoreCallback(
__ TailCallRuntime(Runtime::kStoreCallbackProperty);
// Return the generated code.
- return GetCode(kind(), Code::FAST, name);
+ return GetCode(kind(), name);
}
@@ -777,7 +689,7 @@ Handle<Code> NamedLoadHandlerCompiler::CompileLoadGlobal(
FrontendFooter(name, &miss);
// Return the generated code.
- return GetCode(kind(), Code::NORMAL, name);
+ return GetCode(kind(), name);
}
diff --git a/deps/v8/src/ic/ppc/ic-ppc.cc b/deps/v8/src/ic/ppc/ic-ppc.cc
index 567296c4c5..fd2962d0fa 100644
--- a/deps/v8/src/ic/ppc/ic-ppc.cc
+++ b/deps/v8/src/ic/ppc/ic-ppc.cc
@@ -425,10 +425,8 @@ void KeyedLoadIC::GenerateMegamorphic(MacroAssembler* masm) {
__ LoadRoot(vector, Heap::kDummyVectorRootIndex);
__ LoadSmiLiteral(slot, Smi::FromInt(slot_index));
- Code::Flags flags = Code::RemoveTypeAndHolderFromFlags(
- Code::ComputeHandlerFlags(Code::LOAD_IC));
- masm->isolate()->stub_cache()->GenerateProbe(masm, Code::KEYED_LOAD_IC, flags,
- receiver, key, r7, r8, r9, r10);
+ masm->isolate()->load_stub_cache()->GenerateProbe(masm, receiver, key, r7, r8,
+ r9, r10);
// Cache miss.
GenerateMiss(masm);
@@ -455,8 +453,8 @@ void KeyedLoadIC::GenerateMegamorphic(MacroAssembler* masm) {
static void StoreIC_PushArgs(MacroAssembler* masm) {
__ Push(StoreDescriptor::ReceiverRegister(), StoreDescriptor::NameRegister(),
StoreDescriptor::ValueRegister(),
- VectorStoreICDescriptor::SlotRegister(),
- VectorStoreICDescriptor::VectorRegister());
+ StoreWithVectorDescriptor::SlotRegister(),
+ StoreWithVectorDescriptor::VectorRegister());
}
@@ -639,11 +637,10 @@ void KeyedStoreIC::GenerateMegamorphic(MacroAssembler* masm,
__ JumpIfSmi(receiver, &slow);
// Get the map of the object.
__ LoadP(receiver_map, FieldMemOperand(receiver, HeapObject::kMapOffset));
- // Check that the receiver does not require access checks and is not observed.
- // The generic stub does not perform map checks or handle observed objects.
+ // Check that the receiver does not require access checks.
+ // The generic stub does not perform map checks.
__ lbz(ip, FieldMemOperand(receiver_map, Map::kBitFieldOffset));
- __ andi(r0, ip,
- Operand(1 << Map::kIsAccessCheckNeeded | 1 << Map::kIsObserved));
+ __ andi(r0, ip, Operand(1 << Map::kIsAccessCheckNeeded));
__ bne(&slow, cr0);
// Check if the object is a JS array or not.
__ lbz(r7, FieldMemOperand(receiver_map, Map::kInstanceTypeOffset));
@@ -676,8 +673,8 @@ void KeyedStoreIC::GenerateMegamorphic(MacroAssembler* masm,
// The handlers in the stub cache expect a vector and slot. Since we won't
// change the IC from any downstream misses, a dummy vector can be used.
- Register vector = VectorStoreICDescriptor::VectorRegister();
- Register slot = VectorStoreICDescriptor::SlotRegister();
+ Register vector = StoreWithVectorDescriptor::VectorRegister();
+ Register slot = StoreWithVectorDescriptor::SlotRegister();
DCHECK(!AreAliased(vector, slot, r8, r9, r10, r11));
Handle<TypeFeedbackVector> dummy_vector =
TypeFeedbackVector::DummyVector(masm->isolate());
@@ -686,10 +683,8 @@ void KeyedStoreIC::GenerateMegamorphic(MacroAssembler* masm,
__ LoadRoot(vector, Heap::kDummyVectorRootIndex);
__ LoadSmiLiteral(slot, Smi::FromInt(slot_index));
- Code::Flags flags = Code::RemoveTypeAndHolderFromFlags(
- Code::ComputeHandlerFlags(Code::STORE_IC));
- masm->isolate()->stub_cache()->GenerateProbe(masm, Code::STORE_IC, flags,
- receiver, key, r8, r9, r10, r11);
+ masm->isolate()->store_stub_cache()->GenerateProbe(masm, receiver, key, r8,
+ r9, r10, r11);
// Cache miss.
__ b(&miss);
@@ -738,26 +733,6 @@ void KeyedStoreIC::GenerateMegamorphic(MacroAssembler* masm,
GenerateMiss(masm);
}
-
-void StoreIC::GenerateMegamorphic(MacroAssembler* masm) {
- Register receiver = StoreDescriptor::ReceiverRegister();
- Register name = StoreDescriptor::NameRegister();
- DCHECK(receiver.is(r4));
- DCHECK(name.is(r5));
- DCHECK(StoreDescriptor::ValueRegister().is(r3));
-
- // Get the receiver from the stack and probe the stub cache.
- Code::Flags flags = Code::RemoveTypeAndHolderFromFlags(
- Code::ComputeHandlerFlags(Code::STORE_IC));
-
- masm->isolate()->stub_cache()->GenerateProbe(masm, Code::STORE_IC, flags,
- receiver, name, r6, r7, r8, r9);
-
- // Cache miss: Jump to runtime.
- GenerateMiss(masm);
-}
-
-
void StoreIC::GenerateMiss(MacroAssembler* masm) {
StoreIC_PushArgs(masm);
@@ -775,8 +750,8 @@ void StoreIC::GenerateNormal(MacroAssembler* masm) {
DCHECK(receiver.is(r4));
DCHECK(name.is(r5));
DCHECK(value.is(r3));
- DCHECK(VectorStoreICDescriptor::VectorRegister().is(r6));
- DCHECK(VectorStoreICDescriptor::SlotRegister().is(r7));
+ DCHECK(StoreWithVectorDescriptor::VectorRegister().is(r6));
+ DCHECK(StoreWithVectorDescriptor::SlotRegister().is(r7));
__ LoadP(dictionary, FieldMemOperand(receiver, JSObject::kPropertiesOffset));
@@ -852,8 +827,9 @@ void PatchInlinedSmiCode(Isolate* isolate, Address address,
}
if (FLAG_trace_ic) {
- PrintF("[ patching ic at %p, cmp=%p, delta=%d\n", address,
- cmp_instruction_address, delta);
+ PrintF("[ patching ic at %p, cmp=%p, delta=%d\n",
+ static_cast<void*>(address),
+ static_cast<void*>(cmp_instruction_address), delta);
}
Address patch_address =
diff --git a/deps/v8/src/ic/ppc/stub-cache-ppc.cc b/deps/v8/src/ic/ppc/stub-cache-ppc.cc
index 6030b2cbc8..3dad306f11 100644
--- a/deps/v8/src/ic/ppc/stub-cache-ppc.cc
+++ b/deps/v8/src/ic/ppc/stub-cache-ppc.cc
@@ -14,16 +14,15 @@ namespace internal {
#define __ ACCESS_MASM(masm)
-
-static void ProbeTable(Isolate* isolate, MacroAssembler* masm,
- Code::Kind ic_kind, Code::Flags flags,
+static void ProbeTable(StubCache* stub_cache, MacroAssembler* masm,
StubCache::Table table, Register receiver, Register name,
- // Number of the cache entry, not scaled.
+ // The offset is scaled by 4, based on
+ // kCacheIndexShift, which is two bits
Register offset, Register scratch, Register scratch2,
Register offset_scratch) {
- ExternalReference key_offset(isolate->stub_cache()->key_reference(table));
- ExternalReference value_offset(isolate->stub_cache()->value_reference(table));
- ExternalReference map_offset(isolate->stub_cache()->map_reference(table));
+ ExternalReference key_offset(stub_cache->key_reference(table));
+ ExternalReference value_offset(stub_cache->value_reference(table));
+ ExternalReference map_offset(stub_cache->map_reference(table));
uintptr_t key_off_addr = reinterpret_cast<uintptr_t>(key_offset.address());
uintptr_t value_off_addr =
@@ -73,18 +72,6 @@ static void ProbeTable(Isolate* isolate, MacroAssembler* masm,
scratch2 = no_reg;
__ LoadP(code, MemOperand(base_addr, value_off_addr - key_off_addr));
- // Check that the flags match what we're looking for.
- Register flags_reg = base_addr;
- base_addr = no_reg;
- __ lwz(flags_reg, FieldMemOperand(code, Code::kFlagsOffset));
-
- DCHECK(!r0.is(flags_reg));
- __ li(r0, Operand(Code::kFlagsNotUsedInLookup));
- __ andc(flags_reg, flags_reg, r0);
- __ mov(r0, Operand(flags));
- __ cmpl(flags_reg, r0);
- __ bne(&miss);
-
#ifdef DEBUG
if (FLAG_test_secondary_stub_cache && table == StubCache::kPrimary) {
__ b(&miss);
@@ -102,12 +89,9 @@ static void ProbeTable(Isolate* isolate, MacroAssembler* masm,
__ bind(&miss);
}
-
-void StubCache::GenerateProbe(MacroAssembler* masm, Code::Kind ic_kind,
- Code::Flags flags, Register receiver,
+void StubCache::GenerateProbe(MacroAssembler* masm, Register receiver,
Register name, Register scratch, Register extra,
Register extra2, Register extra3) {
- Isolate* isolate = masm->isolate();
Label miss;
#if V8_TARGET_ARCH_PPC64
@@ -120,9 +104,6 @@ void StubCache::GenerateProbe(MacroAssembler* masm, Code::Kind ic_kind,
DCHECK(sizeof(Entry) == 12);
#endif
- // Make sure the flags does not name a specific type.
- DCHECK(Code::ExtractTypeFromFlags(flags) == 0);
-
// Make sure that there are no register conflicts.
DCHECK(!AreAliased(receiver, name, scratch, extra, extra2, extra3));
@@ -136,12 +117,13 @@ void StubCache::GenerateProbe(MacroAssembler* masm, Code::Kind ic_kind,
// If vector-based ics are in use, ensure that scratch, extra, extra2 and
// extra3 don't conflict with the vector and slot registers, which need
// to be preserved for a handler call or miss.
- if (IC::ICUseVector(ic_kind)) {
+ if (IC::ICUseVector(ic_kind_)) {
Register vector, slot;
- if (ic_kind == Code::STORE_IC || ic_kind == Code::KEYED_STORE_IC) {
- vector = VectorStoreICDescriptor::VectorRegister();
- slot = VectorStoreICDescriptor::SlotRegister();
+ if (ic_kind_ == Code::STORE_IC || ic_kind_ == Code::KEYED_STORE_IC) {
+ vector = StoreWithVectorDescriptor::VectorRegister();
+ slot = StoreWithVectorDescriptor::SlotRegister();
} else {
+ DCHECK(ic_kind_ == Code::LOAD_IC || ic_kind_ == Code::KEYED_LOAD_IC);
vector = LoadWithVectorDescriptor::VectorRegister();
slot = LoadWithVectorDescriptor::SlotRegister();
}
@@ -160,24 +142,24 @@ void StubCache::GenerateProbe(MacroAssembler* masm, Code::Kind ic_kind,
__ lwz(scratch, FieldMemOperand(name, Name::kHashFieldOffset));
__ LoadP(ip, FieldMemOperand(receiver, HeapObject::kMapOffset));
__ add(scratch, scratch, ip);
- __ xori(scratch, scratch, Operand(flags));
+ __ Xor(scratch, scratch, Operand(kPrimaryMagic));
// The mask omits the last two bits because they are not part of the hash.
__ andi(scratch, scratch,
Operand((kPrimaryTableSize - 1) << kCacheIndexShift));
// Probe the primary table.
- ProbeTable(isolate, masm, ic_kind, flags, kPrimary, receiver, name, scratch,
- extra, extra2, extra3);
+ ProbeTable(this, masm, kPrimary, receiver, name, scratch, extra, extra2,
+ extra3);
// Primary miss: Compute hash for secondary probe.
__ sub(scratch, scratch, name);
- __ addi(scratch, scratch, Operand(flags));
+ __ Add(scratch, scratch, kSecondaryMagic, r0);
__ andi(scratch, scratch,
Operand((kSecondaryTableSize - 1) << kCacheIndexShift));
// Probe the secondary table.
- ProbeTable(isolate, masm, ic_kind, flags, kSecondary, receiver, name, scratch,
- extra, extra2, extra3);
+ ProbeTable(this, masm, kSecondary, receiver, name, scratch, extra, extra2,
+ extra3);
// Cache miss: Fall-through and let caller handle the miss by
// entering the runtime system.
diff --git a/deps/v8/src/ic/s390/OWNERS b/deps/v8/src/ic/s390/OWNERS
index eb007cb908..752e8e3d81 100644
--- a/deps/v8/src/ic/s390/OWNERS
+++ b/deps/v8/src/ic/s390/OWNERS
@@ -3,3 +3,4 @@ dstence@us.ibm.com
joransiu@ca.ibm.com
mbrandy@us.ibm.com
michael_dawson@ca.ibm.com
+bjaideep@ca.ibm.com
diff --git a/deps/v8/src/ic/s390/access-compiler-s390.cc b/deps/v8/src/ic/s390/access-compiler-s390.cc
index 316be715c2..0a3285d5aa 100644
--- a/deps/v8/src/ic/s390/access-compiler-s390.cc
+++ b/deps/v8/src/ic/s390/access-compiler-s390.cc
@@ -19,18 +19,18 @@ void PropertyAccessCompiler::GenerateTailCall(MacroAssembler* masm,
}
Register* PropertyAccessCompiler::load_calling_convention() {
- // receiver, name, scratch1, scratch2, scratch3, scratch4.
+ // receiver, name, scratch1, scratch2, scratch3.
Register receiver = LoadDescriptor::ReceiverRegister();
Register name = LoadDescriptor::NameRegister();
- static Register registers[] = {receiver, name, r5, r2, r6, r7};
+ static Register registers[] = {receiver, name, r5, r2, r6};
return registers;
}
Register* PropertyAccessCompiler::store_calling_convention() {
- // receiver, name, scratch1, scratch2, scratch3.
+ // receiver, name, scratch1, scratch2.
Register receiver = StoreDescriptor::ReceiverRegister();
Register name = StoreDescriptor::NameRegister();
- static Register registers[] = {receiver, name, r5, r6, r7};
+ static Register registers[] = {receiver, name, r5, r6};
return registers;
}
diff --git a/deps/v8/src/ic/s390/handler-compiler-s390.cc b/deps/v8/src/ic/s390/handler-compiler-s390.cc
index 1b39782c28..b399c5a601 100644
--- a/deps/v8/src/ic/s390/handler-compiler-s390.cc
+++ b/deps/v8/src/ic/s390/handler-compiler-s390.cc
@@ -187,9 +187,11 @@ void NamedLoadHandlerCompiler::GenerateLoadFunctionPrototype(
void PropertyHandlerCompiler::GenerateCheckPropertyCell(
MacroAssembler* masm, Handle<JSGlobalObject> global, Handle<Name> name,
Register scratch, Label* miss) {
- Handle<PropertyCell> cell = JSGlobalObject::EnsurePropertyCell(global, name);
- DCHECK(cell->value()->IsTheHole());
- Handle<WeakCell> weak_cell = masm->isolate()->factory()->NewWeakCell(cell);
+ Handle<PropertyCell> cell = JSGlobalObject::EnsureEmptyPropertyCell(
+ global, name, PropertyCellType::kInvalidated);
+ Isolate* isolate = masm->isolate();
+ DCHECK(cell->value()->IsTheHole(isolate));
+ Handle<WeakCell> weak_cell = isolate->factory()->NewWeakCell(cell);
__ LoadWeakValue(scratch, weak_cell, miss);
__ LoadP(scratch, FieldMemOperand(scratch, PropertyCell::kValueOffset));
__ CompareRoot(scratch, Heap::kTheHoleValueRootIndex);
@@ -270,7 +272,7 @@ void PropertyHandlerCompiler::GenerateApiAccessorCall(
Handle<CallHandlerInfo> api_call_info = optimization.api_call_info();
bool call_data_undefined = false;
// Put call data in place.
- if (api_call_info->data()->IsUndefined()) {
+ if (api_call_info->data()->IsUndefined(isolate)) {
call_data_undefined = true;
__ LoadRoot(data, Heap::kUndefinedValueRootIndex);
} else {
@@ -311,16 +313,8 @@ void PropertyHandlerCompiler::GenerateApiAccessorCall(
static void StoreIC_PushArgs(MacroAssembler* masm) {
__ Push(StoreDescriptor::ReceiverRegister(), StoreDescriptor::NameRegister(),
StoreDescriptor::ValueRegister(),
- VectorStoreICDescriptor::SlotRegister(),
- VectorStoreICDescriptor::VectorRegister());
-}
-
-void NamedStoreHandlerCompiler::GenerateSlow(MacroAssembler* masm) {
- StoreIC_PushArgs(masm);
-
- // The slow case calls into the runtime to complete the store without causing
- // an IC miss that would otherwise cause a transition to the generic stub.
- __ TailCallRuntime(Runtime::kStoreIC_Slow);
+ StoreWithVectorDescriptor::SlotRegister(),
+ StoreWithVectorDescriptor::VectorRegister());
}
void ElementHandlerCompiler::GenerateStoreSlow(MacroAssembler* masm) {
@@ -406,28 +400,25 @@ 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);
- }
+ 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);
- }
+ // 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.
@@ -462,8 +453,10 @@ Register PropertyHandlerCompiler::CheckPrototypes(
!current_map->is_access_check_needed());
prototype = handle(JSObject::cast(current_map->prototype()));
- if (current_map->is_dictionary_map() &&
- !current_map->IsJSGlobalObjectMap()) {
+ if (current_map->IsJSGlobalObjectMap()) {
+ GenerateCheckPropertyCell(masm(), Handle<JSGlobalObject>::cast(current),
+ name, scratch2, miss);
+ } else if (current_map->is_dictionary_map()) {
DCHECK(!current_map->IsJSGlobalProxyMap()); // Proxy maps are fast.
if (!name->IsUniqueName()) {
DCHECK(name->IsString());
@@ -473,33 +466,12 @@ Register PropertyHandlerCompiler::CheckPrototypes(
current->property_dictionary()->FindEntry(name) ==
NameDictionary::kNotFound);
- if (FLAG_eliminate_prototype_chain_checks && depth > 1) {
+ if (depth > 1) {
// TODO(jkummerow): Cache and re-use weak cell.
__ LoadWeakValue(reg, isolate()->factory()->NewWeakCell(current), miss);
}
GenerateDictionaryNegativeLookup(masm(), miss, reg, name, scratch1,
scratch2);
- if (!FLAG_eliminate_prototype_chain_checks) {
- __ LoadP(scratch1, FieldMemOperand(reg, HeapObject::kMapOffset));
- __ LoadP(holder_reg, FieldMemOperand(scratch1, Map::kPrototypeOffset));
- }
- } else {
- Register map_reg = scratch1;
- 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 (!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);
- }
- 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.
@@ -513,17 +485,8 @@ Register PropertyHandlerCompiler::CheckPrototypes(
// Log the check depth.
LOG(isolate(), IntEvent("check-maps-depth", depth + 1));
- 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);
- __ CmpWeakValue(scratch1, cell, scratch2);
- __ bne(miss);
- }
-
bool return_holder = return_what == RETURN_HOLDER;
- if (FLAG_eliminate_prototype_chain_checks && return_holder && depth != 0) {
+ if (return_holder && depth != 0) {
__ LoadWeakValue(reg, isolate()->factory()->NewWeakCell(current), miss);
}
@@ -562,59 +525,10 @@ void NamedLoadHandlerCompiler::GenerateLoadConstant(Handle<Object> value) {
__ Ret();
}
-void NamedLoadHandlerCompiler::GenerateLoadCallback(
- Register reg, Handle<AccessorInfo> callback) {
- DCHECK(!AreAliased(scratch2(), scratch3(), scratch4(), receiver()));
- DCHECK(!AreAliased(scratch2(), scratch3(), scratch4(), reg));
-
- // Build v8::PropertyCallbackInfo::args_ array on the stack and push property
- // name below the exit frame to make GC aware of them.
- STATIC_ASSERT(PropertyCallbackArguments::kShouldThrowOnErrorIndex == 0);
- STATIC_ASSERT(PropertyCallbackArguments::kHolderIndex == 1);
- STATIC_ASSERT(PropertyCallbackArguments::kIsolateIndex == 2);
- STATIC_ASSERT(PropertyCallbackArguments::kReturnValueDefaultValueIndex == 3);
- STATIC_ASSERT(PropertyCallbackArguments::kReturnValueOffset == 4);
- STATIC_ASSERT(PropertyCallbackArguments::kDataIndex == 5);
- STATIC_ASSERT(PropertyCallbackArguments::kThisIndex == 6);
- STATIC_ASSERT(PropertyCallbackArguments::kArgsLength == 7);
-
- __ Push(receiver());
- // Push data from AccessorInfo.
- Handle<Object> data(callback->data(), isolate());
- if (data->IsUndefined() || data->IsSmi()) {
- __ Move(scratch2(), data);
- } else {
- Handle<WeakCell> cell =
- isolate()->factory()->NewWeakCell(Handle<HeapObject>::cast(data));
- // The callback is alive if this instruction is executed,
- // so the weak cell is not cleared and points to data.
- __ GetWeakValue(scratch2(), cell);
- }
- __ push(scratch2());
- __ LoadRoot(scratch2(), Heap::kUndefinedValueRootIndex);
- __ Push(scratch2(), scratch2());
- __ mov(scratch2(), Operand(ExternalReference::isolate_address(isolate())));
- // should_throw_on_error -> false
- __ mov(scratch3(), Operand(Smi::FromInt(0)));
- __ Push(scratch2(), reg, scratch3(), name());
-
- // Abi for CallApiGetter
- Register getter_address_reg = ApiGetterDescriptor::function_address();
-
- Address getter_address = v8::ToCData<Address>(callback->getter());
- ApiFunction fun(getter_address);
- ExternalReference::Type type = ExternalReference::DIRECT_GETTER_CALL;
- ExternalReference ref = ExternalReference(&fun, type, isolate());
- __ mov(getter_address_reg, Operand(ref));
-
- CallApiGetterStub stub(isolate());
- __ TailCallStub(&stub);
-}
-
void NamedLoadHandlerCompiler::GenerateLoadInterceptorWithFollowup(
LookupIterator* it, Register holder_reg) {
DCHECK(holder()->HasNamedInterceptor());
- DCHECK(!holder()->GetNamedInterceptor()->getter()->IsUndefined());
+ DCHECK(!holder()->GetNamedInterceptor()->getter()->IsUndefined(isolate()));
// Compile the interceptor call, followed by inline code to load the
// property from further up the prototype chain if the call fails.
@@ -672,7 +586,7 @@ void NamedLoadHandlerCompiler::GenerateLoadInterceptorWithFollowup(
void NamedLoadHandlerCompiler::GenerateLoadInterceptor(Register holder_reg) {
// Call the runtime system to load the interceptor.
DCHECK(holder()->HasNamedInterceptor());
- DCHECK(!holder()->GetNamedInterceptor()->getter()->IsUndefined());
+ DCHECK(!holder()->GetNamedInterceptor()->getter()->IsUndefined(isolate()));
PushInterceptorArguments(masm(), receiver(), holder_reg, this->name(),
holder());
@@ -688,7 +602,7 @@ Handle<Code> NamedStoreHandlerCompiler::CompileStoreCallback(
// If the callback cannot leak, then push the callback directly,
// otherwise wrap it in a weak cell.
- if (callback->data()->IsUndefined() || callback->data()->IsSmi()) {
+ if (callback->data()->IsUndefined(isolate()) || callback->data()->IsSmi()) {
__ mov(ip, Operand(callback));
} else {
Handle<WeakCell> cell = isolate()->factory()->NewWeakCell(callback);
@@ -703,7 +617,7 @@ Handle<Code> NamedStoreHandlerCompiler::CompileStoreCallback(
__ TailCallRuntime(Runtime::kStoreCallbackProperty);
// Return the generated code.
- return GetCode(kind(), Code::FAST, name);
+ return GetCode(kind(), name);
}
Register NamedStoreHandlerCompiler::value() {
@@ -740,7 +654,7 @@ Handle<Code> NamedLoadHandlerCompiler::CompileLoadGlobal(
FrontendFooter(name, &miss);
// Return the generated code.
- return GetCode(kind(), Code::NORMAL, name);
+ return GetCode(kind(), name);
}
#undef __
diff --git a/deps/v8/src/ic/s390/ic-s390.cc b/deps/v8/src/ic/s390/ic-s390.cc
index d4f28868e7..6bb484a2fd 100644
--- a/deps/v8/src/ic/s390/ic-s390.cc
+++ b/deps/v8/src/ic/s390/ic-s390.cc
@@ -412,10 +412,8 @@ void KeyedLoadIC::GenerateMegamorphic(MacroAssembler* masm) {
__ LoadRoot(vector, Heap::kDummyVectorRootIndex);
__ LoadSmiLiteral(slot, Smi::FromInt(slot_index));
- Code::Flags flags = Code::RemoveTypeAndHolderFromFlags(
- Code::ComputeHandlerFlags(Code::LOAD_IC));
- masm->isolate()->stub_cache()->GenerateProbe(masm, Code::KEYED_LOAD_IC, flags,
- receiver, key, r6, r7, r8, r9);
+ masm->isolate()->load_stub_cache()->GenerateProbe(masm, receiver, key, r6, r7,
+ r8, r9);
// Cache miss.
GenerateMiss(masm);
@@ -441,8 +439,8 @@ void KeyedLoadIC::GenerateMegamorphic(MacroAssembler* masm) {
static void StoreIC_PushArgs(MacroAssembler* masm) {
__ Push(StoreDescriptor::ReceiverRegister(), StoreDescriptor::NameRegister(),
StoreDescriptor::ValueRegister(),
- VectorStoreICDescriptor::SlotRegister(),
- VectorStoreICDescriptor::VectorRegister());
+ StoreWithVectorDescriptor::SlotRegister(),
+ StoreWithVectorDescriptor::VectorRegister());
}
void KeyedStoreIC::GenerateMiss(MacroAssembler* masm) {
@@ -625,11 +623,10 @@ void KeyedStoreIC::GenerateMegamorphic(MacroAssembler* masm,
__ JumpIfSmi(receiver, &slow);
// Get the map of the object.
__ LoadP(receiver_map, FieldMemOperand(receiver, HeapObject::kMapOffset));
- // Check that the receiver does not require access checks and is not observed.
- // The generic stub does not perform map checks or handle observed objects.
+ // Check that the receiver does not require access checks.
+ // The generic stub does not perform map checks.
__ LoadlB(ip, FieldMemOperand(receiver_map, Map::kBitFieldOffset));
- __ AndP(r0, ip,
- Operand(1 << Map::kIsAccessCheckNeeded | 1 << Map::kIsObserved));
+ __ AndP(r0, ip, Operand(1 << Map::kIsAccessCheckNeeded));
__ bne(&slow, Label::kNear);
// Check if the object is a JS array or not.
__ LoadlB(r6, FieldMemOperand(receiver_map, Map::kInstanceTypeOffset));
@@ -661,8 +658,8 @@ void KeyedStoreIC::GenerateMegamorphic(MacroAssembler* masm,
// The handlers in the stub cache expect a vector and slot. Since we won't
// change the IC from any downstream misses, a dummy vector can be used.
- Register vector = VectorStoreICDescriptor::VectorRegister();
- Register slot = VectorStoreICDescriptor::SlotRegister();
+ Register vector = StoreWithVectorDescriptor::VectorRegister();
+ Register slot = StoreWithVectorDescriptor::SlotRegister();
DCHECK(!AreAliased(vector, slot, r7, r8, r9, ip));
Handle<TypeFeedbackVector> dummy_vector =
TypeFeedbackVector::DummyVector(masm->isolate());
@@ -671,10 +668,8 @@ void KeyedStoreIC::GenerateMegamorphic(MacroAssembler* masm,
__ LoadRoot(vector, Heap::kDummyVectorRootIndex);
__ LoadSmiLiteral(slot, Smi::FromInt(slot_index));
- Code::Flags flags = Code::RemoveTypeAndHolderFromFlags(
- Code::ComputeHandlerFlags(Code::STORE_IC));
- masm->isolate()->stub_cache()->GenerateProbe(masm, Code::STORE_IC, flags,
- receiver, key, r7, r8, r9, ip);
+ masm->isolate()->store_stub_cache()->GenerateProbe(masm, receiver, key, r7,
+ r8, r9, ip);
// Cache miss.
__ b(&miss);
@@ -720,24 +715,6 @@ void KeyedStoreIC::GenerateMegamorphic(MacroAssembler* masm,
GenerateMiss(masm);
}
-void StoreIC::GenerateMegamorphic(MacroAssembler* masm) {
- Register receiver = StoreDescriptor::ReceiverRegister();
- Register name = StoreDescriptor::NameRegister();
- DCHECK(receiver.is(r3));
- DCHECK(name.is(r4));
- DCHECK(StoreDescriptor::ValueRegister().is(r2));
-
- // Get the receiver from the stack and probe the stub cache.
- Code::Flags flags = Code::RemoveTypeAndHolderFromFlags(
- Code::ComputeHandlerFlags(Code::STORE_IC));
-
- masm->isolate()->stub_cache()->GenerateProbe(masm, Code::STORE_IC, flags,
- receiver, name, r5, r6, r7, r8);
-
- // Cache miss: Jump to runtime.
- GenerateMiss(masm);
-}
-
void StoreIC::GenerateMiss(MacroAssembler* masm) {
StoreIC_PushArgs(masm);
@@ -754,8 +731,8 @@ void StoreIC::GenerateNormal(MacroAssembler* masm) {
DCHECK(receiver.is(r3));
DCHECK(name.is(r4));
DCHECK(value.is(r2));
- DCHECK(VectorStoreICDescriptor::VectorRegister().is(r5));
- DCHECK(VectorStoreICDescriptor::SlotRegister().is(r6));
+ DCHECK(StoreWithVectorDescriptor::VectorRegister().is(r5));
+ DCHECK(StoreWithVectorDescriptor::SlotRegister().is(r6));
__ LoadP(dictionary, FieldMemOperand(receiver, JSObject::kPropertiesOffset));
@@ -829,8 +806,9 @@ void PatchInlinedSmiCode(Isolate* isolate, Address address,
}
if (FLAG_trace_ic) {
- PrintF("[ patching ic at %p, cmp=%p, delta=%d\n", address,
- cmp_instruction_address, delta);
+ PrintF("[ patching ic at %p, cmp=%p, delta=%d\n",
+ static_cast<void*>(address),
+ static_cast<void*>(cmp_instruction_address), delta);
}
// Expected sequence to enable by changing the following
diff --git a/deps/v8/src/ic/s390/stub-cache-s390.cc b/deps/v8/src/ic/s390/stub-cache-s390.cc
index 054b946df8..a0564a3be3 100644
--- a/deps/v8/src/ic/s390/stub-cache-s390.cc
+++ b/deps/v8/src/ic/s390/stub-cache-s390.cc
@@ -14,15 +14,15 @@ namespace internal {
#define __ ACCESS_MASM(masm)
-static void ProbeTable(Isolate* isolate, MacroAssembler* masm,
- Code::Kind ic_kind, Code::Flags flags,
+static void ProbeTable(StubCache* stub_cache, MacroAssembler* masm,
StubCache::Table table, Register receiver, Register name,
- // Number of the cache entry, not scaled.
+ // The offset is scaled by 4, based on
+ // kCacheIndexShift, which is two bits
Register offset, Register scratch, Register scratch2,
Register offset_scratch) {
- ExternalReference key_offset(isolate->stub_cache()->key_reference(table));
- ExternalReference value_offset(isolate->stub_cache()->value_reference(table));
- ExternalReference map_offset(isolate->stub_cache()->map_reference(table));
+ ExternalReference key_offset(stub_cache->key_reference(table));
+ ExternalReference value_offset(stub_cache->value_reference(table));
+ ExternalReference map_offset(stub_cache->map_reference(table));
uintptr_t key_off_addr = reinterpret_cast<uintptr_t>(key_offset.address());
uintptr_t value_off_addr =
@@ -70,16 +70,6 @@ static void ProbeTable(Isolate* isolate, MacroAssembler* masm,
scratch2 = no_reg;
__ LoadP(code, MemOperand(base_addr, value_off_addr - key_off_addr));
- // Check that the flags match what we're looking for.
- Register flags_reg = base_addr;
- base_addr = no_reg;
- __ LoadlW(flags_reg, FieldMemOperand(code, Code::kFlagsOffset));
-
- DCHECK(!r0.is(flags_reg));
- __ AndP(flags_reg, flags_reg, Operand(~Code::kFlagsNotUsedInLookup));
- __ CmpLogicalP(flags_reg, Operand(flags));
- __ bne(&miss, Label::kNear);
-
#ifdef DEBUG
if (FLAG_test_secondary_stub_cache && table == StubCache::kPrimary) {
__ b(&miss, Label::kNear);
@@ -97,11 +87,9 @@ static void ProbeTable(Isolate* isolate, MacroAssembler* masm,
__ bind(&miss);
}
-void StubCache::GenerateProbe(MacroAssembler* masm, Code::Kind ic_kind,
- Code::Flags flags, Register receiver,
+void StubCache::GenerateProbe(MacroAssembler* masm, Register receiver,
Register name, Register scratch, Register extra,
Register extra2, Register extra3) {
- Isolate* isolate = masm->isolate();
Label miss;
#if V8_TARGET_ARCH_S390X
@@ -114,9 +102,6 @@ void StubCache::GenerateProbe(MacroAssembler* masm, Code::Kind ic_kind,
DCHECK(sizeof(Entry) == 12);
#endif
- // Make sure the flags does not name a specific type.
- DCHECK(Code::ExtractTypeFromFlags(flags) == 0);
-
// Make sure that there are no register conflicts.
DCHECK(!AreAliased(receiver, name, scratch, extra, extra2, extra3));
@@ -130,12 +115,13 @@ void StubCache::GenerateProbe(MacroAssembler* masm, Code::Kind ic_kind,
// If vector-based ics are in use, ensure that scratch, extra, extra2 and
// extra3 don't conflict with the vector and slot registers, which need
// to be preserved for a handler call or miss.
- if (IC::ICUseVector(ic_kind)) {
+ if (IC::ICUseVector(ic_kind_)) {
Register vector, slot;
- if (ic_kind == Code::STORE_IC || ic_kind == Code::KEYED_STORE_IC) {
- vector = VectorStoreICDescriptor::VectorRegister();
- slot = VectorStoreICDescriptor::SlotRegister();
+ if (ic_kind_ == Code::STORE_IC || ic_kind_ == Code::KEYED_STORE_IC) {
+ vector = StoreWithVectorDescriptor::VectorRegister();
+ slot = StoreWithVectorDescriptor::SlotRegister();
} else {
+ DCHECK(ic_kind_ == Code::LOAD_IC || ic_kind_ == Code::KEYED_LOAD_IC);
vector = LoadWithVectorDescriptor::VectorRegister();
slot = LoadWithVectorDescriptor::SlotRegister();
}
@@ -154,24 +140,24 @@ void StubCache::GenerateProbe(MacroAssembler* masm, Code::Kind ic_kind,
__ LoadlW(scratch, FieldMemOperand(name, Name::kHashFieldOffset));
__ LoadP(ip, FieldMemOperand(receiver, HeapObject::kMapOffset));
__ AddP(scratch, scratch, ip);
- __ XorP(scratch, scratch, Operand(flags));
+ __ XorP(scratch, scratch, Operand(kPrimaryMagic));
// The mask omits the last two bits because they are not part of the hash.
__ AndP(scratch, scratch,
Operand((kPrimaryTableSize - 1) << kCacheIndexShift));
// Probe the primary table.
- ProbeTable(isolate, masm, ic_kind, flags, kPrimary, receiver, name, scratch,
- extra, extra2, extra3);
+ ProbeTable(this, masm, kPrimary, receiver, name, scratch, extra, extra2,
+ extra3);
// Primary miss: Compute hash for secondary probe.
__ SubP(scratch, scratch, name);
- __ AddP(scratch, scratch, Operand(flags));
+ __ AddP(scratch, scratch, Operand(kSecondaryMagic));
__ AndP(scratch, scratch,
Operand((kSecondaryTableSize - 1) << kCacheIndexShift));
// Probe the secondary table.
- ProbeTable(isolate, masm, ic_kind, flags, kSecondary, receiver, name, scratch,
- extra, extra2, extra3);
+ ProbeTable(this, masm, kSecondary, receiver, name, scratch, extra, extra2,
+ extra3);
// Cache miss: Fall-through and let caller handle the miss by
// entering the runtime system.
diff --git a/deps/v8/src/ic/stub-cache.cc b/deps/v8/src/ic/stub-cache.cc
index 4a5f9bd7ad..31d7e2e0a8 100644
--- a/deps/v8/src/ic/stub-cache.cc
+++ b/deps/v8/src/ic/stub-cache.cc
@@ -10,9 +10,8 @@
namespace v8 {
namespace internal {
-
-StubCache::StubCache(Isolate* isolate) : isolate_(isolate) {}
-
+StubCache::StubCache(Isolate* isolate, Code::Kind ic_kind)
+ : isolate_(isolate), ic_kind_(ic_kind) {}
void StubCache::Initialize() {
DCHECK(base::bits::IsPowerOfTwo32(kPrimaryTableSize));
@@ -20,35 +19,34 @@ void StubCache::Initialize() {
Clear();
}
+#ifdef DEBUG
+namespace {
-static Code::Flags CommonStubCacheChecks(Name* name, Map* map,
- Code::Flags flags) {
- flags = Code::RemoveTypeAndHolderFromFlags(flags);
-
+bool CommonStubCacheChecks(StubCache* stub_cache, Name* name, Map* map,
+ Code* code) {
// Validate that the name does not move on scavenge, and that we
// can use identity checks instead of structural equality checks.
DCHECK(!name->GetHeap()->InNewSpace(name));
DCHECK(name->IsUniqueName());
-
- // The state bits are not important to the hash function because the stub
- // cache only contains handlers. Make sure that the bits are the least
- // significant so they will be the ones masked out.
- DCHECK_EQ(Code::HANDLER, Code::ExtractKindFromFlags(flags));
- STATIC_ASSERT((Code::ICStateField::kMask & 1) == 1);
-
- // Make sure that the code type and cache holder are not included in the hash.
- DCHECK(Code::ExtractTypeFromFlags(flags) == 0);
- DCHECK(Code::ExtractCacheHolderFromFlags(flags) == 0);
-
- return flags;
+ DCHECK(name->HasHashCode());
+ if (code) {
+ Code::Flags expected_flags = Code::RemoveHolderFromFlags(
+ Code::ComputeHandlerFlags(stub_cache->ic_kind()));
+ Code::Flags flags = Code::RemoveHolderFromFlags(code->flags());
+ DCHECK_EQ(expected_flags, flags);
+ DCHECK_EQ(Code::HANDLER, Code::ExtractKindFromFlags(code->flags()));
+ }
+ return true;
}
+} // namespace
+#endif
Code* StubCache::Set(Name* name, Map* map, Code* code) {
- Code::Flags flags = CommonStubCacheChecks(name, map, code->flags());
+ DCHECK(CommonStubCacheChecks(this, name, map, code));
// Compute the primary entry.
- int primary_offset = PrimaryOffset(name, flags, map);
+ int primary_offset = PrimaryOffset(name, map);
Entry* primary = entry(primary_, primary_offset);
Code* old_code = primary->value;
@@ -56,10 +54,8 @@ Code* StubCache::Set(Name* name, Map* map, Code* code) {
// secondary cache before overwriting it.
if (old_code != isolate_->builtins()->builtin(Builtins::kIllegal)) {
Map* old_map = primary->map;
- Code::Flags old_flags =
- Code::RemoveTypeAndHolderFromFlags(old_code->flags());
- int seed = PrimaryOffset(primary->key, old_flags, old_map);
- int secondary_offset = SecondaryOffset(primary->key, old_flags, seed);
+ int seed = PrimaryOffset(primary->key, old_map);
+ int secondary_offset = SecondaryOffset(primary->key, seed);
Entry* secondary = entry(secondary_, secondary_offset);
*secondary = *primary;
}
@@ -72,15 +68,14 @@ Code* StubCache::Set(Name* name, Map* map, Code* code) {
return code;
}
-
-Code* StubCache::Get(Name* name, Map* map, Code::Flags flags) {
- flags = CommonStubCacheChecks(name, map, flags);
- int primary_offset = PrimaryOffset(name, flags, map);
+Code* StubCache::Get(Name* name, Map* map) {
+ DCHECK(CommonStubCacheChecks(this, name, map, nullptr));
+ int primary_offset = PrimaryOffset(name, map);
Entry* primary = entry(primary_, primary_offset);
if (primary->key == name && primary->map == map) {
return primary->value;
}
- int secondary_offset = SecondaryOffset(name, flags, primary_offset);
+ int secondary_offset = SecondaryOffset(name, primary_offset);
Entry* secondary = entry(secondary_, secondary_offset);
if (secondary->key == name && secondary->map == map) {
return secondary->value;
@@ -105,7 +100,6 @@ void StubCache::Clear() {
void StubCache::CollectMatchingMaps(SmallMapList* types, Handle<Name> name,
- Code::Flags flags,
Handle<Context> native_context,
Zone* zone) {
for (int i = 0; i < kPrimaryTableSize; i++) {
@@ -115,7 +109,7 @@ void StubCache::CollectMatchingMaps(SmallMapList* types, Handle<Name> name,
// with a primitive receiver.
if (map == NULL) continue;
- int offset = PrimaryOffset(*name, flags, map);
+ int offset = PrimaryOffset(*name, map);
if (entry(primary_, offset) == &primary_[i] &&
TypeFeedbackOracle::IsRelevantFeedback(map, *native_context)) {
types->AddMapIfMissing(Handle<Map>(map), zone);
@@ -131,10 +125,10 @@ void StubCache::CollectMatchingMaps(SmallMapList* types, Handle<Name> name,
if (map == NULL) continue;
// Lookup in primary table and skip duplicates.
- int primary_offset = PrimaryOffset(*name, flags, map);
+ int primary_offset = PrimaryOffset(*name, map);
// Lookup in secondary table and add matches.
- int offset = SecondaryOffset(*name, flags, primary_offset);
+ int offset = SecondaryOffset(*name, primary_offset);
if (entry(secondary_, offset) == &secondary_[i] &&
TypeFeedbackOracle::IsRelevantFeedback(map, *native_context)) {
types->AddMapIfMissing(Handle<Map>(map), zone);
diff --git a/deps/v8/src/ic/stub-cache.h b/deps/v8/src/ic/stub-cache.h
index 4b27e6e396..a053555d9f 100644
--- a/deps/v8/src/ic/stub-cache.h
+++ b/deps/v8/src/ic/stub-cache.h
@@ -41,19 +41,17 @@ class StubCache {
void Initialize();
// Access cache for entry hash(name, map).
Code* Set(Name* name, Map* map, Code* code);
- Code* Get(Name* name, Map* map, Code::Flags flags);
+ Code* Get(Name* name, Map* map);
// Clear the lookup table (@ mark compact collection).
void Clear();
- // Collect all maps that match the name and flags.
+ // Collect all maps that match the name.
void CollectMatchingMaps(SmallMapList* types, Handle<Name> name,
- Code::Flags flags, Handle<Context> native_context,
- Zone* zone);
+ Handle<Context> native_context, Zone* zone);
// Generate code for probing the stub cache table.
// Arguments extra, extra2 and extra3 may be used to pass additional scratch
// registers. Set to no_reg if not needed.
// If leave_frame is true, then exit a frame before the tail call.
- void GenerateProbe(MacroAssembler* masm, Code::Kind ic_kind,
- Code::Flags flags, Register receiver, Register name,
+ void GenerateProbe(MacroAssembler* masm, Register receiver, Register name,
Register scratch, Register extra, Register extra2 = no_reg,
Register extra3 = no_reg);
@@ -86,15 +84,34 @@ class StubCache {
}
Isolate* isolate() { return isolate_; }
+ Code::Kind ic_kind() const { return ic_kind_; }
// Setting the entry size such that the index is shifted by Name::kHashShift
// is convenient; shifting down the length field (to extract the hash code)
// automatically discards the hash bit field.
static const int kCacheIndexShift = Name::kHashShift;
- private:
- explicit StubCache(Isolate* isolate);
+ static const int kPrimaryTableBits = 11;
+ static const int kPrimaryTableSize = (1 << kPrimaryTableBits);
+ static const int kSecondaryTableBits = 9;
+ static const int kSecondaryTableSize = (1 << kSecondaryTableBits);
+ // Some magic number used in primary and secondary hash computations.
+ static const int kPrimaryMagic = 0x3d532433;
+ static const int kSecondaryMagic = 0xb16b00b5;
+
+ static int PrimaryOffsetForTesting(Name* name, Map* map) {
+ return PrimaryOffset(name, map);
+ }
+
+ static int SecondaryOffsetForTesting(Name* name, int seed) {
+ return SecondaryOffset(name, seed);
+ }
+
+ // The constructor is made public only for the purposes of testing.
+ StubCache(Isolate* isolate, Code::Kind ic_kind);
+
+ private:
// The stub cache has a primary and secondary level. The two levels have
// different hashing algorithms in order to avoid simultaneous collisions
// in both caches. Unlike a probing strategy (quadratic or otherwise) the
@@ -105,7 +122,7 @@ class StubCache {
// Hash algorithm for the primary table. This algorithm is replicated in
// assembler for every architecture. Returns an index into the table that
// is scaled by 1 << kCacheIndexShift.
- static int PrimaryOffset(Name* name, Code::Flags flags, Map* map) {
+ static int PrimaryOffset(Name* name, Map* map) {
STATIC_ASSERT(kCacheIndexShift == Name::kHashShift);
// Compute the hash of the name (use entire hash field).
DCHECK(name->HasHashCode());
@@ -115,27 +132,19 @@ class StubCache {
// 4Gb (and not at all if it isn't).
uint32_t map_low32bits =
static_cast<uint32_t>(reinterpret_cast<uintptr_t>(map));
- // We always set the in_loop bit to zero when generating the lookup code
- // so do it here too so the hash codes match.
- uint32_t iflags =
- (static_cast<uint32_t>(flags) & ~Code::kFlagsNotUsedInLookup);
- // Base the offset on a simple combination of name, flags, and map.
- uint32_t key = (map_low32bits + field) ^ iflags;
+ // Base the offset on a simple combination of name and map.
+ uint32_t key = (map_low32bits + field) ^ kPrimaryMagic;
return key & ((kPrimaryTableSize - 1) << kCacheIndexShift);
}
// Hash algorithm for the secondary table. This algorithm is replicated in
// assembler for every architecture. Returns an index into the table that
// is scaled by 1 << kCacheIndexShift.
- static int SecondaryOffset(Name* name, Code::Flags flags, int seed) {
+ static int SecondaryOffset(Name* name, int seed) {
// Use the seed from the primary cache in the secondary cache.
uint32_t name_low32bits =
static_cast<uint32_t>(reinterpret_cast<uintptr_t>(name));
- // We always set the in_loop bit to zero when generating the lookup code
- // so do it here too so the hash codes match.
- uint32_t iflags =
- (static_cast<uint32_t>(flags) & ~Code::kFlagsNotUsedInLookup);
- uint32_t key = (seed - name_low32bits) + iflags;
+ uint32_t key = (seed - name_low32bits) + kSecondaryMagic;
return key & ((kSecondaryTableSize - 1) << kCacheIndexShift);
}
@@ -150,15 +159,11 @@ class StubCache {
offset * multiplier);
}
- static const int kPrimaryTableBits = 11;
- static const int kPrimaryTableSize = (1 << kPrimaryTableBits);
- static const int kSecondaryTableBits = 9;
- static const int kSecondaryTableSize = (1 << kSecondaryTableBits);
-
private:
Entry primary_[kPrimaryTableSize];
Entry secondary_[kSecondaryTableSize];
Isolate* isolate_;
+ Code::Kind ic_kind_;
friend class Isolate;
friend class SCTableReference;
diff --git a/deps/v8/src/ic/x64/access-compiler-x64.cc b/deps/v8/src/ic/x64/access-compiler-x64.cc
index b8d50b3d2c..2b292528c8 100644
--- a/deps/v8/src/ic/x64/access-compiler-x64.cc
+++ b/deps/v8/src/ic/x64/access-compiler-x64.cc
@@ -19,19 +19,19 @@ void PropertyAccessCompiler::GenerateTailCall(MacroAssembler* masm,
Register* PropertyAccessCompiler::load_calling_convention() {
- // receiver, name, scratch1, scratch2, scratch3, scratch4.
+ // receiver, name, scratch1, scratch2, scratch3.
Register receiver = LoadDescriptor::ReceiverRegister();
Register name = LoadDescriptor::NameRegister();
- static Register registers[] = {receiver, name, rax, rbx, rdi, r8};
+ static Register registers[] = {receiver, name, rax, rbx, rdi};
return registers;
}
Register* PropertyAccessCompiler::store_calling_convention() {
- // receiver, name, scratch1, scratch2, scratch3.
+ // receiver, name, scratch1, scratch2.
Register receiver = StoreDescriptor::ReceiverRegister();
Register name = StoreDescriptor::NameRegister();
- static Register registers[] = {receiver, name, rbx, rdi, r8};
+ static Register registers[] = {receiver, name, rbx, rdi};
return registers;
}
diff --git a/deps/v8/src/ic/x64/handler-compiler-x64.cc b/deps/v8/src/ic/x64/handler-compiler-x64.cc
index dde61691d5..ba4daed32c 100644
--- a/deps/v8/src/ic/x64/handler-compiler-x64.cc
+++ b/deps/v8/src/ic/x64/handler-compiler-x64.cc
@@ -180,7 +180,7 @@ void PropertyHandlerCompiler::GenerateApiAccessorCall(
Handle<CallHandlerInfo> api_call_info = optimization.api_call_info();
bool call_data_undefined = false;
// Put call data in place.
- if (api_call_info->data()->IsUndefined()) {
+ if (api_call_info->data()->IsUndefined(isolate)) {
call_data_undefined = true;
__ LoadRoot(data, Heap::kUndefinedValueRootIndex);
} else {
@@ -219,13 +219,14 @@ void PropertyHandlerCompiler::GenerateApiAccessorCall(
void PropertyHandlerCompiler::GenerateCheckPropertyCell(
MacroAssembler* masm, Handle<JSGlobalObject> global, Handle<Name> name,
Register scratch, Label* miss) {
- Handle<PropertyCell> cell = JSGlobalObject::EnsurePropertyCell(global, name);
- DCHECK(cell->value()->IsTheHole());
- Factory* factory = masm->isolate()->factory();
- Handle<WeakCell> weak_cell = factory->NewWeakCell(cell);
+ Handle<PropertyCell> cell = JSGlobalObject::EnsureEmptyPropertyCell(
+ global, name, PropertyCellType::kInvalidated);
+ Isolate* isolate = masm->isolate();
+ DCHECK(cell->value()->IsTheHole(isolate));
+ Handle<WeakCell> weak_cell = isolate->factory()->NewWeakCell(cell);
__ LoadWeakValue(scratch, weak_cell, miss);
__ Cmp(FieldOperand(scratch, PropertyCell::kValueOffset),
- factory->the_hole_value());
+ isolate->factory()->the_hole_value());
__ j(not_equal, miss);
}
@@ -326,8 +327,8 @@ static void StoreIC_PushArgs(MacroAssembler* masm) {
Register name = StoreDescriptor::NameRegister();
Register value = StoreDescriptor::ValueRegister();
- Register slot = VectorStoreICDescriptor::SlotRegister();
- Register vector = VectorStoreICDescriptor::VectorRegister();
+ Register slot = StoreWithVectorDescriptor::SlotRegister();
+ Register vector = StoreWithVectorDescriptor::VectorRegister();
__ PopReturnAddressTo(r11);
__ Push(receiver);
@@ -339,15 +340,6 @@ static void StoreIC_PushArgs(MacroAssembler* masm) {
}
-void NamedStoreHandlerCompiler::GenerateSlow(MacroAssembler* masm) {
- // Return address is on the stack.
- StoreIC_PushArgs(masm);
-
- // Do tail-call to runtime routine.
- __ TailCallRuntime(Runtime::kStoreIC_Slow);
-}
-
-
void ElementHandlerCompiler::GenerateStoreSlow(MacroAssembler* masm) {
// Return address is on the stack.
StoreIC_PushArgs(masm);
@@ -440,29 +432,26 @@ 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);
- }
+ 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);
- }
+ // 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
@@ -500,8 +489,10 @@ Register PropertyHandlerCompiler::CheckPrototypes(
!current_map->is_access_check_needed());
prototype = handle(JSObject::cast(current_map->prototype()));
- if (current_map->is_dictionary_map() &&
- !current_map->IsJSGlobalObjectMap()) {
+ if (current_map->IsJSGlobalObjectMap()) {
+ GenerateCheckPropertyCell(masm(), Handle<JSGlobalObject>::cast(current),
+ name, scratch2, miss);
+ } else if (current_map->is_dictionary_map()) {
DCHECK(!current_map->IsJSGlobalProxyMap()); // Proxy maps are fast.
if (!name->IsUniqueName()) {
DCHECK(name->IsString());
@@ -511,34 +502,12 @@ Register PropertyHandlerCompiler::CheckPrototypes(
current->property_dictionary()->FindEntry(name) ==
NameDictionary::kNotFound);
- if (FLAG_eliminate_prototype_chain_checks && depth > 1) {
+ if (depth > 1) {
// TODO(jkummerow): Cache and re-use weak cell.
__ LoadWeakValue(reg, isolate()->factory()->NewWeakCell(current), miss);
}
GenerateDictionaryNegativeLookup(masm(), miss, reg, name, scratch1,
scratch2);
-
- if (!FLAG_eliminate_prototype_chain_checks) {
- __ movp(scratch1, FieldOperand(reg, HeapObject::kMapOffset));
- __ movp(holder_reg, FieldOperand(scratch1, Map::kPrototypeOffset));
- }
- } else {
- Register map_reg = scratch1;
- 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 (!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);
- }
- 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.
@@ -552,17 +521,8 @@ Register PropertyHandlerCompiler::CheckPrototypes(
// Log the check depth.
LOG(isolate(), IntEvent("check-maps-depth", depth + 1));
- 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) {
+ if (return_holder && depth != 0) {
__ LoadWeakValue(reg, isolate()->factory()->NewWeakCell(current), miss);
}
@@ -597,58 +557,6 @@ void NamedStoreHandlerCompiler::FrontendFooter(Handle<Name> name, Label* miss) {
}
}
-
-void NamedLoadHandlerCompiler::GenerateLoadCallback(
- Register reg, Handle<AccessorInfo> callback) {
- DCHECK(!AreAliased(kScratchRegister, scratch2(), scratch3(), receiver()));
- DCHECK(!AreAliased(kScratchRegister, scratch2(), scratch3(), reg));
-
- // Insert additional parameters into the stack frame above return address.
- __ PopReturnAddressTo(scratch3());
-
- // Build v8::PropertyCallbackInfo::args_ array on the stack and push property
- // name below the exit frame to make GC aware of them.
- STATIC_ASSERT(PropertyCallbackArguments::kShouldThrowOnErrorIndex == 0);
- STATIC_ASSERT(PropertyCallbackArguments::kHolderIndex == 1);
- STATIC_ASSERT(PropertyCallbackArguments::kIsolateIndex == 2);
- STATIC_ASSERT(PropertyCallbackArguments::kReturnValueDefaultValueIndex == 3);
- STATIC_ASSERT(PropertyCallbackArguments::kReturnValueOffset == 4);
- STATIC_ASSERT(PropertyCallbackArguments::kDataIndex == 5);
- STATIC_ASSERT(PropertyCallbackArguments::kThisIndex == 6);
- STATIC_ASSERT(PropertyCallbackArguments::kArgsLength == 7);
-
- __ Push(receiver()); // receiver
- Handle<Object> data(callback->data(), isolate());
- if (data->IsUndefined() || data->IsSmi()) {
- __ Push(data);
- } else {
- Handle<WeakCell> cell =
- isolate()->factory()->NewWeakCell(Handle<HeapObject>::cast(data));
- // The callback is alive if this instruction is executed,
- // so the weak cell is not cleared and points to data.
- __ GetWeakValue(scratch2(), cell);
- __ Push(scratch2());
- }
- __ LoadRoot(kScratchRegister, Heap::kUndefinedValueRootIndex);
- __ Push(kScratchRegister); // return value
- __ Push(kScratchRegister); // return value default
- __ PushAddress(ExternalReference::isolate_address(isolate()));
- __ Push(reg); // holder
- __ Push(Smi::FromInt(0)); // should_throw_on_error -> false
-
- __ Push(name()); // name
- __ PushReturnAddressFrom(scratch3());
-
- // Abi for CallApiGetter
- Register api_function_address = ApiGetterDescriptor::function_address();
- Address getter_address = v8::ToCData<Address>(callback->getter());
- __ Move(api_function_address, getter_address, RelocInfo::EXTERNAL_REFERENCE);
-
- CallApiGetterStub stub(isolate());
- __ TailCallStub(&stub);
-}
-
-
void NamedLoadHandlerCompiler::GenerateLoadConstant(Handle<Object> value) {
// Return the constant value.
__ Move(rax, value);
@@ -659,7 +567,7 @@ void NamedLoadHandlerCompiler::GenerateLoadConstant(Handle<Object> value) {
void NamedLoadHandlerCompiler::GenerateLoadInterceptorWithFollowup(
LookupIterator* it, Register holder_reg) {
DCHECK(holder()->HasNamedInterceptor());
- DCHECK(!holder()->GetNamedInterceptor()->getter()->IsUndefined());
+ DCHECK(!holder()->GetNamedInterceptor()->getter()->IsUndefined(isolate()));
// Compile the interceptor call, followed by inline code to load the
// property from further up the prototype chain if the call fails.
@@ -721,7 +629,7 @@ void NamedLoadHandlerCompiler::GenerateLoadInterceptorWithFollowup(
void NamedLoadHandlerCompiler::GenerateLoadInterceptor(Register holder_reg) {
// Call the runtime system to load the interceptor.
DCHECK(holder()->HasNamedInterceptor());
- DCHECK(!holder()->GetNamedInterceptor()->getter()->IsUndefined());
+ DCHECK(!holder()->GetNamedInterceptor()->getter()->IsUndefined(isolate()));
__ PopReturnAddressTo(scratch2());
PushInterceptorArguments(masm(), receiver(), holder_reg, this->name(),
holder());
@@ -741,7 +649,7 @@ Handle<Code> NamedStoreHandlerCompiler::CompileStoreCallback(
__ Push(holder_reg);
// If the callback cannot leak, then push the callback directly,
// otherwise wrap it in a weak cell.
- if (callback->data()->IsUndefined() || callback->data()->IsSmi()) {
+ if (callback->data()->IsUndefined(isolate()) || callback->data()->IsSmi()) {
__ Push(callback);
} else {
Handle<WeakCell> cell = isolate()->factory()->NewWeakCell(callback);
@@ -756,7 +664,7 @@ Handle<Code> NamedStoreHandlerCompiler::CompileStoreCallback(
__ TailCallRuntime(Runtime::kStoreCallbackProperty);
// Return the generated code.
- return GetCode(kind(), Code::FAST, name);
+ return GetCode(kind(), name);
}
@@ -798,7 +706,7 @@ Handle<Code> NamedLoadHandlerCompiler::CompileLoadGlobal(
FrontendFooter(name, &miss);
// Return the generated code.
- return GetCode(kind(), Code::NORMAL, name);
+ return GetCode(kind(), name);
}
diff --git a/deps/v8/src/ic/x64/ic-x64.cc b/deps/v8/src/ic/x64/ic-x64.cc
index 247116d7fe..21a114830f 100644
--- a/deps/v8/src/ic/x64/ic-x64.cc
+++ b/deps/v8/src/ic/x64/ic-x64.cc
@@ -340,11 +340,8 @@ void KeyedLoadIC::GenerateMegamorphic(MacroAssembler* masm) {
__ Move(vector, dummy_vector);
__ Move(slot, Smi::FromInt(slot_index));
- Code::Flags flags = Code::RemoveTypeAndHolderFromFlags(
- Code::ComputeHandlerFlags(Code::LOAD_IC));
- masm->isolate()->stub_cache()->GenerateProbe(masm, Code::KEYED_LOAD_IC, flags,
- receiver, key,
- megamorphic_scratch, no_reg);
+ masm->isolate()->load_stub_cache()->GenerateProbe(
+ masm, receiver, key, megamorphic_scratch, no_reg);
// Cache miss.
GenerateMiss(masm);
@@ -451,7 +448,7 @@ static void KeyedStoreGenerateMegamorphicHelper(
__ JumpIfDictionaryInPrototypeChain(receiver, rdi, kScratchRegister, slow);
__ bind(&fast_double_without_map_check);
- __ StoreNumberToDoubleElements(value, rbx, key, xmm0,
+ __ StoreNumberToDoubleElements(value, rbx, key, kScratchDoubleReg,
&transition_double_elements);
if (increment_length == kIncrementLength) {
// Add 1 to receiver->length.
@@ -519,10 +516,10 @@ void KeyedStoreIC::GenerateMegamorphic(MacroAssembler* masm,
__ JumpIfSmi(receiver, &slow_with_tagged_index);
// Get the map from the receiver.
__ movp(r9, FieldOperand(receiver, HeapObject::kMapOffset));
- // Check that the receiver does not require access checks and is not observed.
- // The generic stub does not perform map checks or handle observed objects.
+ // Check that the receiver does not require access checks.
+ // The generic stub does not perform map checks.
__ testb(FieldOperand(r9, Map::kBitFieldOffset),
- Immediate(1 << Map::kIsAccessCheckNeeded | 1 << Map::kIsObserved));
+ Immediate(1 << Map::kIsAccessCheckNeeded));
__ j(not_zero, &slow_with_tagged_index);
// Check that the key is a smi.
__ JumpIfNotSmi(key, &maybe_name_key);
@@ -556,8 +553,8 @@ void KeyedStoreIC::GenerateMegamorphic(MacroAssembler* masm,
__ movzxbp(r9, FieldOperand(r9, Map::kInstanceTypeOffset));
__ JumpIfNotUniqueNameInstanceType(r9, &slow_with_tagged_index);
- Register vector = VectorStoreICDescriptor::VectorRegister();
- Register slot = VectorStoreICDescriptor::SlotRegister();
+ Register vector = StoreWithVectorDescriptor::VectorRegister();
+ Register slot = StoreWithVectorDescriptor::SlotRegister();
// The handlers in the stub cache expect a vector and slot. Since we won't
// change the IC from any downstream misses, a dummy vector can be used.
Handle<TypeFeedbackVector> dummy_vector =
@@ -567,10 +564,8 @@ void KeyedStoreIC::GenerateMegamorphic(MacroAssembler* masm,
__ Move(vector, dummy_vector);
__ Move(slot, Smi::FromInt(slot_index));
- Code::Flags flags = Code::RemoveTypeAndHolderFromFlags(
- Code::ComputeHandlerFlags(Code::STORE_IC));
- masm->isolate()->stub_cache()->GenerateProbe(masm, Code::STORE_IC, flags,
- receiver, key, r9, no_reg);
+ masm->isolate()->store_stub_cache()->GenerateProbe(masm, receiver, key, r9,
+ no_reg);
// Cache miss.
__ jmp(&miss);
@@ -710,13 +705,6 @@ void KeyedLoadIC::GenerateRuntimeGetProperty(MacroAssembler* masm) {
__ TailCallRuntime(Runtime::kKeyedGetProperty);
}
-
-void StoreIC::GenerateMegamorphic(MacroAssembler* masm) {
- // This shouldn't be called.
- __ int3();
-}
-
-
static void StoreIC_PushArgs(MacroAssembler* masm) {
Register receiver = StoreDescriptor::ReceiverRegister();
Register name = StoreDescriptor::NameRegister();
@@ -728,8 +716,8 @@ static void StoreIC_PushArgs(MacroAssembler* masm) {
__ Push(receiver);
__ Push(name);
__ Push(value);
- Register slot = VectorStoreICDescriptor::SlotRegister();
- Register vector = VectorStoreICDescriptor::VectorRegister();
+ Register slot = StoreWithVectorDescriptor::SlotRegister();
+ Register vector = StoreWithVectorDescriptor::VectorRegister();
DCHECK(!temp.is(slot) && !temp.is(vector));
__ Push(slot);
__ Push(vector);
@@ -751,8 +739,8 @@ void StoreIC::GenerateNormal(MacroAssembler* masm) {
Register name = StoreDescriptor::NameRegister();
Register value = StoreDescriptor::ValueRegister();
Register dictionary = r11;
- DCHECK(!AreAliased(dictionary, VectorStoreICDescriptor::VectorRegister(),
- VectorStoreICDescriptor::SlotRegister()));
+ DCHECK(!AreAliased(dictionary, StoreWithVectorDescriptor::VectorRegister(),
+ StoreWithVectorDescriptor::SlotRegister()));
Label miss;
@@ -829,8 +817,9 @@ void PatchInlinedSmiCode(Isolate* isolate, Address address,
// condition code uses at the patched jump.
uint8_t delta = *reinterpret_cast<uint8_t*>(delta_address);
if (FLAG_trace_ic) {
- PrintF("[ patching ic at %p, test=%p, delta=%d\n", address,
- test_instruction_address, delta);
+ PrintF("[ patching ic at %p, test=%p, delta=%d\n",
+ static_cast<void*>(address),
+ static_cast<void*>(test_instruction_address), delta);
}
// Patch with a short conditional jump. Enabling means switching from a short
diff --git a/deps/v8/src/ic/x64/stub-cache-x64.cc b/deps/v8/src/ic/x64/stub-cache-x64.cc
index 9a9dfe9f4b..946aee51fc 100644
--- a/deps/v8/src/ic/x64/stub-cache-x64.cc
+++ b/deps/v8/src/ic/x64/stub-cache-x64.cc
@@ -14,9 +14,7 @@ namespace internal {
#define __ ACCESS_MASM(masm)
-
-static void ProbeTable(Isolate* isolate, MacroAssembler* masm,
- Code::Kind ic_kind, Code::Flags flags,
+static void ProbeTable(StubCache* stub_cache, MacroAssembler* masm,
StubCache::Table table, Register receiver, Register name,
// The offset is scaled by 4, based on
// kCacheIndexShift, which is two bits
@@ -31,8 +29,8 @@ static void ProbeTable(Isolate* isolate, MacroAssembler* masm,
DCHECK_EQ(3u * kPointerSize, sizeof(StubCache::Entry));
// The offset register holds the entry offset times four (due to masking
// and shifting optimizations).
- ExternalReference key_offset(isolate->stub_cache()->key_reference(table));
- ExternalReference value_offset(isolate->stub_cache()->value_reference(table));
+ ExternalReference key_offset(stub_cache->key_reference(table));
+ ExternalReference value_offset(stub_cache->value_reference(table));
Label miss;
// Multiply by 3 because there are 3 fields per entry (name, code, map).
@@ -46,8 +44,8 @@ static void ProbeTable(Isolate* isolate, MacroAssembler* masm,
// Get the map entry from the cache.
// Use key_offset + kPointerSize * 2, rather than loading map_offset.
- DCHECK(isolate->stub_cache()->map_reference(table).address() -
- isolate->stub_cache()->key_reference(table).address() ==
+ DCHECK(stub_cache->map_reference(table).address() -
+ stub_cache->key_reference(table).address() ==
kPointerSize * 2);
__ movp(kScratchRegister,
Operand(kScratchRegister, offset, scale_factor, kPointerSize * 2));
@@ -58,12 +56,6 @@ static void ProbeTable(Isolate* isolate, MacroAssembler* masm,
__ LoadAddress(kScratchRegister, value_offset);
__ movp(kScratchRegister, Operand(kScratchRegister, offset, scale_factor, 0));
- // Check that the flags match what we're looking for.
- __ movl(offset, FieldOperand(kScratchRegister, Code::kFlagsOffset));
- __ andp(offset, Immediate(~Code::kFlagsNotUsedInLookup));
- __ cmpl(offset, Immediate(flags));
- __ j(not_equal, &miss);
-
#ifdef DEBUG
if (FLAG_test_secondary_stub_cache && table == StubCache::kPrimary) {
__ jmp(&miss);
@@ -79,12 +71,9 @@ static void ProbeTable(Isolate* isolate, MacroAssembler* masm,
__ bind(&miss);
}
-
-void StubCache::GenerateProbe(MacroAssembler* masm, Code::Kind ic_kind,
- Code::Flags flags, Register receiver,
+void StubCache::GenerateProbe(MacroAssembler* masm, Register receiver,
Register name, Register scratch, Register extra,
Register extra2, Register extra3) {
- Isolate* isolate = masm->isolate();
Label miss;
USE(extra); // The register extra is not used on the X64 platform.
USE(extra2); // The register extra2 is not used on the X64 platform.
@@ -93,9 +82,6 @@ void StubCache::GenerateProbe(MacroAssembler* masm, Code::Kind ic_kind,
// entry size being 3 * kPointerSize.
DCHECK(sizeof(Entry) == 3 * kPointerSize);
- // Make sure the flags do not name a specific type.
- DCHECK(Code::ExtractTypeFromFlags(flags) == 0);
-
// Make sure that there are no register conflicts.
DCHECK(!scratch.is(receiver));
DCHECK(!scratch.is(name));
@@ -109,15 +95,15 @@ void StubCache::GenerateProbe(MacroAssembler* masm, Code::Kind ic_kind,
// If vector-based ics are in use, ensure that scratch doesn't conflict with
// the vector and slot registers, which need to be preserved for a handler
// call or miss.
- if (IC::ICUseVector(ic_kind)) {
- if (ic_kind == Code::LOAD_IC || ic_kind == Code::KEYED_LOAD_IC) {
+ if (IC::ICUseVector(ic_kind_)) {
+ if (ic_kind_ == Code::LOAD_IC || ic_kind_ == Code::KEYED_LOAD_IC) {
Register vector = LoadWithVectorDescriptor::VectorRegister();
Register slot = LoadDescriptor::SlotRegister();
DCHECK(!AreAliased(vector, slot, scratch));
} else {
- DCHECK(ic_kind == Code::STORE_IC || ic_kind == Code::KEYED_STORE_IC);
- Register vector = VectorStoreICDescriptor::VectorRegister();
- Register slot = VectorStoreICDescriptor::SlotRegister();
+ DCHECK(ic_kind_ == Code::STORE_IC || ic_kind_ == Code::KEYED_STORE_IC);
+ Register vector = StoreWithVectorDescriptor::VectorRegister();
+ Register slot = StoreWithVectorDescriptor::SlotRegister();
DCHECK(!AreAliased(vector, slot, scratch));
}
}
@@ -133,26 +119,25 @@ void StubCache::GenerateProbe(MacroAssembler* masm, Code::Kind ic_kind,
__ movl(scratch, FieldOperand(name, Name::kHashFieldOffset));
// Use only the low 32 bits of the map pointer.
__ addl(scratch, FieldOperand(receiver, HeapObject::kMapOffset));
- __ xorp(scratch, Immediate(flags));
+ __ xorp(scratch, Immediate(kPrimaryMagic));
// We mask out the last two bits because they are not part of the hash and
// they are always 01 for maps. Also in the two 'and' instructions below.
__ andp(scratch, Immediate((kPrimaryTableSize - 1) << kCacheIndexShift));
// Probe the primary table.
- ProbeTable(isolate, masm, ic_kind, flags, kPrimary, receiver, name, scratch);
+ ProbeTable(this, masm, kPrimary, receiver, name, scratch);
// Primary miss: Compute hash for secondary probe.
__ movl(scratch, FieldOperand(name, Name::kHashFieldOffset));
__ addl(scratch, FieldOperand(receiver, HeapObject::kMapOffset));
- __ xorp(scratch, Immediate(flags));
+ __ xorp(scratch, Immediate(kPrimaryMagic));
__ andp(scratch, Immediate((kPrimaryTableSize - 1) << kCacheIndexShift));
__ subl(scratch, name);
- __ addl(scratch, Immediate(flags));
+ __ addl(scratch, Immediate(kSecondaryMagic));
__ andp(scratch, Immediate((kSecondaryTableSize - 1) << kCacheIndexShift));
// Probe the secondary table.
- ProbeTable(isolate, masm, ic_kind, flags, kSecondary, receiver, name,
- scratch);
+ ProbeTable(this, masm, kSecondary, receiver, name, scratch);
// Cache miss: Fall-through and let caller handle the miss by
// entering the runtime system.
diff --git a/deps/v8/src/ic/x87/access-compiler-x87.cc b/deps/v8/src/ic/x87/access-compiler-x87.cc
index 2c1b942756..e528de65ba 100644
--- a/deps/v8/src/ic/x87/access-compiler-x87.cc
+++ b/deps/v8/src/ic/x87/access-compiler-x87.cc
@@ -18,19 +18,19 @@ void PropertyAccessCompiler::GenerateTailCall(MacroAssembler* masm,
Register* PropertyAccessCompiler::load_calling_convention() {
- // receiver, name, scratch1, scratch2, scratch3, scratch4.
+ // receiver, name, scratch1, scratch2, scratch3.
Register receiver = LoadDescriptor::ReceiverRegister();
Register name = LoadDescriptor::NameRegister();
- static Register registers[] = {receiver, name, ebx, eax, edi, no_reg};
+ static Register registers[] = {receiver, name, ebx, eax, edi};
return registers;
}
Register* PropertyAccessCompiler::store_calling_convention() {
- // receiver, name, scratch1, scratch2, scratch3.
+ // receiver, name, scratch1, scratch2.
Register receiver = StoreDescriptor::ReceiverRegister();
Register name = StoreDescriptor::NameRegister();
- static Register registers[] = {receiver, name, ebx, edi, no_reg};
+ static Register registers[] = {receiver, name, ebx, edi};
return registers;
}
diff --git a/deps/v8/src/ic/x87/handler-compiler-x87.cc b/deps/v8/src/ic/x87/handler-compiler-x87.cc
index 281faba3c7..4bf0af2569 100644
--- a/deps/v8/src/ic/x87/handler-compiler-x87.cc
+++ b/deps/v8/src/ic/x87/handler-compiler-x87.cc
@@ -199,7 +199,7 @@ void PropertyHandlerCompiler::GenerateApiAccessorCall(
Handle<CallHandlerInfo> api_call_info = optimization.api_call_info();
bool call_data_undefined = false;
// Put call data in place.
- if (api_call_info->data()->IsUndefined()) {
+ if (api_call_info->data()->IsUndefined(isolate)) {
call_data_undefined = true;
__ mov(data, Immediate(isolate->factory()->undefined_value()));
} else {
@@ -236,13 +236,14 @@ void PropertyHandlerCompiler::GenerateApiAccessorCall(
void PropertyHandlerCompiler::GenerateCheckPropertyCell(
MacroAssembler* masm, Handle<JSGlobalObject> global, Handle<Name> name,
Register scratch, Label* miss) {
- Handle<PropertyCell> cell = JSGlobalObject::EnsurePropertyCell(global, name);
- DCHECK(cell->value()->IsTheHole());
- Factory* factory = masm->isolate()->factory();
- Handle<WeakCell> weak_cell = factory->NewWeakCell(cell);
+ Handle<PropertyCell> cell = JSGlobalObject::EnsureEmptyPropertyCell(
+ global, name, PropertyCellType::kInvalidated);
+ Isolate* isolate = masm->isolate();
+ DCHECK(cell->value()->IsTheHole(isolate));
+ Handle<WeakCell> weak_cell = isolate->factory()->NewWeakCell(cell);
__ LoadWeakValue(scratch, weak_cell, miss);
__ cmp(FieldOperand(scratch, PropertyCell::kValueOffset),
- Immediate(factory->the_hole_value()));
+ Immediate(isolate->factory()->the_hole_value()));
__ j(not_equal, miss);
}
@@ -320,8 +321,8 @@ static void StoreIC_PushArgs(MacroAssembler* masm) {
Register receiver = StoreDescriptor::ReceiverRegister();
Register name = StoreDescriptor::NameRegister();
Register value = StoreDescriptor::ValueRegister();
- Register slot = VectorStoreICDescriptor::SlotRegister();
- Register vector = VectorStoreICDescriptor::VectorRegister();
+ Register slot = StoreWithVectorDescriptor::SlotRegister();
+ Register vector = StoreWithVectorDescriptor::VectorRegister();
__ xchg(receiver, Operand(esp, 0));
__ push(name);
@@ -332,15 +333,6 @@ static void StoreIC_PushArgs(MacroAssembler* masm) {
}
-void NamedStoreHandlerCompiler::GenerateSlow(MacroAssembler* masm) {
- // Return address is on the stack.
- StoreIC_PushArgs(masm);
-
- // Do tail-call to runtime routine.
- __ TailCallRuntime(Runtime::kStoreIC_Slow);
-}
-
-
void ElementHandlerCompiler::GenerateStoreSlow(MacroAssembler* masm) {
// Return address is on the stack.
StoreIC_PushArgs(masm);
@@ -439,28 +431,25 @@ 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);
- }
+ 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);
- }
+ // 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.
@@ -496,8 +485,10 @@ Register PropertyHandlerCompiler::CheckPrototypes(
!current_map->is_access_check_needed());
prototype = handle(JSObject::cast(current_map->prototype()));
- if (current_map->is_dictionary_map() &&
- !current_map->IsJSGlobalObjectMap()) {
+ if (current_map->IsJSGlobalObjectMap()) {
+ GenerateCheckPropertyCell(masm(), Handle<JSGlobalObject>::cast(current),
+ name, scratch2, miss);
+ } else if (current_map->is_dictionary_map()) {
DCHECK(!current_map->IsJSGlobalProxyMap()); // Proxy maps are fast.
if (!name->IsUniqueName()) {
DCHECK(name->IsString());
@@ -507,34 +498,12 @@ Register PropertyHandlerCompiler::CheckPrototypes(
current->property_dictionary()->FindEntry(name) ==
NameDictionary::kNotFound);
- if (FLAG_eliminate_prototype_chain_checks && depth > 1) {
+ if (depth > 1) {
// TODO(jkummerow): Cache and re-use weak cell.
__ LoadWeakValue(reg, isolate()->factory()->NewWeakCell(current), miss);
}
GenerateDictionaryNegativeLookup(masm(), miss, reg, name, scratch1,
scratch2);
-
- if (!FLAG_eliminate_prototype_chain_checks) {
- __ mov(scratch1, FieldOperand(reg, HeapObject::kMapOffset));
- __ mov(holder_reg, FieldOperand(scratch1, Map::kPrototypeOffset));
- }
- } else {
- Register map_reg = scratch1;
- 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 (!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);
- }
- 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.
@@ -548,17 +517,8 @@ Register PropertyHandlerCompiler::CheckPrototypes(
// Log the check depth.
LOG(isolate(), IntEvent("check-maps-depth", depth + 1));
- 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);
- __ 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) {
+ if (return_holder && depth != 0) {
__ LoadWeakValue(reg, isolate()->factory()->NewWeakCell(current), miss);
}
@@ -594,58 +554,6 @@ void NamedStoreHandlerCompiler::FrontendFooter(Handle<Name> name, Label* miss) {
}
-void NamedLoadHandlerCompiler::GenerateLoadCallback(
- Register reg, Handle<AccessorInfo> callback) {
- DCHECK(!AreAliased(scratch2(), scratch3(), receiver()));
- DCHECK(!AreAliased(scratch2(), scratch3(), reg));
-
- // Insert additional parameters into the stack frame above return address.
- __ pop(scratch3()); // Get return address to place it below.
-
- // Build v8::PropertyCallbackInfo::args_ array on the stack and push property
- // name below the exit frame to make GC aware of them.
- STATIC_ASSERT(PropertyCallbackArguments::kShouldThrowOnErrorIndex == 0);
- STATIC_ASSERT(PropertyCallbackArguments::kHolderIndex == 1);
- STATIC_ASSERT(PropertyCallbackArguments::kIsolateIndex == 2);
- STATIC_ASSERT(PropertyCallbackArguments::kReturnValueDefaultValueIndex == 3);
- STATIC_ASSERT(PropertyCallbackArguments::kReturnValueOffset == 4);
- STATIC_ASSERT(PropertyCallbackArguments::kDataIndex == 5);
- STATIC_ASSERT(PropertyCallbackArguments::kThisIndex == 6);
- STATIC_ASSERT(PropertyCallbackArguments::kArgsLength == 7);
-
- __ push(receiver()); // receiver
- // Push data from AccessorInfo.
- Handle<Object> data(callback->data(), isolate());
- if (data->IsUndefined() || data->IsSmi()) {
- __ push(Immediate(data));
- } else {
- Handle<WeakCell> cell =
- isolate()->factory()->NewWeakCell(Handle<HeapObject>::cast(data));
- // The callback is alive if this instruction is executed,
- // so the weak cell is not cleared and points to data.
- __ GetWeakValue(scratch2(), cell);
- __ push(scratch2());
- }
- __ push(Immediate(isolate()->factory()->undefined_value())); // ReturnValue
- // ReturnValue default value
- __ push(Immediate(isolate()->factory()->undefined_value()));
- __ push(Immediate(reinterpret_cast<int>(isolate())));
- __ push(reg); // holder
- __ push(Immediate(Smi::FromInt(0))); // should_throw_on_error -> false
-
- __ push(name()); // name
- __ push(scratch3()); // Restore return address.
-
- // Abi for CallApiGetter
- Register getter_address = ApiGetterDescriptor::function_address();
- Address function_address = v8::ToCData<Address>(callback->getter());
- __ mov(getter_address, Immediate(function_address));
-
- CallApiGetterStub stub(isolate());
- __ TailCallStub(&stub);
-}
-
-
void NamedLoadHandlerCompiler::GenerateLoadConstant(Handle<Object> value) {
// Return the constant value.
__ LoadObject(eax, value);
@@ -656,7 +564,7 @@ void NamedLoadHandlerCompiler::GenerateLoadConstant(Handle<Object> value) {
void NamedLoadHandlerCompiler::GenerateLoadInterceptorWithFollowup(
LookupIterator* it, Register holder_reg) {
DCHECK(holder()->HasNamedInterceptor());
- DCHECK(!holder()->GetNamedInterceptor()->getter()->IsUndefined());
+ DCHECK(!holder()->GetNamedInterceptor()->getter()->IsUndefined(isolate()));
// Compile the interceptor call, followed by inline code to load the
// property from further up the prototype chain if the call fails.
@@ -723,7 +631,7 @@ void NamedLoadHandlerCompiler::GenerateLoadInterceptorWithFollowup(
void NamedLoadHandlerCompiler::GenerateLoadInterceptor(Register holder_reg) {
DCHECK(holder()->HasNamedInterceptor());
- DCHECK(!holder()->GetNamedInterceptor()->getter()->IsUndefined());
+ DCHECK(!holder()->GetNamedInterceptor()->getter()->IsUndefined(isolate()));
// Call the runtime system to load the interceptor.
__ pop(scratch2()); // save old return address
PushInterceptorArguments(masm(), receiver(), holder_reg, this->name(),
@@ -744,7 +652,7 @@ Handle<Code> NamedStoreHandlerCompiler::CompileStoreCallback(
__ push(holder_reg);
// If the callback cannot leak, then push the callback directly,
// otherwise wrap it in a weak cell.
- if (callback->data()->IsUndefined() || callback->data()->IsSmi()) {
+ if (callback->data()->IsUndefined(isolate()) || callback->data()->IsSmi()) {
__ Push(callback);
} else {
Handle<WeakCell> cell = isolate()->factory()->NewWeakCell(callback);
@@ -759,7 +667,7 @@ Handle<Code> NamedStoreHandlerCompiler::CompileStoreCallback(
__ TailCallRuntime(Runtime::kStoreCallbackProperty);
// Return the generated code.
- return GetCode(kind(), Code::FAST, name);
+ return GetCode(kind(), name);
}
@@ -801,7 +709,7 @@ Handle<Code> NamedLoadHandlerCompiler::CompileLoadGlobal(
FrontendFooter(name, &miss);
// Return the generated code.
- return GetCode(kind(), Code::NORMAL, name);
+ return GetCode(kind(), name);
}
diff --git a/deps/v8/src/ic/x87/ic-x87.cc b/deps/v8/src/ic/x87/ic-x87.cc
index b51045bee8..76933f01bb 100644
--- a/deps/v8/src/ic/x87/ic-x87.cc
+++ b/deps/v8/src/ic/x87/ic-x87.cc
@@ -336,10 +336,8 @@ void KeyedLoadIC::GenerateMegamorphic(MacroAssembler* masm) {
__ push(Immediate(Smi::FromInt(slot)));
__ push(Immediate(dummy_vector));
- Code::Flags flags = Code::RemoveTypeAndHolderFromFlags(
- Code::ComputeHandlerFlags(Code::LOAD_IC));
- masm->isolate()->stub_cache()->GenerateProbe(masm, Code::KEYED_LOAD_IC, flags,
- receiver, key, ebx, edi);
+ masm->isolate()->load_stub_cache()->GenerateProbe(masm, receiver, key, ebx,
+ edi);
__ pop(LoadWithVectorDescriptor::VectorRegister());
__ pop(LoadDescriptor::SlotRegister());
@@ -519,10 +517,10 @@ void KeyedStoreIC::GenerateMegamorphic(MacroAssembler* masm,
__ JumpIfSmi(receiver, &slow);
// Get the map from the receiver.
__ mov(edi, FieldOperand(receiver, HeapObject::kMapOffset));
- // Check that the receiver does not require access checks and is not observed.
- // The generic stub does not perform map checks or handle observed objects.
+ // Check that the receiver does not require access checks.
+ // The generic stub does not perform map checks.
__ test_b(FieldOperand(edi, Map::kBitFieldOffset),
- Immediate(1 << Map::kIsAccessCheckNeeded | 1 << Map::kIsObserved));
+ Immediate(1 << Map::kIsAccessCheckNeeded));
__ j(not_zero, &slow);
// Check that the key is a smi.
__ JumpIfNotSmi(key, &maybe_name_key);
@@ -563,13 +561,11 @@ void KeyedStoreIC::GenerateMegamorphic(MacroAssembler* masm,
__ push(Immediate(Smi::FromInt(slot)));
__ push(Immediate(dummy_vector));
- Code::Flags flags = Code::RemoveTypeAndHolderFromFlags(
- Code::ComputeHandlerFlags(Code::STORE_IC));
- masm->isolate()->stub_cache()->GenerateProbe(masm, Code::STORE_IC, flags,
- receiver, key, edi, no_reg);
+ masm->isolate()->store_stub_cache()->GenerateProbe(masm, receiver, key, edi,
+ no_reg);
- __ pop(VectorStoreICDescriptor::VectorRegister());
- __ pop(VectorStoreICDescriptor::SlotRegister());
+ __ pop(StoreWithVectorDescriptor::VectorRegister());
+ __ pop(StoreWithVectorDescriptor::SlotRegister());
// Cache miss.
__ jmp(&miss);
@@ -708,21 +704,12 @@ void KeyedLoadIC::GenerateRuntimeGetProperty(MacroAssembler* masm) {
__ TailCallRuntime(Runtime::kKeyedGetProperty);
}
-
-void StoreIC::GenerateMegamorphic(MacroAssembler* masm) {
- // This shouldn't be called.
- // TODO(mvstanton): remove this method.
- __ int3();
- return;
-}
-
-
static void StoreIC_PushArgs(MacroAssembler* masm) {
Register receiver = StoreDescriptor::ReceiverRegister();
Register name = StoreDescriptor::NameRegister();
Register value = StoreDescriptor::ValueRegister();
- Register slot = VectorStoreICDescriptor::SlotRegister();
- Register vector = VectorStoreICDescriptor::VectorRegister();
+ Register slot = StoreWithVectorDescriptor::SlotRegister();
+ Register vector = StoreWithVectorDescriptor::VectorRegister();
__ xchg(receiver, Operand(esp, 0));
__ push(name);
@@ -747,8 +734,8 @@ void StoreIC::GenerateNormal(MacroAssembler* masm) {
Register receiver = StoreDescriptor::ReceiverRegister();
Register name = StoreDescriptor::NameRegister();
Register value = StoreDescriptor::ValueRegister();
- Register vector = VectorStoreICDescriptor::VectorRegister();
- Register slot = VectorStoreICDescriptor::SlotRegister();
+ Register vector = StoreWithVectorDescriptor::VectorRegister();
+ Register slot = StoreWithVectorDescriptor::SlotRegister();
// A lot of registers are needed for storing to slow case
// objects. Push and restore receiver but rely on
@@ -836,8 +823,9 @@ void PatchInlinedSmiCode(Isolate* isolate, Address address,
// condition code uses at the patched jump.
uint8_t delta = *reinterpret_cast<uint8_t*>(delta_address);
if (FLAG_trace_ic) {
- PrintF("[ patching ic at %p, test=%p, delta=%d\n", address,
- test_instruction_address, delta);
+ PrintF("[ patching ic at %p, test=%p, delta=%d\n",
+ static_cast<void*>(address),
+ static_cast<void*>(test_instruction_address), delta);
}
// Patch with a short conditional jump. Enabling means switching from a short
diff --git a/deps/v8/src/ic/x87/stub-cache-x87.cc b/deps/v8/src/ic/x87/stub-cache-x87.cc
index dfc0ef6c66..e0656f7cff 100644
--- a/deps/v8/src/ic/x87/stub-cache-x87.cc
+++ b/deps/v8/src/ic/x87/stub-cache-x87.cc
@@ -14,19 +14,19 @@ namespace internal {
#define __ ACCESS_MASM(masm)
-
-static void ProbeTable(Isolate* isolate, MacroAssembler* masm,
- Code::Kind ic_kind, Code::Flags flags,
+static void ProbeTable(StubCache* stub_cache, MacroAssembler* masm,
StubCache::Table table, Register name, Register receiver,
- // Number of the cache entry pointer-size scaled.
+ // The offset is scaled by 4, based on
+ // kCacheIndexShift, which is two bits
Register offset, Register extra) {
- ExternalReference key_offset(isolate->stub_cache()->key_reference(table));
- ExternalReference value_offset(isolate->stub_cache()->value_reference(table));
- ExternalReference map_offset(isolate->stub_cache()->map_reference(table));
+ ExternalReference key_offset(stub_cache->key_reference(table));
+ ExternalReference value_offset(stub_cache->value_reference(table));
+ ExternalReference map_offset(stub_cache->map_reference(table));
ExternalReference virtual_register =
ExternalReference::virtual_handler_register(masm->isolate());
Label miss;
+ Code::Kind ic_kind = stub_cache->ic_kind();
bool is_vector_store =
IC::ICUseVector(ic_kind) &&
(ic_kind == Code::STORE_IC || ic_kind == Code::KEYED_STORE_IC);
@@ -47,12 +47,6 @@ static void ProbeTable(Isolate* isolate, MacroAssembler* masm,
__ cmp(offset, FieldOperand(receiver, HeapObject::kMapOffset));
__ j(not_equal, &miss);
- // Check that the flags match what we're looking for.
- __ mov(offset, FieldOperand(extra, Code::kFlagsOffset));
- __ and_(offset, ~Code::kFlagsNotUsedInLookup);
- __ cmp(offset, flags);
- __ j(not_equal, &miss);
-
#ifdef DEBUG
if (FLAG_test_secondary_stub_cache && table == StubCache::kPrimary) {
__ jmp(&miss);
@@ -65,8 +59,8 @@ static void ProbeTable(Isolate* isolate, MacroAssembler* masm,
// probe, and need to be dropped before calling the handler.
if (is_vector_store) {
// The overlap here is rather embarrassing. One does what one must.
- Register vector = VectorStoreICDescriptor::VectorRegister();
- DCHECK(extra.is(VectorStoreICDescriptor::SlotRegister()));
+ Register vector = StoreWithVectorDescriptor::VectorRegister();
+ DCHECK(extra.is(StoreWithVectorDescriptor::SlotRegister()));
__ add(extra, Immediate(Code::kHeaderSize - kHeapObjectTag));
__ pop(vector);
__ mov(Operand::StaticVariable(virtual_register), extra);
@@ -102,12 +96,6 @@ static void ProbeTable(Isolate* isolate, MacroAssembler* masm,
// Get the code entry from the cache.
__ mov(offset, Operand::StaticArray(offset, times_1, value_offset));
- // Check that the flags match what we're looking for.
- __ mov(offset, FieldOperand(offset, Code::kFlagsOffset));
- __ and_(offset, ~Code::kFlagsNotUsedInLookup);
- __ cmp(offset, flags);
- __ j(not_equal, &miss);
-
#ifdef DEBUG
if (FLAG_test_secondary_stub_cache && table == StubCache::kPrimary) {
__ jmp(&miss);
@@ -124,8 +112,8 @@ static void ProbeTable(Isolate* isolate, MacroAssembler* masm,
if (is_vector_store) {
// The vector and slot were pushed onto the stack before starting the
// probe, and need to be dropped before calling the handler.
- Register vector = VectorStoreICDescriptor::VectorRegister();
- DCHECK(offset.is(VectorStoreICDescriptor::SlotRegister()));
+ Register vector = StoreWithVectorDescriptor::VectorRegister();
+ DCHECK(offset.is(StoreWithVectorDescriptor::SlotRegister()));
__ add(offset, Immediate(Code::kHeaderSize - kHeapObjectTag));
__ mov(Operand::StaticVariable(virtual_register), offset);
__ pop(vector);
@@ -142,9 +130,7 @@ static void ProbeTable(Isolate* isolate, MacroAssembler* masm,
}
}
-
-void StubCache::GenerateProbe(MacroAssembler* masm, Code::Kind ic_kind,
- Code::Flags flags, Register receiver,
+void StubCache::GenerateProbe(MacroAssembler* masm, Register receiver,
Register name, Register scratch, Register extra,
Register extra2, Register extra3) {
Label miss;
@@ -153,9 +139,6 @@ void StubCache::GenerateProbe(MacroAssembler* masm, Code::Kind ic_kind,
// being 12.
DCHECK(sizeof(Entry) == 12);
- // Assert the flags do not name a specific type.
- DCHECK(Code::ExtractTypeFromFlags(flags) == 0);
-
// Assert that there are no register conflicts.
DCHECK(!scratch.is(receiver));
DCHECK(!scratch.is(name));
@@ -180,7 +163,7 @@ void StubCache::GenerateProbe(MacroAssembler* masm, Code::Kind ic_kind,
// Get the map of the receiver and compute the hash.
__ mov(offset, FieldOperand(name, Name::kHashFieldOffset));
__ add(offset, FieldOperand(receiver, HeapObject::kMapOffset));
- __ xor_(offset, flags);
+ __ xor_(offset, kPrimaryMagic);
// We mask out the last two bits because they are not part of the hash and
// they are always 01 for maps. Also in the two 'and' instructions below.
__ and_(offset, (kPrimaryTableSize - 1) << kCacheIndexShift);
@@ -189,21 +172,19 @@ void StubCache::GenerateProbe(MacroAssembler* masm, Code::Kind ic_kind,
DCHECK(kCacheIndexShift == kPointerSizeLog2);
// Probe the primary table.
- ProbeTable(isolate(), masm, ic_kind, flags, kPrimary, name, receiver, offset,
- extra);
+ ProbeTable(this, masm, kPrimary, name, receiver, offset, extra);
// Primary miss: Compute hash for secondary probe.
__ mov(offset, FieldOperand(name, Name::kHashFieldOffset));
__ add(offset, FieldOperand(receiver, HeapObject::kMapOffset));
- __ xor_(offset, flags);
+ __ xor_(offset, kPrimaryMagic);
__ and_(offset, (kPrimaryTableSize - 1) << kCacheIndexShift);
__ sub(offset, name);
- __ add(offset, Immediate(flags));
+ __ add(offset, Immediate(kSecondaryMagic));
__ and_(offset, (kSecondaryTableSize - 1) << kCacheIndexShift);
// Probe the secondary table.
- ProbeTable(isolate(), masm, ic_kind, flags, kSecondary, name, receiver,
- offset, extra);
+ ProbeTable(this, masm, kSecondary, name, receiver, offset, extra);
// Cache miss: Fall-through and let caller handle the miss by
// entering the runtime system.