diff options
author | Michaël Zasso <targos@protonmail.com> | 2016-09-06 22:49:51 +0200 |
---|---|---|
committer | Michaël Zasso <targos@protonmail.com> | 2016-09-22 09:51:19 +0200 |
commit | ec02b811a8a5c999bab4de312be2d732b7d9d50b (patch) | |
tree | ca3068017254f238cf413a451c57a803572983a4 /deps/v8/src/ic | |
parent | d2eb7ce0105369a9cad82787cb33a665e9bd00ad (diff) | |
download | android-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')
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. |