[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}
This commit is contained in:
ishell 2016-09-23 07:29:08 -07:00 committed by Commit bot
parent 84145a149b
commit 49695346ae
33 changed files with 354 additions and 319 deletions

View File

@ -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);

View File

@ -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

View File

@ -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(

View File

@ -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_); }

View File

@ -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)

View File

@ -3321,11 +3321,10 @@ static void HandlePolymorphicStoreCase(MacroAssembler* masm, Register receiver,
Label load_smi_map, compare_map;
Label start_polymorphic;
Label pop_and_miss;
ExternalReference virtual_register =
ExternalReference::virtual_handler_register(masm->isolate());
__ push(receiver);
__ push(vector);
// Value, vector and slot are passed on the stack, so no need to save/restore
// them.
Register receiver_map = receiver;
Register cached_map = vector;
@ -3346,12 +3345,9 @@ static void HandlePolymorphicStoreCase(MacroAssembler* masm, Register receiver,
Register handler = feedback;
DCHECK(handler.is(StoreWithVectorDescriptor::ValueRegister()));
__ mov(handler, FieldOperand(feedback, FixedArray::OffsetOfElementAt(1)));
__ pop(vector);
__ pop(receiver);
__ lea(handler, FieldOperand(handler, Code::kHeaderSize));
__ mov(Operand::StaticVariable(virtual_register), handler);
__ pop(handler); // Pop "value".
__ jmp(Operand::StaticVariable(virtual_register));
__ jmp(handler);
// Polymorphic, we have to loop from 2 to N
__ bind(&start_polymorphic);
@ -3375,11 +3371,8 @@ static void HandlePolymorphicStoreCase(MacroAssembler* masm, Register receiver,
FixedArray::kHeaderSize + kPointerSize));
__ lea(handler, FieldOperand(handler, Code::kHeaderSize));
__ pop(key);
__ pop(vector);
__ pop(receiver);
__ mov(Operand::StaticVariable(virtual_register), handler);
__ pop(handler); // Pop "value".
__ jmp(Operand::StaticVariable(virtual_register));
__ jmp(handler);
__ bind(&prepare_next);
__ add(counter, Immediate(Smi::FromInt(2)));
@ -3389,7 +3382,6 @@ static void HandlePolymorphicStoreCase(MacroAssembler* masm, Register receiver,
// We exhausted our array of map handler pairs.
__ bind(&pop_and_miss);
__ pop(key);
__ pop(vector);
__ pop(receiver);
__ jmp(miss);
@ -3405,8 +3397,6 @@ static void HandleMonomorphicStoreCase(MacroAssembler* masm, Register receiver,
Label* miss) {
// The store ic value is on the stack.
DCHECK(weak_cell.is(StoreWithVectorDescriptor::ValueRegister()));
ExternalReference virtual_register =
ExternalReference::virtual_handler_register(masm->isolate());
// feedback initially contains the feedback array
Label compare_smi_map;
@ -3422,11 +3412,8 @@ static void HandleMonomorphicStoreCase(MacroAssembler* masm, Register receiver,
__ mov(weak_cell, FieldOperand(vector, slot, times_half_pointer_size,
FixedArray::kHeaderSize + kPointerSize));
__ lea(weak_cell, FieldOperand(weak_cell, Code::kHeaderSize));
// Put the store ic value back in it's register.
__ mov(Operand::StaticVariable(virtual_register), weak_cell);
__ pop(weak_cell); // Pop "value".
// jump to the handler.
__ jmp(Operand::StaticVariable(virtual_register));
__ jmp(weak_cell);
// In microbenchmarks, it made sense to unroll this code so that the call to
// the handler is duplicated for a HeapObject receiver and a Smi receiver.
@ -3436,10 +3423,8 @@ static void HandleMonomorphicStoreCase(MacroAssembler* masm, Register receiver,
__ mov(weak_cell, FieldOperand(vector, slot, times_half_pointer_size,
FixedArray::kHeaderSize + kPointerSize));
__ lea(weak_cell, FieldOperand(weak_cell, Code::kHeaderSize));
__ mov(Operand::StaticVariable(virtual_register), weak_cell);
__ pop(weak_cell); // Pop "value".
// jump to the handler.
__ jmp(Operand::StaticVariable(virtual_register));
__ jmp(weak_cell);
}
void StoreICStub::GenerateImpl(MacroAssembler* masm, bool in_frame) {
@ -3469,11 +3454,8 @@ void StoreICStub::GenerateImpl(MacroAssembler* masm, bool in_frame) {
__ mov(vector, Operand(esp, 1 * kPointerSize));
}
__ mov(slot, Operand(esp, 2 * kPointerSize));
__ mov(value, Operand(esp, 3 * kPointerSize));
}
__ push(value);
Register scratch = value;
__ mov(scratch, FieldOperand(vector, slot, times_half_pointer_size,
FixedArray::kHeaderSize));
@ -3496,19 +3478,9 @@ void StoreICStub::GenerateImpl(MacroAssembler* masm, bool in_frame) {
__ CompareRoot(scratch, Heap::kmegamorphic_symbolRootIndex);
__ j(not_equal, &miss);
__ pop(value);
__ push(slot);
__ push(vector);
masm->isolate()->store_stub_cache()->GenerateProbe(masm, receiver, key, slot,
no_reg);
__ pop(vector);
__ pop(slot);
Label no_pop_miss;
__ jmp(&no_pop_miss);
__ bind(&miss);
__ pop(value);
__ bind(&no_pop_miss);
StoreIC::GenerateMiss(masm);
}
@ -3530,17 +3502,13 @@ static void HandlePolymorphicKeyedStoreCase(MacroAssembler* masm,
Label load_smi_map, compare_map;
Label transition_call;
Label pop_and_miss;
ExternalReference virtual_register =
ExternalReference::virtual_handler_register(masm->isolate());
ExternalReference virtual_slot =
ExternalReference::virtual_slot_register(masm->isolate());
__ push(receiver);
__ push(vector);
// Value, vector and slot are passed on the stack, so no need to save/restore
// them.
Register receiver_map = receiver;
Register cached_map = vector;
Register value = StoreDescriptor::ValueRegister();
// Receiver might not be a heap object.
__ JumpIfSmi(receiver, &load_smi_map);
@ -3551,15 +3519,18 @@ static void HandlePolymorphicKeyedStoreCase(MacroAssembler* masm,
__ push(key);
// Current stack layout:
// - esp[0] -- key
// - esp[4] -- vector
// - esp[8] -- receiver
// - esp[12] -- value
// - esp[16] -- return address
// - esp[4] -- receiver
// - esp[8] -- return address
// - esp[12] -- vector
// - esp[16] -- slot
// - esp[20] -- value
//
// Required stack layout for handler call:
// Required stack layout for handler call (see StoreWithVectorDescriptor):
// - esp[0] -- return address
// - receiver, key, value, vector, slot in registers.
// - handler in virtual register.
// - esp[4] -- vector
// - esp[8] -- slot
// - esp[12] -- value
// - receiver, key, handler in registers.
Register counter = key;
__ mov(counter, Immediate(Smi::FromInt(0)));
__ bind(&next_loop);
@ -3574,32 +3545,28 @@ static void HandlePolymorphicKeyedStoreCase(MacroAssembler* masm,
__ mov(feedback, FieldOperand(feedback, counter, times_half_pointer_size,
FixedArray::kHeaderSize + 2 * kPointerSize));
__ pop(key);
__ pop(vector);
__ pop(receiver);
__ lea(feedback, FieldOperand(feedback, Code::kHeaderSize));
__ mov(Operand::StaticVariable(virtual_register), feedback);
__ pop(value);
// Call store handler using StoreWithVectorDescriptor calling convention.
__ jmp(Operand::StaticVariable(virtual_register));
__ jmp(feedback);
__ bind(&transition_call);
// Current stack layout:
// - esp[0] -- key
// - esp[4] -- vector
// - esp[8] -- receiver
// - esp[12] -- value
// - esp[16] -- return address
// - esp[4] -- receiver
// - esp[8] -- return address
// - esp[12] -- vector
// - esp[16] -- slot
// - esp[20] -- value
//
// Required stack layout for handler call:
// Required stack layout for handler call (see StoreTransitionDescriptor):
// - esp[0] -- return address
// - receiver, key, value, map, vector in registers.
// - handler and slot in virtual registers.
__ mov(Operand::StaticVariable(virtual_slot), slot);
// - esp[4] -- vector
// - esp[8] -- slot
// - esp[12] -- value
// - receiver, key, map, handler in registers.
__ mov(feedback, FieldOperand(feedback, counter, times_half_pointer_size,
FixedArray::kHeaderSize + 2 * kPointerSize));
__ lea(feedback, FieldOperand(feedback, Code::kHeaderSize));
__ mov(Operand::StaticVariable(virtual_register), feedback);
__ mov(cached_map, FieldOperand(cached_map, WeakCell::kValueOffset));
// The weak cell may have been cleared.
@ -3610,9 +3577,7 @@ static void HandlePolymorphicKeyedStoreCase(MacroAssembler* masm,
// Call store transition handler using StoreTransitionDescriptor calling
// convention.
__ pop(key);
__ pop(vector);
__ pop(receiver);
__ pop(value);
// 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.
@ -3630,7 +3595,7 @@ static void HandlePolymorphicKeyedStoreCase(MacroAssembler* masm,
StoreWithVectorDescriptor::kVector ==
StoreTransitionDescriptor::kParameterCount -
StoreTransitionDescriptor::kVector);
__ jmp(Operand::StaticVariable(virtual_register));
__ jmp(feedback);
__ bind(&prepare_next);
__ add(counter, Immediate(Smi::FromInt(3)));
@ -3640,7 +3605,6 @@ static void HandlePolymorphicKeyedStoreCase(MacroAssembler* masm,
// We exhausted our array of map handler pairs.
__ bind(&pop_and_miss);
__ pop(key);
__ pop(vector);
__ pop(receiver);
__ jmp(miss);
@ -3676,11 +3640,8 @@ void KeyedStoreICStub::GenerateImpl(MacroAssembler* masm, bool in_frame) {
__ mov(vector, Operand(esp, 1 * kPointerSize));
}
__ mov(slot, Operand(esp, 2 * kPointerSize));
__ mov(value, Operand(esp, 3 * kPointerSize));
}
__ push(value);
Register scratch = value;
__ mov(scratch, FieldOperand(vector, slot, times_half_pointer_size,
FixedArray::kHeaderSize));
@ -3704,8 +3665,6 @@ void KeyedStoreICStub::GenerateImpl(MacroAssembler* masm, bool in_frame) {
__ CompareRoot(scratch, Heap::kmegamorphic_symbolRootIndex);
__ j(not_equal, &try_poly_name);
__ pop(value);
Handle<Code> megamorphic_stub =
KeyedStoreIC::ChooseMegamorphicStub(masm->isolate(), GetExtraICState());
__ jmp(megamorphic_stub, RelocInfo::CODE_TARGET);
@ -3722,7 +3681,6 @@ void KeyedStoreICStub::GenerateImpl(MacroAssembler* masm, bool in_frame) {
&miss);
__ bind(&miss);
__ pop(value);
KeyedStoreIC::GenerateMiss(masm);
}

View File

@ -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);

View File

@ -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,

View File

@ -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,

View File

@ -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);

View File

@ -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);

View File

@ -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[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.

View File

@ -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
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), StoreDescriptor::ReceiverRegister());
__ mov(Operand(esp, 8), StoreDescriptor::NameRegister());
__ mov(Operand(esp, 4), StoreDescriptor::ValueRegister());
__ 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

View File

@ -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();
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();
// 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.
__ 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);

View File

@ -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);
}
// Pop at miss.
__ bind(&miss);

View File

@ -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,

View File

@ -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,

View File

@ -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,

View File

@ -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) {

View File

@ -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,

View File

@ -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[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.

View File

@ -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
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), StoreDescriptor::ReceiverRegister());
__ mov(Operand(esp, 8), StoreDescriptor::NameRegister());
__ mov(Operand(esp, 4), StoreDescriptor::ValueRegister());
__ 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

View File

@ -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();
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();
// 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.
__ 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);

View File

@ -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);
}
// Pop at miss.
__ bind(&miss);

View File

@ -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

View File

@ -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.

View File

@ -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,

View File

@ -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,

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -3133,11 +3133,10 @@ static void HandlePolymorphicStoreCase(MacroAssembler* masm, Register receiver,
Label load_smi_map, compare_map;
Label start_polymorphic;
Label pop_and_miss;
ExternalReference virtual_register =
ExternalReference::virtual_handler_register(masm->isolate());
__ push(receiver);
__ push(vector);
// Value, vector and slot are passed on the stack, so no need to save/restore
// them.
Register receiver_map = receiver;
Register cached_map = vector;
@ -3158,12 +3157,9 @@ static void HandlePolymorphicStoreCase(MacroAssembler* masm, Register receiver,
Register handler = feedback;
DCHECK(handler.is(StoreWithVectorDescriptor::ValueRegister()));
__ mov(handler, FieldOperand(feedback, FixedArray::OffsetOfElementAt(1)));
__ pop(vector);
__ pop(receiver);
__ lea(handler, FieldOperand(handler, Code::kHeaderSize));
__ mov(Operand::StaticVariable(virtual_register), handler);
__ pop(handler); // Pop "value".
__ jmp(Operand::StaticVariable(virtual_register));
__ jmp(handler);
// Polymorphic, we have to loop from 2 to N
__ bind(&start_polymorphic);
@ -3187,11 +3183,8 @@ static void HandlePolymorphicStoreCase(MacroAssembler* masm, Register receiver,
FixedArray::kHeaderSize + kPointerSize));
__ lea(handler, FieldOperand(handler, Code::kHeaderSize));
__ pop(key);
__ pop(vector);
__ pop(receiver);
__ mov(Operand::StaticVariable(virtual_register), handler);
__ pop(handler); // Pop "value".
__ jmp(Operand::StaticVariable(virtual_register));
__ jmp(handler);
__ bind(&prepare_next);
__ add(counter, Immediate(Smi::FromInt(2)));
@ -3201,7 +3194,6 @@ static void HandlePolymorphicStoreCase(MacroAssembler* masm, Register receiver,
// We exhausted our array of map handler pairs.
__ bind(&pop_and_miss);
__ pop(key);
__ pop(vector);
__ pop(receiver);
__ jmp(miss);
@ -3217,8 +3209,6 @@ static void HandleMonomorphicStoreCase(MacroAssembler* masm, Register receiver,
Label* miss) {
// The store ic value is on the stack.
DCHECK(weak_cell.is(StoreWithVectorDescriptor::ValueRegister()));
ExternalReference virtual_register =
ExternalReference::virtual_handler_register(masm->isolate());
// feedback initially contains the feedback array
Label compare_smi_map;
@ -3234,11 +3224,8 @@ static void HandleMonomorphicStoreCase(MacroAssembler* masm, Register receiver,
__ mov(weak_cell, FieldOperand(vector, slot, times_half_pointer_size,
FixedArray::kHeaderSize + kPointerSize));
__ lea(weak_cell, FieldOperand(weak_cell, Code::kHeaderSize));
// Put the store ic value back in it's register.
__ mov(Operand::StaticVariable(virtual_register), weak_cell);
__ pop(weak_cell); // Pop "value".
// jump to the handler.
__ jmp(Operand::StaticVariable(virtual_register));
__ jmp(weak_cell);
// In microbenchmarks, it made sense to unroll this code so that the call to
// the handler is duplicated for a HeapObject receiver and a Smi receiver.
@ -3248,10 +3235,8 @@ static void HandleMonomorphicStoreCase(MacroAssembler* masm, Register receiver,
__ mov(weak_cell, FieldOperand(vector, slot, times_half_pointer_size,
FixedArray::kHeaderSize + kPointerSize));
__ lea(weak_cell, FieldOperand(weak_cell, Code::kHeaderSize));
__ mov(Operand::StaticVariable(virtual_register), weak_cell);
__ pop(weak_cell); // Pop "value".
// jump to the handler.
__ jmp(Operand::StaticVariable(virtual_register));
__ jmp(weak_cell);
}
void StoreICStub::GenerateImpl(MacroAssembler* masm, bool in_frame) {
@ -3281,11 +3266,8 @@ void StoreICStub::GenerateImpl(MacroAssembler* masm, bool in_frame) {
__ mov(vector, Operand(esp, 1 * kPointerSize));
}
__ mov(slot, Operand(esp, 2 * kPointerSize));
__ mov(value, Operand(esp, 3 * kPointerSize));
}
__ push(value);
Register scratch = value;
__ mov(scratch, FieldOperand(vector, slot, times_half_pointer_size,
FixedArray::kHeaderSize));
@ -3308,19 +3290,9 @@ void StoreICStub::GenerateImpl(MacroAssembler* masm, bool in_frame) {
__ CompareRoot(scratch, Heap::kmegamorphic_symbolRootIndex);
__ j(not_equal, &miss);
__ pop(value);
__ push(slot);
__ push(vector);
masm->isolate()->store_stub_cache()->GenerateProbe(masm, receiver, key, slot,
no_reg);
__ pop(vector);
__ pop(slot);
Label no_pop_miss;
__ jmp(&no_pop_miss);
__ bind(&miss);
__ pop(value);
__ bind(&no_pop_miss);
StoreIC::GenerateMiss(masm);
}
@ -3342,17 +3314,13 @@ static void HandlePolymorphicKeyedStoreCase(MacroAssembler* masm,
Label load_smi_map, compare_map;
Label transition_call;
Label pop_and_miss;
ExternalReference virtual_register =
ExternalReference::virtual_handler_register(masm->isolate());
ExternalReference virtual_slot =
ExternalReference::virtual_slot_register(masm->isolate());
__ push(receiver);
__ push(vector);
// Value, vector and slot are passed on the stack, so no need to save/restore
// them.
Register receiver_map = receiver;
Register cached_map = vector;
Register value = StoreDescriptor::ValueRegister();
// Receiver might not be a heap object.
__ JumpIfSmi(receiver, &load_smi_map);
@ -3363,15 +3331,18 @@ static void HandlePolymorphicKeyedStoreCase(MacroAssembler* masm,
__ push(key);
// Current stack layout:
// - esp[0] -- key
// - esp[4] -- vector
// - esp[8] -- receiver
// - esp[12] -- value
// - esp[16] -- return address
// - esp[4] -- receiver
// - esp[8] -- return address
// - esp[12] -- vector
// - esp[16] -- slot
// - esp[20] -- value
//
// Required stack layout for handler call:
// Required stack layout for handler call (see StoreWithVectorDescriptor):
// - esp[0] -- return address
// - receiver, key, value, vector, slot in registers.
// - handler in virtual register.
// - esp[4] -- vector
// - esp[8] -- slot
// - esp[12] -- value
// - receiver, key, handler in registers.
Register counter = key;
__ mov(counter, Immediate(Smi::FromInt(0)));
__ bind(&next_loop);
@ -3386,32 +3357,28 @@ static void HandlePolymorphicKeyedStoreCase(MacroAssembler* masm,
__ mov(feedback, FieldOperand(feedback, counter, times_half_pointer_size,
FixedArray::kHeaderSize + 2 * kPointerSize));
__ pop(key);
__ pop(vector);
__ pop(receiver);
__ lea(feedback, FieldOperand(feedback, Code::kHeaderSize));
__ mov(Operand::StaticVariable(virtual_register), feedback);
__ pop(value);
// Call store handler using StoreWithVectorDescriptor calling convention.
__ jmp(Operand::StaticVariable(virtual_register));
__ jmp(feedback);
__ bind(&transition_call);
// Current stack layout:
// - esp[0] -- key
// - esp[4] -- vector
// - esp[8] -- receiver
// - esp[12] -- value
// - esp[16] -- return address
// - esp[4] -- receiver
// - esp[8] -- return address
// - esp[12] -- vector
// - esp[16] -- slot
// - esp[20] -- value
//
// Required stack layout for handler call:
// Required stack layout for handler call (see StoreTransitionDescriptor):
// - esp[0] -- return address
// - receiver, key, value, map, vector in registers.
// - handler and slot in virtual registers.
__ mov(Operand::StaticVariable(virtual_slot), slot);
// - esp[4] -- vector
// - esp[8] -- slot
// - esp[12] -- value
// - receiver, key, map, handler in registers.
__ mov(feedback, FieldOperand(feedback, counter, times_half_pointer_size,
FixedArray::kHeaderSize + 2 * kPointerSize));
__ lea(feedback, FieldOperand(feedback, Code::kHeaderSize));
__ mov(Operand::StaticVariable(virtual_register), feedback);
__ mov(cached_map, FieldOperand(cached_map, WeakCell::kValueOffset));
// The weak cell may have been cleared.
@ -3422,9 +3389,7 @@ static void HandlePolymorphicKeyedStoreCase(MacroAssembler* masm,
// Call store transition handler using StoreTransitionDescriptor calling
// convention.
__ pop(key);
__ pop(vector);
__ pop(receiver);
__ pop(value);
// 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.
@ -3442,7 +3407,7 @@ static void HandlePolymorphicKeyedStoreCase(MacroAssembler* masm,
StoreWithVectorDescriptor::kVector ==
StoreTransitionDescriptor::kParameterCount -
StoreTransitionDescriptor::kVector);
__ jmp(Operand::StaticVariable(virtual_register));
__ jmp(feedback);
__ bind(&prepare_next);
__ add(counter, Immediate(Smi::FromInt(3)));
@ -3452,7 +3417,6 @@ static void HandlePolymorphicKeyedStoreCase(MacroAssembler* masm,
// We exhausted our array of map handler pairs.
__ bind(&pop_and_miss);
__ pop(key);
__ pop(vector);
__ pop(receiver);
__ jmp(miss);
@ -3488,11 +3452,8 @@ void KeyedStoreICStub::GenerateImpl(MacroAssembler* masm, bool in_frame) {
__ mov(vector, Operand(esp, 1 * kPointerSize));
}
__ mov(slot, Operand(esp, 2 * kPointerSize));
__ mov(value, Operand(esp, 3 * kPointerSize));
}
__ push(value);
Register scratch = value;
__ mov(scratch, FieldOperand(vector, slot, times_half_pointer_size,
FixedArray::kHeaderSize));
@ -3516,8 +3477,6 @@ void KeyedStoreICStub::GenerateImpl(MacroAssembler* masm, bool in_frame) {
__ CompareRoot(scratch, Heap::kmegamorphic_symbolRootIndex);
__ j(not_equal, &try_poly_name);
__ pop(value);
Handle<Code> megamorphic_stub =
KeyedStoreIC::ChooseMegamorphicStub(masm->isolate(), GetExtraICState());
__ jmp(megamorphic_stub, RelocInfo::CODE_TARGET);
@ -3534,7 +3493,6 @@ void KeyedStoreICStub::GenerateImpl(MacroAssembler* masm, bool in_frame) {
&miss);
__ bind(&miss);
__ pop(value);
KeyedStoreIC::GenerateMiss(masm);
}

View File

@ -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);