Use platform specific stubs for vector-based Load/KeyedLoad.
authormvstanton <mvstanton@chromium.org>
Tue, 17 Mar 2015 11:28:09 +0000 (04:28 -0700)
committerCommit bot <commit-bot@chromium.org>
Tue, 17 Mar 2015 11:28:21 +0000 (11:28 +0000)
A hydrogen code stub is not the best approach because it builds a frame
and doesn't have the technology to discard roots at tail call exits.
Platform-specific stubs provide much better performance at this point.

R=verwaest@chromium.org

BUG=

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

Cr-Commit-Position: refs/heads/master@{#27235}

13 files changed:
src/arm/code-stubs-arm.cc
src/arm64/code-stubs-arm64.cc
src/code-stubs-hydrogen.cc
src/code-stubs.cc
src/code-stubs.h
src/ia32/code-stubs-ia32.cc
src/ic/ic.cc
src/mips/code-stubs-mips.cc
src/mips64/code-stubs-mips64.cc
src/type-feedback-vector.cc
src/type-feedback-vector.h
src/x64/code-stubs-x64.cc
test/cctest/test-feedback-vector.cc

index 7a4923d0d9545767328434864fcb26d088bc9ba2..8cc87ef0711aa223e37508f2fb51757f1af821b8 100644 (file)
@@ -12,6 +12,7 @@
 #include "src/codegen.h"
 #include "src/ic/handler-compiler.h"
 #include "src/ic/ic.h"
+#include "src/ic/stub-cache.h"
 #include "src/isolate.h"
 #include "src/jsregexp.h"
 #include "src/regexp-macro-assembler.h"
@@ -4323,15 +4324,15 @@ void StubFailureTrampolineStub::Generate(MacroAssembler* masm) {
 
 void LoadICTrampolineStub::Generate(MacroAssembler* masm) {
   EmitLoadTypeFeedbackVector(masm, VectorLoadICDescriptor::VectorRegister());
-  VectorLoadStub stub(isolate(), state());
-  __ Jump(stub.GetCode(), RelocInfo::CODE_TARGET);
+  VectorRawLoadStub stub(isolate(), state());
+  stub.GenerateForTrampoline(masm);
 }
 
 
 void KeyedLoadICTrampolineStub::Generate(MacroAssembler* masm) {
   EmitLoadTypeFeedbackVector(masm, VectorLoadICDescriptor::VectorRegister());
-  VectorKeyedLoadStub stub(isolate());
-  __ Jump(stub.GetCode(), RelocInfo::CODE_TARGET);
+  VectorRawKeyedLoadStub stub(isolate());
+  stub.GenerateForTrampoline(masm);
 }
 
 
@@ -4349,6 +4350,239 @@ void CallIC_ArrayTrampolineStub::Generate(MacroAssembler* masm) {
 }
 
 
+void VectorRawLoadStub::Generate(MacroAssembler* masm) {
+  GenerateImpl(masm, false);
+}
+
+
+void VectorRawLoadStub::GenerateForTrampoline(MacroAssembler* masm) {
+  GenerateImpl(masm, true);
+}
+
+
+static void HandleArrayCases(MacroAssembler* masm, Register receiver,
+                             Register key, Register vector, Register slot,
+                             Register feedback, Register scratch1,
+                             Register scratch2, Register scratch3,
+                             bool is_polymorphic, Label* miss) {
+  // feedback initially contains the feedback array
+  Label next_loop, prepare_next;
+  Label load_smi_map, compare_map;
+  Label start_polymorphic;
+
+  Register receiver_map = scratch1;
+  Register cached_map = scratch2;
+
+  // Receiver might not be a heap object.
+  __ JumpIfSmi(receiver, &load_smi_map);
+  __ ldr(receiver_map, FieldMemOperand(receiver, HeapObject::kMapOffset));
+  __ bind(&compare_map);
+  __ ldr(cached_map,
+         FieldMemOperand(feedback, FixedArray::OffsetOfElementAt(0)));
+  __ ldr(cached_map, FieldMemOperand(cached_map, WeakCell::kValueOffset));
+  __ cmp(receiver_map, cached_map);
+  __ b(ne, &start_polymorphic);
+  // found, now call handler.
+  Register handler = feedback;
+  __ ldr(handler, FieldMemOperand(feedback, FixedArray::OffsetOfElementAt(1)));
+  __ add(pc, handler, Operand(Code::kHeaderSize - kHeapObjectTag));
+
+
+  Register length = scratch3;
+  __ bind(&start_polymorphic);
+  __ ldr(length, FieldMemOperand(feedback, FixedArray::kLengthOffset));
+  if (!is_polymorphic) {
+    // If the IC could be monomorphic we have to make sure we don't go past the
+    // end of the feedback array.
+    __ cmp(length, Operand(Smi::FromInt(2)));
+    __ b(eq, miss);
+  }
+
+  Register too_far = length;
+  Register pointer_reg = feedback;
+
+  // +-----+------+------+-----+-----+ ... ----+
+  // | map | len  | wm0  | h0  | wm1 |      hN |
+  // +-----+------+------+-----+-----+ ... ----+
+  //                 0      1     2        len-1
+  //                              ^              ^
+  //                              |              |
+  //                         pointer_reg      too_far
+  //                         aka feedback     scratch3
+  // also need receiver_map (aka scratch1)
+  // use cached_map (scratch2) to look in the weak map values.
+  __ add(too_far, feedback, Operand::PointerOffsetFromSmiKey(length));
+  __ add(too_far, too_far, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
+  __ add(pointer_reg, feedback,
+         Operand(FixedArray::OffsetOfElementAt(2) - kHeapObjectTag));
+
+  __ bind(&next_loop);
+  __ ldr(cached_map, MemOperand(pointer_reg));
+  __ ldr(cached_map, FieldMemOperand(cached_map, WeakCell::kValueOffset));
+  __ cmp(receiver_map, cached_map);
+  __ b(ne, &prepare_next);
+  __ ldr(handler, MemOperand(pointer_reg, kPointerSize));
+  __ add(pc, handler, Operand(Code::kHeaderSize - kHeapObjectTag));
+
+  __ bind(&prepare_next);
+  __ add(pointer_reg, pointer_reg, Operand(kPointerSize * 2));
+  __ cmp(pointer_reg, too_far);
+  __ b(lt, &next_loop);
+
+  // We exhausted our array of map handler pairs.
+  __ jmp(miss);
+
+  __ bind(&load_smi_map);
+  __ LoadRoot(receiver_map, Heap::kHeapNumberMapRootIndex);
+  __ jmp(&compare_map);
+}
+
+
+static void HandleMonomorphicCase(MacroAssembler* masm, Register receiver,
+                                  Register key, Register vector, Register slot,
+                                  Register weak_cell, Register scratch,
+                                  Label* miss) {
+  // feedback initially contains the feedback array
+  Label compare_smi_map;
+  Register receiver_map = scratch;
+  Register cached_map = weak_cell;
+
+  // Move the weak map into the weak_cell register.
+  __ ldr(cached_map, FieldMemOperand(weak_cell, WeakCell::kValueOffset));
+
+  // Receiver might not be a heap object.
+  __ JumpIfSmi(receiver, &compare_smi_map);
+  __ ldr(receiver_map, FieldMemOperand(receiver, HeapObject::kMapOffset));
+  __ cmp(cached_map, receiver_map);
+  __ b(ne, miss);
+
+  Register handler = weak_cell;
+  __ add(handler, vector, Operand::PointerOffsetFromSmiKey(slot));
+  __ ldr(handler,
+         FieldMemOperand(handler, FixedArray::kHeaderSize + kPointerSize));
+  __ add(pc, handler, Operand(Code::kHeaderSize - kHeapObjectTag));
+
+  // 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(weak_cell, Heap::kHeapNumberMapRootIndex);
+  __ b(ne, miss);
+  __ add(handler, vector, Operand::PointerOffsetFromSmiKey(slot));
+  __ ldr(handler,
+         FieldMemOperand(handler, FixedArray::kHeaderSize + kPointerSize));
+  __ add(pc, handler, Operand(Code::kHeaderSize - kHeapObjectTag));
+}
+
+
+void VectorRawLoadStub::GenerateImpl(MacroAssembler* masm, bool in_frame) {
+  Register receiver = VectorLoadICDescriptor::ReceiverRegister();  // r1
+  Register name = VectorLoadICDescriptor::NameRegister();          // r2
+  Register vector = VectorLoadICDescriptor::VectorRegister();      // r3
+  Register slot = VectorLoadICDescriptor::SlotRegister();          // r0
+  Register feedback = r4;
+  Register scratch1 = r5;
+
+  __ add(feedback, vector, Operand::PointerOffsetFromSmiKey(slot));
+  __ ldr(feedback, FieldMemOperand(feedback, FixedArray::kHeaderSize));
+
+  // Is it a weak cell?
+  Label try_array;
+  Label not_array, smi_key, key_okay, miss;
+  __ ldr(scratch1, FieldMemOperand(feedback, HeapObject::kMapOffset));
+  __ CompareRoot(scratch1, Heap::kWeakCellMapRootIndex);
+  __ b(ne, &try_array);
+  HandleMonomorphicCase(masm, receiver, name, vector, slot, feedback, scratch1,
+                        &miss);
+
+  // Is it a fixed array?
+  __ bind(&try_array);
+  __ CompareRoot(scratch1, Heap::kFixedArrayMapRootIndex);
+  __ b(ne, &not_array);
+  HandleArrayCases(masm, receiver, name, vector, slot, feedback, scratch1, r8,
+                   r9, true, &miss);
+
+  __ bind(&not_array);
+  __ CompareRoot(feedback, Heap::kmegamorphic_symbolRootIndex);
+  __ b(ne, &miss);
+  Code::Flags code_flags = Code::RemoveTypeAndHolderFromFlags(
+      Code::ComputeHandlerFlags(Code::LOAD_IC));
+  masm->isolate()->stub_cache()->GenerateProbe(masm, Code::LOAD_IC, code_flags,
+                                               false, receiver, name, feedback,
+                                               scratch1, r8, r9);
+
+  __ bind(&miss);
+  LoadIC::GenerateMiss(masm);
+}
+
+
+void VectorRawKeyedLoadStub::Generate(MacroAssembler* masm) {
+  GenerateImpl(masm, false);
+}
+
+
+void VectorRawKeyedLoadStub::GenerateForTrampoline(MacroAssembler* masm) {
+  GenerateImpl(masm, true);
+}
+
+
+void VectorRawKeyedLoadStub::GenerateImpl(MacroAssembler* masm, bool in_frame) {
+  Register receiver = VectorLoadICDescriptor::ReceiverRegister();  // r1
+  Register key = VectorLoadICDescriptor::NameRegister();           // r2
+  Register vector = VectorLoadICDescriptor::VectorRegister();      // r3
+  Register slot = VectorLoadICDescriptor::SlotRegister();          // r0
+  Register feedback = r4;
+  Register scratch1 = r5;
+
+  __ add(feedback, vector, Operand::PointerOffsetFromSmiKey(slot));
+  __ ldr(feedback, FieldMemOperand(feedback, FixedArray::kHeaderSize));
+
+  // Is it a weak cell?
+  Label try_array;
+  Label not_array, smi_key, key_okay, miss;
+  __ ldr(scratch1, FieldMemOperand(feedback, HeapObject::kMapOffset));
+  __ CompareRoot(scratch1, Heap::kWeakCellMapRootIndex);
+  __ b(ne, &try_array);
+  __ JumpIfNotSmi(key, &miss);
+  HandleMonomorphicCase(masm, receiver, key, vector, slot, feedback, scratch1,
+                        &miss);
+
+  __ bind(&try_array);
+  // Is it a fixed array?
+  __ CompareRoot(scratch1, Heap::kFixedArrayMapRootIndex);
+  __ b(ne, &not_array);
+  // We have a polymorphic element handler.
+  __ JumpIfNotSmi(key, &miss);
+
+  Label polymorphic, try_poly_name;
+  __ bind(&polymorphic);
+  HandleArrayCases(masm, receiver, key, vector, slot, feedback, scratch1, r8,
+                   r9, true, &miss);
+
+  __ bind(&not_array);
+  // Is it generic?
+  __ CompareRoot(feedback, Heap::kmegamorphic_symbolRootIndex);
+  __ b(ne, &try_poly_name);
+  Handle<Code> megamorphic_stub =
+      KeyedLoadIC::ChooseMegamorphicStub(masm->isolate());
+  __ Jump(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, feedback);
+  __ b(ne, &miss);
+  // If the name comparison succeeded, we know we have a fixed array with
+  // at least one map/handler pair.
+  __ add(feedback, vector, Operand::PointerOffsetFromSmiKey(slot));
+  __ ldr(feedback,
+         FieldMemOperand(feedback, FixedArray::kHeaderSize + kPointerSize));
+  HandleArrayCases(masm, receiver, key, vector, slot, feedback, scratch1, r8,
+                   r9, false, &miss);
+
+  __ bind(&miss);
+  KeyedLoadIC::GenerateMiss(masm);
+}
+
+
 void ProfileEntryHookStub::MaybeCallEntryHook(MacroAssembler* masm) {
   if (masm->isolate()->function_entry_hook() != NULL) {
     ProfileEntryHookStub stub(masm->isolate());
index a92e1431886b22d52e5bdb64df58572f3f5a863d..cc499d18442dc8cf0b8db531aa3f38be5676ea7a 100644 (file)
@@ -11,6 +11,7 @@
 #include "src/codegen.h"
 #include "src/ic/handler-compiler.h"
 #include "src/ic/ic.h"
+#include "src/ic/stub-cache.h"
 #include "src/isolate.h"
 #include "src/jsregexp.h"
 #include "src/regexp-macro-assembler.h"
@@ -4451,15 +4452,15 @@ void StubFailureTrampolineStub::Generate(MacroAssembler* masm) {
 
 void LoadICTrampolineStub::Generate(MacroAssembler* masm) {
   EmitLoadTypeFeedbackVector(masm, VectorLoadICDescriptor::VectorRegister());
-  VectorLoadStub stub(isolate(), state());
-  __ Jump(stub.GetCode(), RelocInfo::CODE_TARGET);
+  VectorRawLoadStub stub(isolate(), state());
+  stub.GenerateForTrampoline(masm);
 }
 
 
 void KeyedLoadICTrampolineStub::Generate(MacroAssembler* masm) {
   EmitLoadTypeFeedbackVector(masm, VectorLoadICDescriptor::VectorRegister());
-  VectorKeyedLoadStub stub(isolate());
-  __ Jump(stub.GetCode(), RelocInfo::CODE_TARGET);
+  VectorRawKeyedLoadStub stub(isolate());
+  stub.GenerateForTrampoline(masm);
 }
 
 
@@ -4477,6 +4478,236 @@ void CallIC_ArrayTrampolineStub::Generate(MacroAssembler* masm) {
 }
 
 
+void VectorRawLoadStub::Generate(MacroAssembler* masm) {
+  GenerateImpl(masm, false);
+}
+
+
+void VectorRawLoadStub::GenerateForTrampoline(MacroAssembler* masm) {
+  GenerateImpl(masm, true);
+}
+
+
+static void HandleArrayCases(MacroAssembler* masm, Register receiver,
+                             Register key, Register vector, Register slot,
+                             Register feedback, Register scratch1,
+                             Register scratch2, Register scratch3,
+                             bool is_polymorphic, Label* miss) {
+  // feedback initially contains the feedback array
+  Label next_loop, prepare_next;
+  Label load_smi_map, compare_map;
+  Label start_polymorphic;
+
+  Register receiver_map = scratch1;
+  Register cached_map = scratch2;
+
+  // Receiver might not be a heap object.
+  __ JumpIfSmi(receiver, &load_smi_map);
+  __ Ldr(receiver_map, FieldMemOperand(receiver, HeapObject::kMapOffset));
+  __ Bind(&compare_map);
+  __ Ldr(cached_map,
+         FieldMemOperand(feedback, FixedArray::OffsetOfElementAt(0)));
+  __ Ldr(cached_map, FieldMemOperand(cached_map, WeakCell::kValueOffset));
+  __ Cmp(receiver_map, cached_map);
+  __ B(ne, &start_polymorphic);
+  // found, now call handler.
+  Register handler = feedback;
+  __ Ldr(handler, FieldMemOperand(feedback, FixedArray::OffsetOfElementAt(1)));
+  __ Add(handler, handler, Code::kHeaderSize - kHeapObjectTag);
+  __ Jump(feedback);
+
+  Register length = scratch3;
+  __ Bind(&start_polymorphic);
+  __ Ldr(length, FieldMemOperand(feedback, FixedArray::kLengthOffset));
+  if (!is_polymorphic) {
+    __ Cmp(length, Operand(Smi::FromInt(2)));
+    __ B(eq, miss);
+  }
+
+  Register too_far = length;
+  Register pointer_reg = feedback;
+
+  // +-----+------+------+-----+-----+ ... ----+
+  // | map | len  | wm0  | h0  | wm1 |      hN |
+  // +-----+------+------+-----+-----+ ... ----+
+  //                 0      1     2        len-1
+  //                              ^              ^
+  //                              |              |
+  //                         pointer_reg      too_far
+  //                         aka feedback     scratch3
+  // also need receiver_map (aka scratch1)
+  // use cached_map (scratch2) to look in the weak map values.
+  __ Add(too_far, feedback,
+         Operand::UntagSmiAndScale(length, kPointerSizeLog2));
+  __ Add(too_far, too_far, FixedArray::kHeaderSize - kHeapObjectTag);
+  __ Add(pointer_reg, feedback,
+         FixedArray::OffsetOfElementAt(2) - kHeapObjectTag);
+
+  __ Bind(&next_loop);
+  __ Ldr(cached_map, MemOperand(pointer_reg));
+  __ Ldr(cached_map, FieldMemOperand(cached_map, WeakCell::kValueOffset));
+  __ Cmp(receiver_map, cached_map);
+  __ B(ne, &prepare_next);
+  __ Ldr(handler, MemOperand(pointer_reg, kPointerSize));
+  __ Add(handler, handler, Code::kHeaderSize - kHeapObjectTag);
+  __ Jump(handler);
+
+  __ Bind(&prepare_next);
+  __ Add(pointer_reg, pointer_reg, kPointerSize * 2);
+  __ Cmp(pointer_reg, too_far);
+  __ B(lt, &next_loop);
+
+  // We exhausted our array of map handler pairs.
+  __ jmp(miss);
+
+  __ Bind(&load_smi_map);
+  __ LoadRoot(receiver_map, Heap::kHeapNumberMapRootIndex);
+  __ jmp(&compare_map);
+}
+
+
+static void HandleMonomorphicCase(MacroAssembler* masm, Register receiver,
+                                  Register key, Register vector, Register slot,
+                                  Register weak_cell, Register scratch,
+                                  Label* miss) {
+  // feedback initially contains the feedback array
+  Label compare_smi_map;
+  Register receiver_map = scratch;
+  Register cached_map = weak_cell;
+
+  // Move the weak map into the weak_cell register.
+  __ Ldr(cached_map, FieldMemOperand(weak_cell, WeakCell::kValueOffset));
+
+  // Receiver might not be a heap object.
+  __ JumpIfSmi(receiver, &compare_smi_map);
+  __ Ldr(receiver_map, FieldMemOperand(receiver, HeapObject::kMapOffset));
+  __ Cmp(cached_map, receiver_map);
+  __ B(ne, miss);
+
+  Register handler = weak_cell;
+  __ Add(handler, vector, Operand::UntagSmiAndScale(slot, kPointerSizeLog2));
+  __ Ldr(handler,
+         FieldMemOperand(handler, FixedArray::kHeaderSize + kPointerSize));
+  __ Add(handler, handler, Code::kHeaderSize - kHeapObjectTag);
+  __ Jump(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.
+  // TODO(mvstanton): does this hold on ARM?
+  __ Bind(&compare_smi_map);
+  __ JumpIfNotRoot(weak_cell, Heap::kHeapNumberMapRootIndex, miss);
+  __ Add(handler, vector, Operand::UntagSmiAndScale(slot, kPointerSizeLog2));
+  __ Ldr(handler,
+         FieldMemOperand(handler, FixedArray::kHeaderSize + kPointerSize));
+  __ Add(handler, handler, Code::kHeaderSize - kHeapObjectTag);
+  __ Jump(handler);
+}
+
+
+void VectorRawLoadStub::GenerateImpl(MacroAssembler* masm, bool in_frame) {
+  Register receiver = VectorLoadICDescriptor::ReceiverRegister();  // x1
+  Register name = VectorLoadICDescriptor::NameRegister();          // x2
+  Register vector = VectorLoadICDescriptor::VectorRegister();      // x3
+  Register slot = VectorLoadICDescriptor::SlotRegister();          // x0
+  Register feedback = x4;
+  Register scratch1 = x5;
+
+  __ Add(feedback, vector, Operand::UntagSmiAndScale(slot, kPointerSizeLog2));
+  __ Ldr(feedback, FieldMemOperand(feedback, FixedArray::kHeaderSize));
+
+  // Is it a weak cell?
+  Label try_array;
+  Label not_array, smi_key, key_okay, miss;
+  __ Ldr(scratch1, FieldMemOperand(feedback, HeapObject::kMapOffset));
+  __ JumpIfNotRoot(scratch1, Heap::kWeakCellMapRootIndex, &try_array);
+  HandleMonomorphicCase(masm, receiver, name, vector, slot, feedback, scratch1,
+                        &miss);
+
+  // Is it a fixed array?
+  __ Bind(&try_array);
+  __ JumpIfNotRoot(scratch1, Heap::kFixedArrayMapRootIndex, &not_array);
+  HandleArrayCases(masm, receiver, name, vector, slot, feedback, scratch1, x6,
+                   x7, true, &miss);
+
+  __ Bind(&not_array);
+  __ JumpIfNotRoot(feedback, Heap::kmegamorphic_symbolRootIndex, &miss);
+  Code::Flags code_flags = Code::RemoveTypeAndHolderFromFlags(
+      Code::ComputeHandlerFlags(Code::LOAD_IC));
+  masm->isolate()->stub_cache()->GenerateProbe(masm, Code::LOAD_IC, code_flags,
+                                               false, receiver, name, feedback,
+                                               scratch1, x6, x7);
+
+  __ Bind(&miss);
+  LoadIC::GenerateMiss(masm);
+}
+
+
+void VectorRawKeyedLoadStub::Generate(MacroAssembler* masm) {
+  GenerateImpl(masm, false);
+}
+
+
+void VectorRawKeyedLoadStub::GenerateForTrampoline(MacroAssembler* masm) {
+  GenerateImpl(masm, true);
+}
+
+
+void VectorRawKeyedLoadStub::GenerateImpl(MacroAssembler* masm, bool in_frame) {
+  Register receiver = VectorLoadICDescriptor::ReceiverRegister();  // x1
+  Register key = VectorLoadICDescriptor::NameRegister();           // x2
+  Register vector = VectorLoadICDescriptor::VectorRegister();      // x3
+  Register slot = VectorLoadICDescriptor::SlotRegister();          // x0
+  Register feedback = x4;
+  Register scratch1 = x5;
+
+  __ Add(feedback, vector, Operand::UntagSmiAndScale(slot, kPointerSizeLog2));
+  __ Ldr(feedback, FieldMemOperand(feedback, FixedArray::kHeaderSize));
+
+  // Is it a weak cell?
+  Label try_array;
+  Label not_array, smi_key, key_okay, miss;
+  __ Ldr(scratch1, FieldMemOperand(feedback, HeapObject::kMapOffset));
+  __ JumpIfNotRoot(scratch1, Heap::kWeakCellMapRootIndex, &try_array);
+  __ JumpIfNotSmi(key, &miss);
+  HandleMonomorphicCase(masm, receiver, key, vector, slot, feedback, scratch1,
+                        &miss);
+
+  __ Bind(&try_array);
+  // Is it a fixed array?
+  __ JumpIfNotRoot(scratch1, Heap::kFixedArrayMapRootIndex, &not_array);
+  // We have a polymorphic element handler.
+  __ JumpIfNotSmi(key, &miss);
+
+  Label polymorphic, try_poly_name;
+  __ Bind(&polymorphic);
+  HandleArrayCases(masm, receiver, key, vector, slot, feedback, scratch1, x6,
+                   x7, true, &miss);
+
+  __ Bind(&not_array);
+  // Is it generic?
+  __ JumpIfNotRoot(feedback, Heap::kmegamorphic_symbolRootIndex,
+                   &try_poly_name);
+  Handle<Code> megamorphic_stub =
+      KeyedLoadIC::ChooseMegamorphicStub(masm->isolate());
+  __ Jump(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, feedback);
+  __ B(ne, &miss);
+  // If the name comparison succeeded, we know we have a fixed array with
+  // at least one map/handler pair.
+  __ Add(feedback, vector, Operand::UntagSmiAndScale(slot, kPointerSizeLog2));
+  __ Ldr(feedback,
+         FieldMemOperand(feedback, FixedArray::kHeaderSize + kPointerSize));
+  HandleArrayCases(masm, receiver, key, vector, slot, feedback, scratch1, x6,
+                   x7, false, &miss);
+
+  __ Bind(&miss);
+  KeyedLoadIC::GenerateMiss(masm);
+}
+
+
 // The entry hook is a "BumpSystemStackPointer" instruction (sub), followed by
 // a "Push lr" instruction, followed by a call.
 static const unsigned int kProfileEntryHookCallSize =
index f776abc043cb8d7e8f4c26f4ad4365819df2f5c8..95fa2a2e15df55c97f6292022240b97b5c8ac6ef 100644 (file)
@@ -100,21 +100,6 @@ class CodeStubGraphBuilderBase : public HGraphBuilder {
                                         HValue* shared_info,
                                         HValue* native_context);
 
-  // Tail calls handler found at array[map_index + 1].
-  void TailCallHandler(HValue* receiver, HValue* name, HValue* array,
-                       HValue* map_index, HValue* slot, HValue* vector);
-
-  // Tail calls handler_code.
-  void TailCallHandler(HValue* receiver, HValue* name, HValue* slot,
-                       HValue* vector, HValue* handler_code);
-
-  void TailCallMiss(HValue* receiver, HValue* name, HValue* slot,
-                    HValue* vector, bool keyed_load);
-
-  // Handle MONOMORPHIC and POLYMORPHIC LoadIC and KeyedLoadIC cases.
-  void HandleArrayCases(HValue* array, HValue* receiver, HValue* name,
-                        HValue* slot, HValue* vector, bool keyed_load);
-
  private:
   HValue* BuildArraySingleArgumentConstructor(JSArrayBuilder* builder);
   HValue* BuildArrayNArgumentsConstructor(JSArrayBuilder* builder,
@@ -2029,211 +2014,6 @@ Handle<Code> KeyedLoadGenericStub::GenerateCode() {
 }
 
 
-void CodeStubGraphBuilderBase::TailCallHandler(HValue* receiver, HValue* name,
-                                               HValue* array, HValue* map_index,
-                                               HValue* slot, HValue* vector) {
-  // The handler is at array[map_index + 1]. Compute this with a custom offset
-  // to HLoadKeyed.
-  int offset =
-      GetDefaultHeaderSizeForElementsKind(FAST_ELEMENTS) + kPointerSize;
-  HValue* handler_code = Add<HLoadKeyed>(
-      array, map_index, nullptr, FAST_ELEMENTS, NEVER_RETURN_HOLE, offset);
-  TailCallHandler(receiver, name, slot, vector, handler_code);
-}
-
-
-void CodeStubGraphBuilderBase::TailCallHandler(HValue* receiver, HValue* name,
-                                               HValue* slot, HValue* vector,
-                                               HValue* handler_code) {
-  VectorLoadICDescriptor descriptor(isolate());
-  HValue* op_vals[] = {context(), receiver, name, slot, vector};
-  Add<HCallWithDescriptor>(handler_code, 0, descriptor,
-                           Vector<HValue*>(op_vals, 5), TAIL_CALL);
-  // We never return here, it is a tail call.
-}
-
-
-void CodeStubGraphBuilderBase::TailCallMiss(HValue* receiver, HValue* name,
-                                            HValue* slot, HValue* vector,
-                                            bool keyed_load) {
-  DCHECK(FLAG_vector_ics);
-  Add<HTailCallThroughMegamorphicCache>(
-      receiver, name, slot, vector,
-      HTailCallThroughMegamorphicCache::ComputeFlags(keyed_load, true));
-  // We never return here, it is a tail call.
-}
-
-
-void CodeStubGraphBuilderBase::HandleArrayCases(HValue* array, HValue* receiver,
-                                                HValue* name, HValue* slot,
-                                                HValue* vector,
-                                                bool keyed_load) {
-  HConstant* constant_two = Add<HConstant>(2);
-  HConstant* constant_three = Add<HConstant>(3);
-
-  IfBuilder if_receiver_heap_object(this);
-  if_receiver_heap_object.IfNot<HIsSmiAndBranch>(receiver);
-  if_receiver_heap_object.Then();
-  Push(AddLoadMap(receiver, nullptr));
-  if_receiver_heap_object.Else();
-  HConstant* heap_number_map =
-      Add<HConstant>(isolate()->factory()->heap_number_map());
-  Push(heap_number_map);
-  if_receiver_heap_object.End();
-  HValue* receiver_map = Pop();
-
-  HValue* start =
-      keyed_load ? graph()->GetConstant1() : graph()->GetConstant0();
-  HValue* weak_cell =
-      Add<HLoadKeyed>(array, start, nullptr, FAST_ELEMENTS, ALLOW_RETURN_HOLE);
-  // Load the weak cell value. It may be Smi(0), or a map. Compare nonetheless
-  // against the receiver_map.
-  HValue* array_map = Add<HLoadNamedField>(weak_cell, nullptr,
-                                           HObjectAccess::ForWeakCellValue());
-
-  IfBuilder if_correct_map(this);
-  if_correct_map.If<HCompareObjectEqAndBranch>(receiver_map, array_map);
-  if_correct_map.Then();
-  { TailCallHandler(receiver, name, array, start, slot, vector); }
-  if_correct_map.Else();
-  {
-    // If our array has more elements, the ic is polymorphic. Look for the
-    // receiver map in the rest of the array.
-    HValue* length = AddLoadFixedArrayLength(array, nullptr);
-    LoopBuilder builder(this, context(), LoopBuilder::kPostIncrement,
-                        constant_two);
-    start = keyed_load ? constant_three : constant_two;
-    HValue* key = builder.BeginBody(start, length, Token::LT);
-    {
-      HValue* weak_cell = Add<HLoadKeyed>(array, key, nullptr, FAST_ELEMENTS,
-                                          ALLOW_RETURN_HOLE);
-      HValue* array_map = Add<HLoadNamedField>(
-          weak_cell, nullptr, HObjectAccess::ForWeakCellValue());
-      IfBuilder if_correct_poly_map(this);
-      if_correct_poly_map.If<HCompareObjectEqAndBranch>(receiver_map,
-                                                        array_map);
-      if_correct_poly_map.Then();
-      { TailCallHandler(receiver, name, array, key, slot, vector); }
-    }
-    builder.EndBody();
-  }
-  if_correct_map.End();
-}
-
-
-template <>
-HValue* CodeStubGraphBuilder<VectorLoadStub>::BuildCodeStub() {
-  HValue* receiver = GetParameter(VectorLoadICDescriptor::kReceiverIndex);
-  HValue* name = GetParameter(VectorLoadICDescriptor::kNameIndex);
-  HValue* slot = GetParameter(VectorLoadICDescriptor::kSlotIndex);
-  HValue* vector = GetParameter(VectorLoadICDescriptor::kVectorIndex);
-
-  // If the feedback is an array, then the IC is in the monomorphic or
-  // polymorphic state.
-  HValue* feedback =
-      Add<HLoadKeyed>(vector, slot, nullptr, FAST_ELEMENTS, ALLOW_RETURN_HOLE);
-  IfBuilder array_checker(this);
-  array_checker.If<HCompareMap>(feedback,
-                                isolate()->factory()->fixed_array_map());
-  array_checker.Then();
-  { HandleArrayCases(feedback, receiver, name, slot, vector, false); }
-  array_checker.Else();
-  {
-    // Is the IC megamorphic?
-    IfBuilder mega_checker(this);
-    HConstant* megamorphic_symbol =
-        Add<HConstant>(isolate()->factory()->megamorphic_symbol());
-    mega_checker.If<HCompareObjectEqAndBranch>(feedback, megamorphic_symbol);
-    mega_checker.Then();
-    {
-      // Probe the stub cache.
-      Add<HTailCallThroughMegamorphicCache>(
-          receiver, name, slot, vector,
-          HTailCallThroughMegamorphicCache::ComputeFlags(false, false));
-    }
-    mega_checker.End();
-  }
-  array_checker.End();
-
-  TailCallMiss(receiver, name, slot, vector, false);
-  return graph()->GetConstant0();
-}
-
-
-Handle<Code> VectorLoadStub::GenerateCode() { return DoGenerateCode(this); }
-
-
-template <>
-HValue* CodeStubGraphBuilder<VectorKeyedLoadStub>::BuildCodeStub() {
-  HValue* receiver = GetParameter(VectorLoadICDescriptor::kReceiverIndex);
-  HValue* name = GetParameter(VectorLoadICDescriptor::kNameIndex);
-  HValue* slot = GetParameter(VectorLoadICDescriptor::kSlotIndex);
-  HValue* vector = GetParameter(VectorLoadICDescriptor::kVectorIndex);
-  HConstant* zero = graph()->GetConstant0();
-
-  // If the feedback is an array, then the IC is in the monomorphic or
-  // polymorphic state.
-  HValue* feedback =
-      Add<HLoadKeyed>(vector, slot, nullptr, FAST_ELEMENTS, ALLOW_RETURN_HOLE);
-  IfBuilder array_checker(this);
-  array_checker.If<HCompareMap>(feedback,
-                                isolate()->factory()->fixed_array_map());
-  array_checker.Then();
-  {
-    // If feedback[0] is 0, then the IC has element handlers and name should be
-    // a smi. If feedback[0] is a string, verify that it matches name.
-    HValue* recorded_name = Add<HLoadKeyed>(feedback, zero, nullptr,
-                                            FAST_ELEMENTS, ALLOW_RETURN_HOLE);
-
-    IfBuilder recorded_name_is_zero(this);
-    recorded_name_is_zero.If<HCompareObjectEqAndBranch>(recorded_name, zero);
-    recorded_name_is_zero.Then();
-    { Add<HCheckSmi>(name); }
-    recorded_name_is_zero.Else();
-    {
-      IfBuilder strings_match(this);
-      strings_match.IfNot<HCompareObjectEqAndBranch>(name, recorded_name);
-      strings_match.Then();
-      TailCallMiss(receiver, name, slot, vector, true);
-      strings_match.End();
-    }
-    recorded_name_is_zero.End();
-
-    HandleArrayCases(feedback, receiver, name, slot, vector, true);
-  }
-  array_checker.Else();
-  {
-    // Check if the IC is in megamorphic state.
-    IfBuilder megamorphic_checker(this);
-    HConstant* megamorphic_symbol =
-        Add<HConstant>(isolate()->factory()->megamorphic_symbol());
-    megamorphic_checker.If<HCompareObjectEqAndBranch>(feedback,
-                                                      megamorphic_symbol);
-    megamorphic_checker.Then();
-    {
-      // Tail-call to the megamorphic KeyedLoadIC, treating it like a handler.
-      Handle<Code> stub = KeyedLoadIC::ChooseMegamorphicStub(isolate());
-      HValue* constant_stub = Add<HConstant>(stub);
-      LoadDescriptor descriptor(isolate());
-      HValue* op_vals[] = {context(), receiver, name};
-      Add<HCallWithDescriptor>(constant_stub, 0, descriptor,
-                               Vector<HValue*>(op_vals, 3), TAIL_CALL);
-      // We never return here, it is a tail call.
-    }
-    megamorphic_checker.End();
-  }
-  array_checker.End();
-
-  TailCallMiss(receiver, name, slot, vector, true);
-  return zero;
-}
-
-
-Handle<Code> VectorKeyedLoadStub::GenerateCode() {
-  return DoGenerateCode(this);
-}
-
-
 Handle<Code> MegamorphicLoadStub::GenerateCode() {
   return DoGenerateCode(this);
 }
index 0d32028aa74e7cd7c3deef8e4b5ef8c4641e2000..f600cf316d7f2d999eb52f9f1d2e420035c4ffdd 100644 (file)
@@ -620,26 +620,6 @@ CallInterfaceDescriptor StoreTransitionStub::GetCallInterfaceDescriptor() {
 }
 
 
-static void InitializeVectorLoadStub(Isolate* isolate,
-                                     CodeStubDescriptor* descriptor,
-                                     Address deoptimization_handler) {
-  DCHECK(FLAG_vector_ics);
-  descriptor->Initialize(deoptimization_handler);
-}
-
-
-void VectorLoadStub::InitializeDescriptor(CodeStubDescriptor* descriptor) {
-  InitializeVectorLoadStub(isolate(), descriptor,
-                           FUNCTION_ADDR(LoadIC_MissFromStubFailure));
-}
-
-
-void VectorKeyedLoadStub::InitializeDescriptor(CodeStubDescriptor* descriptor) {
-  InitializeVectorLoadStub(isolate(), descriptor,
-                           FUNCTION_ADDR(KeyedLoadIC_MissFromStubFailure));
-}
-
-
 void MegamorphicLoadStub::InitializeDescriptor(CodeStubDescriptor* d) {}
 
 
index 5a2d2691a0548c8142ce7cc06aba5e6a9c97341a..f5eeb0949247a3f7007185191586036a4f7de6e1 100644 (file)
@@ -85,8 +85,8 @@ namespace internal {
   V(StringAdd)                              \
   V(ToBoolean)                              \
   V(TransitionElementsKind)                 \
-  V(VectorKeyedLoad)                        \
-  V(VectorLoad)                             \
+  V(VectorRawKeyedLoad)                     \
+  V(VectorRawLoad)                          \
   /* IC Handler stubs */                    \
   V(LoadConstant)                           \
   V(LoadField)                              \
@@ -2062,38 +2062,49 @@ class MegamorphicLoadStub : public HydrogenCodeStub {
 };
 
 
-class VectorLoadStub : public HydrogenCodeStub {
+class VectorRawLoadStub : public PlatformCodeStub {
  public:
-  explicit VectorLoadStub(Isolate* isolate, const LoadICState& state)
-      : HydrogenCodeStub(isolate) {
-    set_sub_minor_key(state.GetExtraICState());
+  explicit VectorRawLoadStub(Isolate* isolate, const LoadICState& state)
+      : PlatformCodeStub(isolate) {
+    minor_key_ = state.GetExtraICState();
   }
 
-  Code::Kind GetCodeKind() const OVERRIDE { return Code::LOAD_IC; }
+  void GenerateForTrampoline(MacroAssembler* masm);
 
-  InlineCacheState GetICState() const FINAL { return DEFAULT; }
+  virtual Code::Kind GetCodeKind() const OVERRIDE { return Code::LOAD_IC; }
 
-  ExtraICState GetExtraICState() const FINAL {
-    return static_cast<ExtraICState>(sub_minor_key());
-  }
+  virtual InlineCacheState GetICState() const FINAL OVERRIDE { return DEFAULT; }
 
- private:
-  LoadICState state() const { return LoadICState(GetExtraICState()); }
+  virtual ExtraICState GetExtraICState() const FINAL OVERRIDE {
+    return static_cast<ExtraICState>(minor_key_);
+  }
 
   DEFINE_CALL_INTERFACE_DESCRIPTOR(VectorLoadIC);
-  DEFINE_HYDROGEN_CODE_STUB(VectorLoad, HydrogenCodeStub);
+  DEFINE_PLATFORM_CODE_STUB(VectorRawLoad, PlatformCodeStub);
+
+ protected:
+  void GenerateImpl(MacroAssembler* masm, bool in_frame);
 };
 
 
-class VectorKeyedLoadStub : public VectorLoadStub {
+class VectorRawKeyedLoadStub : public PlatformCodeStub {
  public:
-  explicit VectorKeyedLoadStub(Isolate* isolate)
-      : VectorLoadStub(isolate, LoadICState(0)) {}
+  explicit VectorRawKeyedLoadStub(Isolate* isolate)
+      : PlatformCodeStub(isolate) {}
 
-  Code::Kind GetCodeKind() const OVERRIDE { return Code::KEYED_LOAD_IC; }
+  void GenerateForTrampoline(MacroAssembler* masm);
+
+  virtual Code::Kind GetCodeKind() const OVERRIDE {
+    return Code::KEYED_LOAD_IC;
+  }
+
+  virtual InlineCacheState GetICState() const FINAL OVERRIDE { return DEFAULT; }
 
   DEFINE_CALL_INTERFACE_DESCRIPTOR(VectorLoadIC);
-  DEFINE_HYDROGEN_CODE_STUB(VectorKeyedLoad, VectorLoadStub);
+  DEFINE_PLATFORM_CODE_STUB(VectorRawKeyedLoad, PlatformCodeStub);
+
+ protected:
+  void GenerateImpl(MacroAssembler* masm, bool in_frame);
 };
 
 
index 74715d9a83782a45069100aac6bc5a23b0849001..4f8de8ae386f0dbc89d3896a747cc7e05064dd49 100644 (file)
@@ -12,6 +12,7 @@
 #include "src/codegen.h"
 #include "src/ic/handler-compiler.h"
 #include "src/ic/ic.h"
+#include "src/ic/stub-cache.h"
 #include "src/isolate.h"
 #include "src/jsregexp.h"
 #include "src/regexp-macro-assembler.h"
@@ -4399,15 +4400,236 @@ void StubFailureTrampolineStub::Generate(MacroAssembler* masm) {
 
 void LoadICTrampolineStub::Generate(MacroAssembler* masm) {
   EmitLoadTypeFeedbackVector(masm, VectorLoadICDescriptor::VectorRegister());
-  VectorLoadStub stub(isolate(), state());
-  __ jmp(stub.GetCode(), RelocInfo::CODE_TARGET);
+  VectorRawLoadStub stub(isolate(), state());
+  stub.GenerateForTrampoline(masm);
 }
 
 
 void KeyedLoadICTrampolineStub::Generate(MacroAssembler* masm) {
   EmitLoadTypeFeedbackVector(masm, VectorLoadICDescriptor::VectorRegister());
-  VectorKeyedLoadStub stub(isolate());
-  __ jmp(stub.GetCode(), RelocInfo::CODE_TARGET);
+  VectorRawKeyedLoadStub stub(isolate());
+  stub.GenerateForTrampoline(masm);
+}
+
+
+static void HandleArrayCases(MacroAssembler* masm, Register receiver,
+                             Register key, Register vector, Register slot,
+                             Register feedback, bool is_polymorphic,
+                             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 load 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, is_polymorphic ? &start_polymorphic : &next);
+
+  // found, now call handler.
+  Register handler = feedback;
+  __ mov(handler, FieldOperand(feedback, FixedArray::OffsetOfElementAt(1)));
+  __ pop(vector);
+  __ pop(receiver);
+  __ lea(handler, FieldOperand(handler, Code::kHeaderSize));
+  __ jmp(handler);
+
+  if (!is_polymorphic) {
+    __ bind(&next);
+    __ cmp(FieldOperand(feedback, FixedArray::kLengthOffset),
+           Immediate(Smi::FromInt(2)));
+    __ j(not_equal, &start_polymorphic);
+    __ pop(vector);
+    __ pop(receiver);
+    __ jmp(miss);
+  }
+
+  // Polymorphic, we have to loop from 2 to N
+  __ 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));
+  __ jmp(handler);
+
+  __ 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 HandleMonomorphicCase(MacroAssembler* masm, Register receiver,
+                                  Register key, Register vector, Register slot,
+                                  Register weak_cell, Label* miss) {
+  // 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);
+  Register handler = weak_cell;
+  __ mov(handler, FieldOperand(vector, slot, times_half_pointer_size,
+                               FixedArray::kHeaderSize + kPointerSize));
+  __ lea(handler, FieldOperand(handler, Code::kHeaderSize));
+  __ jmp(handler);
+
+  // 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(handler, FieldOperand(vector, slot, times_half_pointer_size,
+                               FixedArray::kHeaderSize + kPointerSize));
+  __ lea(handler, FieldOperand(handler, Code::kHeaderSize));
+  __ jmp(handler);
+}
+
+
+void VectorRawLoadStub::Generate(MacroAssembler* masm) {
+  GenerateImpl(masm, false);
+}
+
+
+void VectorRawLoadStub::GenerateForTrampoline(MacroAssembler* masm) {
+  GenerateImpl(masm, true);
+}
+
+
+void VectorRawLoadStub::GenerateImpl(MacroAssembler* masm, bool in_frame) {
+  Register receiver = VectorLoadICDescriptor::ReceiverRegister();  // edx
+  Register name = VectorLoadICDescriptor::NameRegister();          // ecx
+  Register vector = VectorLoadICDescriptor::VectorRegister();      // ebx
+  Register slot = VectorLoadICDescriptor::SlotRegister();          // eax
+  Register scratch = edi;
+  __ 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, miss;
+  __ CompareRoot(FieldOperand(scratch, 0), Heap::kWeakCellMapRootIndex);
+  __ j(not_equal, &try_array);
+  HandleMonomorphicCase(masm, receiver, name, vector, slot, scratch, &miss);
+
+  // Is it a fixed array?
+  __ bind(&try_array);
+  __ CompareRoot(FieldOperand(scratch, 0), Heap::kFixedArrayMapRootIndex);
+  __ j(not_equal, &not_array);
+  HandleArrayCases(masm, receiver, name, vector, slot, scratch, true, &miss);
+
+  __ bind(&not_array);
+  __ CompareRoot(scratch, Heap::kmegamorphic_symbolRootIndex);
+  __ j(not_equal, &miss);
+  __ push(slot);
+  __ push(vector);
+  Code::Flags code_flags = Code::RemoveTypeAndHolderFromFlags(
+      Code::ComputeHandlerFlags(Code::LOAD_IC));
+  masm->isolate()->stub_cache()->GenerateProbe(
+      masm, Code::LOAD_IC, code_flags, false, receiver, name, vector, scratch);
+  __ pop(vector);
+  __ pop(slot);
+
+  __ bind(&miss);
+  LoadIC::GenerateMiss(masm);
+}
+
+
+void VectorRawKeyedLoadStub::Generate(MacroAssembler* masm) {
+  GenerateImpl(masm, false);
+}
+
+
+void VectorRawKeyedLoadStub::GenerateForTrampoline(MacroAssembler* masm) {
+  GenerateImpl(masm, true);
+}
+
+
+void VectorRawKeyedLoadStub::GenerateImpl(MacroAssembler* masm, bool in_frame) {
+  Register receiver = VectorLoadICDescriptor::ReceiverRegister();  // edx
+  Register key = VectorLoadICDescriptor::NameRegister();           // ecx
+  Register vector = VectorLoadICDescriptor::VectorRegister();      // ebx
+  Register slot = VectorLoadICDescriptor::SlotRegister();          // eax
+  Register feedback = edi;
+  __ mov(feedback, FieldOperand(vector, slot, times_half_pointer_size,
+                                FixedArray::kHeaderSize));
+  // Is it a weak cell?
+  Label try_array;
+  Label not_array, smi_key, key_okay, miss;
+  __ CompareRoot(FieldOperand(feedback, 0), Heap::kWeakCellMapRootIndex);
+  __ j(not_equal, &try_array);
+  __ JumpIfNotSmi(key, &miss);
+  HandleMonomorphicCase(masm, receiver, key, vector, slot, feedback, &miss);
+
+  __ bind(&try_array);
+  // Is it a fixed array?
+  __ CompareRoot(FieldOperand(feedback, 0), Heap::kFixedArrayMapRootIndex);
+  __ j(not_equal, &not_array);
+  // We have a polymorphic element handler.
+  __ JumpIfNotSmi(key, &miss);
+
+  Label polymorphic, try_poly_name;
+  __ bind(&polymorphic);
+  HandleArrayCases(masm, receiver, key, vector, slot, feedback, true, &miss);
+
+  __ bind(&not_array);
+  // Is it generic?
+  __ CompareRoot(feedback, Heap::kmegamorphic_symbolRootIndex);
+  __ j(not_equal, &try_poly_name);
+  Handle<Code> megamorphic_stub =
+      KeyedLoadIC::ChooseMegamorphicStub(masm->isolate());
+  __ 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, feedback);
+  __ j(not_equal, &miss);
+  // If the name comparison succeeded, we know we have a fixed array with
+  // at least one map/handler pair.
+  __ mov(feedback, FieldOperand(vector, slot, times_half_pointer_size,
+                                FixedArray::kHeaderSize + kPointerSize));
+  HandleArrayCases(masm, receiver, key, vector, slot, feedback, false, &miss);
+
+  __ bind(&miss);
+  KeyedLoadIC::GenerateMiss(masm);
 }
 
 
index 92a6e29109a892aea3f9b6a7c4edb27fc95bd2c0..6c31429f1655ac55a11d958b0ab91da5176e36d8 100644 (file)
@@ -988,7 +988,7 @@ Handle<Code> LoadIC::load_global(Isolate* isolate, Handle<GlobalObject> global,
 Handle<Code> LoadIC::initialize_stub_in_optimized_code(
     Isolate* isolate, ExtraICState extra_state, State initialization_state) {
   if (FLAG_vector_ics) {
-    return VectorLoadStub(isolate, LoadICState(extra_state)).GetCode();
+    return VectorRawLoadStub(isolate, LoadICState(extra_state)).GetCode();
   }
   return PropertyICCompiler::ComputeLoad(isolate, initialization_state,
                                          extra_state);
@@ -1007,7 +1007,7 @@ Handle<Code> KeyedLoadIC::initialize_stub(Isolate* isolate) {
 Handle<Code> KeyedLoadIC::initialize_stub_in_optimized_code(
     Isolate* isolate, State initialization_state) {
   if (FLAG_vector_ics) {
-    return VectorKeyedLoadStub(isolate).GetCode();
+    return VectorRawKeyedLoadStub(isolate).GetCode();
   }
   switch (initialization_state) {
     case UNINITIALIZED:
index dd608e63254052d168285b42be6b3d7c71eed095..60ba09f0633cb02caf2337a2729fd21a0e0cdb21 100644 (file)
@@ -12,6 +12,7 @@
 #include "src/codegen.h"
 #include "src/ic/handler-compiler.h"
 #include "src/ic/ic.h"
+#include "src/ic/stub-cache.h"
 #include "src/isolate.h"
 #include "src/jsregexp.h"
 #include "src/regexp-macro-assembler.h"
@@ -4554,15 +4555,15 @@ void StubFailureTrampolineStub::Generate(MacroAssembler* masm) {
 
 void LoadICTrampolineStub::Generate(MacroAssembler* masm) {
   EmitLoadTypeFeedbackVector(masm, VectorLoadICDescriptor::VectorRegister());
-  VectorLoadStub stub(isolate(), state());
-  __ Jump(stub.GetCode(), RelocInfo::CODE_TARGET);
+  VectorRawLoadStub stub(isolate(), state());
+  stub.GenerateForTrampoline(masm);
 }
 
 
 void KeyedLoadICTrampolineStub::Generate(MacroAssembler* masm) {
   EmitLoadTypeFeedbackVector(masm, VectorLoadICDescriptor::VectorRegister());
-  VectorKeyedLoadStub stub(isolate());
-  __ Jump(stub.GetCode(), RelocInfo::CODE_TARGET);
+  VectorRawKeyedLoadStub stub(isolate());
+  stub.GenerateForTrampoline(masm);
 }
 
 
@@ -4580,6 +4581,243 @@ void CallIC_ArrayTrampolineStub::Generate(MacroAssembler* masm) {
 }
 
 
+void VectorRawLoadStub::Generate(MacroAssembler* masm) {
+  GenerateImpl(masm, false);
+}
+
+
+void VectorRawLoadStub::GenerateForTrampoline(MacroAssembler* masm) {
+  GenerateImpl(masm, true);
+}
+
+
+static void HandleArrayCases(MacroAssembler* masm, Register receiver,
+                             Register key, Register vector, Register slot,
+                             Register feedback, Register scratch1,
+                             Register scratch2, Register scratch3,
+                             bool is_polymorphic, Label* miss) {
+  // feedback initially contains the feedback array
+  Label next_loop, prepare_next;
+  Label load_smi_map, compare_map;
+  Label start_polymorphic;
+
+  Register receiver_map = scratch1;
+  Register cached_map = scratch2;
+
+  // Receiver might not be a heap object.
+  __ JumpIfSmi(receiver, &load_smi_map);
+  __ lw(receiver_map, FieldMemOperand(receiver, HeapObject::kMapOffset));
+  __ bind(&compare_map);
+  __ lw(cached_map,
+        FieldMemOperand(feedback, FixedArray::OffsetOfElementAt(0)));
+  __ lw(cached_map, FieldMemOperand(cached_map, WeakCell::kValueOffset));
+  __ Branch(&start_polymorphic, ne, receiver_map, Operand(cached_map));
+  // found, now call handler.
+  Register handler = feedback;
+  __ lw(handler, FieldMemOperand(feedback, FixedArray::OffsetOfElementAt(1)));
+  __ Addu(t9, handler, Operand(Code::kHeaderSize - kHeapObjectTag));
+  __ Jump(t9);
+
+
+  Register length = scratch3;
+  __ bind(&start_polymorphic);
+  __ lw(length, FieldMemOperand(feedback, FixedArray::kLengthOffset));
+  if (!is_polymorphic) {
+    // If the IC could be monomorphic we have to make sure we don't go past the
+    // end of the feedback array.
+    __ Branch(miss, eq, length, Operand(Smi::FromInt(2)));
+  }
+
+  Register too_far = length;
+  Register pointer_reg = feedback;
+
+  // +-----+------+------+-----+-----+ ... ----+
+  // | map | len  | wm0  | h0  | wm1 |      hN |
+  // +-----+------+------+-----+-----+ ... ----+
+  //                 0      1     2        len-1
+  //                              ^              ^
+  //                              |              |
+  //                         pointer_reg      too_far
+  //                         aka feedback     scratch3
+  // also need receiver_map (aka scratch1)
+  // use cached_map (scratch2) to look in the weak map values.
+  __ sll(at, length, kPointerSizeLog2 - kSmiTagSize);
+  __ Addu(too_far, feedback, Operand(at));
+  __ Addu(too_far, too_far, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
+  __ Addu(pointer_reg, feedback,
+          Operand(FixedArray::OffsetOfElementAt(2) - kHeapObjectTag));
+
+  __ bind(&next_loop);
+  __ lw(cached_map, MemOperand(pointer_reg));
+  __ lw(cached_map, FieldMemOperand(cached_map, WeakCell::kValueOffset));
+  __ Branch(&prepare_next, ne, receiver_map, Operand(cached_map));
+  __ lw(handler, MemOperand(pointer_reg, kPointerSize));
+  __ Addu(t9, handler, Operand(Code::kHeaderSize - kHeapObjectTag));
+  __ Jump(t9);
+
+  __ bind(&prepare_next);
+  __ Addu(pointer_reg, pointer_reg, Operand(kPointerSize * 2));
+  __ Branch(&next_loop, lt, pointer_reg, Operand(too_far));
+
+  // We exhausted our array of map handler pairs.
+  __ jmp(miss);
+
+  __ bind(&load_smi_map);
+  __ LoadRoot(receiver_map, Heap::kHeapNumberMapRootIndex);
+  __ jmp(&compare_map);
+}
+
+
+static void HandleMonomorphicCase(MacroAssembler* masm, Register receiver,
+                                  Register key, Register vector, Register slot,
+                                  Register weak_cell, Register scratch,
+                                  Label* miss) {
+  // feedback initially contains the feedback array
+  Label compare_smi_map;
+  Register receiver_map = scratch;
+  Register cached_map = weak_cell;
+
+  // Move the weak map into the weak_cell register.
+  __ lw(cached_map, FieldMemOperand(weak_cell, WeakCell::kValueOffset));
+
+  // Receiver might not be a heap object.
+  __ JumpIfSmi(receiver, &compare_smi_map);
+  __ lw(receiver_map, FieldMemOperand(receiver, HeapObject::kMapOffset));
+  __ Branch(miss, ne, cached_map, Operand(receiver_map));
+
+  Register handler = weak_cell;
+  __ sll(at, slot, kPointerSizeLog2 - kSmiTagSize);
+  __ Addu(handler, vector, Operand(at));
+  __ lw(handler,
+        FieldMemOperand(handler, FixedArray::kHeaderSize + kPointerSize));
+  __ Addu(t9, handler, Operand(Code::kHeaderSize - kHeapObjectTag));
+  __ Jump(t9);
+
+  // 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);
+  __ LoadRoot(at, Heap::kHeapNumberMapRootIndex);
+  __ Branch(miss, ne, at, Operand(weak_cell));
+  __ sll(at, slot, kPointerSizeLog2 - kSmiTagSize);
+  __ Addu(handler, vector, Operand(at));
+  __ lw(handler,
+        FieldMemOperand(handler, FixedArray::kHeaderSize + kPointerSize));
+  __ Addu(t9, handler, Operand(Code::kHeaderSize - kHeapObjectTag));
+  __ Jump(t9);
+}
+
+
+void VectorRawLoadStub::GenerateImpl(MacroAssembler* masm, bool in_frame) {
+  Register receiver = VectorLoadICDescriptor::ReceiverRegister();  // a1
+  Register name = VectorLoadICDescriptor::NameRegister();          // a2
+  Register vector = VectorLoadICDescriptor::VectorRegister();      // a3
+  Register slot = VectorLoadICDescriptor::SlotRegister();          // a0
+  Register feedback = t0;
+  Register scratch1 = t1;
+
+  __ sll(at, slot, kPointerSizeLog2 - kSmiTagSize);
+  __ Addu(feedback, vector, Operand(at));
+  __ lw(feedback, FieldMemOperand(feedback, FixedArray::kHeaderSize));
+
+  // Is it a weak cell?
+  Label try_array;
+  Label not_array, smi_key, key_okay, miss;
+  __ lw(scratch1, FieldMemOperand(feedback, HeapObject::kMapOffset));
+  __ LoadRoot(at, Heap::kWeakCellMapRootIndex);
+  __ Branch(&try_array, ne, at, Operand(scratch1));
+  HandleMonomorphicCase(masm, receiver, name, vector, slot, feedback, scratch1,
+                        &miss);
+
+  // Is it a fixed array?
+  __ bind(&try_array);
+  __ LoadRoot(at, Heap::kFixedArrayMapRootIndex);
+  __ Branch(&not_array, ne, at, Operand(scratch1));
+  HandleArrayCases(masm, receiver, name, vector, slot, feedback, scratch1, t4,
+                   t5, true, &miss);
+
+  __ bind(&not_array);
+  __ LoadRoot(at, Heap::kmegamorphic_symbolRootIndex);
+  __ Branch(&miss, ne, at, Operand(feedback));
+  Code::Flags code_flags = Code::RemoveTypeAndHolderFromFlags(
+      Code::ComputeHandlerFlags(Code::LOAD_IC));
+  masm->isolate()->stub_cache()->GenerateProbe(masm, Code::LOAD_IC, code_flags,
+                                               false, receiver, name, feedback,
+                                               scratch1, t4, t5);
+
+  __ bind(&miss);
+  LoadIC::GenerateMiss(masm);
+}
+
+
+void VectorRawKeyedLoadStub::Generate(MacroAssembler* masm) {
+  GenerateImpl(masm, false);
+}
+
+
+void VectorRawKeyedLoadStub::GenerateForTrampoline(MacroAssembler* masm) {
+  GenerateImpl(masm, true);
+}
+
+
+void VectorRawKeyedLoadStub::GenerateImpl(MacroAssembler* masm, bool in_frame) {
+  Register receiver = VectorLoadICDescriptor::ReceiverRegister();  // a1
+  Register key = VectorLoadICDescriptor::NameRegister();           // a2
+  Register vector = VectorLoadICDescriptor::VectorRegister();      // a3
+  Register slot = VectorLoadICDescriptor::SlotRegister();          // a0
+  Register feedback = t0;
+  Register scratch1 = t1;
+
+  __ sll(at, slot, kPointerSizeLog2 - kSmiTagSize);
+  __ Addu(feedback, vector, Operand(at));
+  __ lw(feedback, FieldMemOperand(feedback, FixedArray::kHeaderSize));
+
+  // Is it a weak cell?
+  Label try_array;
+  Label not_array, smi_key, key_okay, miss;
+  __ lw(scratch1, FieldMemOperand(feedback, HeapObject::kMapOffset));
+  __ LoadRoot(at, Heap::kWeakCellMapRootIndex);
+  __ Branch(&try_array, ne, at, Operand(scratch1));
+  __ JumpIfNotSmi(key, &miss);
+  HandleMonomorphicCase(masm, receiver, key, vector, slot, feedback, scratch1,
+                        &miss);
+
+  __ bind(&try_array);
+  // Is it a fixed array?
+  __ LoadRoot(at, Heap::kFixedArrayMapRootIndex);
+  __ Branch(&not_array, ne, at, Operand(scratch1));
+  // We have a polymorphic element handler.
+  __ JumpIfNotSmi(key, &miss);
+
+  Label polymorphic, try_poly_name;
+  __ bind(&polymorphic);
+  HandleArrayCases(masm, receiver, key, vector, slot, feedback, scratch1, t4,
+                   t5, true, &miss);
+
+  __ bind(&not_array);
+  // Is it generic?
+  __ LoadRoot(at, Heap::kmegamorphic_symbolRootIndex);
+  __ Branch(&try_poly_name, ne, at, Operand(feedback));
+  Handle<Code> megamorphic_stub =
+      KeyedLoadIC::ChooseMegamorphicStub(masm->isolate());
+  __ Jump(megamorphic_stub, RelocInfo::CODE_TARGET);
+
+  __ bind(&try_poly_name);
+  // We might have a name in feedback, and a fixed array in the next slot.
+  __ Branch(&miss, ne, key, Operand(feedback));
+  // If the name comparison succeeded, we know we have a fixed array with
+  // at least one map/handler pair.
+  __ sll(at, slot, kPointerSizeLog2 - kSmiTagSize);
+  __ Addu(feedback, vector, Operand(at));
+  __ lw(feedback,
+        FieldMemOperand(feedback, FixedArray::kHeaderSize + kPointerSize));
+  HandleArrayCases(masm, receiver, key, vector, slot, feedback, scratch1, t4,
+                   t5, false, &miss);
+
+  __ bind(&miss);
+  KeyedLoadIC::GenerateMiss(masm);
+}
+
+
 void ProfileEntryHookStub::MaybeCallEntryHook(MacroAssembler* masm) {
   if (masm->isolate()->function_entry_hook() != NULL) {
     ProfileEntryHookStub stub(masm->isolate());
index 7f367fe9a8cc614861c76bf93db0e0651d2c6a75..458a5da0c49e67f30b96b26bf09ce3acf229d783 100644 (file)
@@ -11,6 +11,7 @@
 #include "src/codegen.h"
 #include "src/ic/handler-compiler.h"
 #include "src/ic/ic.h"
+#include "src/ic/stub-cache.h"
 #include "src/isolate.h"
 #include "src/jsregexp.h"
 #include "src/regexp-macro-assembler.h"
@@ -4597,15 +4598,15 @@ void StubFailureTrampolineStub::Generate(MacroAssembler* masm) {
 
 void LoadICTrampolineStub::Generate(MacroAssembler* masm) {
   EmitLoadTypeFeedbackVector(masm, VectorLoadICDescriptor::VectorRegister());
-  VectorLoadStub stub(isolate(), state());
-  __ Jump(stub.GetCode(), RelocInfo::CODE_TARGET);
+  VectorRawLoadStub stub(isolate(), state());
+  stub.GenerateForTrampoline(masm);
 }
 
 
 void KeyedLoadICTrampolineStub::Generate(MacroAssembler* masm) {
   EmitLoadTypeFeedbackVector(masm, VectorLoadICDescriptor::VectorRegister());
-  VectorKeyedLoadStub stub(isolate());
-  __ Jump(stub.GetCode(), RelocInfo::CODE_TARGET);
+  VectorRawKeyedLoadStub stub(isolate());
+  stub.GenerateForTrampoline(masm);
 }
 
 
@@ -4623,6 +4624,243 @@ void CallIC_ArrayTrampolineStub::Generate(MacroAssembler* masm) {
 }
 
 
+void VectorRawLoadStub::Generate(MacroAssembler* masm) {
+  GenerateImpl(masm, false);
+}
+
+
+void VectorRawLoadStub::GenerateForTrampoline(MacroAssembler* masm) {
+  GenerateImpl(masm, true);
+}
+
+
+static void HandleArrayCases(MacroAssembler* masm, Register receiver,
+                             Register key, Register vector, Register slot,
+                             Register feedback, Register scratch1,
+                             Register scratch2, Register scratch3,
+                             bool is_polymorphic, Label* miss) {
+  // feedback initially contains the feedback array
+  Label next_loop, prepare_next;
+  Label load_smi_map, compare_map;
+  Label start_polymorphic;
+
+  Register receiver_map = scratch1;
+  Register cached_map = scratch2;
+
+  // Receiver might not be a heap object.
+  __ JumpIfSmi(receiver, &load_smi_map);
+  __ ld(receiver_map, FieldMemOperand(receiver, HeapObject::kMapOffset));
+  __ bind(&compare_map);
+  __ ld(cached_map,
+        FieldMemOperand(feedback, FixedArray::OffsetOfElementAt(0)));
+  __ ld(cached_map, FieldMemOperand(cached_map, WeakCell::kValueOffset));
+  __ Branch(&start_polymorphic, ne, receiver_map, Operand(cached_map));
+  // found, now call handler.
+  Register handler = feedback;
+  __ ld(handler, FieldMemOperand(feedback, FixedArray::OffsetOfElementAt(1)));
+  __ Daddu(t9, handler, Operand(Code::kHeaderSize - kHeapObjectTag));
+  __ Jump(t9);
+
+  Register length = scratch3;
+  __ bind(&start_polymorphic);
+  __ ld(length, FieldMemOperand(feedback, FixedArray::kLengthOffset));
+  if (!is_polymorphic) {
+    // If the IC could be monomorphic we have to make sure we don't go past the
+    // end of the feedback array.
+    __ Branch(miss, eq, length, Operand(Smi::FromInt(2)));
+  }
+
+  Register too_far = length;
+  Register pointer_reg = feedback;
+
+  // +-----+------+------+-----+-----+ ... ----+
+  // | map | len  | wm0  | h0  | wm1 |      hN |
+  // +-----+------+------+-----+-----+ ... ----+
+  //                 0      1     2        len-1
+  //                              ^              ^
+  //                              |              |
+  //                         pointer_reg      too_far
+  //                         aka feedback     scratch3
+  // also need receiver_map (aka scratch1)
+  // use cached_map (scratch2) to look in the weak map values.
+  __ SmiScale(too_far, length, kPointerSizeLog2);
+  __ Daddu(too_far, feedback, Operand(too_far));
+  __ Daddu(too_far, too_far, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
+  __ Daddu(pointer_reg, feedback,
+           Operand(FixedArray::OffsetOfElementAt(2) - kHeapObjectTag));
+
+  __ bind(&next_loop);
+  __ ld(cached_map, MemOperand(pointer_reg));
+  __ ld(cached_map, FieldMemOperand(cached_map, WeakCell::kValueOffset));
+  __ Branch(&prepare_next, ne, receiver_map, Operand(cached_map));
+  __ ld(handler, MemOperand(pointer_reg, kPointerSize));
+  __ Daddu(t9, handler, Operand(Code::kHeaderSize - kHeapObjectTag));
+  __ Jump(t9);
+
+  __ bind(&prepare_next);
+  __ Daddu(pointer_reg, pointer_reg, Operand(kPointerSize * 2));
+  __ Branch(&next_loop, lt, pointer_reg, Operand(too_far));
+
+  // We exhausted our array of map handler pairs.
+  __ Branch(miss);
+
+  __ bind(&load_smi_map);
+  __ LoadRoot(receiver_map, Heap::kHeapNumberMapRootIndex);
+  __ Branch(&compare_map);
+}
+
+
+static void HandleMonomorphicCase(MacroAssembler* masm, Register receiver,
+                                  Register key, Register vector, Register slot,
+                                  Register weak_cell, Register scratch,
+                                  Label* miss) {
+  // feedback initially contains the feedback array
+  Label compare_smi_map;
+  Register receiver_map = scratch;
+  Register cached_map = weak_cell;
+
+  // Move the weak map into the weak_cell register.
+  __ ld(cached_map, FieldMemOperand(weak_cell, WeakCell::kValueOffset));
+
+  // Receiver might not be a heap object.
+  __ JumpIfSmi(receiver, &compare_smi_map);
+  __ ld(receiver_map, FieldMemOperand(receiver, HeapObject::kMapOffset));
+  __ Branch(miss, ne, cached_map, Operand(receiver_map));
+
+  Register handler = weak_cell;
+  __ SmiScale(handler, slot, kPointerSizeLog2);
+  __ Daddu(handler, vector, Operand(handler));
+  __ ld(handler,
+        FieldMemOperand(handler, FixedArray::kHeaderSize + kPointerSize));
+  __ Daddu(t9, handler, Code::kHeaderSize - kHeapObjectTag);
+  __ Jump(t9);
+
+  // 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.
+  // TODO(mvstanton): does this hold on ARM?
+  __ bind(&compare_smi_map);
+  __ LoadRoot(at, Heap::kHeapNumberMapRootIndex);
+  __ Branch(miss, ne, weak_cell, Operand(at));
+  __ SmiScale(handler, slot, kPointerSizeLog2);
+  __ Daddu(handler, vector, Operand(handler));
+  __ ld(handler,
+        FieldMemOperand(handler, FixedArray::kHeaderSize + kPointerSize));
+  __ Daddu(t9, handler, Code::kHeaderSize - kHeapObjectTag);
+  __ Jump(t9);
+}
+
+
+void VectorRawLoadStub::GenerateImpl(MacroAssembler* masm, bool in_frame) {
+  Register receiver = VectorLoadICDescriptor::ReceiverRegister();  // a1
+  Register name = VectorLoadICDescriptor::NameRegister();          // a2
+  Register vector = VectorLoadICDescriptor::VectorRegister();      // a3
+  Register slot = VectorLoadICDescriptor::SlotRegister();          // a0
+  Register feedback = a4;
+  Register scratch1 = a5;
+
+  __ SmiScale(feedback, slot, kPointerSizeLog2);
+  __ Daddu(feedback, vector, Operand(feedback));
+  __ ld(feedback, FieldMemOperand(feedback, FixedArray::kHeaderSize));
+
+  // Is it a weak cell?
+  Label try_array;
+  Label not_array, smi_key, key_okay, miss;
+  __ ld(scratch1, FieldMemOperand(feedback, HeapObject::kMapOffset));
+  __ LoadRoot(at, Heap::kWeakCellMapRootIndex);
+  __ Branch(&try_array, ne, scratch1, Operand(at));
+  HandleMonomorphicCase(masm, receiver, name, vector, slot, feedback, scratch1,
+                        &miss);
+
+  // Is it a fixed array?
+  __ bind(&try_array);
+  __ LoadRoot(at, Heap::kFixedArrayMapRootIndex);
+  __ Branch(&not_array, ne, scratch1, Operand(at));
+  HandleArrayCases(masm, receiver, name, vector, slot, feedback, scratch1, a6,
+                   a7, true, &miss);
+
+  __ bind(&not_array);
+  __ LoadRoot(at, Heap::kmegamorphic_symbolRootIndex);
+  __ Branch(&miss, ne, feedback, Operand(at));
+  Code::Flags code_flags = Code::RemoveTypeAndHolderFromFlags(
+      Code::ComputeHandlerFlags(Code::LOAD_IC));
+  masm->isolate()->stub_cache()->GenerateProbe(masm, Code::LOAD_IC, code_flags,
+                                               false, receiver, name, feedback,
+                                               scratch1, a6, a7);
+
+  __ bind(&miss);
+  LoadIC::GenerateMiss(masm);
+}
+
+
+void VectorRawKeyedLoadStub::Generate(MacroAssembler* masm) {
+  GenerateImpl(masm, false);
+}
+
+
+void VectorRawKeyedLoadStub::GenerateForTrampoline(MacroAssembler* masm) {
+  GenerateImpl(masm, true);
+}
+
+
+void VectorRawKeyedLoadStub::GenerateImpl(MacroAssembler* masm, bool in_frame) {
+  Register receiver = VectorLoadICDescriptor::ReceiverRegister();  // a1
+  Register key = VectorLoadICDescriptor::NameRegister();           // a2
+  Register vector = VectorLoadICDescriptor::VectorRegister();      // a3
+  Register slot = VectorLoadICDescriptor::SlotRegister();          // a0
+  Register feedback = a4;
+  Register scratch1 = a5;
+
+  __ SmiScale(feedback, slot, kPointerSizeLog2);
+  __ Daddu(feedback, vector, Operand(feedback));
+  __ ld(feedback, FieldMemOperand(feedback, FixedArray::kHeaderSize));
+
+  // Is it a weak cell?
+  Label try_array;
+  Label not_array, smi_key, key_okay, miss;
+  __ ld(scratch1, FieldMemOperand(feedback, HeapObject::kMapOffset));
+  __ LoadRoot(at, Heap::kWeakCellMapRootIndex);
+  __ Branch(&try_array, ne, scratch1, Operand(at));
+  __ JumpIfNotSmi(key, &miss);
+  HandleMonomorphicCase(masm, receiver, key, vector, slot, feedback, scratch1,
+                        &miss);
+
+  __ bind(&try_array);
+  // Is it a fixed array?
+  __ LoadRoot(at, Heap::kFixedArrayMapRootIndex);
+  __ Branch(&not_array, ne, scratch1, Operand(at));
+  // We have a polymorphic element handler.
+  __ JumpIfNotSmi(key, &miss);
+
+  Label polymorphic, try_poly_name;
+  __ bind(&polymorphic);
+  HandleArrayCases(masm, receiver, key, vector, slot, feedback, scratch1, a6,
+                   a7, true, &miss);
+
+  __ bind(&not_array);
+  // Is it generic?
+  __ LoadRoot(at, Heap::kmegamorphic_symbolRootIndex);
+  __ Branch(&try_poly_name, ne, feedback, Operand(at));
+  Handle<Code> megamorphic_stub =
+      KeyedLoadIC::ChooseMegamorphicStub(masm->isolate());
+  __ Jump(megamorphic_stub, RelocInfo::CODE_TARGET);
+
+  __ bind(&try_poly_name);
+  // We might have a name in feedback, and a fixed array in the next slot.
+  __ Branch(&miss, ne, key, Operand(feedback));
+  // If the name comparison succeeded, we know we have a fixed array with
+  // at least one map/handler pair.
+  __ SmiScale(feedback, slot, kPointerSizeLog2);
+  __ Daddu(feedback, vector, Operand(feedback));
+  __ ld(feedback,
+        FieldMemOperand(feedback, FixedArray::kHeaderSize + kPointerSize));
+  HandleArrayCases(masm, receiver, key, vector, slot, feedback, scratch1, a6,
+                   a7, false, &miss);
+
+  __ bind(&miss);
+  KeyedLoadIC::GenerateMiss(masm);
+}
+
+
 void ProfileEntryHookStub::MaybeCallEntryHook(MacroAssembler* masm) {
   if (masm->isolate()->function_entry_hook() != NULL) {
     ProfileEntryHookStub stub(masm->isolate());
index b0be315b2b612bfd3733da6f6f0efbb236d68363..371a309ea7b0115cba18163774e5e7d5ca4b8050 100644 (file)
@@ -82,8 +82,8 @@ Handle<TypeFeedbackVector> TypeFeedbackVector::Allocate(
   const int ic_slot_count = spec.ic_slots();
   const int index_count =
       FLAG_vector_ics ? VectorICComputer::word_count(ic_slot_count) : 0;
-  const int length =
-      slot_count + ic_slot_count + index_count + kReservedIndexCount;
+  const int length = slot_count + (ic_slot_count * elements_per_ic_slot()) +
+                     index_count + kReservedIndexCount;
   if (length == kReservedIndexCount) {
     return Handle<TypeFeedbackVector>::cast(
         isolate->factory()->empty_fixed_array());
@@ -207,16 +207,28 @@ Handle<FixedArray> FeedbackNexus::EnsureArrayOfSize(int length) {
 }
 
 
-void FeedbackNexus::InstallHandlers(int start_index, MapHandleList* maps,
-                                    CodeHandleList* handlers) {
+Handle<FixedArray> FeedbackNexus::EnsureExtraArrayOfSize(int length) {
   Isolate* isolate = GetIsolate();
-  Handle<FixedArray> array = handle(FixedArray::cast(GetFeedback()), isolate);
+  Handle<Object> feedback_extra = handle(GetFeedbackExtra(), isolate);
+  if (!feedback_extra->IsFixedArray() ||
+      FixedArray::cast(*feedback_extra)->length() != length) {
+    Handle<FixedArray> array = isolate->factory()->NewFixedArray(length);
+    SetFeedbackExtra(*array);
+    return array;
+  }
+  return Handle<FixedArray>::cast(feedback_extra);
+}
+
+
+void FeedbackNexus::InstallHandlers(Handle<FixedArray> array,
+                                    MapHandleList* maps,
+                                    CodeHandleList* handlers) {
   int receiver_count = maps->length();
   for (int current = 0; current < receiver_count; ++current) {
     Handle<Map> map = maps->at(current);
     Handle<WeakCell> cell = Map::WeakCellForMap(map);
-    array->set(start_index + (current * 2), *cell);
-    array->set(start_index + (current * 2 + 1), *handlers->at(current));
+    array->set(current * 2, *cell);
+    array->set(current * 2 + 1, *handlers->at(current));
   }
 }
 
@@ -224,6 +236,7 @@ void FeedbackNexus::InstallHandlers(int start_index, MapHandleList* maps,
 InlineCacheState LoadICNexus::StateFromFeedback() const {
   Isolate* isolate = GetIsolate();
   Object* feedback = GetFeedback();
+
   if (feedback == *vector()->UninitializedSentinel(isolate)) {
     return UNINITIALIZED;
   } else if (feedback == *vector()->MegamorphicSentinel(isolate)) {
@@ -233,10 +246,10 @@ InlineCacheState LoadICNexus::StateFromFeedback() const {
   } else if (feedback->IsFixedArray()) {
     // Determine state purely by our structure, don't check if the maps are
     // cleared.
-    FixedArray* array = FixedArray::cast(feedback);
-    int length = array->length();
-    DCHECK(length >= 2);
-    return length == 2 ? MONOMORPHIC : POLYMORPHIC;
+    return POLYMORPHIC;
+  } else if (feedback->IsWeakCell()) {
+    // Don't check if the map is cleared.
+    return MONOMORPHIC;
   }
 
   return UNINITIALIZED;
@@ -246,6 +259,7 @@ InlineCacheState LoadICNexus::StateFromFeedback() const {
 InlineCacheState KeyedLoadICNexus::StateFromFeedback() const {
   Isolate* isolate = GetIsolate();
   Object* feedback = GetFeedback();
+
   if (feedback == *vector()->UninitializedSentinel(isolate)) {
     return UNINITIALIZED;
   } else if (feedback == *vector()->PremonomorphicSentinel(isolate)) {
@@ -255,10 +269,14 @@ InlineCacheState KeyedLoadICNexus::StateFromFeedback() const {
   } else if (feedback->IsFixedArray()) {
     // Determine state purely by our structure, don't check if the maps are
     // cleared.
-    FixedArray* array = FixedArray::cast(feedback);
-    int length = array->length();
-    DCHECK(length >= 3);
-    return length == 3 ? MONOMORPHIC : POLYMORPHIC;
+    return POLYMORPHIC;
+  } else if (feedback->IsWeakCell()) {
+    // Don't check if the map is cleared.
+    return MONOMORPHIC;
+  } else if (feedback->IsName()) {
+    Object* extra = GetFeedbackExtra();
+    FixedArray* extra_array = FixedArray::cast(extra);
+    return extra_array->length() > 2 ? POLYMORPHIC : MONOMORPHIC;
   }
 
   return UNINITIALIZED;
@@ -268,6 +286,8 @@ InlineCacheState KeyedLoadICNexus::StateFromFeedback() const {
 InlineCacheState CallICNexus::StateFromFeedback() const {
   Isolate* isolate = GetIsolate();
   Object* feedback = GetFeedback();
+  DCHECK(!FLAG_vector_ics ||
+         GetFeedbackExtra() == *vector()->UninitializedSentinel(isolate));
 
   if (feedback == *vector()->MegamorphicSentinel(isolate)) {
     return GENERIC;
@@ -311,56 +331,68 @@ void CallICNexus::ConfigureMonomorphic(Handle<JSFunction> function) {
 
 
 void KeyedLoadICNexus::ConfigureMegamorphic() {
-  SetFeedback(*vector()->MegamorphicSentinel(GetIsolate()), SKIP_WRITE_BARRIER);
+  Isolate* isolate = GetIsolate();
+  SetFeedback(*vector()->MegamorphicSentinel(isolate), SKIP_WRITE_BARRIER);
+  SetFeedbackExtra(*vector()->UninitializedSentinel(isolate),
+                   SKIP_WRITE_BARRIER);
 }
 
 
 void LoadICNexus::ConfigureMegamorphic() {
   SetFeedback(*vector()->MegamorphicSentinel(GetIsolate()), SKIP_WRITE_BARRIER);
+  SetFeedbackExtra(*vector()->UninitializedSentinel(GetIsolate()),
+                   SKIP_WRITE_BARRIER);
 }
 
 
 void LoadICNexus::ConfigurePremonomorphic() {
   SetFeedback(*vector()->PremonomorphicSentinel(GetIsolate()),
               SKIP_WRITE_BARRIER);
+  SetFeedbackExtra(*vector()->UninitializedSentinel(GetIsolate()),
+                   SKIP_WRITE_BARRIER);
 }
 
 
 void KeyedLoadICNexus::ConfigurePremonomorphic() {
-  SetFeedback(*vector()->PremonomorphicSentinel(GetIsolate()),
-              SKIP_WRITE_BARRIER);
+  Isolate* isolate = GetIsolate();
+  SetFeedback(*vector()->PremonomorphicSentinel(isolate), SKIP_WRITE_BARRIER);
+  SetFeedbackExtra(*vector()->UninitializedSentinel(isolate),
+                   SKIP_WRITE_BARRIER);
 }
 
 
 void LoadICNexus::ConfigureMonomorphic(Handle<Map> receiver_map,
                                        Handle<Code> handler) {
-  Handle<FixedArray> array = EnsureArrayOfSize(2);
   Handle<WeakCell> cell = Map::WeakCellForMap(receiver_map);
-  array->set(0, *cell);
-  array->set(1, *handler);
+  SetFeedback(*cell);
+  SetFeedbackExtra(*handler);
 }
 
 
 void KeyedLoadICNexus::ConfigureMonomorphic(Handle<Name> name,
                                             Handle<Map> receiver_map,
                                             Handle<Code> handler) {
-  Handle<FixedArray> array = EnsureArrayOfSize(3);
+  Handle<WeakCell> cell = Map::WeakCellForMap(receiver_map);
   if (name.is_null()) {
-    array->set(0, Smi::FromInt(0));
+    SetFeedback(*cell);
+    SetFeedbackExtra(*handler);
   } else {
-    array->set(0, *name);
+    SetFeedback(*name);
+    Handle<FixedArray> array = EnsureExtraArrayOfSize(2);
+    array->set(0, *cell);
+    array->set(1, *handler);
   }
-  Handle<WeakCell> cell = Map::WeakCellForMap(receiver_map);
-  array->set(1, *cell);
-  array->set(2, *handler);
 }
 
 
 void LoadICNexus::ConfigurePolymorphic(MapHandleList* maps,
                                        CodeHandleList* handlers) {
+  Isolate* isolate = GetIsolate();
   int receiver_count = maps->length();
-  EnsureArrayOfSize(receiver_count * 2);
-  InstallHandlers(0, maps, handlers);
+  Handle<FixedArray> array = EnsureArrayOfSize(receiver_count * 2);
+  InstallHandlers(array, maps, handlers);
+  SetFeedbackExtra(*vector()->UninitializedSentinel(isolate),
+                   SKIP_WRITE_BARRIER);
 }
 
 
@@ -368,26 +400,34 @@ void KeyedLoadICNexus::ConfigurePolymorphic(Handle<Name> name,
                                             MapHandleList* maps,
                                             CodeHandleList* handlers) {
   int receiver_count = maps->length();
-  Handle<FixedArray> array = EnsureArrayOfSize(1 + receiver_count * 2);
+  DCHECK(receiver_count > 1);
+  Handle<FixedArray> array;
   if (name.is_null()) {
-    array->set(0, Smi::FromInt(0));
+    array = EnsureArrayOfSize(receiver_count * 2);
+    SetFeedbackExtra(*vector()->UninitializedSentinel(GetIsolate()),
+                     SKIP_WRITE_BARRIER);
   } else {
-    array->set(0, *name);
+    SetFeedback(*name);
+    array = EnsureExtraArrayOfSize(receiver_count * 2);
   }
-  InstallHandlers(1, maps, handlers);
+
+  InstallHandlers(array, maps, handlers);
 }
 
 
-int FeedbackNexus::ExtractMaps(int start_index, MapHandleList* maps) const {
+int FeedbackNexus::ExtractMaps(MapHandleList* maps) const {
   Isolate* isolate = GetIsolate();
   Object* feedback = GetFeedback();
-  if (feedback->IsFixedArray()) {
+  if (feedback->IsFixedArray() || feedback->IsString()) {
     int found = 0;
+    if (feedback->IsString()) {
+      feedback = GetFeedbackExtra();
+    }
     FixedArray* array = FixedArray::cast(feedback);
     // The array should be of the form [<optional name>], then
     // [map, handler, map, handler, ... ]
-    DCHECK(array->length() >= (2 + start_index));
-    for (int i = start_index; i < array->length(); i += 2) {
+    DCHECK(array->length() >= 2);
+    for (int i = 0; i < array->length(); i += 2) {
       WeakCell* cell = WeakCell::cast(array->get(i));
       if (!cell->cleared()) {
         Map* map = Map::cast(cell->value());
@@ -396,18 +436,27 @@ int FeedbackNexus::ExtractMaps(int start_index, MapHandleList* maps) const {
       }
     }
     return found;
+  } else if (feedback->IsWeakCell()) {
+    WeakCell* cell = WeakCell::cast(feedback);
+    if (!cell->cleared()) {
+      Map* map = Map::cast(cell->value());
+      maps->Add(handle(map, isolate));
+      return 1;
+    }
   }
 
   return 0;
 }
 
 
-MaybeHandle<Code> FeedbackNexus::FindHandlerForMap(int start_index,
-                                                   Handle<Map> map) const {
+MaybeHandle<Code> FeedbackNexus::FindHandlerForMap(Handle<Map> map) const {
   Object* feedback = GetFeedback();
-  if (feedback->IsFixedArray()) {
+  if (feedback->IsFixedArray() || feedback->IsString()) {
+    if (feedback->IsString()) {
+      feedback = GetFeedbackExtra();
+    }
     FixedArray* array = FixedArray::cast(feedback);
-    for (int i = start_index; i < array->length(); i += 2) {
+    for (int i = 0; i < array->length(); i += 2) {
       WeakCell* cell = WeakCell::cast(array->get(i));
       if (!cell->cleared()) {
         Map* array_map = Map::cast(cell->value());
@@ -418,23 +467,34 @@ MaybeHandle<Code> FeedbackNexus::FindHandlerForMap(int start_index,
         }
       }
     }
+  } else if (feedback->IsWeakCell()) {
+    WeakCell* cell = WeakCell::cast(feedback);
+    if (!cell->cleared()) {
+      Map* cell_map = Map::cast(cell->value());
+      if (cell_map == *map) {
+        Code* code = Code::cast(GetFeedbackExtra());
+        DCHECK(code->kind() == Code::HANDLER);
+        return handle(code);
+      }
+    }
   }
 
   return MaybeHandle<Code>();
 }
 
 
-bool FeedbackNexus::FindHandlers(int start_index, CodeHandleList* code_list,
-                                 int length) const {
+bool FeedbackNexus::FindHandlers(CodeHandleList* code_list, int length) const {
   Object* feedback = GetFeedback();
   int count = 0;
-  if (feedback->IsFixedArray()) {
+  if (feedback->IsFixedArray() || feedback->IsString()) {
+    if (feedback->IsString()) {
+      feedback = GetFeedbackExtra();
+    }
     FixedArray* array = FixedArray::cast(feedback);
-    // The array should be of the form [<optional name>], then
-    // [map, handler, map, handler, ... ]. Be sure to skip handlers whose maps
-    // have been cleared.
-    DCHECK(array->length() >= (2 + start_index));
-    for (int i = start_index; i < array->length(); i += 2) {
+    // The array should be of the form [map, handler, map, handler, ... ].
+    // Be sure to skip handlers whose maps have been cleared.
+    DCHECK(array->length() >= 2);
+    for (int i = 0; i < array->length(); i += 2) {
       WeakCell* cell = WeakCell::cast(array->get(i));
       if (!cell->cleared()) {
         Code* code = Code::cast(array->get(i + 1));
@@ -443,16 +503,19 @@ bool FeedbackNexus::FindHandlers(int start_index, CodeHandleList* code_list,
         count++;
       }
     }
+  } else if (feedback->IsWeakCell()) {
+    WeakCell* cell = WeakCell::cast(feedback);
+    if (!cell->cleared()) {
+      Code* code = Code::cast(GetFeedbackExtra());
+      DCHECK(code->kind() == Code::HANDLER);
+      code_list->Add(handle(code));
+      count++;
+    }
   }
   return count == length;
 }
 
 
-int LoadICNexus::ExtractMaps(MapHandleList* maps) const {
-  return FeedbackNexus::ExtractMaps(0, maps);
-}
-
-
 void LoadICNexus::Clear(Code* host) { LoadIC::Clear(GetIsolate(), host, this); }
 
 
@@ -461,39 +524,10 @@ void KeyedLoadICNexus::Clear(Code* host) {
 }
 
 
-int KeyedLoadICNexus::ExtractMaps(MapHandleList* maps) const {
-  return FeedbackNexus::ExtractMaps(1, maps);
-}
-
-
-MaybeHandle<Code> LoadICNexus::FindHandlerForMap(Handle<Map> map) const {
-  return FeedbackNexus::FindHandlerForMap(0, map);
-}
-
-
-MaybeHandle<Code> KeyedLoadICNexus::FindHandlerForMap(Handle<Map> map) const {
-  return FeedbackNexus::FindHandlerForMap(1, map);
-}
-
-
-bool LoadICNexus::FindHandlers(CodeHandleList* code_list, int length) const {
-  return FeedbackNexus::FindHandlers(0, code_list, length);
-}
-
-
-bool KeyedLoadICNexus::FindHandlers(CodeHandleList* code_list,
-                                    int length) const {
-  return FeedbackNexus::FindHandlers(1, code_list, length);
-}
-
-
 Name* KeyedLoadICNexus::FindFirstName() const {
   Object* feedback = GetFeedback();
-  if (feedback->IsFixedArray()) {
-    FixedArray* array = FixedArray::cast(feedback);
-    DCHECK(array->length() >= 3);
-    Object* name = array->get(0);
-    if (name->IsName()) return Name::cast(name);
+  if (feedback->IsString()) {
+    return Name::cast(feedback);
   }
   return NULL;
 }
index b7abad51f1db466da33e33ed5d5e40e395cd83dc..aba42a6c91027a4d6a660594f82ed77519131941 100644 (file)
@@ -74,6 +74,8 @@ class TypeFeedbackVector : public FixedArray {
   static const int kWithTypesIndex = 1;
   static const int kGenericCountIndex = 2;
 
+  static int elements_per_ic_slot() { return FLAG_vector_ics ? 2 : 1; }
+
   int first_ic_slot_index() const {
     DCHECK(length() >= kReservedIndexCount);
     return Smi::cast(get(kFirstICSlotIndex))->value();
@@ -114,7 +116,7 @@ class TypeFeedbackVector : public FixedArray {
 
   int ICSlots() const {
     if (length() == 0) return 0;
-    return length() - first_ic_slot_index();
+    return (length() - first_ic_slot_index()) / elements_per_ic_slot();
   }
 
   // Conversion from a slot or ic slot to an integer index to the underlying
@@ -127,7 +129,7 @@ class TypeFeedbackVector : public FixedArray {
   int GetIndex(FeedbackVectorICSlot slot) const {
     int first_ic_slot = first_ic_slot_index();
     DCHECK(slot.ToInt() < ICSlots());
-    return first_ic_slot + slot.ToInt();
+    return first_ic_slot + slot.ToInt() * elements_per_ic_slot();
   }
 
   // Conversion from an integer index to either a slot or an ic slot. The caller
@@ -140,7 +142,8 @@ class TypeFeedbackVector : public FixedArray {
 
   FeedbackVectorICSlot ToICSlot(int index) const {
     DCHECK(index >= first_ic_slot_index() && index < length());
-    return FeedbackVectorICSlot(index - first_ic_slot_index());
+    int ic_slot = (index - first_ic_slot_index()) / elements_per_ic_slot();
+    return FeedbackVectorICSlot(ic_slot);
   }
 
   Object* Get(FeedbackVectorSlot slot) const { return get(GetIndex(slot)); }
@@ -244,14 +247,17 @@ class FeedbackNexus {
   void FindAllMaps(MapHandleList* maps) const { ExtractMaps(maps); }
 
   virtual InlineCacheState StateFromFeedback() const = 0;
-  virtual int ExtractMaps(MapHandleList* maps) const = 0;
-  virtual MaybeHandle<Code> FindHandlerForMap(Handle<Map> map) const = 0;
-  virtual bool FindHandlers(CodeHandleList* code_list, int length = -1) const {
-    return length == 0;
-  }
+  virtual int ExtractMaps(MapHandleList* maps) const;
+  virtual MaybeHandle<Code> FindHandlerForMap(Handle<Map> map) const;
+  virtual bool FindHandlers(CodeHandleList* code_list, int length = -1) const;
   virtual Name* FindFirstName() const { return NULL; }
 
   Object* GetFeedback() const { return vector()->Get(slot()); }
+  Object* GetFeedbackExtra() const {
+    DCHECK(TypeFeedbackVector::elements_per_ic_slot() > 1);
+    int extra_index = vector()->GetIndex(slot()) + 1;
+    return vector()->get(extra_index);
+  }
 
  protected:
   Isolate* GetIsolate() const { return vector()->GetIsolate(); }
@@ -261,13 +267,17 @@ class FeedbackNexus {
     vector()->Set(slot(), feedback, mode);
   }
 
+  void SetFeedbackExtra(Object* feedback_extra,
+                        WriteBarrierMode mode = UPDATE_WRITE_BARRIER) {
+    DCHECK(TypeFeedbackVector::elements_per_ic_slot() > 1);
+    int index = vector()->GetIndex(slot()) + 1;
+    vector()->set(index, feedback_extra, mode);
+  }
+
   Handle<FixedArray> EnsureArrayOfSize(int length);
-  void InstallHandlers(int start_index, MapHandleList* maps,
+  Handle<FixedArray> EnsureExtraArrayOfSize(int length);
+  void InstallHandlers(Handle<FixedArray> array, MapHandleList* maps,
                        CodeHandleList* handlers);
-  int ExtractMaps(int start_index, MapHandleList* maps) const;
-  MaybeHandle<Code> FindHandlerForMap(int start_index, Handle<Map> map) const;
-  bool FindHandlers(int start_index, CodeHandleList* code_list,
-                    int length) const;
 
  private:
   // The reason for having a vector handle and a raw pointer is that we can and
@@ -334,10 +344,6 @@ class LoadICNexus : public FeedbackNexus {
   void ConfigurePolymorphic(MapHandleList* maps, CodeHandleList* handlers);
 
   InlineCacheState StateFromFeedback() const OVERRIDE;
-  int ExtractMaps(MapHandleList* maps) const OVERRIDE;
-  MaybeHandle<Code> FindHandlerForMap(Handle<Map> map) const OVERRIDE;
-  virtual bool FindHandlers(CodeHandleList* code_list,
-                            int length = -1) const OVERRIDE;
 };
 
 
@@ -364,10 +370,6 @@ class KeyedLoadICNexus : public FeedbackNexus {
                             CodeHandleList* handlers);
 
   InlineCacheState StateFromFeedback() const OVERRIDE;
-  int ExtractMaps(MapHandleList* maps) const OVERRIDE;
-  MaybeHandle<Code> FindHandlerForMap(Handle<Map> map) const OVERRIDE;
-  virtual bool FindHandlers(CodeHandleList* code_list,
-                            int length = -1) const OVERRIDE;
   Name* FindFirstName() const OVERRIDE;
 };
 }
index e5836fd33e1031b7b56df60fcacc476de35e5658..1d1f9b44246061518278527d50f535606ab89939 100644 (file)
@@ -11,6 +11,7 @@
 #include "src/codegen.h"
 #include "src/ic/handler-compiler.h"
 #include "src/ic/ic.h"
+#include "src/ic/stub-cache.h"
 #include "src/isolate.h"
 #include "src/jsregexp.h"
 #include "src/regexp-macro-assembler.h"
@@ -4337,15 +4338,230 @@ void StubFailureTrampolineStub::Generate(MacroAssembler* masm) {
 
 void LoadICTrampolineStub::Generate(MacroAssembler* masm) {
   EmitLoadTypeFeedbackVector(masm, VectorLoadICDescriptor::VectorRegister());
-  VectorLoadStub stub(isolate(), state());
-  __ jmp(stub.GetCode(), RelocInfo::CODE_TARGET);
+  VectorRawLoadStub stub(isolate(), state());
+  stub.GenerateForTrampoline(masm);
 }
 
 
 void KeyedLoadICTrampolineStub::Generate(MacroAssembler* masm) {
   EmitLoadTypeFeedbackVector(masm, VectorLoadICDescriptor::VectorRegister());
-  VectorKeyedLoadStub stub(isolate());
-  __ jmp(stub.GetCode(), RelocInfo::CODE_TARGET);
+  VectorRawKeyedLoadStub stub(isolate());
+  stub.GenerateForTrampoline(masm);
+}
+
+
+static void HandleArrayCases(MacroAssembler* masm, Register receiver,
+                             Register key, Register vector, Register slot,
+                             Register feedback, Register scratch1,
+                             Register scratch2, Register scratch3,
+                             Register scratch4, bool is_polymorphic,
+                             Label* miss) {
+  // feedback initially contains the feedback array
+  Label next_loop, prepare_next;
+  Label load_smi_map, compare_map;
+  Label start_polymorphic;
+
+  Register receiver_map = scratch1;
+  Register counter = scratch2;
+  Register length = scratch3;
+  Register cached_map = scratch4;
+
+  // Receiver might not be a heap object.
+  __ JumpIfSmi(receiver, &load_smi_map);
+  __ movp(receiver_map, FieldOperand(receiver, 0));
+  __ bind(&compare_map);
+  __ movp(cached_map, FieldOperand(feedback, FixedArray::OffsetOfElementAt(0)));
+  __ cmpp(receiver_map, FieldOperand(cached_map, WeakCell::kValueOffset));
+  __ j(not_equal, &start_polymorphic);
+
+  // found, now call handler.
+  Register handler = feedback;
+  __ movp(handler, FieldOperand(feedback, FixedArray::OffsetOfElementAt(1)));
+  __ leap(handler, FieldOperand(handler, Code::kHeaderSize));
+  __ jmp(handler);
+
+  // Polymorphic, we have to loop from 2 to N
+  __ bind(&start_polymorphic);
+  __ SmiToInteger32(length, FieldOperand(feedback, FixedArray::kLengthOffset));
+  if (!is_polymorphic) {
+    // If the IC could be monomorphic we have to make sure we don't go past the
+    // end of the feedback array.
+    __ cmpl(length, Immediate(2));
+    __ j(equal, miss);
+  }
+  __ movl(counter, Immediate(2));
+
+  __ bind(&next_loop);
+  __ movp(cached_map, FieldOperand(feedback, counter, times_pointer_size,
+                                   FixedArray::kHeaderSize));
+  __ cmpp(receiver_map, FieldOperand(cached_map, WeakCell::kValueOffset));
+  __ j(not_equal, &prepare_next);
+  __ movp(handler, FieldOperand(feedback, counter, times_pointer_size,
+                                FixedArray::kHeaderSize + kPointerSize));
+  __ leap(handler, FieldOperand(handler, Code::kHeaderSize));
+  __ jmp(handler);
+
+  __ bind(&prepare_next);
+  __ addl(counter, Immediate(2));
+  __ cmpl(counter, length);
+  __ j(less, &next_loop);
+
+  // We exhausted our array of map handler pairs.
+  __ jmp(miss);
+
+  __ bind(&load_smi_map);
+  __ LoadRoot(receiver_map, Heap::kHeapNumberMapRootIndex);
+  __ jmp(&compare_map);
+}
+
+
+static void HandleMonomorphicCase(MacroAssembler* masm, Register receiver,
+                                  Register key, Register vector, Register slot,
+                                  Register weak_cell, Register integer_slot,
+                                  Label* miss) {
+  // feedback initially contains the feedback array
+  Label compare_smi_map;
+
+  // Move the weak map into the weak_cell register.
+  Register ic_map = weak_cell;
+  __ movp(ic_map, FieldOperand(weak_cell, WeakCell::kValueOffset));
+
+  // Receiver might not be a heap object.
+  __ JumpIfSmi(receiver, &compare_smi_map);
+  __ cmpp(ic_map, FieldOperand(receiver, 0));
+  __ j(not_equal, miss);
+  Register handler = weak_cell;
+  __ movp(handler, FieldOperand(vector, integer_slot, times_pointer_size,
+                                FixedArray::kHeaderSize + kPointerSize));
+  __ leap(handler, FieldOperand(handler, Code::kHeaderSize));
+  __ jmp(handler);
+
+  // 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);
+  __ movp(handler, FieldOperand(vector, integer_slot, times_pointer_size,
+                                FixedArray::kHeaderSize + kPointerSize));
+  __ leap(handler, FieldOperand(handler, Code::kHeaderSize));
+  __ jmp(handler);
+}
+
+
+void VectorRawLoadStub::Generate(MacroAssembler* masm) {
+  GenerateImpl(masm, false);
+}
+
+
+void VectorRawLoadStub::GenerateForTrampoline(MacroAssembler* masm) {
+  GenerateImpl(masm, true);
+}
+
+
+void VectorRawLoadStub::GenerateImpl(MacroAssembler* masm, bool in_frame) {
+  Register receiver = VectorLoadICDescriptor::ReceiverRegister();  // rdx
+  Register name = VectorLoadICDescriptor::NameRegister();          // rcx
+  Register vector = VectorLoadICDescriptor::VectorRegister();      // rbx
+  Register slot = VectorLoadICDescriptor::SlotRegister();          // rax
+  Register feedback = rdi;
+  Register integer_slot = r8;
+
+  __ SmiToInteger32(integer_slot, slot);
+  __ movp(feedback, FieldOperand(vector, integer_slot, times_pointer_size,
+                                 FixedArray::kHeaderSize));
+
+  // Is it a weak cell?
+  Label try_array;
+  Label not_array, smi_key, key_okay, miss;
+  __ CompareRoot(FieldOperand(feedback, 0), Heap::kWeakCellMapRootIndex);
+  __ j(not_equal, &try_array);
+  HandleMonomorphicCase(masm, receiver, name, vector, slot, feedback,
+                        integer_slot, &miss);
+
+  // Is it a fixed array?
+  __ bind(&try_array);
+  __ CompareRoot(FieldOperand(feedback, 0), Heap::kFixedArrayMapRootIndex);
+  __ j(not_equal, &not_array);
+  HandleArrayCases(masm, receiver, name, vector, slot, feedback, integer_slot,
+                   r9, r11, r15, true, &miss);
+
+  __ bind(&not_array);
+  __ CompareRoot(feedback, Heap::kmegamorphic_symbolRootIndex);
+  __ j(not_equal, &miss);
+  Code::Flags code_flags = Code::RemoveTypeAndHolderFromFlags(
+      Code::ComputeHandlerFlags(Code::LOAD_IC));
+  masm->isolate()->stub_cache()->GenerateProbe(
+      masm, Code::LOAD_IC, code_flags, false, receiver, name, feedback, no_reg);
+
+  __ bind(&miss);
+  LoadIC::GenerateMiss(masm);
+}
+
+
+void VectorRawKeyedLoadStub::Generate(MacroAssembler* masm) {
+  GenerateImpl(masm, false);
+}
+
+
+void VectorRawKeyedLoadStub::GenerateForTrampoline(MacroAssembler* masm) {
+  GenerateImpl(masm, true);
+}
+
+
+void VectorRawKeyedLoadStub::GenerateImpl(MacroAssembler* masm, bool in_frame) {
+  Register receiver = VectorLoadICDescriptor::ReceiverRegister();  // rdx
+  Register key = VectorLoadICDescriptor::NameRegister();           // rcx
+  Register vector = VectorLoadICDescriptor::VectorRegister();      // rbx
+  Register slot = VectorLoadICDescriptor::SlotRegister();          // rax
+  Register feedback = rdi;
+  Register integer_slot = r8;
+
+  __ SmiToInteger32(integer_slot, slot);
+  __ movp(feedback, FieldOperand(vector, integer_slot, times_pointer_size,
+                                 FixedArray::kHeaderSize));
+
+  // Is it a weak cell?
+  Label try_array;
+  Label not_array, smi_key, key_okay, miss;
+  __ CompareRoot(FieldOperand(feedback, 0), Heap::kWeakCellMapRootIndex);
+  __ j(not_equal, &try_array);
+  __ JumpIfNotSmi(key, &miss);
+  HandleMonomorphicCase(masm, receiver, key, vector, slot, feedback,
+                        integer_slot, &miss);
+
+  __ bind(&try_array);
+  // Is it a fixed array?
+  __ CompareRoot(FieldOperand(feedback, 0), Heap::kFixedArrayMapRootIndex);
+  __ j(not_equal, &not_array);
+  // We have a polymorphic element handler.
+  __ JumpIfNotSmi(key, &miss);
+
+  Label polymorphic, try_poly_name;
+  __ bind(&polymorphic);
+  HandleArrayCases(masm, receiver, key, vector, slot, feedback, integer_slot,
+                   r9, r11, r15, true, &miss);
+
+  __ bind(&not_array);
+  // Is it generic?
+  __ CompareRoot(feedback, Heap::kmegamorphic_symbolRootIndex);
+  __ j(not_equal, &try_poly_name);
+  Handle<Code> megamorphic_stub =
+      KeyedLoadIC::ChooseMegamorphicStub(masm->isolate());
+  __ 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.
+  __ cmpp(key, feedback);
+  __ j(not_equal, &miss);
+  // If the name comparison succeeded, we know we have a fixed array with
+  // at least one map/handler pair.
+  __ movp(feedback, FieldOperand(vector, integer_slot, times_pointer_size,
+                                 FixedArray::kHeaderSize + kPointerSize));
+  HandleArrayCases(masm, receiver, key, vector, slot, feedback, integer_slot,
+                   r9, r11, r15, false, &miss);
+
+  __ bind(&miss);
+  KeyedLoadIC::GenerateMiss(masm);
 }
 
 
index fe7198cded852d63a4bb3e3001dc4abe3483a023..d375ba36a0b79c69755aca8dac7718f08f715a3d 100644 (file)
@@ -71,8 +71,8 @@ TEST(VectorStructure) {
   CHECK_EQ(index,
            TypeFeedbackVector::kReservedIndexCount + metadata_length + 3);
   CHECK(FeedbackVectorICSlot(0) == vector->ToICSlot(index));
-
-  CHECK_EQ(TypeFeedbackVector::kReservedIndexCount + metadata_length + 3 + 5,
+  CHECK_EQ(TypeFeedbackVector::kReservedIndexCount + metadata_length + 3 +
+               5 * TypeFeedbackVector::elements_per_ic_slot(),
            vector->length());
 }