[ic][ia32][x87] Pass value, slot and vector to StoreIC and KeyedStoreIC through the stack.
The handlers cleanup will be done in a follow-up CL. BUG=v8:5407 Review-Url: https://codereview.chromium.org/2357163003 Cr-Commit-Position: refs/heads/master@{#39617}
This commit is contained in:
parent
502b9aa71b
commit
76cfb388de
@ -88,8 +88,10 @@ void JSGenericLowering::ReplaceWithStubCall(Node* node, Callable callable,
|
||||
void JSGenericLowering::ReplaceWithStubCall(Node* node, Callable callable,
|
||||
CallDescriptor::Flags flags,
|
||||
Operator::Properties properties) {
|
||||
const CallInterfaceDescriptor& descriptor = callable.descriptor();
|
||||
CallDescriptor* desc = Linkage::GetStubCallDescriptor(
|
||||
isolate(), zone(), callable.descriptor(), 0, flags, properties);
|
||||
isolate(), zone(), descriptor, descriptor.GetStackParameterCount(), flags,
|
||||
properties);
|
||||
Node* stub_code = jsgraph()->HeapConstant(callable.code());
|
||||
node->InsertInput(zone(), 0, stub_code);
|
||||
NodeProperties::ChangeOp(node, common()->Call(desc));
|
||||
|
@ -237,6 +237,14 @@ void FullCodeGenerator::CallLoadGlobalIC(TypeofMode typeof_mode,
|
||||
|
||||
void FullCodeGenerator::CallStoreIC(TypeFeedbackId id) {
|
||||
Handle<Code> ic = CodeFactory::StoreIC(isolate(), language_mode()).code();
|
||||
|
||||
STATIC_ASSERT(!StoreDescriptor::kPassLastArgsOnStack ||
|
||||
StoreDescriptor::kStackArgumentsCount == 2);
|
||||
if (StoreDescriptor::kPassLastArgsOnStack) {
|
||||
__ Push(StoreDescriptor::ValueRegister());
|
||||
__ Push(StoreDescriptor::SlotRegister());
|
||||
}
|
||||
|
||||
CallIC(ic, id);
|
||||
RestoreContext();
|
||||
}
|
||||
@ -244,6 +252,14 @@ void FullCodeGenerator::CallStoreIC(TypeFeedbackId id) {
|
||||
void FullCodeGenerator::CallKeyedStoreIC() {
|
||||
Handle<Code> ic =
|
||||
CodeFactory::KeyedStoreIC(isolate(), language_mode()).code();
|
||||
|
||||
STATIC_ASSERT(!StoreDescriptor::kPassLastArgsOnStack ||
|
||||
StoreDescriptor::kStackArgumentsCount == 2);
|
||||
if (StoreDescriptor::kPassLastArgsOnStack) {
|
||||
__ Push(StoreDescriptor::ValueRegister());
|
||||
__ Push(StoreDescriptor::SlotRegister());
|
||||
}
|
||||
|
||||
CallIC(ic);
|
||||
RestoreContext();
|
||||
}
|
||||
|
@ -3671,6 +3671,28 @@ void StoreICStub::GenerateImpl(MacroAssembler* masm, bool in_frame) {
|
||||
Register slot = StoreWithVectorDescriptor::SlotRegister(); // edi
|
||||
Label miss;
|
||||
|
||||
if (StoreWithVectorDescriptor::kPassLastArgsOnStack) {
|
||||
// Current stack layout:
|
||||
// - esp[8] -- value
|
||||
// - esp[4] -- slot
|
||||
// - esp[0] -- return address
|
||||
STATIC_ASSERT(StoreDescriptor::kStackArgumentsCount == 2);
|
||||
STATIC_ASSERT(StoreWithVectorDescriptor::kStackArgumentsCount == 3);
|
||||
if (in_frame) {
|
||||
__ RecordComment("[ StoreDescriptor -> StoreWithVectorDescriptor");
|
||||
// If the vector is not on the stack, then insert the vector beneath
|
||||
// return address in order to prepare for calling handler with
|
||||
// StoreWithVector calling convention.
|
||||
__ push(Operand(esp, 0));
|
||||
__ mov(Operand(esp, 4), StoreWithVectorDescriptor::VectorRegister());
|
||||
__ RecordComment("]");
|
||||
} else {
|
||||
__ mov(vector, Operand(esp, 1 * kPointerSize));
|
||||
}
|
||||
__ mov(slot, Operand(esp, 2 * kPointerSize));
|
||||
__ mov(value, Operand(esp, 3 * kPointerSize));
|
||||
}
|
||||
|
||||
__ push(value);
|
||||
|
||||
Register scratch = value;
|
||||
@ -3812,12 +3834,23 @@ static void HandlePolymorphicKeyedStoreCase(MacroAssembler* masm,
|
||||
__ pop(vector);
|
||||
__ pop(receiver);
|
||||
__ pop(value);
|
||||
{
|
||||
// Put vector and slot beneath return address.
|
||||
__ push(vector);
|
||||
__ push(Operand(esp, 1 * kPointerSize)); // push return address
|
||||
__ mov(Operand(esp, 2 * kPointerSize), slot);
|
||||
}
|
||||
// Ensure that the transition handler we are going to call has the same
|
||||
// number of stack arguments which means that we don't have to adapt them
|
||||
// before the call.
|
||||
STATIC_ASSERT(StoreWithVectorDescriptor::kStackArgumentsCount == 3);
|
||||
STATIC_ASSERT(StoreTransitionDescriptor::kStackArgumentsCount == 3);
|
||||
STATIC_ASSERT(StoreWithVectorDescriptor::kParameterCount -
|
||||
StoreWithVectorDescriptor::kValue ==
|
||||
StoreTransitionDescriptor::kParameterCount -
|
||||
StoreTransitionDescriptor::kValue);
|
||||
STATIC_ASSERT(StoreWithVectorDescriptor::kParameterCount -
|
||||
StoreWithVectorDescriptor::kSlot ==
|
||||
StoreTransitionDescriptor::kParameterCount -
|
||||
StoreTransitionDescriptor::kSlot);
|
||||
STATIC_ASSERT(StoreWithVectorDescriptor::kParameterCount -
|
||||
StoreWithVectorDescriptor::kVector ==
|
||||
StoreTransitionDescriptor::kParameterCount -
|
||||
StoreTransitionDescriptor::kVector);
|
||||
__ jmp(Operand::StaticVariable(virtual_register));
|
||||
|
||||
__ bind(&prepare_next);
|
||||
@ -3845,6 +3878,28 @@ void KeyedStoreICStub::GenerateImpl(MacroAssembler* masm, bool in_frame) {
|
||||
Register slot = StoreWithVectorDescriptor::SlotRegister(); // edi
|
||||
Label miss;
|
||||
|
||||
if (StoreWithVectorDescriptor::kPassLastArgsOnStack) {
|
||||
// Current stack layout:
|
||||
// - esp[8] -- value
|
||||
// - esp[4] -- slot
|
||||
// - esp[0] -- return address
|
||||
STATIC_ASSERT(StoreDescriptor::kStackArgumentsCount == 2);
|
||||
STATIC_ASSERT(StoreWithVectorDescriptor::kStackArgumentsCount == 3);
|
||||
if (in_frame) {
|
||||
__ RecordComment("[ StoreDescriptor -> StoreWithVectorDescriptor");
|
||||
// If the vector is not on the stack, then insert the vector beneath
|
||||
// return address in order to prepare for calling handler with
|
||||
// StoreWithVector calling convention.
|
||||
__ push(Operand(esp, 0));
|
||||
__ mov(Operand(esp, 4), StoreWithVectorDescriptor::VectorRegister());
|
||||
__ RecordComment("]");
|
||||
} else {
|
||||
__ mov(vector, Operand(esp, 1 * kPointerSize));
|
||||
}
|
||||
__ mov(slot, Operand(esp, 2 * kPointerSize));
|
||||
__ mov(value, Operand(esp, 3 * kPointerSize));
|
||||
}
|
||||
|
||||
__ push(value);
|
||||
|
||||
Register scratch = value;
|
||||
|
@ -129,13 +129,13 @@ Register NamedStoreHandlerCompiler::FrontendHeader(Register object_reg,
|
||||
|
||||
Register PropertyHandlerCompiler::Frontend(Handle<Name> name) {
|
||||
Label miss;
|
||||
if (IC::ICUseVector(kind())) {
|
||||
if (IC::ShouldPushPopSlotAndVector(kind())) {
|
||||
PushVectorAndSlot();
|
||||
}
|
||||
Register reg = FrontendHeader(receiver(), name, &miss, RETURN_HOLDER);
|
||||
FrontendFooter(name, &miss);
|
||||
// The footer consumes the vector and slot from the stack if miss occurs.
|
||||
if (IC::ICUseVector(kind())) {
|
||||
if (IC::ShouldPushPopSlotAndVector(kind())) {
|
||||
DiscardVectorAndSlot();
|
||||
}
|
||||
return reg;
|
||||
@ -209,12 +209,12 @@ Handle<Code> NamedLoadHandlerCompiler::CompileLoadConstant(Handle<Name> name,
|
||||
Handle<Code> NamedLoadHandlerCompiler::CompileLoadNonexistent(
|
||||
Handle<Name> name) {
|
||||
Label miss;
|
||||
if (IC::ICUseVector(kind())) {
|
||||
if (IC::ShouldPushPopSlotAndVector(kind())) {
|
||||
DCHECK(kind() == Code::LOAD_IC);
|
||||
PushVectorAndSlot();
|
||||
}
|
||||
NonexistentFrontendHeader(name, &miss, scratch2(), scratch3());
|
||||
if (IC::ICUseVector(kind())) {
|
||||
if (IC::ShouldPushPopSlotAndVector(kind())) {
|
||||
DiscardVectorAndSlot();
|
||||
}
|
||||
GenerateLoadConstant(isolate()->factory()->undefined_value());
|
||||
@ -247,7 +247,7 @@ Handle<Code> NamedLoadHandlerCompiler::CompileLoadCallback(
|
||||
|
||||
|
||||
void NamedLoadHandlerCompiler::InterceptorVectorSlotPush(Register holder_reg) {
|
||||
if (IC::ICUseVector(kind())) {
|
||||
if (IC::ShouldPushPopSlotAndVector(kind())) {
|
||||
if (holder_reg.is(receiver())) {
|
||||
PushVectorAndSlot();
|
||||
} else {
|
||||
@ -260,7 +260,7 @@ void NamedLoadHandlerCompiler::InterceptorVectorSlotPush(Register holder_reg) {
|
||||
|
||||
void NamedLoadHandlerCompiler::InterceptorVectorSlotPop(Register holder_reg,
|
||||
PopMode mode) {
|
||||
if (IC::ICUseVector(kind())) {
|
||||
if (IC::ShouldPushPopSlotAndVector(kind())) {
|
||||
if (mode == DISCARD) {
|
||||
DiscardVectorAndSlot();
|
||||
} else {
|
||||
@ -438,16 +438,28 @@ Handle<Code> NamedStoreHandlerCompiler::CompileStoreTransition(
|
||||
Handle<Map> transition, Handle<Name> name) {
|
||||
Label miss;
|
||||
|
||||
bool vector_and_slot_on_stack =
|
||||
StoreTransitionDescriptor::PassVectorAndSlotOnStack();
|
||||
if (vector_and_slot_on_stack) {
|
||||
// Speculatively prepare for calling StoreTransitionStub by converting
|
||||
// StoreWithVectorDescriptor arguments to StoreTransitionDescriptor
|
||||
// arguments.
|
||||
PopReturnAddress(this->name());
|
||||
PushVectorAndSlot();
|
||||
PushReturnAddress(this->name());
|
||||
} else {
|
||||
// Ensure that the StoreTransitionStub we are going to call has the same
|
||||
// number of stack arguments. This means that we don't have to adapt them
|
||||
// if we decide to call the transition or miss stub.
|
||||
STATIC_ASSERT(StoreWithVectorDescriptor::kStackArgumentsCount ==
|
||||
StoreTransitionDescriptor::kStackArgumentsCount);
|
||||
STATIC_ASSERT(StoreWithVectorDescriptor::kStackArgumentsCount == 0 ||
|
||||
StoreWithVectorDescriptor::kStackArgumentsCount == 3);
|
||||
STATIC_ASSERT(StoreWithVectorDescriptor::kParameterCount -
|
||||
StoreWithVectorDescriptor::kValue ==
|
||||
StoreTransitionDescriptor::kParameterCount -
|
||||
StoreTransitionDescriptor::kValue);
|
||||
STATIC_ASSERT(StoreWithVectorDescriptor::kParameterCount -
|
||||
StoreWithVectorDescriptor::kSlot ==
|
||||
StoreTransitionDescriptor::kParameterCount -
|
||||
StoreTransitionDescriptor::kSlot);
|
||||
STATIC_ASSERT(StoreWithVectorDescriptor::kParameterCount -
|
||||
StoreWithVectorDescriptor::kVector ==
|
||||
StoreTransitionDescriptor::kParameterCount -
|
||||
StoreTransitionDescriptor::kVector);
|
||||
|
||||
bool need_save_restore = IC::ShouldPushPopSlotAndVector(kind());
|
||||
if (need_save_restore) {
|
||||
PushVectorAndSlot();
|
||||
}
|
||||
|
||||
@ -487,7 +499,7 @@ Handle<Code> NamedStoreHandlerCompiler::CompileStoreTransition(
|
||||
DCHECK(descriptors->GetValue(descriptor)->IsJSFunction());
|
||||
GenerateRestoreMap(transition, map_reg, scratch1(), &miss);
|
||||
GenerateConstantCheck(map_reg, descriptor, value(), scratch1(), &miss);
|
||||
if (!vector_and_slot_on_stack) {
|
||||
if (need_save_restore) {
|
||||
PopVectorAndSlot();
|
||||
}
|
||||
GenerateRestoreName(name);
|
||||
@ -504,7 +516,7 @@ Handle<Code> NamedStoreHandlerCompiler::CompileStoreTransition(
|
||||
? StoreTransitionStub::ExtendStorageAndStoreMapAndValue
|
||||
: StoreTransitionStub::StoreMapAndValue;
|
||||
GenerateRestoreMap(transition, map_reg, scratch1(), &miss);
|
||||
if (!vector_and_slot_on_stack) {
|
||||
if (need_save_restore) {
|
||||
PopVectorAndSlot();
|
||||
}
|
||||
GenerateRestoreName(name);
|
||||
@ -515,12 +527,7 @@ Handle<Code> NamedStoreHandlerCompiler::CompileStoreTransition(
|
||||
}
|
||||
|
||||
__ bind(&miss);
|
||||
if (vector_and_slot_on_stack) {
|
||||
// Prepare for calling miss builtin with StoreWithVectorDescriptor.
|
||||
PopReturnAddress(this->name());
|
||||
PopVectorAndSlot();
|
||||
PushReturnAddress(this->name());
|
||||
} else {
|
||||
if (need_save_restore) {
|
||||
PopVectorAndSlot();
|
||||
}
|
||||
GenerateRestoreName(name);
|
||||
@ -542,7 +549,7 @@ Handle<Code> NamedStoreHandlerCompiler::CompileStoreField(LookupIterator* it) {
|
||||
FieldType* field_type = *it->GetFieldType();
|
||||
bool need_save_restore = false;
|
||||
if (RequiresFieldTypeChecks(field_type)) {
|
||||
need_save_restore = IC::ICUseVector(kind());
|
||||
need_save_restore = IC::ShouldPushPopSlotAndVector(kind());
|
||||
if (need_save_restore) PushVectorAndSlot();
|
||||
GenerateFieldTypeChecks(field_type, value(), &miss);
|
||||
if (need_save_restore) PopVectorAndSlot();
|
||||
|
@ -165,6 +165,13 @@ void PropertyHandlerCompiler::GenerateApiAccessorCall(
|
||||
DCHECK(!accessor_holder.is(scratch));
|
||||
// Copy return value.
|
||||
__ pop(scratch);
|
||||
|
||||
if (is_store) {
|
||||
// Discard stack arguments.
|
||||
__ add(esp, Immediate(StoreWithVectorDescriptor::kStackArgumentsCount *
|
||||
kPointerSize));
|
||||
}
|
||||
|
||||
// receiver
|
||||
__ push(receiver);
|
||||
// Write the arguments to stack frame.
|
||||
@ -305,7 +312,14 @@ void NamedStoreHandlerCompiler::GenerateStoreViaSetter(
|
||||
// Restore context register.
|
||||
__ pop(esi);
|
||||
}
|
||||
__ ret(0);
|
||||
if (accessor_index >= 0) {
|
||||
__ ret(StoreWithVectorDescriptor::kStackArgumentsCount * kPointerSize);
|
||||
} else {
|
||||
// If we generate a global code snippet for deoptimization only, don't try
|
||||
// to drop stack arguments for the StoreIC because they are not a part of
|
||||
// expression stack and deoptimizer does not reconstruct them.
|
||||
__ ret(0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -508,7 +522,7 @@ void NamedLoadHandlerCompiler::FrontendFooter(Handle<Name> name, Label* miss) {
|
||||
Label success;
|
||||
__ jmp(&success);
|
||||
__ bind(miss);
|
||||
if (IC::ICUseVector(kind())) {
|
||||
if (IC::ShouldPushPopSlotAndVector(kind())) {
|
||||
DCHECK(kind() == Code::LOAD_IC);
|
||||
PopVectorAndSlot();
|
||||
}
|
||||
@ -523,7 +537,7 @@ void NamedStoreHandlerCompiler::FrontendFooter(Handle<Name> name, Label* miss) {
|
||||
Label success;
|
||||
__ jmp(&success);
|
||||
GenerateRestoreName(miss, name);
|
||||
if (IC::ICUseVector(kind())) PopVectorAndSlot();
|
||||
DCHECK(!IC::ShouldPushPopSlotAndVector(kind()));
|
||||
TailCallBuiltin(masm(), MissBuiltin(kind()));
|
||||
__ bind(&success);
|
||||
}
|
||||
@ -624,6 +638,9 @@ Handle<Code> NamedStoreHandlerCompiler::CompileStoreCallback(
|
||||
Register holder_reg = Frontend(name);
|
||||
|
||||
__ pop(scratch1()); // remove the return address
|
||||
// Discard stack arguments.
|
||||
__ add(esp, Immediate(StoreWithVectorDescriptor::kStackArgumentsCount *
|
||||
kPointerSize));
|
||||
__ push(receiver());
|
||||
__ push(holder_reg);
|
||||
// If the callback cannot leak, then push the callback directly,
|
||||
@ -655,7 +672,7 @@ Register NamedStoreHandlerCompiler::value() {
|
||||
Handle<Code> NamedLoadHandlerCompiler::CompileLoadGlobal(
|
||||
Handle<PropertyCell> cell, Handle<Name> name, bool is_configurable) {
|
||||
Label miss;
|
||||
if (IC::ICUseVector(kind())) {
|
||||
if (IC::ShouldPushPopSlotAndVector(kind())) {
|
||||
PushVectorAndSlot();
|
||||
}
|
||||
FrontendHeader(receiver(), name, &miss, DONT_RETURN_ANYTHING);
|
||||
@ -677,7 +694,7 @@ Handle<Code> NamedLoadHandlerCompiler::CompileLoadGlobal(
|
||||
Counters* counters = isolate()->counters();
|
||||
__ IncrementCounter(counters->ic_named_load_global_stub(), 1);
|
||||
// The code above already loads the result into the return register.
|
||||
if (IC::ICUseVector(kind())) {
|
||||
if (IC::ShouldPushPopSlotAndVector(kind())) {
|
||||
DiscardVectorAndSlot();
|
||||
}
|
||||
__ ret(0);
|
||||
|
@ -15,14 +15,17 @@ namespace internal {
|
||||
|
||||
void PropertyICCompiler::GenerateRuntimeSetProperty(
|
||||
MacroAssembler* masm, LanguageMode language_mode) {
|
||||
// Return address is on the stack.
|
||||
DCHECK(!ebx.is(StoreDescriptor::ReceiverRegister()) &&
|
||||
!ebx.is(StoreDescriptor::NameRegister()) &&
|
||||
!ebx.is(StoreDescriptor::ValueRegister()));
|
||||
STATIC_ASSERT(StoreWithVectorDescriptor::kStackArgumentsCount == 3);
|
||||
// Current stack layout:
|
||||
// - esp[12] -- value
|
||||
// - esp[8] -- slot
|
||||
// - esp[4] -- vector
|
||||
// - esp[0] -- return address
|
||||
|
||||
__ mov(Operand(esp, 12), StoreDescriptor::ReceiverRegister());
|
||||
__ mov(Operand(esp, 8), StoreDescriptor::NameRegister());
|
||||
__ mov(Operand(esp, 4), StoreDescriptor::ValueRegister());
|
||||
__ pop(ebx);
|
||||
__ push(StoreDescriptor::ReceiverRegister());
|
||||
__ push(StoreDescriptor::NameRegister());
|
||||
__ push(StoreDescriptor::ValueRegister());
|
||||
__ push(Immediate(Smi::FromInt(language_mode)));
|
||||
__ push(ebx); // return address
|
||||
|
||||
|
@ -409,7 +409,7 @@ static void KeyedStoreGenerateMegamorphicHelper(
|
||||
}
|
||||
// It's irrelevant whether array is smi-only or not when writing a smi.
|
||||
__ mov(FixedArrayElementOperand(ebx, key), value);
|
||||
__ ret(0);
|
||||
__ ret(StoreWithVectorDescriptor::kStackArgumentsCount * kPointerSize);
|
||||
|
||||
__ bind(&non_smi_value);
|
||||
// Escape to elements kind transition case.
|
||||
@ -428,7 +428,7 @@ static void KeyedStoreGenerateMegamorphicHelper(
|
||||
__ mov(edx, value); // Preserve the value which is returned.
|
||||
__ RecordWriteArray(ebx, edx, key, kDontSaveFPRegs, EMIT_REMEMBERED_SET,
|
||||
OMIT_SMI_CHECK);
|
||||
__ ret(0);
|
||||
__ ret(StoreWithVectorDescriptor::kStackArgumentsCount * kPointerSize);
|
||||
|
||||
__ bind(fast_double);
|
||||
if (check_map == kCheckMap) {
|
||||
@ -457,7 +457,7 @@ static void KeyedStoreGenerateMegamorphicHelper(
|
||||
__ add(FieldOperand(receiver, JSArray::kLengthOffset),
|
||||
Immediate(Smi::FromInt(1)));
|
||||
}
|
||||
__ ret(0);
|
||||
__ ret(StoreWithVectorDescriptor::kStackArgumentsCount * kPointerSize);
|
||||
|
||||
__ bind(&transition_smi_elements);
|
||||
__ mov(ebx, FieldOperand(receiver, HeapObject::kMapOffset));
|
||||
@ -705,18 +705,21 @@ void KeyedLoadIC::GenerateRuntimeGetProperty(MacroAssembler* masm) {
|
||||
}
|
||||
|
||||
static void StoreIC_PushArgs(MacroAssembler* masm) {
|
||||
Register receiver = StoreDescriptor::ReceiverRegister();
|
||||
Register name = StoreDescriptor::NameRegister();
|
||||
Register value = StoreDescriptor::ValueRegister();
|
||||
Register slot = StoreWithVectorDescriptor::SlotRegister();
|
||||
Register vector = StoreWithVectorDescriptor::VectorRegister();
|
||||
Register receiver = StoreWithVectorDescriptor::ReceiverRegister();
|
||||
Register name = StoreWithVectorDescriptor::NameRegister();
|
||||
|
||||
__ xchg(value, Operand(esp, 0));
|
||||
__ push(slot);
|
||||
__ push(vector);
|
||||
STATIC_ASSERT(StoreWithVectorDescriptor::kStackArgumentsCount == 3);
|
||||
// Current stack layout:
|
||||
// - esp[12] -- value
|
||||
// - esp[8] -- slot
|
||||
// - esp[4] -- vector
|
||||
// - esp[0] -- return address
|
||||
|
||||
Register return_address = StoreWithVectorDescriptor::SlotRegister();
|
||||
__ pop(return_address);
|
||||
__ push(receiver);
|
||||
__ push(name);
|
||||
__ push(value); // Contains the return address.
|
||||
__ push(return_address);
|
||||
}
|
||||
|
||||
|
||||
@ -751,7 +754,7 @@ void StoreIC::GenerateNormal(MacroAssembler* masm) {
|
||||
__ Drop(3);
|
||||
Counters* counters = masm->isolate()->counters();
|
||||
__ IncrementCounter(counters->ic_store_normal_hit(), 1);
|
||||
__ ret(0);
|
||||
__ ret(StoreWithVectorDescriptor::kStackArgumentsCount * kPointerSize);
|
||||
|
||||
__ bind(&restore_miss);
|
||||
__ pop(slot);
|
||||
|
13
src/ic/ic.cc
13
src/ic/ic.cc
@ -183,6 +183,19 @@ IC::IC(FrameDepth depth, Isolate* isolate, FeedbackNexus* nexus)
|
||||
extra_ic_state_ = target->extra_ic_state();
|
||||
}
|
||||
|
||||
// The ICs that don't pass slot and vector through the stack have to
|
||||
// save/restore them in the dispatcher.
|
||||
bool IC::ShouldPushPopSlotAndVector(Code::Kind kind) {
|
||||
if (kind == Code::LOAD_IC || kind == Code::LOAD_GLOBAL_IC ||
|
||||
kind == Code::KEYED_LOAD_IC || kind == Code::CALL_IC) {
|
||||
return true;
|
||||
}
|
||||
if (kind == Code::STORE_IC || kind == Code::KEYED_STORE_IC) {
|
||||
return !StoreWithVectorDescriptor::kPassLastArgsOnStack;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
InlineCacheState IC::StateFromCode(Code* code) {
|
||||
Isolate* isolate = code->GetIsolate();
|
||||
switch (code->kind()) {
|
||||
|
@ -75,6 +75,10 @@ class IC {
|
||||
kind == Code::STORE_IC || kind == Code::KEYED_STORE_IC;
|
||||
}
|
||||
|
||||
// The ICs that don't pass slot and vector through the stack have to
|
||||
// save/restore them in the dispatcher.
|
||||
static bool ShouldPushPopSlotAndVector(Code::Kind kind);
|
||||
|
||||
static InlineCacheState StateFromCode(Code* code);
|
||||
|
||||
protected:
|
||||
|
@ -165,6 +165,13 @@ void PropertyHandlerCompiler::GenerateApiAccessorCall(
|
||||
DCHECK(!accessor_holder.is(scratch));
|
||||
// Copy return value.
|
||||
__ pop(scratch);
|
||||
|
||||
if (is_store) {
|
||||
// Discard stack arguments.
|
||||
__ add(esp, Immediate(StoreWithVectorDescriptor::kStackArgumentsCount *
|
||||
kPointerSize));
|
||||
}
|
||||
|
||||
// receiver
|
||||
__ push(receiver);
|
||||
// Write the arguments to stack frame.
|
||||
@ -305,7 +312,14 @@ void NamedStoreHandlerCompiler::GenerateStoreViaSetter(
|
||||
// Restore context register.
|
||||
__ pop(esi);
|
||||
}
|
||||
__ ret(0);
|
||||
if (accessor_index >= 0) {
|
||||
__ ret(StoreWithVectorDescriptor::kStackArgumentsCount * kPointerSize);
|
||||
} else {
|
||||
// If we generate a global code snippet for deoptimization only, don't try
|
||||
// to drop stack arguments for the StoreIC because they are not a part of
|
||||
// expression stack and deoptimizer does not reconstruct them.
|
||||
__ ret(0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -508,7 +522,7 @@ void NamedLoadHandlerCompiler::FrontendFooter(Handle<Name> name, Label* miss) {
|
||||
Label success;
|
||||
__ jmp(&success);
|
||||
__ bind(miss);
|
||||
if (IC::ICUseVector(kind())) {
|
||||
if (IC::ShouldPushPopSlotAndVector(kind())) {
|
||||
DCHECK(kind() == Code::LOAD_IC);
|
||||
PopVectorAndSlot();
|
||||
}
|
||||
@ -523,7 +537,7 @@ void NamedStoreHandlerCompiler::FrontendFooter(Handle<Name> name, Label* miss) {
|
||||
Label success;
|
||||
__ jmp(&success);
|
||||
GenerateRestoreName(miss, name);
|
||||
if (IC::ICUseVector(kind())) PopVectorAndSlot();
|
||||
DCHECK(!IC::ShouldPushPopSlotAndVector(kind()));
|
||||
TailCallBuiltin(masm(), MissBuiltin(kind()));
|
||||
__ bind(&success);
|
||||
}
|
||||
@ -624,6 +638,9 @@ Handle<Code> NamedStoreHandlerCompiler::CompileStoreCallback(
|
||||
Register holder_reg = Frontend(name);
|
||||
|
||||
__ pop(scratch1()); // remove the return address
|
||||
// Discard stack arguments.
|
||||
__ add(esp, Immediate(StoreWithVectorDescriptor::kStackArgumentsCount *
|
||||
kPointerSize));
|
||||
__ push(receiver());
|
||||
__ push(holder_reg);
|
||||
// If the callback cannot leak, then push the callback directly,
|
||||
@ -655,7 +672,7 @@ Register NamedStoreHandlerCompiler::value() {
|
||||
Handle<Code> NamedLoadHandlerCompiler::CompileLoadGlobal(
|
||||
Handle<PropertyCell> cell, Handle<Name> name, bool is_configurable) {
|
||||
Label miss;
|
||||
if (IC::ICUseVector(kind())) {
|
||||
if (IC::ShouldPushPopSlotAndVector(kind())) {
|
||||
PushVectorAndSlot();
|
||||
}
|
||||
FrontendHeader(receiver(), name, &miss, DONT_RETURN_ANYTHING);
|
||||
@ -677,7 +694,7 @@ Handle<Code> NamedLoadHandlerCompiler::CompileLoadGlobal(
|
||||
Counters* counters = isolate()->counters();
|
||||
__ IncrementCounter(counters->ic_named_load_global_stub(), 1);
|
||||
// The code above already loads the result into the return register.
|
||||
if (IC::ICUseVector(kind())) {
|
||||
if (IC::ShouldPushPopSlotAndVector(kind())) {
|
||||
DiscardVectorAndSlot();
|
||||
}
|
||||
__ ret(0);
|
||||
|
@ -15,14 +15,17 @@ namespace internal {
|
||||
|
||||
void PropertyICCompiler::GenerateRuntimeSetProperty(
|
||||
MacroAssembler* masm, LanguageMode language_mode) {
|
||||
// Return address is on the stack.
|
||||
DCHECK(!ebx.is(StoreDescriptor::ReceiverRegister()) &&
|
||||
!ebx.is(StoreDescriptor::NameRegister()) &&
|
||||
!ebx.is(StoreDescriptor::ValueRegister()));
|
||||
STATIC_ASSERT(StoreWithVectorDescriptor::kStackArgumentsCount == 3);
|
||||
// Current stack layout:
|
||||
// - esp[12] -- value
|
||||
// - esp[8] -- slot
|
||||
// - esp[4] -- vector
|
||||
// - esp[0] -- return address
|
||||
|
||||
__ mov(Operand(esp, 12), StoreDescriptor::ReceiverRegister());
|
||||
__ mov(Operand(esp, 8), StoreDescriptor::NameRegister());
|
||||
__ mov(Operand(esp, 4), StoreDescriptor::ValueRegister());
|
||||
__ pop(ebx);
|
||||
__ push(StoreDescriptor::ReceiverRegister());
|
||||
__ push(StoreDescriptor::NameRegister());
|
||||
__ push(StoreDescriptor::ValueRegister());
|
||||
__ push(Immediate(Smi::FromInt(language_mode)));
|
||||
__ push(ebx); // return address
|
||||
|
||||
|
@ -409,7 +409,7 @@ static void KeyedStoreGenerateMegamorphicHelper(
|
||||
}
|
||||
// It's irrelevant whether array is smi-only or not when writing a smi.
|
||||
__ mov(FixedArrayElementOperand(ebx, key), value);
|
||||
__ ret(0);
|
||||
__ ret(StoreWithVectorDescriptor::kStackArgumentsCount * kPointerSize);
|
||||
|
||||
__ bind(&non_smi_value);
|
||||
// Escape to elements kind transition case.
|
||||
@ -428,7 +428,7 @@ static void KeyedStoreGenerateMegamorphicHelper(
|
||||
__ mov(edx, value); // Preserve the value which is returned.
|
||||
__ RecordWriteArray(ebx, edx, key, kDontSaveFPRegs, EMIT_REMEMBERED_SET,
|
||||
OMIT_SMI_CHECK);
|
||||
__ ret(0);
|
||||
__ ret(StoreWithVectorDescriptor::kStackArgumentsCount * kPointerSize);
|
||||
|
||||
__ bind(fast_double);
|
||||
if (check_map == kCheckMap) {
|
||||
@ -457,7 +457,7 @@ static void KeyedStoreGenerateMegamorphicHelper(
|
||||
__ add(FieldOperand(receiver, JSArray::kLengthOffset),
|
||||
Immediate(Smi::FromInt(1)));
|
||||
}
|
||||
__ ret(0);
|
||||
__ ret(StoreWithVectorDescriptor::kStackArgumentsCount * kPointerSize);
|
||||
|
||||
__ bind(&transition_smi_elements);
|
||||
__ mov(ebx, FieldOperand(receiver, HeapObject::kMapOffset));
|
||||
@ -705,18 +705,21 @@ void KeyedLoadIC::GenerateRuntimeGetProperty(MacroAssembler* masm) {
|
||||
}
|
||||
|
||||
static void StoreIC_PushArgs(MacroAssembler* masm) {
|
||||
Register receiver = StoreDescriptor::ReceiverRegister();
|
||||
Register name = StoreDescriptor::NameRegister();
|
||||
Register value = StoreDescriptor::ValueRegister();
|
||||
Register slot = StoreWithVectorDescriptor::SlotRegister();
|
||||
Register vector = StoreWithVectorDescriptor::VectorRegister();
|
||||
Register receiver = StoreWithVectorDescriptor::ReceiverRegister();
|
||||
Register name = StoreWithVectorDescriptor::NameRegister();
|
||||
|
||||
__ xchg(value, Operand(esp, 0));
|
||||
__ push(slot);
|
||||
__ push(vector);
|
||||
STATIC_ASSERT(StoreWithVectorDescriptor::kStackArgumentsCount == 3);
|
||||
// Current stack layout:
|
||||
// - esp[12] -- value
|
||||
// - esp[8] -- slot
|
||||
// - esp[4] -- vector
|
||||
// - esp[0] -- return address
|
||||
|
||||
Register return_address = StoreWithVectorDescriptor::SlotRegister();
|
||||
__ pop(return_address);
|
||||
__ push(receiver);
|
||||
__ push(name);
|
||||
__ push(value); // Contains the return address.
|
||||
__ push(return_address);
|
||||
}
|
||||
|
||||
|
||||
@ -751,7 +754,7 @@ void StoreIC::GenerateNormal(MacroAssembler* masm) {
|
||||
__ Drop(3);
|
||||
Counters* counters = masm->isolate()->counters();
|
||||
__ IncrementCounter(counters->ic_store_normal_hit(), 1);
|
||||
__ ret(0);
|
||||
__ ret(StoreWithVectorDescriptor::kStackArgumentsCount * kPointerSize);
|
||||
|
||||
__ bind(&restore_miss);
|
||||
__ pop(slot);
|
||||
|
@ -134,15 +134,9 @@ void StoreDescriptor::InitializePlatformSpecific(
|
||||
CallInterfaceDescriptorData* data) {
|
||||
Register registers[] = {ReceiverRegister(), NameRegister(), ValueRegister(),
|
||||
SlotRegister()};
|
||||
data->InitializePlatformSpecific(arraysize(registers), registers);
|
||||
}
|
||||
|
||||
bool StoreTransitionDescriptor::PassVectorAndSlotOnStack() {
|
||||
#if V8_TARGET_ARCH_IA32 || V8_TARGET_ARCH_X87
|
||||
return true;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
int len = arraysize(registers) - kStackArgumentsCount;
|
||||
data->InitializePlatformSpecific(len, registers);
|
||||
}
|
||||
|
||||
void StoreTransitionDescriptor::InitializePlatformSpecific(
|
||||
@ -151,11 +145,7 @@ void StoreTransitionDescriptor::InitializePlatformSpecific(
|
||||
ReceiverRegister(), NameRegister(), MapRegister(),
|
||||
ValueRegister(), SlotRegister(), VectorRegister(),
|
||||
};
|
||||
int len = arraysize(registers);
|
||||
if (PassVectorAndSlotOnStack()) {
|
||||
// Pass slot and vector on the stack.
|
||||
len -= 2;
|
||||
}
|
||||
int len = arraysize(registers) - kStackArgumentsCount;
|
||||
data->InitializePlatformSpecific(len, registers);
|
||||
}
|
||||
|
||||
@ -243,7 +233,8 @@ void StoreWithVectorDescriptor::InitializePlatformSpecific(
|
||||
CallInterfaceDescriptorData* data) {
|
||||
Register registers[] = {ReceiverRegister(), NameRegister(), ValueRegister(),
|
||||
SlotRegister(), VectorRegister()};
|
||||
data->InitializePlatformSpecific(arraysize(registers), registers);
|
||||
int len = arraysize(registers) - kStackArgumentsCount;
|
||||
data->InitializePlatformSpecific(len, registers);
|
||||
}
|
||||
|
||||
void BinaryOpWithVectorDescriptor::InitializePlatformIndependent(
|
||||
|
@ -324,6 +324,15 @@ class StoreDescriptor : public CallInterfaceDescriptor {
|
||||
static const Register NameRegister();
|
||||
static const Register ValueRegister();
|
||||
static const Register SlotRegister();
|
||||
|
||||
#if V8_TARGET_ARCH_IA32 || V8_TARGET_ARCH_X87
|
||||
static const bool kPassLastArgsOnStack = true;
|
||||
#else
|
||||
static const bool kPassLastArgsOnStack = false;
|
||||
#endif
|
||||
|
||||
// Pass value and slot through the stack.
|
||||
static const int kStackArgumentsCount = kPassLastArgsOnStack ? 2 : 0;
|
||||
};
|
||||
|
||||
class StoreTransitionDescriptor : public StoreDescriptor {
|
||||
@ -336,7 +345,8 @@ class StoreTransitionDescriptor : public StoreDescriptor {
|
||||
static const Register SlotRegister();
|
||||
static const Register VectorRegister();
|
||||
|
||||
static bool PassVectorAndSlotOnStack();
|
||||
// Pass value, slot and vector through the stack.
|
||||
static const int kStackArgumentsCount = kPassLastArgsOnStack ? 3 : 0;
|
||||
};
|
||||
|
||||
class StoreWithVectorDescriptor : public StoreDescriptor {
|
||||
@ -346,6 +356,9 @@ class StoreWithVectorDescriptor : public StoreDescriptor {
|
||||
StoreDescriptor)
|
||||
|
||||
static const Register VectorRegister();
|
||||
|
||||
// Pass value, slot and vector through the stack.
|
||||
static const int kStackArgumentsCount = kPassLastArgsOnStack ? 3 : 0;
|
||||
};
|
||||
|
||||
class LoadWithVectorDescriptor : public LoadDescriptor {
|
||||
|
@ -3483,6 +3483,28 @@ void StoreICStub::GenerateImpl(MacroAssembler* masm, bool in_frame) {
|
||||
Register slot = StoreWithVectorDescriptor::SlotRegister(); // edi
|
||||
Label miss;
|
||||
|
||||
if (StoreWithVectorDescriptor::kPassLastArgsOnStack) {
|
||||
// Current stack layout:
|
||||
// - esp[8] -- value
|
||||
// - esp[4] -- slot
|
||||
// - esp[0] -- return address
|
||||
STATIC_ASSERT(StoreDescriptor::kStackArgumentsCount == 2);
|
||||
STATIC_ASSERT(StoreWithVectorDescriptor::kStackArgumentsCount == 3);
|
||||
if (in_frame) {
|
||||
__ RecordComment("[ StoreDescriptor -> StoreWithVectorDescriptor");
|
||||
// If the vector is not on the stack, then insert the vector beneath
|
||||
// return address in order to prepare for calling handler with
|
||||
// StoreWithVector calling convention.
|
||||
__ push(Operand(esp, 0));
|
||||
__ mov(Operand(esp, 4), StoreWithVectorDescriptor::VectorRegister());
|
||||
__ RecordComment("]");
|
||||
} else {
|
||||
__ mov(vector, Operand(esp, 1 * kPointerSize));
|
||||
}
|
||||
__ mov(slot, Operand(esp, 2 * kPointerSize));
|
||||
__ mov(value, Operand(esp, 3 * kPointerSize));
|
||||
}
|
||||
|
||||
__ push(value);
|
||||
|
||||
Register scratch = value;
|
||||
@ -3624,12 +3646,23 @@ static void HandlePolymorphicKeyedStoreCase(MacroAssembler* masm,
|
||||
__ pop(vector);
|
||||
__ pop(receiver);
|
||||
__ pop(value);
|
||||
{
|
||||
// Put vector and slot beneath return address.
|
||||
__ push(vector);
|
||||
__ push(Operand(esp, 1 * kPointerSize)); // push return address
|
||||
__ mov(Operand(esp, 2 * kPointerSize), slot);
|
||||
}
|
||||
// Ensure that the transition handler we are going to call has the same
|
||||
// number of stack arguments which means that we don't have to adapt them
|
||||
// before the call.
|
||||
STATIC_ASSERT(StoreWithVectorDescriptor::kStackArgumentsCount == 3);
|
||||
STATIC_ASSERT(StoreTransitionDescriptor::kStackArgumentsCount == 3);
|
||||
STATIC_ASSERT(StoreWithVectorDescriptor::kParameterCount -
|
||||
StoreWithVectorDescriptor::kValue ==
|
||||
StoreTransitionDescriptor::kParameterCount -
|
||||
StoreTransitionDescriptor::kValue);
|
||||
STATIC_ASSERT(StoreWithVectorDescriptor::kParameterCount -
|
||||
StoreWithVectorDescriptor::kSlot ==
|
||||
StoreTransitionDescriptor::kParameterCount -
|
||||
StoreTransitionDescriptor::kSlot);
|
||||
STATIC_ASSERT(StoreWithVectorDescriptor::kParameterCount -
|
||||
StoreWithVectorDescriptor::kVector ==
|
||||
StoreTransitionDescriptor::kParameterCount -
|
||||
StoreTransitionDescriptor::kVector);
|
||||
__ jmp(Operand::StaticVariable(virtual_register));
|
||||
|
||||
__ bind(&prepare_next);
|
||||
@ -3657,6 +3690,28 @@ void KeyedStoreICStub::GenerateImpl(MacroAssembler* masm, bool in_frame) {
|
||||
Register slot = StoreWithVectorDescriptor::SlotRegister(); // edi
|
||||
Label miss;
|
||||
|
||||
if (StoreWithVectorDescriptor::kPassLastArgsOnStack) {
|
||||
// Current stack layout:
|
||||
// - esp[8] -- value
|
||||
// - esp[4] -- slot
|
||||
// - esp[0] -- return address
|
||||
STATIC_ASSERT(StoreDescriptor::kStackArgumentsCount == 2);
|
||||
STATIC_ASSERT(StoreWithVectorDescriptor::kStackArgumentsCount == 3);
|
||||
if (in_frame) {
|
||||
__ RecordComment("[ StoreDescriptor -> StoreWithVectorDescriptor");
|
||||
// If the vector is not on the stack, then insert the vector beneath
|
||||
// return address in order to prepare for calling handler with
|
||||
// StoreWithVector calling convention.
|
||||
__ push(Operand(esp, 0));
|
||||
__ mov(Operand(esp, 4), StoreWithVectorDescriptor::VectorRegister());
|
||||
__ RecordComment("]");
|
||||
} else {
|
||||
__ mov(vector, Operand(esp, 1 * kPointerSize));
|
||||
}
|
||||
__ mov(slot, Operand(esp, 2 * kPointerSize));
|
||||
__ mov(value, Operand(esp, 3 * kPointerSize));
|
||||
}
|
||||
|
||||
__ push(value);
|
||||
|
||||
Register scratch = value;
|
||||
|
Loading…
Reference in New Issue
Block a user