Commit 49695346 authored by ishell's avatar ishell Committed by Commit bot

[ic][ia32][x87] Don't push/pop value/slot/vector in store handlers.

According to new store IC calling convention the value, slot and vector are passed
on the stack and there's no need in trying to preserve values or respective registers
in store handlers.

Nice bonus: we also don't need virtual registers anymore.

BUG=v8:5407

Review-Url: https://codereview.chromium.org/2357323003
Cr-Commit-Position: refs/heads/master@{#39672}
parent 84145a14
......@@ -123,6 +123,18 @@ class MacroAssembler: public Assembler {
void CallDeoptimizer(Address target);
static int CallDeoptimizerSize();
// Emit code that loads |parameter_index|'th parameter from the stack to
// the register according to the CallInterfaceDescriptor definition.
// |sp_to_caller_sp_offset_in_words| specifies the number of words pushed
// below the caller's sp.
template <class Descriptor>
void LoadParameterFromStack(
Register reg, typename Descriptor::ParameterIndices parameter_index,
int sp_to_ra_offset_in_words = 0) {
DCHECK(Descriptor::kPassLastArgsOnStack);
UNIMPLEMENTED();
}
// Emit code to discard a non-negative number of pointer-sized elements
// from the stack, clobbering only the sp register.
void Drop(int count, Condition cond = al);
......
......@@ -742,6 +742,18 @@ class MacroAssembler : public Assembler {
// csp must be aligned to 16 bytes.
void PeekPair(const CPURegister& dst1, const CPURegister& dst2, int offset);
// Emit code that loads |parameter_index|'th parameter from the stack to
// the register according to the CallInterfaceDescriptor definition.
// |sp_to_caller_sp_offset_in_words| specifies the number of words pushed
// below the caller's sp.
template <class Descriptor>
void LoadParameterFromStack(
Register reg, typename Descriptor::ParameterIndices parameter_index,
int sp_to_ra_offset_in_words = 0) {
DCHECK(Descriptor::kPassLastArgsOnStack);
UNIMPLEMENTED();
}
// Claim or drop stack space without actually accessing memory.
//
// In debug mode, both of these will write invalid data into the claimed or
......
......@@ -1601,17 +1601,6 @@ ExternalReference ExternalReference::debug_after_break_target_address(
}
ExternalReference ExternalReference::virtual_handler_register(
Isolate* isolate) {
return ExternalReference(isolate->virtual_handler_register_address());
}
ExternalReference ExternalReference::virtual_slot_register(Isolate* isolate) {
return ExternalReference(isolate->virtual_slot_register_address());
}
ExternalReference ExternalReference::runtime_function_table_address(
Isolate* isolate) {
return ExternalReference(
......
......@@ -1035,9 +1035,6 @@ class ExternalReference BASE_EMBEDDED {
static ExternalReference invoke_function_callback(Isolate* isolate);
static ExternalReference invoke_accessor_getter_callback(Isolate* isolate);
static ExternalReference virtual_handler_register(Isolate* isolate);
static ExternalReference virtual_slot_register(Isolate* isolate);
static ExternalReference runtime_function_table_address(Isolate* isolate);
Address address() const { return reinterpret_cast<Address>(address_); }
......
......@@ -215,10 +215,6 @@ void ExternalReferenceTable::AddReferences(Isolate* isolate) {
"double_constants.minus_one_half");
Add(ExternalReference::stress_deopt_count(isolate).address(),
"Isolate::stress_deopt_count_address()");
Add(ExternalReference::virtual_handler_register(isolate).address(),
"Isolate::virtual_handler_register()");
Add(ExternalReference::virtual_slot_register(isolate).address(),
"Isolate::virtual_slot_register()");
Add(ExternalReference::runtime_function_table_address(isolate).address(),
"Runtime::runtime_function_table_address()");
Add(ExternalReference::is_tail_call_elimination_enabled_address(isolate)
......
This diff is collapsed.
......@@ -798,6 +798,24 @@ class MacroAssembler: public Assembler {
// may be bigger than 2^16 - 1. Requires a scratch register.
void Ret(int bytes_dropped, Register scratch);
// Emit code that loads |parameter_index|'th parameter from the stack to
// the register according to the CallInterfaceDescriptor definition.
// |sp_to_caller_sp_offset_in_words| specifies the number of words pushed
// below the caller's sp (on ia32 it's at least return address).
template <class Descriptor>
void LoadParameterFromStack(
Register reg, typename Descriptor::ParameterIndices parameter_index,
int sp_to_ra_offset_in_words = 1) {
DCHECK(Descriptor::kPassLastArgsOnStack);
DCHECK_LT(parameter_index, Descriptor::kParameterCount);
DCHECK_LE(Descriptor::kParameterCount - Descriptor::kStackArgumentsCount,
parameter_index);
int offset = (Descriptor::kParameterCount - parameter_index - 1 +
sp_to_ra_offset_in_words) *
kPointerSize;
mov(reg, Operand(esp, offset));
}
// Emit code to discard a non-negative number of pointer-sized elements
// from the stack, clobbering only the esp register.
void Drop(int element_count);
......
......@@ -614,6 +614,9 @@ void NamedLoadHandlerCompiler::GenerateLoadInterceptor(Register holder_reg) {
__ TailCallRuntime(Runtime::kLoadPropertyWithInterceptor);
}
void NamedStoreHandlerCompiler::ZapStackArgumentsRegisterAliases() {
STATIC_ASSERT(!StoreWithVectorDescriptor::kPassLastArgsOnStack);
}
Handle<Code> NamedStoreHandlerCompiler::CompileStoreCallback(
Handle<JSObject> object, Handle<Name> name, Handle<AccessorInfo> callback,
......
......@@ -648,6 +648,9 @@ void NamedLoadHandlerCompiler::GenerateLoadInterceptor(Register holder_reg) {
__ TailCallRuntime(Runtime::kLoadPropertyWithInterceptor);
}
void NamedStoreHandlerCompiler::ZapStackArgumentsRegisterAliases() {
STATIC_ASSERT(!StoreWithVectorDescriptor::kPassLastArgsOnStack);
}
Handle<Code> NamedStoreHandlerCompiler::CompileStoreCallback(
Handle<JSObject> object, Handle<Name> name, Handle<AccessorInfo> callback,
......
......@@ -441,23 +441,24 @@ Handle<Code> NamedStoreHandlerCompiler::CompileStoreTransition(
// 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 ==
STATIC_ASSERT(Descriptor::kStackArgumentsCount ==
StoreTransitionDescriptor::kStackArgumentsCount);
STATIC_ASSERT(StoreWithVectorDescriptor::kStackArgumentsCount == 0 ||
StoreWithVectorDescriptor::kStackArgumentsCount == 3);
STATIC_ASSERT(StoreWithVectorDescriptor::kParameterCount -
StoreWithVectorDescriptor::kValue ==
STATIC_ASSERT(Descriptor::kStackArgumentsCount == 0 ||
Descriptor::kStackArgumentsCount == 3);
STATIC_ASSERT(Descriptor::kParameterCount - Descriptor::kValue ==
StoreTransitionDescriptor::kParameterCount -
StoreTransitionDescriptor::kValue);
STATIC_ASSERT(StoreWithVectorDescriptor::kParameterCount -
StoreWithVectorDescriptor::kSlot ==
STATIC_ASSERT(Descriptor::kParameterCount - Descriptor::kSlot ==
StoreTransitionDescriptor::kParameterCount -
StoreTransitionDescriptor::kSlot);
STATIC_ASSERT(StoreWithVectorDescriptor::kParameterCount -
StoreWithVectorDescriptor::kVector ==
STATIC_ASSERT(Descriptor::kParameterCount - Descriptor::kVector ==
StoreTransitionDescriptor::kParameterCount -
StoreTransitionDescriptor::kVector);
if (Descriptor::kPassLastArgsOnStack) {
__ LoadParameterFromStack<Descriptor>(value(), Descriptor::kValue);
}
bool need_save_restore = IC::ShouldPushPopSlotAndVector(kind());
if (need_save_restore) {
PushVectorAndSlot();
......@@ -550,6 +551,9 @@ Handle<Code> NamedStoreHandlerCompiler::CompileStoreField(LookupIterator* it) {
bool need_save_restore = false;
if (RequiresFieldTypeChecks(field_type)) {
need_save_restore = IC::ShouldPushPopSlotAndVector(kind());
if (Descriptor::kPassLastArgsOnStack) {
__ LoadParameterFromStack<Descriptor>(value(), Descriptor::kValue);
}
if (need_save_restore) PushVectorAndSlot();
GenerateFieldTypeChecks(field_type, value(), &miss);
if (need_save_restore) PopVectorAndSlot();
......@@ -583,6 +587,9 @@ Handle<Code> NamedStoreHandlerCompiler::CompileStoreCallback(
GenerateTailCall(masm(), slow_stub);
}
Register holder = Frontend(name);
if (Descriptor::kPassLastArgsOnStack) {
__ LoadParameterFromStack<Descriptor>(value(), Descriptor::kValue);
}
GenerateApiAccessorCall(masm(), call_optimization, handle(object->map()),
receiver(), scratch2(), true, value(), holder,
accessor_index);
......
......@@ -215,13 +215,24 @@ class NamedLoadHandlerCompiler : public PropertyHandlerCompiler {
class NamedStoreHandlerCompiler : public PropertyHandlerCompiler {
public:
// All store handlers use StoreWithVectorDescriptor calling convention.
typedef StoreWithVectorDescriptor Descriptor;
explicit NamedStoreHandlerCompiler(Isolate* isolate, Handle<Map> map,
Handle<JSObject> holder)
: PropertyHandlerCompiler(isolate, Code::STORE_IC, map, holder,
kCacheOnReceiver) {}
kCacheOnReceiver) {
#ifdef DEBUG
if (Descriptor::kPassLastArgsOnStack) {
ZapStackArgumentsRegisterAliases();
}
#endif
}
virtual ~NamedStoreHandlerCompiler() {}
void ZapStackArgumentsRegisterAliases();
Handle<Code> CompileStoreTransition(Handle<Map> transition,
Handle<Name> name);
Handle<Code> CompileStoreField(LookupIterator* it);
......
......@@ -171,13 +171,10 @@ void PropertyHandlerCompiler::GenerateApiAccessorCall(
__ add(esp, Immediate(StoreWithVectorDescriptor::kStackArgumentsCount *
kPointerSize));
}
// receiver
// Write the receiver and arguments to stack frame.
__ push(receiver);
// Write the arguments to stack frame.
if (is_store) {
DCHECK(!receiver.is(store_parameter));
DCHECK(!scratch.is(store_parameter));
DCHECK(!AreAliased(receiver, scratch, store_parameter));
__ push(store_parameter);
}
__ push(scratch);
......@@ -274,8 +271,13 @@ void NamedStoreHandlerCompiler::GenerateStoreViaSetter(
MacroAssembler* masm, Handle<Map> map, Register receiver, Register holder,
int accessor_index, int expected_arguments, Register scratch) {
// ----------- S t a t e -------------
// -- esp[0] : return address
// -- esp[12] : value
// -- esp[8] : slot
// -- esp[4] : vector
// -- esp[0] : return address
// -----------------------------------
__ LoadParameterFromStack<Descriptor>(value(), Descriptor::kValue);
{
FrameScope scope(masm, StackFrame::INTERNAL);
......@@ -631,11 +633,21 @@ void NamedLoadHandlerCompiler::GenerateLoadInterceptor(Register holder_reg) {
__ TailCallRuntime(Runtime::kLoadPropertyWithInterceptor);
}
void NamedStoreHandlerCompiler::ZapStackArgumentsRegisterAliases() {
// Zap register aliases of the arguments passed on the stack to ensure they
// are properly loaded by the handler (debug-only).
STATIC_ASSERT(Descriptor::kPassLastArgsOnStack);
STATIC_ASSERT(Descriptor::kStackArgumentsCount == 3);
__ mov(Descriptor::ValueRegister(), Immediate(kDebugZapValue));
__ mov(Descriptor::SlotRegister(), Immediate(kDebugZapValue));
__ mov(Descriptor::VectorRegister(), Immediate(kDebugZapValue));
}
Handle<Code> NamedStoreHandlerCompiler::CompileStoreCallback(
Handle<JSObject> object, Handle<Name> name, Handle<AccessorInfo> callback,
LanguageMode language_mode) {
Register holder_reg = Frontend(name);
__ LoadParameterFromStack<Descriptor>(value(), Descriptor::kValue);
__ pop(scratch1()); // remove the return address
// Discard stack arguments.
......
......@@ -15,16 +15,20 @@ namespace internal {
void PropertyICCompiler::GenerateRuntimeSetProperty(
MacroAssembler* masm, LanguageMode language_mode) {
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());
typedef StoreWithVectorDescriptor Descriptor;
STATIC_ASSERT(Descriptor::kStackArgumentsCount == 3);
// ----------- S t a t e -------------
// -- esp[12] : value
// -- esp[8] : slot
// -- esp[4] : vector
// -- esp[0] : return address
// -----------------------------------
__ LoadParameterFromStack<Descriptor>(Descriptor::ValueRegister(),
Descriptor::kValue);
__ mov(Operand(esp, 12), Descriptor::ReceiverRegister());
__ mov(Operand(esp, 8), Descriptor::NameRegister());
__ mov(Operand(esp, 4), Descriptor::ValueRegister());
__ pop(ebx);
__ push(Immediate(Smi::FromInt(language_mode)));
__ push(ebx); // return address
......
......@@ -504,12 +504,13 @@ static void KeyedStoreGenerateMegamorphicHelper(
void KeyedStoreIC::GenerateMegamorphic(MacroAssembler* masm,
LanguageMode language_mode) {
typedef StoreWithVectorDescriptor Descriptor;
// Return address is on the stack.
Label slow, fast_object, fast_object_grow;
Label fast_double, fast_double_grow;
Label array, extra, check_if_double_array, maybe_name_key, miss;
Register receiver = StoreDescriptor::ReceiverRegister();
Register key = StoreDescriptor::NameRegister();
Register receiver = Descriptor::ReceiverRegister();
Register key = Descriptor::NameRegister();
DCHECK(receiver.is(edx));
DCHECK(key.is(ecx));
......@@ -522,6 +523,10 @@ void KeyedStoreIC::GenerateMegamorphic(MacroAssembler* masm,
__ test_b(FieldOperand(edi, Map::kBitFieldOffset),
Immediate(1 << Map::kIsAccessCheckNeeded));
__ j(not_zero, &slow);
__ LoadParameterFromStack<Descriptor>(Descriptor::ValueRegister(),
Descriptor::kValue);
// Check that the key is a smi.
__ JumpIfNotSmi(key, &maybe_name_key);
__ CmpInstanceType(edi, JS_ARRAY_TYPE);
......@@ -551,22 +556,9 @@ void KeyedStoreIC::GenerateMegamorphic(MacroAssembler* masm,
__ movzx_b(ebx, FieldOperand(ebx, Map::kInstanceTypeOffset));
__ JumpIfNotUniqueNameInstanceType(ebx, &slow);
// 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 =
TypeFeedbackVector::DummyVector(masm->isolate());
int slot = dummy_vector->GetIndex(
FeedbackVectorSlot(TypeFeedbackVector::kDummyKeyedStoreICSlot));
__ push(Immediate(Smi::FromInt(slot)));
__ push(Immediate(dummy_vector));
masm->isolate()->store_stub_cache()->GenerateProbe(masm, receiver, key, edi,
no_reg);
__ pop(StoreWithVectorDescriptor::VectorRegister());
__ pop(StoreWithVectorDescriptor::SlotRegister());
// Cache miss.
__ jmp(&miss);
......@@ -733,32 +725,33 @@ void StoreIC::GenerateMiss(MacroAssembler* masm) {
void StoreIC::GenerateNormal(MacroAssembler* masm) {
typedef StoreWithVectorDescriptor Descriptor;
Label restore_miss;
Register receiver = StoreDescriptor::ReceiverRegister();
Register name = StoreDescriptor::NameRegister();
Register value = StoreDescriptor::ValueRegister();
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
// GenerateDictionaryStore preserving the value and name.
Register receiver = Descriptor::ReceiverRegister();
Register name = Descriptor::NameRegister();
Register value = Descriptor::ValueRegister();
// Since the slot and vector values are passed on the stack we can use
// respective registers as scratch registers.
Register scratch1 = Descriptor::VectorRegister();
Register scratch2 = Descriptor::SlotRegister();
__ LoadParameterFromStack<Descriptor>(value, Descriptor::kValue);
// A lot of registers are needed for storing to slow case objects.
// Push and restore receiver but rely on GenerateDictionaryStore preserving
// the value and name.
__ push(receiver);
__ push(vector);
__ push(slot);
Register dictionary = ebx;
Register dictionary = receiver;
__ mov(dictionary, FieldOperand(receiver, JSObject::kPropertiesOffset));
GenerateDictionaryStore(masm, &restore_miss, dictionary, name, value,
receiver, edi);
__ Drop(3);
scratch1, scratch2);
__ Drop(1);
Counters* counters = masm->isolate()->counters();
__ IncrementCounter(counters->ic_store_normal_hit(), 1);
__ ret(StoreWithVectorDescriptor::kStackArgumentsCount * kPointerSize);
__ ret(Descriptor::kStackArgumentsCount * kPointerSize);
__ bind(&restore_miss);
__ pop(slot);
__ pop(vector);
__ pop(receiver);
__ IncrementCounter(counters->ic_store_normal_miss(), 1);
GenerateMiss(masm);
......
......@@ -22,8 +22,6 @@ static void ProbeTable(StubCache* stub_cache, MacroAssembler* masm,
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();
......@@ -55,19 +53,15 @@ static void ProbeTable(StubCache* stub_cache, MacroAssembler* masm,
}
#endif
// The vector and slot were pushed onto the stack before starting the
// 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 = StoreWithVectorDescriptor::VectorRegister();
// The value, vector and slot were passed to the IC on the stack and
// they are still there. So we can just jump to the handler.
DCHECK(extra.is(StoreWithVectorDescriptor::SlotRegister()));
__ add(extra, Immediate(Code::kHeaderSize - kHeapObjectTag));
__ pop(vector);
__ mov(Operand::StaticVariable(virtual_register), extra);
__ pop(extra); // Pop "slot".
// Jump to the first instruction in the code stub.
__ jmp(Operand::StaticVariable(virtual_register));
__ jmp(extra);
} else {
// The vector and slot were pushed onto the stack before starting the
// probe, and need to be dropped before calling the handler.
__ pop(LoadWithVectorDescriptor::VectorRegister());
__ pop(LoadDescriptor::SlotRegister());
__ add(extra, Immediate(Code::kHeaderSize - kHeapObjectTag));
......@@ -110,19 +104,10 @@ static void ProbeTable(StubCache* stub_cache, MacroAssembler* masm,
// Jump to the first instruction in the code stub.
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 = StoreWithVectorDescriptor::VectorRegister();
DCHECK(offset.is(StoreWithVectorDescriptor::SlotRegister()));
__ add(offset, Immediate(Code::kHeaderSize - kHeapObjectTag));
__ mov(Operand::StaticVariable(virtual_register), offset);
__ pop(vector);
__ pop(offset); // Pop "slot".
__ jmp(Operand::StaticVariable(virtual_register));
} else {
__ add(offset, Immediate(Code::kHeaderSize - kHeapObjectTag));
__ jmp(offset);
}
__ add(offset, Immediate(Code::kHeaderSize - kHeapObjectTag));
__ jmp(offset);
// Pop at miss.
__ bind(&miss);
......
......@@ -600,6 +600,9 @@ void NamedLoadHandlerCompiler::GenerateLoadInterceptor(Register holder_reg) {
__ TailCallRuntime(Runtime::kLoadPropertyWithInterceptor);
}
void NamedStoreHandlerCompiler::ZapStackArgumentsRegisterAliases() {
STATIC_ASSERT(!StoreWithVectorDescriptor::kPassLastArgsOnStack);
}
Handle<Code> NamedStoreHandlerCompiler::CompileStoreCallback(
Handle<JSObject> object, Handle<Name> name, Handle<AccessorInfo> callback,
......
......@@ -600,6 +600,9 @@ void NamedLoadHandlerCompiler::GenerateLoadInterceptor(Register holder_reg) {
__ TailCallRuntime(Runtime::kLoadPropertyWithInterceptor);
}
void NamedStoreHandlerCompiler::ZapStackArgumentsRegisterAliases() {
STATIC_ASSERT(!StoreWithVectorDescriptor::kPassLastArgsOnStack);
}
Handle<Code> NamedStoreHandlerCompiler::CompileStoreCallback(
Handle<JSObject> object, Handle<Name> name, Handle<AccessorInfo> callback,
......
......@@ -609,6 +609,9 @@ void NamedLoadHandlerCompiler::GenerateLoadInterceptor(Register holder_reg) {
__ TailCallRuntime(Runtime::kLoadPropertyWithInterceptor);
}
void NamedStoreHandlerCompiler::ZapStackArgumentsRegisterAliases() {
STATIC_ASSERT(!StoreWithVectorDescriptor::kPassLastArgsOnStack);
}
Handle<Code> NamedStoreHandlerCompiler::CompileStoreCallback(
Handle<JSObject> object, Handle<Name> name, Handle<AccessorInfo> callback,
......
......@@ -583,6 +583,10 @@ void NamedLoadHandlerCompiler::GenerateLoadInterceptor(Register holder_reg) {
__ TailCallRuntime(Runtime::kLoadPropertyWithInterceptor);
}
void NamedStoreHandlerCompiler::ZapStackArgumentsRegisterAliases() {
STATIC_ASSERT(!StoreWithVectorDescriptor::kPassLastArgsOnStack);
}
Handle<Code> NamedStoreHandlerCompiler::CompileStoreCallback(
Handle<JSObject> object, Handle<Name> name, Handle<AccessorInfo> callback,
LanguageMode language_mode) {
......
......@@ -613,6 +613,9 @@ void NamedLoadHandlerCompiler::GenerateLoadInterceptor(Register holder_reg) {
__ TailCallRuntime(Runtime::kLoadPropertyWithInterceptor);
}
void NamedStoreHandlerCompiler::ZapStackArgumentsRegisterAliases() {
STATIC_ASSERT(!StoreWithVectorDescriptor::kPassLastArgsOnStack);
}
Handle<Code> NamedStoreHandlerCompiler::CompileStoreCallback(
Handle<JSObject> object, Handle<Name> name, Handle<AccessorInfo> callback,
......
......@@ -171,13 +171,10 @@ void PropertyHandlerCompiler::GenerateApiAccessorCall(
__ add(esp, Immediate(StoreWithVectorDescriptor::kStackArgumentsCount *
kPointerSize));
}
// receiver
// Write the receiver and arguments to stack frame.
__ push(receiver);
// Write the arguments to stack frame.
if (is_store) {
DCHECK(!receiver.is(store_parameter));
DCHECK(!scratch.is(store_parameter));
DCHECK(!AreAliased(receiver, scratch, store_parameter));
__ push(store_parameter);
}
__ push(scratch);
......@@ -274,8 +271,13 @@ void NamedStoreHandlerCompiler::GenerateStoreViaSetter(
MacroAssembler* masm, Handle<Map> map, Register receiver, Register holder,
int accessor_index, int expected_arguments, Register scratch) {
// ----------- S t a t e -------------
// -- esp[0] : return address
// -- esp[12] : value
// -- esp[8] : slot
// -- esp[4] : vector
// -- esp[0] : return address
// -----------------------------------
__ LoadParameterFromStack<Descriptor>(value(), Descriptor::kValue);
{
FrameScope scope(masm, StackFrame::INTERNAL);
......@@ -631,11 +633,21 @@ void NamedLoadHandlerCompiler::GenerateLoadInterceptor(Register holder_reg) {
__ TailCallRuntime(Runtime::kLoadPropertyWithInterceptor);
}
void NamedStoreHandlerCompiler::ZapStackArgumentsRegisterAliases() {
// Zap register aliases of the arguments passed on the stack to ensure they
// are properly loaded by the handler (debug-only).
STATIC_ASSERT(Descriptor::kPassLastArgsOnStack);
STATIC_ASSERT(Descriptor::kStackArgumentsCount == 3);
__ mov(Descriptor::ValueRegister(), Immediate(kDebugZapValue));
__ mov(Descriptor::SlotRegister(), Immediate(kDebugZapValue));
__ mov(Descriptor::VectorRegister(), Immediate(kDebugZapValue));
}
Handle<Code> NamedStoreHandlerCompiler::CompileStoreCallback(
Handle<JSObject> object, Handle<Name> name, Handle<AccessorInfo> callback,
LanguageMode language_mode) {
Register holder_reg = Frontend(name);
__ LoadParameterFromStack<Descriptor>(value(), Descriptor::kValue);
__ pop(scratch1()); // remove the return address
// Discard stack arguments.
......
......@@ -15,16 +15,20 @@ namespace internal {
void PropertyICCompiler::GenerateRuntimeSetProperty(
MacroAssembler* masm, LanguageMode language_mode) {
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());
typedef StoreWithVectorDescriptor Descriptor;
STATIC_ASSERT(Descriptor::kStackArgumentsCount == 3);
// ----------- S t a t e -------------
// -- esp[12] : value
// -- esp[8] : slot
// -- esp[4] : vector
// -- esp[0] : return address
// -----------------------------------
__ LoadParameterFromStack<Descriptor>(Descriptor::ValueRegister(),
Descriptor::kValue);
__ mov(Operand(esp, 12), Descriptor::ReceiverRegister());
__ mov(Operand(esp, 8), Descriptor::NameRegister());
__ mov(Operand(esp, 4), Descriptor::ValueRegister());
__ pop(ebx);
__ push(Immediate(Smi::FromInt(language_mode)));
__ push(ebx); // return address
......
......@@ -504,12 +504,13 @@ static void KeyedStoreGenerateMegamorphicHelper(
void KeyedStoreIC::GenerateMegamorphic(MacroAssembler* masm,
LanguageMode language_mode) {
typedef StoreWithVectorDescriptor Descriptor;
// Return address is on the stack.
Label slow, fast_object, fast_object_grow;
Label fast_double, fast_double_grow;
Label array, extra, check_if_double_array, maybe_name_key, miss;
Register receiver = StoreDescriptor::ReceiverRegister();
Register key = StoreDescriptor::NameRegister();
Register receiver = Descriptor::ReceiverRegister();
Register key = Descriptor::NameRegister();
DCHECK(receiver.is(edx));
DCHECK(key.is(ecx));
......@@ -522,6 +523,10 @@ void KeyedStoreIC::GenerateMegamorphic(MacroAssembler* masm,
__ test_b(FieldOperand(edi, Map::kBitFieldOffset),
Immediate(1 << Map::kIsAccessCheckNeeded));
__ j(not_zero, &slow);
__ LoadParameterFromStack<Descriptor>(Descriptor::ValueRegister(),
Descriptor::kValue);
// Check that the key is a smi.
__ JumpIfNotSmi(key, &maybe_name_key);
__ CmpInstanceType(edi, JS_ARRAY_TYPE);
......@@ -551,22 +556,9 @@ void KeyedStoreIC::GenerateMegamorphic(MacroAssembler* masm,
__ movzx_b(ebx, FieldOperand(ebx, Map::kInstanceTypeOffset));
__ JumpIfNotUniqueNameInstanceType(ebx, &slow);
// 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 =
TypeFeedbackVector::DummyVector(masm->isolate());
int slot = dummy_vector->GetIndex(
FeedbackVectorSlot(TypeFeedbackVector::kDummyKeyedStoreICSlot));
__ push(Immediate(Smi::FromInt(slot)));
__ push(Immediate(dummy_vector));
masm->isolate()->store_stub_cache()->GenerateProbe(masm, receiver, key, edi,
no_reg);
__ pop(StoreWithVectorDescriptor::VectorRegister());
__ pop(StoreWithVectorDescriptor::SlotRegister());
// Cache miss.
__ jmp(&miss);
......@@ -733,32 +725,33 @@ void StoreIC::GenerateMiss(MacroAssembler* masm) {
void StoreIC::GenerateNormal(MacroAssembler* masm) {
typedef StoreWithVectorDescriptor Descriptor;
Label restore_miss;
Register receiver = StoreDescriptor::ReceiverRegister();
Register name = StoreDescriptor::NameRegister();
Register value = StoreDescriptor::ValueRegister();
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
// GenerateDictionaryStore preserving the value and name.
Register receiver = Descriptor::ReceiverRegister();
Register name = Descriptor::NameRegister();
Register value = Descriptor::ValueRegister();
// Since the slot and vector values are passed on the stack we can use
// respective registers as scratch registers.
Register scratch1 = Descriptor::VectorRegister();
Register scratch2 = Descriptor::SlotRegister();
__ LoadParameterFromStack<Descriptor>(value, Descriptor::kValue);
// A lot of registers are needed for storing to slow case objects.
// Push and restore receiver but rely on GenerateDictionaryStore preserving
// the value and name.
__ push(receiver);
__ push(vector);
__ push(slot);
Register dictionary = ebx;
Register dictionary = receiver;
__ mov(dictionary, FieldOperand(receiver, JSObject::kPropertiesOffset));
GenerateDictionaryStore(masm, &restore_miss, dictionary, name, value,
receiver, edi);
__ Drop(3);
scratch1, scratch2);
__ Drop(1);
Counters* counters = masm->isolate()->counters();
__ IncrementCounter(counters->ic_store_normal_hit(), 1);
__ ret(StoreWithVectorDescriptor::kStackArgumentsCount * kPointerSize);
__ ret(Descriptor::kStackArgumentsCount * kPointerSize);
__ bind(&restore_miss);
__ pop(slot);
__ pop(vector);
__ pop(receiver);
__ IncrementCounter(counters->ic_store_normal_miss(), 1);
GenerateMiss(masm);
......
......@@ -22,8 +22,6 @@ static void ProbeTable(StubCache* stub_cache, MacroAssembler* masm,
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();
......@@ -55,19 +53,15 @@ static void ProbeTable(StubCache* stub_cache, MacroAssembler* masm,
}
#endif
// The vector and slot were pushed onto the stack before starting the
// 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 = StoreWithVectorDescriptor::VectorRegister();
// The value, vector and slot were passed to the IC on the stack and
// they are still there. So we can just jump to the handler.
DCHECK(extra.is(StoreWithVectorDescriptor::SlotRegister()));
__ add(extra, Immediate(Code::kHeaderSize - kHeapObjectTag));
__ pop(vector);
__ mov(Operand::StaticVariable(virtual_register), extra);
__ pop(extra); // Pop "slot".
// Jump to the first instruction in the code stub.
__ jmp(Operand::StaticVariable(virtual_register));
__ jmp(extra);
} else {
// The vector and slot were pushed onto the stack before starting the
// probe, and need to be dropped before calling the handler.
__ pop(LoadWithVectorDescriptor::VectorRegister());
__ pop(LoadDescriptor::SlotRegister());
__ add(extra, Immediate(Code::kHeaderSize - kHeapObjectTag));
......@@ -110,19 +104,10 @@ static void ProbeTable(StubCache* stub_cache, MacroAssembler* masm,
// Jump to the first instruction in the code stub.
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 = StoreWithVectorDescriptor::VectorRegister();
DCHECK(offset.is(StoreWithVectorDescriptor::SlotRegister()));
__ add(offset, Immediate(Code::kHeaderSize - kHeapObjectTag));
__ mov(Operand::StaticVariable(virtual_register), offset);
__ pop(vector);
__ pop(offset); // Pop "slot".
__ jmp(Operand::StaticVariable(virtual_register));
} else {
__ add(offset, Immediate(Code::kHeaderSize - kHeapObjectTag));
__ jmp(offset);
}
__ add(offset, Immediate(Code::kHeaderSize - kHeapObjectTag));
__ jmp(offset);
// Pop at miss.
__ bind(&miss);
......
......@@ -1997,8 +1997,6 @@ Isolate::Isolate(bool enable_serializer)
deferred_handles_head_(NULL),
optimizing_compile_dispatcher_(NULL),
stress_deopt_count_(0),
virtual_handler_register_(NULL),
virtual_slot_register_(NULL),
next_optimization_id_(0),
js_calls_from_api_counter_(0),
#if TRACE_MAPS
......
......@@ -1062,12 +1062,6 @@ class Isolate {
void* stress_deopt_count_address() { return &stress_deopt_count_; }
void* virtual_handler_register_address() {
return &virtual_handler_register_;
}
void* virtual_slot_register_address() { return &virtual_slot_register_; }
base::RandomNumberGenerator* random_number_generator();
// Given an address occupied by a live code object, return that object.
......@@ -1412,9 +1406,6 @@ class Isolate {
// Counts deopt points if deopt_every_n_times is enabled.
unsigned int stress_deopt_count_;
Address virtual_handler_register_;
Address virtual_slot_register_;
int next_optimization_id_;
// Counts javascript calls from the API. Wraps around on overflow.
......
......@@ -215,6 +215,18 @@ class MacroAssembler: public Assembler {
Func GetLabelFunction);
#undef COND_ARGS
// Emit code that loads |parameter_index|'th parameter from the stack to
// the register according to the CallInterfaceDescriptor definition.
// |sp_to_caller_sp_offset_in_words| specifies the number of words pushed
// below the caller's sp.
template <class Descriptor>
void LoadParameterFromStack(
Register reg, typename Descriptor::ParameterIndices parameter_index,
int sp_to_ra_offset_in_words = 0) {
DCHECK(Descriptor::kPassLastArgsOnStack);
UNIMPLEMENTED();
}
// Emit code to discard a non-negative number of pointer-sized elements
// from the stack, clobbering only the sp register.
void Drop(int count,
......
......@@ -243,6 +243,18 @@ class MacroAssembler: public Assembler {
Func GetLabelFunction);
#undef COND_ARGS
// Emit code that loads |parameter_index|'th parameter from the stack to
// the register according to the CallInterfaceDescriptor definition.
// |sp_to_caller_sp_offset_in_words| specifies the number of words pushed
// below the caller's sp.
template <class Descriptor>
void LoadParameterFromStack(
Register reg, typename Descriptor::ParameterIndices parameter_index,
int sp_to_ra_offset_in_words = 0) {
DCHECK(Descriptor::kPassLastArgsOnStack);
UNIMPLEMENTED();
}
// Emit code to discard a non-negative number of pointer-sized elements
// from the stack, clobbering only the sp register.
void Drop(int count,
......
......@@ -140,6 +140,18 @@ class MacroAssembler : public Assembler {
void Ret() { blr(); }
void Ret(Condition cond, CRegister cr = cr7) { bclr(cond, cr); }
// Emit code that loads |parameter_index|'th parameter from the stack to
// the register according to the CallInterfaceDescriptor definition.
// |sp_to_caller_sp_offset_in_words| specifies the number of words pushed
// below the caller's sp.
template <class Descriptor>
void LoadParameterFromStack(
Register reg, typename Descriptor::ParameterIndices parameter_index,
int sp_to_ra_offset_in_words = 0) {
DCHECK(Descriptor::kPassLastArgsOnStack);
UNIMPLEMENTED();
}
// Emit code to discard a non-negative number of pointer-sized elements
// from the stack, clobbering only the sp register.
void Drop(int count);
......
......@@ -194,6 +194,18 @@ class MacroAssembler : public Assembler {
void Ret() { b(r14); }
void Ret(Condition cond) { b(cond, r14); }
// Emit code that loads |parameter_index|'th parameter from the stack to
// the register according to the CallInterfaceDescriptor definition.
// |sp_to_caller_sp_offset_in_words| specifies the number of words pushed
// below the caller's sp.
template <class Descriptor>
void LoadParameterFromStack(
Register reg, typename Descriptor::ParameterIndices parameter_index,
int sp_to_ra_offset_in_words = 0) {
DCHECK(Descriptor::kPassLastArgsOnStack);
UNIMPLEMENTED();
}
// Emit code to discard a non-negative number of pointer-sized elements
// from the stack, clobbering only the sp register.
void Drop(int count);
......
......@@ -891,6 +891,18 @@ class MacroAssembler: public Assembler {
// miss label if the weak cell was cleared.
void LoadWeakValue(Register value, Handle<WeakCell> cell, Label* miss);
// Emit code that loads |parameter_index|'th parameter from the stack to
// the register according to the CallInterfaceDescriptor definition.
// |sp_to_caller_sp_offset_in_words| specifies the number of words pushed
// below the caller's sp (on x64 it's at least return address).
template <class Descriptor>
void LoadParameterFromStack(
Register reg, typename Descriptor::ParameterIndices parameter_index,
int sp_to_ra_offset_in_words = 1) {
DCHECK(Descriptor::kPassLastArgsOnStack);
UNIMPLEMENTED();
}
// Emit code to discard a non-negative number of pointer-sized elements
// from the stack, clobbering only the rsp register.
void Drop(int stack_elements);
......
This diff is collapsed.
......@@ -787,6 +787,24 @@ class MacroAssembler: public Assembler {
// may be bigger than 2^16 - 1. Requires a scratch register.
void Ret(int bytes_dropped, Register scratch);
// Emit code that loads |parameter_index|'th parameter from the stack to
// the register according to the CallInterfaceDescriptor definition.
// |sp_to_caller_sp_offset_in_words| specifies the number of words pushed
// below the caller's sp (on x87 it's at least return address).
template <class Descriptor>
void LoadParameterFromStack(
Register reg, typename Descriptor::ParameterIndices parameter_index,
int sp_to_ra_offset_in_words = 1) {
DCHECK(Descriptor::kPassLastArgsOnStack);
DCHECK_LT(parameter_index, Descriptor::kParameterCount);
DCHECK_LE(Descriptor::kParameterCount - Descriptor::kStackArgumentsCount,
parameter_index);
int offset = (Descriptor::kParameterCount - parameter_index - 1 +
sp_to_ra_offset_in_words) *
kPointerSize;
mov(reg, Operand(esp, offset));
}
// Emit code to discard a non-negative number of pointer-sized elements
// from the stack, clobbering only the esp register.
void Drop(int element_count);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment