To aid vector-based load ic work, we need to be able to handle
authormvstanton@chromium.org <mvstanton@chromium.org>
Mon, 8 Sep 2014 12:51:29 +0000 (12:51 +0000)
committermvstanton@chromium.org <mvstanton@chromium.org>
Mon, 8 Sep 2014 12:51:29 +0000 (12:51 +0000)
the megamorphic load case in hydrogen. A simple approach is to
wrap the probe activity in a hydrogen instruction.

The instruction is novel in that it always tail-calls away.

R=yangguo@chromium.org

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

git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@23772 ce2b1a6d-e550-0410-aec6-3dcde31c8c00

30 files changed:
src/arm/lithium-arm.cc
src/arm/lithium-arm.h
src/arm/lithium-codegen-arm.cc
src/arm64/lithium-arm64.cc
src/arm64/lithium-arm64.h
src/arm64/lithium-codegen-arm64.cc
src/code-stubs-hydrogen.cc
src/code-stubs.cc
src/code-stubs.h
src/hydrogen-instructions.cc
src/hydrogen-instructions.h
src/ia32/lithium-codegen-ia32.cc
src/ia32/lithium-ia32.cc
src/ia32/lithium-ia32.h
src/ic/arm/ic-arm.cc
src/ic/arm/stub-cache-arm.cc
src/ic/arm64/ic-arm64.cc
src/ic/arm64/stub-cache-arm64.cc
src/ic/ia32/ic-ia32.cc
src/ic/ia32/stub-cache-ia32.cc
src/ic/ic-compiler.cc
src/ic/ic-compiler.h
src/ic/ic.cc
src/ic/ic.h
src/ic/stub-cache.h
src/ic/x64/ic-x64.cc
src/ic/x64/stub-cache-x64.cc
src/x64/lithium-codegen-x64.cc
src/x64/lithium-x64.cc
src/x64/lithium-x64.h

index 17bfebccd45594072df44c6d298c2a6227147a46..704bb6aa658171f36fc126ff635e755426ede620 100644 (file)
@@ -1099,6 +1099,19 @@ LInstruction* LChunkBuilder::DoCallWithDescriptor(
 }
 
 
+LInstruction* LChunkBuilder::DoTailCallThroughMegamorphicCache(
+    HTailCallThroughMegamorphicCache* instr) {
+  LOperand* context = UseFixed(instr->context(), cp);
+  LOperand* receiver_register =
+      UseFixed(instr->receiver(), LoadDescriptor::ReceiverRegister());
+  LOperand* name_register =
+      UseFixed(instr->name(), LoadDescriptor::NameRegister());
+  // Not marked as call. It can't deoptimize, and it never returns.
+  return new (zone()) LTailCallThroughMegamorphicCache(
+      context, receiver_register, name_register);
+}
+
+
 LInstruction* LChunkBuilder::DoInvokeFunction(HInvokeFunction* instr) {
   LOperand* context = UseFixed(instr->context(), cp);
   LOperand* function = UseFixed(instr->function(), r1);
index 3284d5401d64ddd4ad121cd6300a5a3ebf8a9659..1d0ce1571a7c20b8b0d8a821940f6cea7da69f0f 100644 (file)
@@ -154,6 +154,7 @@ class LCodeGen;
   V(SubI)                                    \
   V(RSubI)                                   \
   V(TaggedToI)                               \
+  V(TailCallThroughMegamorphicCache)         \
   V(ThisFunction)                            \
   V(ToFastProperties)                        \
   V(TransitionElementsKind)                  \
@@ -482,6 +483,26 @@ class LCallStub FINAL : public LTemplateInstruction<1, 1, 0> {
 };
 
 
+class LTailCallThroughMegamorphicCache FINAL
+    : public LTemplateInstruction<0, 3, 0> {
+ public:
+  explicit LTailCallThroughMegamorphicCache(LOperand* context,
+                                            LOperand* receiver,
+                                            LOperand* name) {
+    inputs_[0] = context;
+    inputs_[1] = receiver;
+    inputs_[2] = name;
+  }
+
+  LOperand* context() { return inputs_[0]; }
+  LOperand* receiver() { return inputs_[1]; }
+  LOperand* name() { return inputs_[2]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(TailCallThroughMegamorphicCache,
+                               "tail-call-through-megamorphic-cache")
+  DECLARE_HYDROGEN_ACCESSOR(TailCallThroughMegamorphicCache)
+};
+
 class LUnknownOSRValue FINAL : public LTemplateInstruction<1, 0, 0> {
  public:
   virtual bool HasInterestingComment(LCodeGen* gen) const OVERRIDE {
index 5668bcab620f73e1f8bd607451bbbf95e4cf8283..ab1e45439b7d47d7b5d2c7be1c9b11d6b0359c38 100644 (file)
@@ -9,6 +9,7 @@
 #include "src/base/bits.h"
 #include "src/code-stubs.h"
 #include "src/hydrogen-osr.h"
+#include "src/ic/stub-cache.h"
 
 namespace v8 {
 namespace internal {
@@ -3969,6 +3970,34 @@ void LCodeGen::DoInvokeFunction(LInvokeFunction* instr) {
 }
 
 
+void LCodeGen::DoTailCallThroughMegamorphicCache(
+    LTailCallThroughMegamorphicCache* instr) {
+  Register receiver = ToRegister(instr->receiver());
+  Register name = ToRegister(instr->name());
+  DCHECK(receiver.is(LoadDescriptor::ReceiverRegister()));
+  DCHECK(name.is(LoadDescriptor::NameRegister()));
+  DCHECK(receiver.is(r1));
+  DCHECK(name.is(r2));
+
+  Register scratch = r3;
+  Register extra = r4;
+  Register extra2 = r5;
+  Register extra3 = r6;
+
+  // Important for the tail-call.
+  bool must_teardown_frame = NeedsEagerFrame();
+
+  // The probe will tail call to a handler if found.
+  isolate()->stub_cache()->GenerateProbe(masm(), instr->hydrogen()->flags(),
+                                         must_teardown_frame, receiver, name,
+                                         scratch, extra, extra2, extra3);
+
+  // Tail call to miss if we ended up here.
+  if (must_teardown_frame) __ LeaveFrame(StackFrame::INTERNAL);
+  LoadIC::GenerateMiss(masm());
+}
+
+
 void LCodeGen::DoCallWithDescriptor(LCallWithDescriptor* instr) {
   DCHECK(ToRegister(instr->result()).is(r0));
 
index 739f43ad1ff55aa95f145d2ddc7ab33f86bc7345..0975587fe643c135ffdae36d95f50242a3a83d02 100644 (file)
@@ -1562,6 +1562,19 @@ LInstruction* LChunkBuilder::DoInstanceOfKnownGlobal(
 }
 
 
+LInstruction* LChunkBuilder::DoTailCallThroughMegamorphicCache(
+    HTailCallThroughMegamorphicCache* instr) {
+  LOperand* context = UseFixed(instr->context(), cp);
+  LOperand* receiver_register =
+      UseFixed(instr->receiver(), LoadDescriptor::ReceiverRegister());
+  LOperand* name_register =
+      UseFixed(instr->name(), LoadDescriptor::NameRegister());
+  // Not marked as call. It can't deoptimize, and it never returns.
+  return new (zone()) LTailCallThroughMegamorphicCache(
+      context, receiver_register, name_register);
+}
+
+
 LInstruction* LChunkBuilder::DoInvokeFunction(HInvokeFunction* instr) {
   LOperand* context = UseFixed(instr->context(), cp);
   // The function is required (by MacroAssembler::InvokeFunction) to be in x1.
index f8ba5701477f6256c38775a24a395fca0ec84f6e..2a64d0635aee3e3c85c67b7dfa2c697384545157 100644 (file)
@@ -165,6 +165,7 @@ class LCodeGen;
   V(SubI)                                    \
   V(SubS)                                    \
   V(TaggedToI)                               \
+  V(TailCallThroughMegamorphicCache)         \
   V(ThisFunction)                            \
   V(ToFastProperties)                        \
   V(TransitionElementsKind)                  \
@@ -324,6 +325,27 @@ class LTemplateInstruction : public LTemplateResultInstruction<R> {
 };
 
 
+class LTailCallThroughMegamorphicCache FINAL
+    : public LTemplateInstruction<0, 3, 0> {
+ public:
+  explicit LTailCallThroughMegamorphicCache(LOperand* context,
+                                            LOperand* receiver,
+                                            LOperand* name) {
+    inputs_[0] = context;
+    inputs_[1] = receiver;
+    inputs_[2] = name;
+  }
+
+  LOperand* context() { return inputs_[0]; }
+  LOperand* receiver() { return inputs_[1]; }
+  LOperand* name() { return inputs_[2]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(TailCallThroughMegamorphicCache,
+                               "tail-call-through-megamorphic-cache")
+  DECLARE_HYDROGEN_ACCESSOR(TailCallThroughMegamorphicCache)
+};
+
+
 class LUnknownOSRValue FINAL : public LTemplateInstruction<1, 0, 0> {
  public:
   virtual bool HasInterestingComment(LCodeGen* gen) const OVERRIDE {
index 8c9507c9817a92311846c3b8624bfcf2b4175a19..904eecd2e10a0b2672249241dabf62b2d28ddc9a 100644 (file)
@@ -9,6 +9,7 @@
 #include "src/base/bits.h"
 #include "src/code-stubs.h"
 #include "src/hydrogen-osr.h"
+#include "src/ic/stub-cache.h"
 
 namespace v8 {
 namespace internal {
@@ -2037,6 +2038,34 @@ void LCodeGen::CallKnownFunction(Handle<JSFunction> function,
 }
 
 
+void LCodeGen::DoTailCallThroughMegamorphicCache(
+    LTailCallThroughMegamorphicCache* instr) {
+  Register receiver = ToRegister(instr->receiver());
+  Register name = ToRegister(instr->name());
+  DCHECK(receiver.is(LoadDescriptor::ReceiverRegister()));
+  DCHECK(name.is(LoadDescriptor::NameRegister()));
+  DCHECK(receiver.is(x1));
+  DCHECK(name.is(x2));
+
+  Register scratch = x3;
+  Register extra = x4;
+  Register extra2 = x5;
+  Register extra3 = x6;
+
+  // Important for the tail-call.
+  bool must_teardown_frame = NeedsEagerFrame();
+
+  // The probe will tail call to a handler if found.
+  isolate()->stub_cache()->GenerateProbe(masm(), instr->hydrogen()->flags(),
+                                         must_teardown_frame, receiver, name,
+                                         scratch, extra, extra2, extra3);
+
+  // Tail call to miss if we ended up here.
+  if (must_teardown_frame) __ LeaveFrame(StackFrame::INTERNAL);
+  LoadIC::GenerateMiss(masm());
+}
+
+
 void LCodeGen::DoCallWithDescriptor(LCallWithDescriptor* instr) {
   DCHECK(instr->IsMarkedAsCall());
   DCHECK(ToRegister(instr->result()).Is(x0));
index f2b04f766884ff7dfb8ee8115b95a108a51fbe61..53bbce74c6d45cd8e8146d49a2c7243692ba5c7d 100644 (file)
@@ -1808,4 +1808,25 @@ HValue* CodeStubGraphBuilder<VectorKeyedLoadStub>::BuildCodeStub() {
 Handle<Code> VectorKeyedLoadStub::GenerateCode() {
   return DoGenerateCode(this);
 }
+
+
+Handle<Code> MegamorphicLoadStub::GenerateCode() {
+  return DoGenerateCode(this);
+}
+
+
+template <>
+HValue* CodeStubGraphBuilder<MegamorphicLoadStub>::BuildCodeStub() {
+  // The return address is on the stack.
+  HValue* receiver = GetParameter(LoadDescriptor::kReceiverIndex);
+  HValue* name = GetParameter(LoadDescriptor::kNameIndex);
+
+  // Probe the stub cache.
+  Code::Flags flags = Code::RemoveTypeAndHolderFromFlags(
+      Code::ComputeHandlerFlags(Code::LOAD_IC));
+  Add<HTailCallThroughMegamorphicCache>(receiver, name, flags);
+
+  // We never continue.
+  return graph()->GetConstant0();
+}
 } }  // namespace v8::internal
index d831c618b714e739831577d9f3a3fb68df5af78e..4410692d863f9a03ca568981e9cbdf6ef675f061 100644 (file)
@@ -619,6 +619,13 @@ void VectorKeyedLoadStub::InitializeInterfaceDescriptor(
 }
 
 
+void MegamorphicLoadStub::InitializeInterfaceDescriptor(
+    CodeStubInterfaceDescriptor* descriptor) {
+  LoadDescriptor call_descriptor(isolate());
+  descriptor->Initialize(MajorKey(), call_descriptor);
+}
+
+
 void FastNewClosureStub::InitializeInterfaceDescriptor(
     CodeStubInterfaceDescriptor* descriptor) {
   FastNewClosureDescriptor call_descriptor(isolate());
index 8683837ee17e0a93a62cd98f6a4a73df4dc93c05..93a0dcff4e92695934d4cee33e191c8a629c7ae0 100644 (file)
@@ -67,6 +67,7 @@ namespace internal {
   V(KeyedLoadGeneric)                       \
   V(LoadDictionaryElement)                  \
   V(LoadFastElement)                        \
+  V(MegamorphicLoad)                        \
   V(NameDictionaryLookup)                   \
   V(NumberToString)                         \
   V(RegExpConstructResult)                  \
@@ -1733,6 +1734,27 @@ class KeyedLoadICTrampolineStub : public LoadICTrampolineStub {
 };
 
 
+class MegamorphicLoadStub : public HydrogenCodeStub {
+ public:
+  MegamorphicLoadStub(Isolate* isolate, const LoadIC::State& state)
+      : HydrogenCodeStub(isolate) {
+    set_sub_minor_key(state.GetExtraICState());
+  }
+
+  virtual Code::Kind GetCodeKind() const OVERRIDE { return Code::LOAD_IC; }
+
+  virtual InlineCacheState GetICState() const FINAL OVERRIDE {
+    return MEGAMORPHIC;
+  }
+
+  virtual ExtraICState GetExtraICState() const FINAL OVERRIDE {
+    return static_cast<ExtraICState>(sub_minor_key());
+  }
+
+  DEFINE_HYDROGEN_CODE_STUB(MegamorphicLoad, HydrogenCodeStub);
+};
+
+
 class VectorLoadStub : public HydrogenCodeStub {
  public:
   explicit VectorLoadStub(Isolate* isolate, const LoadIC::State& state)
index 09f6ac120788666ec982a99cd509340b12080fde..8539da21e8e3e86e6042a8f65ece245b8496b8aa 100644 (file)
@@ -846,6 +846,7 @@ bool HInstruction::CanDeoptimize() {
     case HValue::kStoreNamedGeneric:
     case HValue::kStringCharCodeAt:
     case HValue::kStringCharFromCode:
+    case HValue::kTailCallThroughMegamorphicCache:
     case HValue::kThisFunction:
     case HValue::kTypeofIsAndBranch:
     case HValue::kUnknownOSRValue:
@@ -1702,6 +1703,15 @@ OStream& HCallStub::PrintDataTo(OStream& os) const {  // NOLINT
 }
 
 
+OStream& HTailCallThroughMegamorphicCache::PrintDataTo(
+    OStream& os) const {  // NOLINT
+  for (int i = 0; i < OperandCount(); i++) {
+    os << NameOf(OperandAt(i)) << " ";
+  }
+  return os << "flags: " << flags();
+}
+
+
 OStream& HUnknownOSRValue::PrintDataTo(OStream& os) const {  // NOLINT
   const char* type = "expression";
   if (environment_->is_local_index(index_)) type = "local";
index dc087be92b18155a7623f8b96acf50ddd53ac548..1844715dbdf91c7257f964cffd1622b6ab2e9484 100644 (file)
@@ -37,133 +37,134 @@ class LInstruction;
 class LChunkBuilder;
 class OStream;
 
-#define HYDROGEN_ABSTRACT_INSTRUCTION_LIST(V)  \
-  V(ArithmeticBinaryOperation)                 \
-  V(BinaryOperation)                           \
-  V(BitwiseBinaryOperation)                    \
-  V(ControlInstruction)                        \
-  V(Instruction)                               \
-
-
-#define HYDROGEN_CONCRETE_INSTRUCTION_LIST(V)  \
-  V(AbnormalExit)                              \
-  V(AccessArgumentsAt)                         \
-  V(Add)                                       \
-  V(AllocateBlockContext)                      \
-  V(Allocate)                                  \
-  V(ApplyArguments)                            \
-  V(ArgumentsElements)                         \
-  V(ArgumentsLength)                           \
-  V(ArgumentsObject)                           \
-  V(Bitwise)                                   \
-  V(BlockEntry)                                \
-  V(BoundsCheck)                               \
-  V(BoundsCheckBaseIndexInformation)           \
-  V(Branch)                                    \
-  V(CallWithDescriptor)                        \
-  V(CallJSFunction)                            \
-  V(CallFunction)                              \
-  V(CallNew)                                   \
-  V(CallNewArray)                              \
-  V(CallRuntime)                               \
-  V(CallStub)                                  \
-  V(CapturedObject)                            \
-  V(Change)                                    \
-  V(CheckHeapObject)                           \
-  V(CheckInstanceType)                         \
-  V(CheckMaps)                                 \
-  V(CheckMapValue)                             \
-  V(CheckSmi)                                  \
-  V(CheckValue)                                \
-  V(ClampToUint8)                              \
-  V(ClassOfTestAndBranch)                      \
-  V(CompareNumericAndBranch)                   \
-  V(CompareHoleAndBranch)                      \
-  V(CompareGeneric)                            \
-  V(CompareMinusZeroAndBranch)                 \
-  V(CompareObjectEqAndBranch)                  \
-  V(CompareMap)                                \
-  V(Constant)                                  \
-  V(ConstructDouble)                           \
-  V(Context)                                   \
-  V(DateField)                                 \
-  V(DebugBreak)                                \
-  V(DeclareGlobals)                            \
-  V(Deoptimize)                                \
-  V(Div)                                       \
-  V(DoubleBits)                                \
-  V(DummyUse)                                  \
-  V(EnterInlined)                              \
-  V(EnvironmentMarker)                         \
-  V(ForceRepresentation)                       \
-  V(ForInCacheArray)                           \
-  V(ForInPrepareMap)                           \
-  V(FunctionLiteral)                           \
-  V(GetCachedArrayIndex)                       \
-  V(Goto)                                      \
-  V(HasCachedArrayIndexAndBranch)              \
-  V(HasInstanceTypeAndBranch)                  \
-  V(InnerAllocatedObject)                      \
-  V(InstanceOf)                                \
-  V(InstanceOfKnownGlobal)                     \
-  V(InvokeFunction)                            \
-  V(IsConstructCallAndBranch)                  \
-  V(IsObjectAndBranch)                         \
-  V(IsStringAndBranch)                         \
-  V(IsSmiAndBranch)                            \
-  V(IsUndetectableAndBranch)                   \
-  V(LeaveInlined)                              \
-  V(LoadContextSlot)                           \
-  V(LoadFieldByIndex)                          \
-  V(LoadFunctionPrototype)                     \
-  V(LoadGlobalCell)                            \
-  V(LoadGlobalGeneric)                         \
-  V(LoadKeyed)                                 \
-  V(LoadKeyedGeneric)                          \
-  V(LoadNamedField)                            \
-  V(LoadNamedGeneric)                          \
-  V(LoadRoot)                                  \
-  V(MapEnumLength)                             \
-  V(MathFloorOfDiv)                            \
-  V(MathMinMax)                                \
-  V(Mod)                                       \
-  V(Mul)                                       \
-  V(OsrEntry)                                  \
-  V(Parameter)                                 \
-  V(Power)                                     \
-  V(PushArguments)                             \
-  V(RegExpLiteral)                             \
-  V(Return)                                    \
-  V(Ror)                                       \
-  V(Sar)                                       \
-  V(SeqStringGetChar)                          \
-  V(SeqStringSetChar)                          \
-  V(Shl)                                       \
-  V(Shr)                                       \
-  V(Simulate)                                  \
-  V(StackCheck)                                \
-  V(StoreCodeEntry)                            \
-  V(StoreContextSlot)                          \
-  V(StoreFrameContext)                         \
-  V(StoreGlobalCell)                           \
-  V(StoreKeyed)                                \
-  V(StoreKeyedGeneric)                         \
-  V(StoreNamedField)                           \
-  V(StoreNamedGeneric)                         \
-  V(StringAdd)                                 \
-  V(StringCharCodeAt)                          \
-  V(StringCharFromCode)                        \
-  V(StringCompareAndBranch)                    \
-  V(Sub)                                       \
-  V(ThisFunction)                              \
-  V(ToFastProperties)                          \
-  V(TransitionElementsKind)                    \
-  V(TrapAllocationMemento)                     \
-  V(Typeof)                                    \
-  V(TypeofIsAndBranch)                         \
-  V(UnaryMathOperation)                        \
-  V(UnknownOSRValue)                           \
-  V(UseConst)                                  \
+#define HYDROGEN_ABSTRACT_INSTRUCTION_LIST(V) \
+  V(ArithmeticBinaryOperation)                \
+  V(BinaryOperation)                          \
+  V(BitwiseBinaryOperation)                   \
+  V(ControlInstruction)                       \
+  V(Instruction)
+
+
+#define HYDROGEN_CONCRETE_INSTRUCTION_LIST(V) \
+  V(AbnormalExit)                             \
+  V(AccessArgumentsAt)                        \
+  V(Add)                                      \
+  V(AllocateBlockContext)                     \
+  V(Allocate)                                 \
+  V(ApplyArguments)                           \
+  V(ArgumentsElements)                        \
+  V(ArgumentsLength)                          \
+  V(ArgumentsObject)                          \
+  V(Bitwise)                                  \
+  V(BlockEntry)                               \
+  V(BoundsCheck)                              \
+  V(BoundsCheckBaseIndexInformation)          \
+  V(Branch)                                   \
+  V(CallWithDescriptor)                       \
+  V(CallJSFunction)                           \
+  V(CallFunction)                             \
+  V(CallNew)                                  \
+  V(CallNewArray)                             \
+  V(CallRuntime)                              \
+  V(CallStub)                                 \
+  V(CapturedObject)                           \
+  V(Change)                                   \
+  V(CheckHeapObject)                          \
+  V(CheckInstanceType)                        \
+  V(CheckMaps)                                \
+  V(CheckMapValue)                            \
+  V(CheckSmi)                                 \
+  V(CheckValue)                               \
+  V(ClampToUint8)                             \
+  V(ClassOfTestAndBranch)                     \
+  V(CompareNumericAndBranch)                  \
+  V(CompareHoleAndBranch)                     \
+  V(CompareGeneric)                           \
+  V(CompareMinusZeroAndBranch)                \
+  V(CompareObjectEqAndBranch)                 \
+  V(CompareMap)                               \
+  V(Constant)                                 \
+  V(ConstructDouble)                          \
+  V(Context)                                  \
+  V(DateField)                                \
+  V(DebugBreak)                               \
+  V(DeclareGlobals)                           \
+  V(Deoptimize)                               \
+  V(Div)                                      \
+  V(DoubleBits)                               \
+  V(DummyUse)                                 \
+  V(EnterInlined)                             \
+  V(EnvironmentMarker)                        \
+  V(ForceRepresentation)                      \
+  V(ForInCacheArray)                          \
+  V(ForInPrepareMap)                          \
+  V(FunctionLiteral)                          \
+  V(GetCachedArrayIndex)                      \
+  V(Goto)                                     \
+  V(HasCachedArrayIndexAndBranch)             \
+  V(HasInstanceTypeAndBranch)                 \
+  V(InnerAllocatedObject)                     \
+  V(InstanceOf)                               \
+  V(InstanceOfKnownGlobal)                    \
+  V(InvokeFunction)                           \
+  V(IsConstructCallAndBranch)                 \
+  V(IsObjectAndBranch)                        \
+  V(IsStringAndBranch)                        \
+  V(IsSmiAndBranch)                           \
+  V(IsUndetectableAndBranch)                  \
+  V(LeaveInlined)                             \
+  V(LoadContextSlot)                          \
+  V(LoadFieldByIndex)                         \
+  V(LoadFunctionPrototype)                    \
+  V(LoadGlobalCell)                           \
+  V(LoadGlobalGeneric)                        \
+  V(LoadKeyed)                                \
+  V(LoadKeyedGeneric)                         \
+  V(LoadNamedField)                           \
+  V(LoadNamedGeneric)                         \
+  V(LoadRoot)                                 \
+  V(MapEnumLength)                            \
+  V(MathFloorOfDiv)                           \
+  V(MathMinMax)                               \
+  V(Mod)                                      \
+  V(Mul)                                      \
+  V(OsrEntry)                                 \
+  V(Parameter)                                \
+  V(Power)                                    \
+  V(PushArguments)                            \
+  V(RegExpLiteral)                            \
+  V(Return)                                   \
+  V(Ror)                                      \
+  V(Sar)                                      \
+  V(SeqStringGetChar)                         \
+  V(SeqStringSetChar)                         \
+  V(Shl)                                      \
+  V(Shr)                                      \
+  V(Simulate)                                 \
+  V(StackCheck)                               \
+  V(StoreCodeEntry)                           \
+  V(StoreContextSlot)                         \
+  V(StoreFrameContext)                        \
+  V(StoreGlobalCell)                          \
+  V(StoreKeyed)                               \
+  V(StoreKeyedGeneric)                        \
+  V(StoreNamedField)                          \
+  V(StoreNamedGeneric)                        \
+  V(StringAdd)                                \
+  V(StringCharCodeAt)                         \
+  V(StringCharFromCode)                       \
+  V(StringCompareAndBranch)                   \
+  V(Sub)                                      \
+  V(TailCallThroughMegamorphicCache)          \
+  V(ThisFunction)                             \
+  V(ToFastProperties)                         \
+  V(TransitionElementsKind)                   \
+  V(TrapAllocationMemento)                    \
+  V(Typeof)                                   \
+  V(TypeofIsAndBranch)                        \
+  V(UnaryMathOperation)                       \
+  V(UnknownOSRValue)                          \
+  V(UseConst)                                 \
   V(WrapReceiver)
 
 #define GVN_TRACKED_FLAG_LIST(V)               \
@@ -2324,9 +2325,8 @@ class HCallWithDescriptor FINAL : public HInstruction {
                                   CallInterfaceDescriptor descriptor,
                                   const Vector<HValue*>& operands) {
     DCHECK(operands.length() == descriptor.GetEnvironmentLength());
-    HCallWithDescriptor* res =
-        new(zone) HCallWithDescriptor(target, argument_count,
-                                      descriptor, operands, zone);
+    HCallWithDescriptor* res = new (zone)
+        HCallWithDescriptor(target, argument_count, descriptor, operands, zone);
     return res;
   }
 
@@ -5352,6 +5352,37 @@ class HCallStub FINAL : public HUnaryCall {
 };
 
 
+class HTailCallThroughMegamorphicCache FINAL : public HTemplateInstruction<3> {
+ public:
+  DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P3(HTailCallThroughMegamorphicCache,
+                                              HValue*, HValue*, Code::Flags);
+
+  virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
+    return Representation::Tagged();
+  }
+
+  HValue* context() const { return OperandAt(0); }
+  HValue* receiver() const { return OperandAt(1); }
+  HValue* name() const { return OperandAt(2); }
+  Code::Flags flags() const { return flags_; }
+
+  virtual OStream& PrintDataTo(OStream& os) const OVERRIDE;  // NOLINT
+
+  DECLARE_CONCRETE_INSTRUCTION(TailCallThroughMegamorphicCache)
+
+ private:
+  HTailCallThroughMegamorphicCache(HValue* context, HValue* receiver,
+                                   HValue* name, Code::Flags flags)
+      : flags_(flags) {
+    SetOperandAt(0, context);
+    SetOperandAt(1, receiver);
+    SetOperandAt(2, name);
+  }
+
+  Code::Flags flags_;
+};
+
+
 class HUnknownOSRValue FINAL : public HTemplateInstruction<0> {
  public:
   DECLARE_INSTRUCTION_FACTORY_P2(HUnknownOSRValue, HEnvironment*, int);
index f4cbe8290d6afe9a1e8ce893b858ed1c4d069061..c0945969eedb3c6152bdf4fa5947772d89d49f69 100644 (file)
@@ -12,6 +12,7 @@
 #include "src/deoptimizer.h"
 #include "src/hydrogen-osr.h"
 #include "src/ia32/lithium-codegen-ia32.h"
+#include "src/ic/stub-cache.h"
 
 namespace v8 {
 namespace internal {
@@ -3147,11 +3148,9 @@ void LCodeGen::DoLoadKeyedFixedArray(LLoadKeyed* instr) {
 
   // Load the result.
   __ mov(result,
-         BuildFastArrayOperand(instr->elements(),
-                               instr->key(),
+         BuildFastArrayOperand(instr->elements(), instr->key(),
                                instr->hydrogen()->key()->representation(),
-                               FAST_ELEMENTS,
-                               instr->base_offset()));
+                               FAST_ELEMENTS, instr->base_offset()));
 
   // Check for the hole value.
   if (instr->hydrogen()->RequiresHoleCheck()) {
@@ -3447,6 +3446,32 @@ void LCodeGen::CallKnownFunction(Handle<JSFunction> function,
 }
 
 
+void LCodeGen::DoTailCallThroughMegamorphicCache(
+    LTailCallThroughMegamorphicCache* instr) {
+  Register receiver = ToRegister(instr->receiver());
+  Register name = ToRegister(instr->name());
+  DCHECK(receiver.is(LoadDescriptor::ReceiverRegister()));
+  DCHECK(name.is(LoadDescriptor::NameRegister()));
+
+  Register scratch = ebx;
+  Register extra = eax;
+  DCHECK(!scratch.is(receiver) && !scratch.is(name));
+  DCHECK(!extra.is(receiver) && !extra.is(name));
+
+  // Important for the tail-call.
+  bool must_teardown_frame = NeedsEagerFrame();
+
+  // The probe will tail call to a handler if found.
+  isolate()->stub_cache()->GenerateProbe(masm(), instr->hydrogen()->flags(),
+                                         must_teardown_frame, receiver, name,
+                                         scratch, extra);
+
+  // Tail call to miss if we ended up here.
+  if (must_teardown_frame) __ leave();
+  LoadIC::GenerateMiss(masm());
+}
+
+
 void LCodeGen::DoCallWithDescriptor(LCallWithDescriptor* instr) {
   DCHECK(ToRegister(instr->result()).is(eax));
 
index c156b61f1b74fd74d6ec0b1f8af6a7a0925098b2..67b4e0c8f65879786d68a12dcbf7df27598dd884 100644 (file)
@@ -1139,6 +1139,19 @@ LInstruction* LChunkBuilder::DoCallWithDescriptor(
 }
 
 
+LInstruction* LChunkBuilder::DoTailCallThroughMegamorphicCache(
+    HTailCallThroughMegamorphicCache* instr) {
+  LOperand* context = UseFixed(instr->context(), esi);
+  LOperand* receiver_register =
+      UseFixed(instr->receiver(), LoadDescriptor::ReceiverRegister());
+  LOperand* name_register =
+      UseFixed(instr->name(), LoadDescriptor::NameRegister());
+  // Not marked as call. It can't deoptimize, and it never returns.
+  return new (zone()) LTailCallThroughMegamorphicCache(
+      context, receiver_register, name_register);
+}
+
+
 LInstruction* LChunkBuilder::DoInvokeFunction(HInvokeFunction* instr) {
   LOperand* context = UseFixed(instr->context(), esi);
   LOperand* function = UseFixed(instr->function(), edi);
index 1c24ae7812e370d2f5302b81de4f9bd0269d1b46..c7955fea427fd7337d227e8180b51c63c84149e1 100644 (file)
@@ -155,6 +155,7 @@ class LCodeGen;
   V(StringCompareAndBranch)                  \
   V(SubI)                                    \
   V(TaggedToI)                               \
+  V(TailCallThroughMegamorphicCache)         \
   V(ThisFunction)                            \
   V(ToFastProperties)                        \
   V(TransitionElementsKind)                  \
@@ -479,6 +480,27 @@ class LCallStub FINAL : public LTemplateInstruction<1, 1, 0> {
 };
 
 
+class LTailCallThroughMegamorphicCache FINAL
+    : public LTemplateInstruction<0, 3, 0> {
+ public:
+  explicit LTailCallThroughMegamorphicCache(LOperand* context,
+                                            LOperand* receiver,
+                                            LOperand* name) {
+    inputs_[0] = context;
+    inputs_[1] = receiver;
+    inputs_[2] = name;
+  }
+
+  LOperand* context() { return inputs_[0]; }
+  LOperand* receiver() { return inputs_[1]; }
+  LOperand* name() { return inputs_[2]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(TailCallThroughMegamorphicCache,
+                               "tail-call-through-megamorphic-cache")
+  DECLARE_HYDROGEN_ACCESSOR(TailCallThroughMegamorphicCache)
+};
+
+
 class LUnknownOSRValue FINAL : public LTemplateInstruction<1, 0, 0> {
  public:
   virtual bool HasInterestingComment(LCodeGen* gen) const OVERRIDE {
@@ -1900,9 +1922,10 @@ class LCallWithDescriptor FINAL : public LTemplateResultInstruction<1> {
 
   LOperand* target() const { return inputs_[0]; }
 
+  DECLARE_HYDROGEN_ACCESSOR(CallWithDescriptor)
+
  private:
   DECLARE_CONCRETE_INSTRUCTION(CallWithDescriptor, "call-with-descriptor")
-  DECLARE_HYDROGEN_ACCESSOR(CallWithDescriptor)
 
   virtual void PrintDataTo(StringStream* stream) OVERRIDE;
 
index 76135ef56a38ef6230f30f601db866b80fa616e1..a340580fca450c1df27390fb0e1200d84cde2dba 100644 (file)
@@ -242,24 +242,6 @@ static void GenerateKeyNameCheck(MacroAssembler* masm, Register key,
 }
 
 
-void LoadIC::GenerateMegamorphic(MacroAssembler* masm) {
-  // The return address is in lr.
-  Register receiver = LoadDescriptor::ReceiverRegister();
-  Register name = LoadDescriptor::NameRegister();
-  DCHECK(receiver.is(r1));
-  DCHECK(name.is(r2));
-
-  // Probe the stub cache.
-  Code::Flags flags = Code::RemoveTypeAndHolderFromFlags(
-      Code::ComputeHandlerFlags(Code::LOAD_IC));
-  masm->isolate()->stub_cache()->GenerateProbe(masm, flags, receiver, name, r3,
-                                               r4, r5, r6);
-
-  // Cache miss: Jump to runtime.
-  GenerateMiss(masm);
-}
-
-
 void LoadIC::GenerateNormal(MacroAssembler* masm) {
   Register dictionary = r0;
   DCHECK(!dictionary.is(LoadDescriptor::ReceiverRegister()));
@@ -963,8 +945,8 @@ void StoreIC::GenerateMegamorphic(MacroAssembler* masm) {
   Code::Flags flags = Code::RemoveTypeAndHolderFromFlags(
       Code::ComputeHandlerFlags(Code::STORE_IC));
 
-  masm->isolate()->stub_cache()->GenerateProbe(masm, flags, receiver, name, r3,
-                                               r4, r5, r6);
+  masm->isolate()->stub_cache()->GenerateProbe(masm, flags, false, receiver,
+                                               name, r3, r4, r5, r6);
 
   // Cache miss: Jump to runtime.
   GenerateMiss(masm);
index a8b650beecfc99f06199d6a93dd63da98d46e183..bc8b0fba84ffe7586b312adf0e75c72c41446475 100644 (file)
@@ -16,8 +16,8 @@ namespace internal {
 
 
 static void ProbeTable(Isolate* isolate, MacroAssembler* masm,
-                       Code::Flags flags, StubCache::Table table,
-                       Register receiver, Register name,
+                       Code::Flags flags, bool leave_frame,
+                       StubCache::Table table, Register receiver, Register name,
                        // Number of the cache entry, not scaled.
                        Register offset, Register scratch, Register scratch2,
                        Register offset_scratch) {
@@ -84,6 +84,8 @@ static void ProbeTable(Isolate* isolate, MacroAssembler* masm,
   }
 #endif
 
+  if (leave_frame) __ LeaveFrame(StackFrame::INTERNAL);
+
   // Jump to the first instruction in the code stub.
   __ add(pc, code, Operand(Code::kHeaderSize - kHeapObjectTag));
 
@@ -93,9 +95,9 @@ static void ProbeTable(Isolate* isolate, MacroAssembler* masm,
 
 
 void StubCache::GenerateProbe(MacroAssembler* masm, Code::Flags flags,
-                              Register receiver, Register name,
-                              Register scratch, Register extra, Register extra2,
-                              Register extra3) {
+                              bool leave_frame, Register receiver,
+                              Register name, Register scratch, Register extra,
+                              Register extra2, Register extra3) {
   Isolate* isolate = masm->isolate();
   Label miss;
 
@@ -145,8 +147,8 @@ void StubCache::GenerateProbe(MacroAssembler* masm, Code::Flags flags,
   __ and_(scratch, scratch, Operand(mask));
 
   // Probe the primary table.
-  ProbeTable(isolate, masm, flags, kPrimary, receiver, name, scratch, extra,
-             extra2, extra3);
+  ProbeTable(isolate, masm, flags, leave_frame, kPrimary, receiver, name,
+             scratch, extra, extra2, extra3);
 
   // Primary miss: Compute hash for secondary probe.
   __ sub(scratch, scratch, Operand(name, LSR, kCacheIndexShift));
@@ -155,8 +157,8 @@ void StubCache::GenerateProbe(MacroAssembler* masm, Code::Flags flags,
   __ and_(scratch, scratch, Operand(mask2));
 
   // Probe the secondary table.
-  ProbeTable(isolate, masm, flags, kSecondary, receiver, name, scratch, extra,
-             extra2, extra3);
+  ProbeTable(isolate, masm, flags, leave_frame, kSecondary, receiver, name,
+             scratch, extra, extra2, extra3);
 
   // Cache miss: Fall-through and let caller handle the miss by
   // entering the runtime system.
index 9ea622e9a3dcd57597f102dd3de0a10189009621..1f4647cbd7920f91b10649ccc211e73908590436 100644 (file)
@@ -331,24 +331,6 @@ static MemOperand GenerateUnmappedArgumentsLookup(MacroAssembler* masm,
 }
 
 
-void LoadIC::GenerateMegamorphic(MacroAssembler* masm) {
-  // The return address is in lr.
-  Register receiver = LoadDescriptor::ReceiverRegister();
-  Register name = LoadDescriptor::NameRegister();
-  DCHECK(receiver.is(x1));
-  DCHECK(name.is(x2));
-
-  // Probe the stub cache.
-  Code::Flags flags = Code::RemoveTypeAndHolderFromFlags(
-      Code::ComputeHandlerFlags(Code::LOAD_IC));
-  masm->isolate()->stub_cache()->GenerateProbe(masm, flags, receiver, name, x3,
-                                               x4, x5, x6);
-
-  // Cache miss: Jump to runtime.
-  GenerateMiss(masm);
-}
-
-
 void LoadIC::GenerateNormal(MacroAssembler* masm) {
   Register dictionary = x0;
   DCHECK(!dictionary.is(LoadDescriptor::ReceiverRegister()));
@@ -994,8 +976,8 @@ void StoreIC::GenerateMegamorphic(MacroAssembler* masm) {
   // Probe the stub cache.
   Code::Flags flags = Code::RemoveTypeAndHolderFromFlags(
       Code::ComputeHandlerFlags(Code::STORE_IC));
-  masm->isolate()->stub_cache()->GenerateProbe(masm, flags, receiver, name, x3,
-                                               x4, x5, x6);
+  masm->isolate()->stub_cache()->GenerateProbe(masm, flags, false, receiver,
+                                               name, x3, x4, x5, x6);
 
   // Cache miss: Jump to runtime.
   GenerateMiss(masm);
index f16ffafc072fa65deb12aa75f0b0250922e72995..4d31d4988272ca0aac98ea4c4e2e7656ae400a83 100644 (file)
@@ -23,9 +23,10 @@ namespace internal {
 //
 // 'receiver', 'name' and 'offset' registers are preserved on miss.
 static void ProbeTable(Isolate* isolate, MacroAssembler* masm,
-                       Code::Flags flags, StubCache::Table table,
-                       Register receiver, Register name, Register offset,
-                       Register scratch, Register scratch2, Register scratch3) {
+                       Code::Flags flags, bool leave_frame,
+                       StubCache::Table table, Register receiver, Register name,
+                       Register offset, Register scratch, Register scratch2,
+                       Register scratch3) {
   // Some code below relies on the fact that the Entry struct contains
   // 3 pointers (name, code, map).
   STATIC_ASSERT(sizeof(StubCache::Entry) == (3 * kPointerSize));
@@ -78,6 +79,8 @@ static void ProbeTable(Isolate* isolate, MacroAssembler* masm,
   }
 #endif
 
+  if (leave_frame) __ LeaveFrame(StackFrame::INTERNAL);
+
   // Jump to the first instruction in the code stub.
   __ Add(scratch, scratch, Code::kHeaderSize - kHeapObjectTag);
   __ Br(scratch);
@@ -88,9 +91,9 @@ static void ProbeTable(Isolate* isolate, MacroAssembler* masm,
 
 
 void StubCache::GenerateProbe(MacroAssembler* masm, Code::Flags flags,
-                              Register receiver, Register name,
-                              Register scratch, Register extra, Register extra2,
-                              Register extra3) {
+                              bool leave_frame, Register receiver,
+                              Register name, Register scratch, Register extra,
+                              Register extra2, Register extra3) {
   Isolate* isolate = masm->isolate();
   Label miss;
 
@@ -122,8 +125,8 @@ void StubCache::GenerateProbe(MacroAssembler* masm, Code::Flags flags,
           CountTrailingZeros(kPrimaryTableSize, 64));
 
   // Probe the primary table.
-  ProbeTable(isolate, masm, flags, kPrimary, receiver, name, scratch, extra,
-             extra2, extra3);
+  ProbeTable(isolate, masm, flags, leave_frame, kPrimary, receiver, name,
+             scratch, extra, extra2, extra3);
 
   // Primary miss: Compute hash for secondary table.
   __ Sub(scratch, scratch, Operand(name, LSR, kCacheIndexShift));
@@ -131,8 +134,8 @@ void StubCache::GenerateProbe(MacroAssembler* masm, Code::Flags flags,
   __ And(scratch, scratch, kSecondaryTableSize - 1);
 
   // Probe the secondary table.
-  ProbeTable(isolate, masm, flags, kSecondary, receiver, name, scratch, extra,
-             extra2, extra3);
+  ProbeTable(isolate, masm, flags, leave_frame, kSecondary, receiver, name,
+             scratch, extra, extra2, extra3);
 
   // Cache miss: Fall-through and let caller handle the miss by
   // entering the runtime system.
index d869e43cf5d4b5a92516d2040e8336257b88cbcb..c69e08146964126db5ec553e2fde111fc736c4c7 100644 (file)
@@ -824,24 +824,6 @@ void KeyedStoreIC::GenerateGeneric(MacroAssembler* masm,
 }
 
 
-void LoadIC::GenerateMegamorphic(MacroAssembler* masm) {
-  // The return address is on the stack.
-  Register receiver = LoadDescriptor::ReceiverRegister();
-  Register name = LoadDescriptor::NameRegister();
-  DCHECK(receiver.is(edx));
-  DCHECK(name.is(ecx));
-
-  // Probe the stub cache.
-  Code::Flags flags = Code::RemoveTypeAndHolderFromFlags(
-      Code::ComputeHandlerFlags(Code::LOAD_IC));
-  masm->isolate()->stub_cache()->GenerateProbe(masm, flags, receiver, name, ebx,
-                                               eax);
-
-  // Cache miss: Jump to runtime.
-  GenerateMiss(masm);
-}
-
-
 void LoadIC::GenerateNormal(MacroAssembler* masm) {
   Register dictionary = eax;
   DCHECK(!dictionary.is(LoadDescriptor::ReceiverRegister()));
@@ -922,7 +904,7 @@ void StoreIC::GenerateMegamorphic(MacroAssembler* masm) {
   Code::Flags flags = Code::RemoveTypeAndHolderFromFlags(
       Code::ComputeHandlerFlags(Code::STORE_IC));
   masm->isolate()->stub_cache()->GenerateProbe(
-      masm, flags, StoreDescriptor::ReceiverRegister(),
+      masm, flags, false, StoreDescriptor::ReceiverRegister(),
       StoreDescriptor::NameRegister(), ebx, no_reg);
 
   // Cache miss: Jump to runtime.
index 1babf71a61e8cfb7aff679f7242175db12713ecd..c1f7c9ad314d634f0be45fc457f79f4ff91a2e01 100644 (file)
@@ -16,8 +16,8 @@ namespace internal {
 
 
 static void ProbeTable(Isolate* isolate, MacroAssembler* masm,
-                       Code::Flags flags, StubCache::Table table, Register name,
-                       Register receiver,
+                       Code::Flags flags, bool leave_frame,
+                       StubCache::Table table, Register name, Register receiver,
                        // Number of the cache entry pointer-size scaled.
                        Register offset, Register extra) {
   ExternalReference key_offset(isolate->stub_cache()->key_reference(table));
@@ -56,6 +56,8 @@ static void ProbeTable(Isolate* isolate, MacroAssembler* masm,
     }
 #endif
 
+    if (leave_frame) __ leave();
+
     // Jump to the first instruction in the code stub.
     __ add(extra, Immediate(Code::kHeaderSize - kHeapObjectTag));
     __ jmp(extra);
@@ -98,6 +100,8 @@ static void ProbeTable(Isolate* isolate, MacroAssembler* masm,
     __ pop(offset);
     __ mov(offset, Operand::StaticArray(offset, times_1, value_offset));
 
+    if (leave_frame) __ leave();
+
     // Jump to the first instruction in the code stub.
     __ add(offset, Immediate(Code::kHeaderSize - kHeapObjectTag));
     __ jmp(offset);
@@ -110,9 +114,9 @@ static void ProbeTable(Isolate* isolate, MacroAssembler* masm,
 
 
 void StubCache::GenerateProbe(MacroAssembler* masm, Code::Flags flags,
-                              Register receiver, Register name,
-                              Register scratch, Register extra, Register extra2,
-                              Register extra3) {
+                              bool leave_frame, Register receiver,
+                              Register name, Register scratch, Register extra,
+                              Register extra2, Register extra3) {
   Label miss;
 
   // Assert that code is valid.  The multiplying code relies on the entry size
@@ -155,7 +159,8 @@ void StubCache::GenerateProbe(MacroAssembler* masm, Code::Flags flags,
   DCHECK(kCacheIndexShift == kPointerSizeLog2);
 
   // Probe the primary table.
-  ProbeTable(isolate(), masm, flags, kPrimary, name, receiver, offset, extra);
+  ProbeTable(isolate(), masm, flags, leave_frame, kPrimary, name, receiver,
+             offset, extra);
 
   // Primary miss: Compute hash for secondary probe.
   __ mov(offset, FieldOperand(name, Name::kHashFieldOffset));
@@ -167,7 +172,8 @@ void StubCache::GenerateProbe(MacroAssembler* masm, Code::Flags flags,
   __ and_(offset, (kSecondaryTableSize - 1) << kCacheIndexShift);
 
   // Probe the secondary table.
-  ProbeTable(isolate(), masm, flags, kSecondary, name, receiver, offset, extra);
+  ProbeTable(isolate(), masm, flags, leave_frame, kSecondary, name, receiver,
+             offset, extra);
 
   // Cache miss: Fall-through and let caller handle the miss by
   // entering the runtime system.
index fb6906ce3b90b1e51d9876e47be344a33be2a4f1..b28fe499a53018d5324d73ebf1927f4a5ff72167 100644 (file)
@@ -178,8 +178,6 @@ Handle<Code> PropertyICCompiler::ComputeLoad(Isolate* isolate,
     code = compiler.CompileLoadInitialize(flags);
   } else if (ic_state == PREMONOMORPHIC) {
     code = compiler.CompileLoadPreMonomorphic(flags);
-  } else if (ic_state == MEGAMORPHIC) {
-    code = compiler.CompileLoadMegamorphic(flags);
   } else {
     UNREACHABLE();
   }
@@ -320,14 +318,6 @@ Handle<Code> PropertyICCompiler::CompileLoadPreMonomorphic(Code::Flags flags) {
 }
 
 
-Handle<Code> PropertyICCompiler::CompileLoadMegamorphic(Code::Flags flags) {
-  LoadIC::GenerateMegamorphic(masm());
-  Handle<Code> code = GetCodeWithFlags(flags, "CompileLoadMegamorphic");
-  PROFILE(isolate(), CodeCreateEvent(Logger::LOAD_MEGAMORPHIC_TAG, *code, 0));
-  return code;
-}
-
-
 Handle<Code> PropertyICCompiler::CompileStoreInitialize(Code::Flags flags) {
   StoreIC::GenerateInitialize(masm());
   Handle<Code> code = GetCodeWithFlags(flags, "CompileStoreInitialize");
index 8ee0c384ba047cc8031ed01b1fcaaf65404a0190..3b12157a0786f26148e379acf9dd5ef27b6c1449 100644 (file)
@@ -72,7 +72,6 @@ class PropertyICCompiler : public PropertyAccessCompiler {
 
   Handle<Code> CompileLoadInitialize(Code::Flags flags);
   Handle<Code> CompileLoadPreMonomorphic(Code::Flags flags);
-  Handle<Code> CompileLoadMegamorphic(Code::Flags flags);
   Handle<Code> CompileStoreInitialize(Code::Flags flags);
   Handle<Code> CompileStorePreMonomorphic(Code::Flags flags);
   Handle<Code> CompileStoreGeneric(Code::Flags flags);
index 3fb2ea90decbd2eb460f815d39500507800c18cb..69954a8d183dea998a92a5d59ef87d570a9f8da6 100644 (file)
@@ -815,8 +815,8 @@ Handle<Code> LoadIC::initialize_stub(Isolate* isolate,
 
 Handle<Code> LoadIC::megamorphic_stub() {
   if (kind() == Code::LOAD_IC) {
-    return PropertyICCompiler::ComputeLoad(isolate(), MEGAMORPHIC,
-                                           extra_ic_state());
+    MegamorphicLoadStub stub(isolate(), State(extra_ic_state()));
+    return stub.GetCode();
   } else {
     DCHECK_EQ(Code::KEYED_LOAD_IC, kind());
     return KeyedLoadIC::generic_stub(isolate());
index 1710fee91099e8747c21198fa32a464dee130528..41d54943b9b2ecd5cd17a178b76bd3807b53c26f 100644 (file)
@@ -405,7 +405,6 @@ class LoadIC : public IC {
     GenerateMiss(masm);
   }
   static void GenerateMiss(MacroAssembler* masm);
-  static void GenerateMegamorphic(MacroAssembler* masm);
   static void GenerateNormal(MacroAssembler* masm);
   static void GenerateRuntimeGetProperty(MacroAssembler* masm);
 
index eb5343f85610f7d0b0f87f8612178568584aeab8..7aee6f16ad2f3fc18449286d3f39017e9289b4ca 100644 (file)
@@ -51,9 +51,11 @@ class StubCache {
   // Generate code for probing the stub cache table.
   // Arguments extra, extra2 and extra3 may be used to pass additional scratch
   // registers. Set to no_reg if not needed.
-  void GenerateProbe(MacroAssembler* masm, Code::Flags flags, Register receiver,
-                     Register name, Register scratch, Register extra,
-                     Register extra2 = no_reg, Register extra3 = no_reg);
+  // If leave_frame is true, then exit a frame before the tail call.
+  void GenerateProbe(MacroAssembler* masm, Code::Flags flags, bool leave_frame,
+                     Register receiver, Register name, Register scratch,
+                     Register extra, Register extra2 = no_reg,
+                     Register extra3 = no_reg);
 
   enum Table { kPrimary, kSecondary };
 
@@ -153,6 +155,7 @@ class StubCache {
   static const int kSecondaryTableBits = 9;
   static const int kSecondaryTableSize = (1 << kSecondaryTableBits);
 
+ private:
   Entry primary_[kPrimaryTableSize];
   Entry secondary_[kSecondaryTableSize];
   Isolate* isolate_;
index b242c1dbcd23813c36d938686a9e20bbc2900db3..84667696f11764326bbef80df967762fb3a9c2bf 100644 (file)
@@ -823,23 +823,6 @@ void KeyedStoreIC::GenerateSloppyArguments(MacroAssembler* masm) {
 }
 
 
-void LoadIC::GenerateMegamorphic(MacroAssembler* masm) {
-  // The return address is on the stack.
-  Register receiver = LoadDescriptor::ReceiverRegister();
-  Register name = LoadDescriptor::NameRegister();
-  DCHECK(receiver.is(rdx));
-  DCHECK(name.is(rcx));
-
-  // Probe the stub cache.
-  Code::Flags flags = Code::RemoveTypeAndHolderFromFlags(
-      Code::ComputeHandlerFlags(Code::LOAD_IC));
-  masm->isolate()->stub_cache()->GenerateProbe(masm, flags, receiver, name, rbx,
-                                               rax);
-
-  GenerateMiss(masm);
-}
-
-
 void LoadIC::GenerateNormal(MacroAssembler* masm) {
   Register dictionary = rax;
   DCHECK(!dictionary.is(LoadDescriptor::ReceiverRegister()));
@@ -934,7 +917,7 @@ void StoreIC::GenerateMegamorphic(MacroAssembler* masm) {
   Code::Flags flags = Code::RemoveTypeAndHolderFromFlags(
       Code::ComputeHandlerFlags(Code::STORE_IC));
   masm->isolate()->stub_cache()->GenerateProbe(
-      masm, flags, StoreDescriptor::ReceiverRegister(),
+      masm, flags, false, StoreDescriptor::ReceiverRegister(),
       StoreDescriptor::NameRegister(), rbx, no_reg);
 
   // Cache miss: Jump to runtime.
index 2f270dcb62e693f538c4c74d6e8fd41c087f3c6a..a54ddcaf96c25aaa0609cfb83e598a691efd8d6d 100644 (file)
@@ -16,8 +16,8 @@ namespace internal {
 
 
 static void ProbeTable(Isolate* isolate, MacroAssembler* masm,
-                       Code::Flags flags, StubCache::Table table,
-                       Register receiver, Register name,
+                       Code::Flags flags, bool leave_frame,
+                       StubCache::Table table, Register receiver, Register name,
                        // The offset is scaled by 4, based on
                        // kCacheIndexShift, which is two bits
                        Register offset) {
@@ -72,6 +72,8 @@ static void ProbeTable(Isolate* isolate, MacroAssembler* masm,
   }
 #endif
 
+  if (leave_frame) __ leave();
+
   // Jump to the first instruction in the code stub.
   __ addp(kScratchRegister, Immediate(Code::kHeaderSize - kHeapObjectTag));
   __ jmp(kScratchRegister);
@@ -81,9 +83,9 @@ static void ProbeTable(Isolate* isolate, MacroAssembler* masm,
 
 
 void StubCache::GenerateProbe(MacroAssembler* masm, Code::Flags flags,
-                              Register receiver, Register name,
-                              Register scratch, Register extra, Register extra2,
-                              Register extra3) {
+                              bool leave_frame, Register receiver,
+                              Register name, Register scratch, Register extra,
+                              Register extra2, Register extra3) {
   Isolate* isolate = masm->isolate();
   Label miss;
   USE(extra);   // The register extra is not used on the X64 platform.
@@ -121,7 +123,8 @@ void StubCache::GenerateProbe(MacroAssembler* masm, Code::Flags flags,
   __ andp(scratch, Immediate((kPrimaryTableSize - 1) << kCacheIndexShift));
 
   // Probe the primary table.
-  ProbeTable(isolate, masm, flags, kPrimary, receiver, name, scratch);
+  ProbeTable(isolate, masm, flags, leave_frame, kPrimary, receiver, name,
+             scratch);
 
   // Primary miss: Compute hash for secondary probe.
   __ movl(scratch, FieldOperand(name, Name::kHashFieldOffset));
@@ -133,7 +136,8 @@ void StubCache::GenerateProbe(MacroAssembler* masm, Code::Flags flags,
   __ andp(scratch, Immediate((kSecondaryTableSize - 1) << kCacheIndexShift));
 
   // Probe the secondary table.
-  ProbeTable(isolate, masm, flags, kSecondary, receiver, name, scratch);
+  ProbeTable(isolate, masm, flags, leave_frame, kSecondary, receiver, name,
+             scratch);
 
   // Cache miss: Fall-through and let caller handle the miss by
   // entering the runtime system.
index 0561b57bc718bf0e89a3d33061b7f863518742b9..c39833e2213a7bbce36cc9785ba96da61f53a0f5 100644 (file)
@@ -9,6 +9,7 @@
 #include "src/base/bits.h"
 #include "src/code-stubs.h"
 #include "src/hydrogen-osr.h"
+#include "src/ic/stub-cache.h"
 #include "src/x64/lithium-codegen-x64.h"
 
 namespace v8 {
@@ -3227,11 +3228,9 @@ void LCodeGen::DoLoadKeyedFixedArray(LLoadKeyed* instr) {
   }
 
   __ Load(result,
-          BuildFastArrayOperand(instr->elements(),
-                                key,
+          BuildFastArrayOperand(instr->elements(), key,
                                 instr->hydrogen()->key()->representation(),
-                                FAST_ELEMENTS,
-                                offset),
+                                FAST_ELEMENTS, offset),
           representation);
 
   // Check for the hole value.
@@ -3531,6 +3530,30 @@ void LCodeGen::CallKnownFunction(Handle<JSFunction> function,
 }
 
 
+void LCodeGen::DoTailCallThroughMegamorphicCache(
+    LTailCallThroughMegamorphicCache* instr) {
+  Register receiver = ToRegister(instr->receiver());
+  Register name = ToRegister(instr->name());
+  DCHECK(receiver.is(LoadDescriptor::ReceiverRegister()));
+  DCHECK(name.is(LoadDescriptor::NameRegister()));
+
+  Register scratch = rbx;
+  DCHECK(!scratch.is(receiver) && !scratch.is(name));
+
+  // Important for the tail-call.
+  bool must_teardown_frame = NeedsEagerFrame();
+
+  // The probe will tail call to a handler if found.
+  isolate()->stub_cache()->GenerateProbe(masm(), instr->hydrogen()->flags(),
+                                         must_teardown_frame, receiver, name,
+                                         scratch, no_reg);
+
+  // Tail call to miss if we ended up here.
+  if (must_teardown_frame) __ leave();
+  LoadIC::GenerateMiss(masm());
+}
+
+
 void LCodeGen::DoCallWithDescriptor(LCallWithDescriptor* instr) {
   DCHECK(ToRegister(instr->result()).is(rax));
 
index c343afd851f0d9e572f1a7b2c1199fe506ba00c8..84516799febad8fd280b94fa13f31898eba50eea 100644 (file)
@@ -1119,6 +1119,19 @@ LInstruction* LChunkBuilder::DoCallWithDescriptor(
 }
 
 
+LInstruction* LChunkBuilder::DoTailCallThroughMegamorphicCache(
+    HTailCallThroughMegamorphicCache* instr) {
+  LOperand* context = UseFixed(instr->context(), rsi);
+  LOperand* receiver_register =
+      UseFixed(instr->receiver(), LoadDescriptor::ReceiverRegister());
+  LOperand* name_register =
+      UseFixed(instr->name(), LoadDescriptor::NameRegister());
+  // Not marked as call. It can't deoptimize, and it never returns.
+  return new (zone()) LTailCallThroughMegamorphicCache(
+      context, receiver_register, name_register);
+}
+
+
 LInstruction* LChunkBuilder::DoInvokeFunction(HInvokeFunction* instr) {
   LOperand* context = UseFixed(instr->context(), rsi);
   LOperand* function = UseFixed(instr->function(), rdi);
index a8291473bd31cc8f72a8db698553973093d2c86c..55c599451b406a21c1e9f67536c900026f6d5af5 100644 (file)
@@ -151,6 +151,7 @@ class LCodeGen;
   V(StringCompareAndBranch)                  \
   V(SubI)                                    \
   V(TaggedToI)                               \
+  V(TailCallThroughMegamorphicCache)         \
   V(ThisFunction)                            \
   V(ToFastProperties)                        \
   V(TransitionElementsKind)                  \
@@ -489,6 +490,27 @@ class LCallStub FINAL : public LTemplateInstruction<1, 1, 0> {
 };
 
 
+class LTailCallThroughMegamorphicCache FINAL
+    : public LTemplateInstruction<0, 3, 0> {
+ public:
+  explicit LTailCallThroughMegamorphicCache(LOperand* context,
+                                            LOperand* receiver,
+                                            LOperand* name) {
+    inputs_[0] = context;
+    inputs_[1] = receiver;
+    inputs_[2] = name;
+  }
+
+  LOperand* context() { return inputs_[0]; }
+  LOperand* receiver() { return inputs_[1]; }
+  LOperand* name() { return inputs_[2]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(TailCallThroughMegamorphicCache,
+                               "tail-call-through-megamorphic-cache")
+  DECLARE_HYDROGEN_ACCESSOR(TailCallThroughMegamorphicCache)
+};
+
+
 class LUnknownOSRValue FINAL : public LTemplateInstruction<1, 0, 0> {
  public:
   virtual bool HasInterestingComment(LCodeGen* gen) const OVERRIDE {
@@ -1886,9 +1908,10 @@ class LCallWithDescriptor FINAL : public LTemplateResultInstruction<1> {
 
   LOperand* target() const { return inputs_[0]; }
 
+  DECLARE_HYDROGEN_ACCESSOR(CallWithDescriptor)
+
  private:
   DECLARE_CONCRETE_INSTRUCTION(CallWithDescriptor, "call-with-descriptor")
-  DECLARE_HYDROGEN_ACCESSOR(CallWithDescriptor)
 
   virtual void PrintDataTo(StringStream* stream) OVERRIDE;