X87: Reland Vector ICs: platform support for vector-based stores.

port 40fbed0609 (r30581)

original commit message:

    The last changes for vector store functionality, they are in 3 areas:

    1) The new vector [keyed] store code stubs - implementation.
    2) IC and handler compiler adjustments
    3) Odds and ends. A change in ast.cc, a test update, a small Oracle fix.

BUG=

Review URL: https://codereview.chromium.org/1311413007

Cr-Commit-Position: refs/heads/master@{#30612}
This commit is contained in:
chunyang.dai 2015-09-07 01:19:40 -07:00 committed by Commit bot
parent 0fce748dc6
commit 6b69d5365d
6 changed files with 386 additions and 37 deletions

View File

@ -30,7 +30,8 @@ Register* PropertyAccessCompiler::store_calling_convention() {
// receiver, name, scratch1, scratch2, scratch3.
Register receiver = StoreDescriptor::ReceiverRegister();
Register name = StoreDescriptor::NameRegister();
DCHECK(ebx.is(StoreTransitionDescriptor::MapRegister()));
DCHECK(FLAG_vector_stores ||
ebx.is(StoreTransitionDescriptor::MapRegister()));
static Register registers[] = {receiver, name, ebx, edi, no_reg};
return registers;
}

View File

@ -304,13 +304,24 @@ static void StoreIC_PushArgs(MacroAssembler* masm) {
Register name = StoreDescriptor::NameRegister();
Register value = StoreDescriptor::ValueRegister();
DCHECK(!ebx.is(receiver) && !ebx.is(name) && !ebx.is(value));
if (FLAG_vector_stores) {
Register slot = VectorStoreICDescriptor::SlotRegister();
Register vector = VectorStoreICDescriptor::VectorRegister();
__ pop(ebx);
__ push(receiver);
__ push(name);
__ push(value);
__ push(ebx);
__ xchg(receiver, Operand(esp, 0));
__ push(name);
__ push(value);
__ push(slot);
__ push(vector);
__ push(receiver); // which contains the return address.
} else {
DCHECK(!ebx.is(receiver) && !ebx.is(name) && !ebx.is(value));
__ pop(ebx);
__ push(receiver);
__ push(name);
__ push(value);
__ push(ebx);
}
}
@ -319,7 +330,7 @@ void NamedStoreHandlerCompiler::GenerateSlow(MacroAssembler* masm) {
StoreIC_PushArgs(masm);
// Do tail-call to runtime routine.
__ TailCallRuntime(Runtime::kStoreIC_Slow, 3, 1);
__ TailCallRuntime(Runtime::kStoreIC_Slow, FLAG_vector_stores ? 5 : 3, 1);
}
@ -328,7 +339,8 @@ void ElementHandlerCompiler::GenerateStoreSlow(MacroAssembler* masm) {
StoreIC_PushArgs(masm);
// Do tail-call to runtime routine.
__ TailCallRuntime(Runtime::kKeyedStoreIC_Slow, 3, 1);
__ TailCallRuntime(Runtime::kKeyedStoreIC_Slow, FLAG_vector_stores ? 5 : 3,
1);
}
@ -352,10 +364,16 @@ void NamedStoreHandlerCompiler::GenerateRestoreName(Handle<Name> name) {
void NamedStoreHandlerCompiler::GeneratePushMap(Register map_reg,
Register scratch) {
// Get the return address, push the argument and then continue.
__ pop(scratch);
// current after GeneratePushMap
// -------------------------------------------------
// ret addr slot
// vector vector
// sp -> slot map
// sp -> ret addr
//
__ xchg(map_reg, Operand(esp, 0));
__ xchg(map_reg, Operand(esp, 2 * kPointerSize));
__ push(map_reg);
__ push(scratch);
}
@ -575,6 +593,7 @@ void NamedStoreHandlerCompiler::FrontendFooter(Handle<Name> name, Label* miss) {
Label success;
__ jmp(&success);
GenerateRestoreName(miss, name);
if (IC::ICUseVector(kind())) PopVectorAndSlot();
TailCallBuiltin(masm(), MissBuiltin(kind()));
__ bind(&success);
}

View File

@ -112,7 +112,10 @@ Handle<Code> PropertyICCompiler::CompileKeyedStorePolymorphic(
Label next_map;
__ j(not_equal, &next_map, Label::kNear);
Handle<WeakCell> cell = Map::WeakCellForMap(transitioned_maps->at(i));
__ LoadWeakValue(transition_map(), cell, &miss);
Register transition_map = scratch1();
DCHECK(!FLAG_vector_stores &&
transition_map.is(StoreTransitionDescriptor::MapRegister()));
__ LoadWeakValue(transition_map, cell, &miss);
__ jmp(handler_stubs->at(i), RelocInfo::CODE_TARGET);
__ bind(&next_map);
}

View File

@ -577,7 +577,7 @@ void KeyedStoreIC::GenerateMegamorphic(MacroAssembler* masm,
Code::Flags flags = Code::RemoveTypeAndHolderFromFlags(
Code::ComputeHandlerFlags(Code::STORE_IC));
masm->isolate()->stub_cache()->GenerateProbe(masm, Code::STORE_IC, flags,
receiver, key, ebx, no_reg);
receiver, key, edi, no_reg);
if (FLAG_vector_stores) {
__ pop(VectorStoreICDescriptor::VectorRegister());
@ -734,6 +734,12 @@ void KeyedLoadIC::GenerateRuntimeGetProperty(MacroAssembler* masm,
void StoreIC::GenerateMegamorphic(MacroAssembler* masm) {
if (FLAG_vector_stores) {
// This shouldn't be called.
__ int3();
return;
}
// Return address is on the stack.
Code::Flags flags = Code::RemoveTypeAndHolderFromFlags(
Code::ComputeHandlerFlags(Code::STORE_IC));
@ -787,22 +793,32 @@ void StoreIC::GenerateNormal(MacroAssembler* masm) {
Register receiver = StoreDescriptor::ReceiverRegister();
Register name = StoreDescriptor::NameRegister();
Register value = StoreDescriptor::ValueRegister();
Register dictionary = ebx;
__ mov(dictionary, FieldOperand(receiver, JSObject::kPropertiesOffset));
Register vector = VectorStoreICDescriptor::VectorRegister();
Register slot = VectorStoreICDescriptor::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.
__ push(receiver);
if (FLAG_vector_stores) {
__ push(vector);
__ push(slot);
}
Register dictionary = ebx;
__ mov(dictionary, FieldOperand(receiver, JSObject::kPropertiesOffset));
GenerateDictionaryStore(masm, &restore_miss, dictionary, name, value,
receiver, edi);
__ Drop(1);
__ Drop(FLAG_vector_stores ? 3 : 1);
Counters* counters = masm->isolate()->counters();
__ IncrementCounter(counters->store_normal_hit(), 1);
__ ret(0);
__ bind(&restore_miss);
if (FLAG_vector_stores) {
__ pop(slot);
__ pop(vector);
}
__ pop(receiver);
__ IncrementCounter(counters->store_normal_miss(), 1);
GenerateMiss(masm);

View File

@ -25,6 +25,9 @@ static void ProbeTable(Isolate* isolate, MacroAssembler* masm,
ExternalReference map_offset(isolate->stub_cache()->map_reference(table));
Label miss;
bool is_vector_store =
IC::ICUseVector(ic_kind) &&
(ic_kind == Code::STORE_IC || ic_kind == Code::KEYED_STORE_IC);
// Multiply by 3 because there are 3 fields per entry (name, code, map).
__ lea(offset, Operand(offset, offset, times_2, 0));
@ -56,19 +59,28 @@ static void ProbeTable(Isolate* isolate, MacroAssembler* masm,
}
#endif
if (IC::ICUseVector(ic_kind)) {
// The vector and slot were pushed onto the stack before starting the
// probe, and need to be dropped before calling the handler.
// 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 = VectorStoreICDescriptor::VectorRegister();
DCHECK(extra.is(VectorStoreICDescriptor::SlotRegister()));
__ add(extra, Immediate(Code::kHeaderSize - kHeapObjectTag));
__ pop(vector);
__ xchg(extra, Operand(esp, 0));
// Jump to the first instruction in the code stub.
__ ret(0);
} else {
__ pop(LoadWithVectorDescriptor::VectorRegister());
__ pop(LoadDescriptor::SlotRegister());
__ add(extra, Immediate(Code::kHeaderSize - kHeapObjectTag));
__ jmp(extra);
}
// Jump to the first instruction in the code stub.
__ add(extra, Immediate(Code::kHeaderSize - kHeapObjectTag));
__ jmp(extra);
__ bind(&miss);
} else {
DCHECK(ic_kind == Code::STORE_IC || ic_kind == Code::KEYED_STORE_IC);
// Save the offset on the stack.
__ push(offset);
@ -105,21 +117,21 @@ static void ProbeTable(Isolate* isolate, MacroAssembler* masm,
__ pop(offset);
__ mov(offset, Operand::StaticArray(offset, times_1, value_offset));
if (IC::ICUseVector(ic_kind)) {
// 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 = LoadWithVectorDescriptor::VectorRegister();
Register slot = LoadDescriptor::SlotRegister();
DCHECK(!offset.is(vector) && !offset.is(slot));
Register vector = VectorStoreICDescriptor::VectorRegister();
DCHECK(offset.is(VectorStoreICDescriptor::SlotRegister()));
__ add(offset, Immediate(Code::kHeaderSize - kHeapObjectTag));
__ pop(vector);
__ pop(slot);
__ xchg(offset, Operand(esp, 0));
__ ret(0);
} else {
__ add(offset, Immediate(Code::kHeaderSize - kHeapObjectTag));
__ jmp(offset);
}
// Jump to the first instruction in the code stub.
__ add(offset, Immediate(Code::kHeaderSize - kHeapObjectTag));
__ jmp(offset);
// Pop at miss.
__ bind(&miss);
__ pop(offset);

View File

@ -4269,11 +4269,173 @@ void VectorStoreICStub::GenerateForTrampoline(MacroAssembler* masm) {
}
// value is on the stack already.
static void HandlePolymorphicStoreCase(MacroAssembler* masm, Register receiver,
Register key, Register vector,
Register slot, Register feedback,
Label* miss) {
// feedback initially contains the feedback array
Label next, next_loop, prepare_next;
Label load_smi_map, compare_map;
Label start_polymorphic;
__ push(receiver);
__ push(vector);
Register receiver_map = receiver;
Register cached_map = vector;
// Receiver might not be a heap object.
__ JumpIfSmi(receiver, &load_smi_map);
__ mov(receiver_map, FieldOperand(receiver, 0));
__ bind(&compare_map);
__ mov(cached_map, FieldOperand(feedback, FixedArray::OffsetOfElementAt(0)));
// A named keyed store might have a 2 element array, all other cases can count
// on an array with at least 2 {map, handler} pairs, so they can go right
// into polymorphic array handling.
__ cmp(receiver_map, FieldOperand(cached_map, WeakCell::kValueOffset));
__ j(not_equal, &start_polymorphic);
// found, now call handler.
Register handler = feedback;
DCHECK(handler.is(VectorStoreICDescriptor::ValueRegister()));
__ mov(handler, FieldOperand(feedback, FixedArray::OffsetOfElementAt(1)));
__ pop(vector);
__ pop(receiver);
__ lea(handler, FieldOperand(handler, Code::kHeaderSize));
__ xchg(handler, Operand(esp, 0));
__ ret(0);
// Polymorphic, we have to loop from 2 to N
// TODO(mvstanton): I think there is a bug here, we are assuming the
// array has more than one map/handler pair, but we call this function in the
// keyed store with a string key case, where it might be just an array of two
// elements.
__ bind(&start_polymorphic);
__ push(key);
Register counter = key;
__ mov(counter, Immediate(Smi::FromInt(2)));
__ bind(&next_loop);
__ mov(cached_map, FieldOperand(feedback, counter, times_half_pointer_size,
FixedArray::kHeaderSize));
__ cmp(receiver_map, FieldOperand(cached_map, WeakCell::kValueOffset));
__ j(not_equal, &prepare_next);
__ mov(handler, FieldOperand(feedback, counter, times_half_pointer_size,
FixedArray::kHeaderSize + kPointerSize));
__ pop(key);
__ pop(vector);
__ pop(receiver);
__ lea(handler, FieldOperand(handler, Code::kHeaderSize));
__ xchg(handler, Operand(esp, 0));
__ ret(0);
__ bind(&prepare_next);
__ add(counter, Immediate(Smi::FromInt(2)));
__ cmp(counter, FieldOperand(feedback, FixedArray::kLengthOffset));
__ j(less, &next_loop);
// We exhausted our array of map handler pairs.
__ pop(key);
__ pop(vector);
__ pop(receiver);
__ jmp(miss);
__ bind(&load_smi_map);
__ LoadRoot(receiver_map, Heap::kHeapNumberMapRootIndex);
__ jmp(&compare_map);
}
static void HandleMonomorphicStoreCase(MacroAssembler* masm, Register receiver,
Register key, Register vector,
Register slot, Register weak_cell,
Label* miss) {
// The store ic value is on the stack.
DCHECK(weak_cell.is(VectorStoreICDescriptor::ValueRegister()));
// feedback initially contains the feedback array
Label compare_smi_map;
// Move the weak map into the weak_cell register.
Register ic_map = weak_cell;
__ mov(ic_map, FieldOperand(weak_cell, WeakCell::kValueOffset));
// Receiver might not be a heap object.
__ JumpIfSmi(receiver, &compare_smi_map);
__ cmp(ic_map, FieldOperand(receiver, 0));
__ j(not_equal, miss);
__ 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.
__ xchg(weak_cell, Operand(esp, 0));
// "return" to the handler.
__ ret(0);
// 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.
__ bind(&compare_smi_map);
__ CompareRoot(ic_map, Heap::kHeapNumberMapRootIndex);
__ j(not_equal, miss);
__ 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.
__ xchg(weak_cell, Operand(esp, 0));
// "return" to the handler.
__ ret(0);
}
void VectorStoreICStub::GenerateImpl(MacroAssembler* masm, bool in_frame) {
Register receiver = VectorStoreICDescriptor::ReceiverRegister(); // edx
Register key = VectorStoreICDescriptor::NameRegister(); // ecx
Register value = VectorStoreICDescriptor::ValueRegister(); // eax
Register vector = VectorStoreICDescriptor::VectorRegister(); // ebx
Register slot = VectorStoreICDescriptor::SlotRegister(); // edi
Label miss;
// TODO(mvstanton): Implement.
__ push(value);
Register scratch = value;
__ mov(scratch, FieldOperand(vector, slot, times_half_pointer_size,
FixedArray::kHeaderSize));
// Is it a weak cell?
Label try_array;
Label not_array, smi_key, key_okay;
__ CompareRoot(FieldOperand(scratch, 0), Heap::kWeakCellMapRootIndex);
__ j(not_equal, &try_array);
HandleMonomorphicStoreCase(masm, receiver, key, vector, slot, scratch, &miss);
// Is it a fixed array?
__ bind(&try_array);
__ CompareRoot(FieldOperand(scratch, 0), Heap::kFixedArrayMapRootIndex);
__ j(not_equal, &not_array);
HandlePolymorphicStoreCase(masm, receiver, key, vector, slot, scratch, &miss);
__ bind(&not_array);
__ CompareRoot(scratch, Heap::kmegamorphic_symbolRootIndex);
__ j(not_equal, &miss);
__ pop(value);
__ push(slot);
__ push(vector);
Code::Flags code_flags = Code::RemoveTypeAndHolderFromFlags(
Code::ComputeHandlerFlags(Code::STORE_IC));
masm->isolate()->stub_cache()->GenerateProbe(masm, Code::STORE_IC, code_flags,
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);
}
@ -4288,11 +4450,147 @@ void VectorKeyedStoreICStub::GenerateForTrampoline(MacroAssembler* masm) {
}
static void HandlePolymorphicKeyedStoreCase(MacroAssembler* masm,
Register receiver, Register key,
Register vector, Register slot,
Register feedback, Label* miss) {
// feedback initially contains the feedback array
Label next, next_loop, prepare_next;
Label load_smi_map, compare_map;
Label transition_call;
Label pop_and_miss;
__ push(receiver);
__ push(vector);
Register receiver_map = receiver;
Register cached_map = vector;
// Receiver might not be a heap object.
__ JumpIfSmi(receiver, &load_smi_map);
__ mov(receiver_map, FieldOperand(receiver, 0));
__ bind(&compare_map);
// Polymorphic, we have to loop from 0 to N - 1
__ push(key);
// On the stack we have:
// key (esp)
// vector
// receiver
// value
Register counter = key;
__ mov(counter, Immediate(Smi::FromInt(0)));
__ bind(&next_loop);
__ mov(cached_map, FieldOperand(feedback, counter, times_half_pointer_size,
FixedArray::kHeaderSize));
__ cmp(receiver_map, FieldOperand(cached_map, WeakCell::kValueOffset));
__ j(not_equal, &prepare_next);
__ mov(cached_map, FieldOperand(feedback, counter, times_half_pointer_size,
FixedArray::kHeaderSize + kPointerSize));
__ CompareRoot(cached_map, Heap::kUndefinedValueRootIndex);
__ j(not_equal, &transition_call);
__ 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));
__ xchg(feedback, Operand(esp, 0));
__ ret(0);
__ bind(&transition_call);
// Oh holy hell this will be tough.
// The map goes in vector register.
__ mov(receiver, FieldOperand(cached_map, WeakCell::kValueOffset));
// The weak cell may have been cleared.
__ JumpIfSmi(receiver, &pop_and_miss);
// slot goes on the stack, and holds return address.
__ xchg(slot, Operand(esp, 4 * kPointerSize));
// Get the handler in value.
__ mov(feedback, FieldOperand(feedback, counter, times_half_pointer_size,
FixedArray::kHeaderSize + 2 * kPointerSize));
__ lea(feedback, FieldOperand(feedback, Code::kHeaderSize));
// Pop key into place.
__ pop(key);
// Put the return address on top of stack, vector goes in slot.
__ xchg(slot, Operand(esp, 0));
// put the map on the stack, receiver holds receiver.
__ xchg(receiver, Operand(esp, 1 * kPointerSize));
// put the vector on the stack, slot holds value.
__ xchg(slot, Operand(esp, 2 * kPointerSize));
// feedback (value) = value, slot = handler.
__ xchg(feedback, slot);
__ jmp(slot);
__ bind(&prepare_next);
__ add(counter, Immediate(Smi::FromInt(3)));
__ cmp(counter, FieldOperand(feedback, FixedArray::kLengthOffset));
__ j(less, &next_loop);
// We exhausted our array of map handler pairs.
__ bind(&pop_and_miss);
__ pop(key);
__ pop(vector);
__ pop(receiver);
__ jmp(miss);
__ bind(&load_smi_map);
__ LoadRoot(receiver_map, Heap::kHeapNumberMapRootIndex);
__ jmp(&compare_map);
}
void VectorKeyedStoreICStub::GenerateImpl(MacroAssembler* masm, bool in_frame) {
Register receiver = VectorStoreICDescriptor::ReceiverRegister(); // edx
Register key = VectorStoreICDescriptor::NameRegister(); // ecx
Register value = VectorStoreICDescriptor::ValueRegister(); // eax
Register vector = VectorStoreICDescriptor::VectorRegister(); // ebx
Register slot = VectorStoreICDescriptor::SlotRegister(); // edi
Label miss;
// TODO(mvstanton): Implement.
__ push(value);
Register scratch = value;
__ mov(scratch, FieldOperand(vector, slot, times_half_pointer_size,
FixedArray::kHeaderSize));
// Is it a weak cell?
Label try_array;
Label not_array, smi_key, key_okay;
__ CompareRoot(FieldOperand(scratch, 0), Heap::kWeakCellMapRootIndex);
__ j(not_equal, &try_array);
HandleMonomorphicStoreCase(masm, receiver, key, vector, slot, scratch, &miss);
// Is it a fixed array?
__ bind(&try_array);
__ CompareRoot(FieldOperand(scratch, 0), Heap::kFixedArrayMapRootIndex);
__ j(not_equal, &not_array);
HandlePolymorphicKeyedStoreCase(masm, receiver, key, vector, slot, scratch,
&miss);
__ bind(&not_array);
Label try_poly_name;
__ 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);
__ bind(&try_poly_name);
// We might have a name in feedback, and a fixed array in the next slot.
__ cmp(key, scratch);
__ j(not_equal, &miss);
// If the name comparison succeeded, we know we have a fixed array with
// at least one map/handler pair.
__ mov(scratch, FieldOperand(vector, slot, times_half_pointer_size,
FixedArray::kHeaderSize + kPointerSize));
HandlePolymorphicStoreCase(masm, receiver, key, vector, slot, scratch, &miss);
__ bind(&miss);
__ pop(value);
KeyedStoreIC::GenerateMiss(masm);
}