}
-void LoadIC::GenerateMegamorphic(MacroAssembler* masm) {
- // The return address is in lr.
- Register receiver = LoadDescriptor::ReceiverRegister();
- Register name = LoadDescriptor::NameRegister();
- DCHECK(receiver.is(a1));
- DCHECK(name.is(a2));
-
- // Probe the stub cache.
- Code::Flags flags = Code::RemoveTypeAndHolderFromFlags(
- Code::ComputeHandlerFlags(Code::LOAD_IC));
- masm->isolate()->stub_cache()->GenerateProbe(masm, flags, receiver, name, a3,
- t0, t1, t2);
-
- // Cache miss: Jump to runtime.
- GenerateMiss(masm);
-}
-
-
void LoadIC::GenerateNormal(MacroAssembler* masm) {
Register dictionary = a0;
DCHECK(!dictionary.is(LoadDescriptor::ReceiverRegister()));
// Get the receiver from the stack and probe the stub cache.
Code::Flags flags = Code::RemoveTypeAndHolderFromFlags(
Code::ComputeHandlerFlags(Code::STORE_IC));
- masm->isolate()->stub_cache()->GenerateProbe(masm, flags, receiver, name, a3,
- t0, t1, t2);
+ masm->isolate()->stub_cache()->GenerateProbe(masm, flags, false, receiver,
+ name, a3, t0, t1, t2);
// Cache miss: Jump to runtime.
GenerateMiss(masm);
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) {
}
#endif
+ if (leave_frame) __ LeaveFrame(StackFrame::INTERNAL);
+
// Jump to the first instruction in the code stub.
__ Addu(at, code, Operand(Code::kHeaderSize - kHeapObjectTag));
__ Jump(at);
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;
__ 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.
__ srl(at, name, kCacheIndexShift);
__ 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.
}
-void LoadIC::GenerateMegamorphic(MacroAssembler* masm) {
- // The return address is in lr.
- Register receiver = LoadDescriptor::ReceiverRegister();
- Register name = LoadDescriptor::NameRegister();
- DCHECK(receiver.is(a1));
- DCHECK(name.is(a2));
-
- // Probe the stub cache.
- Code::Flags flags = Code::RemoveTypeAndHolderFromFlags(
- Code::ComputeHandlerFlags(Code::LOAD_IC));
- masm->isolate()->stub_cache()->GenerateProbe(masm, flags, receiver, name, a3,
- a4, a5, a6);
-
- // Cache miss: Jump to runtime.
- GenerateMiss(masm);
-}
-
-
void LoadIC::GenerateNormal(MacroAssembler* masm) {
Register dictionary = a0;
DCHECK(!dictionary.is(LoadDescriptor::ReceiverRegister()));
// Get the receiver from the stack and probe the stub cache.
Code::Flags flags = Code::RemoveTypeAndHolderFromFlags(
Code::ComputeHandlerFlags(Code::STORE_IC));
- masm->isolate()->stub_cache()->GenerateProbe(masm, flags, receiver, name, a3,
- a4, a5, a6);
+ masm->isolate()->stub_cache()->GenerateProbe(masm, flags, false, receiver,
+ name, a3, a4, a5, a6);
// Cache miss: Jump to runtime.
GenerateMiss(masm);
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) {
}
#endif
+ if (leave_frame) __ LeaveFrame(StackFrame::INTERNAL);
+
// Jump to the first instruction in the code stub.
__ Daddu(at, code, Operand(Code::kHeaderSize - kHeapObjectTag));
__ Jump(at);
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;
__ 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.
__ dsrl(at, name, kCacheIndexShift);
__ 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.
#include "src/base/bits.h"
#include "src/code-stubs.h"
#include "src/hydrogen-osr.h"
+#include "src/ic/stub-cache.h"
#include "src/mips/lithium-codegen-mips.h"
#include "src/mips/lithium-gap-resolver-mips.h"
}
+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(a1));
+ DCHECK(name.is(a2));
+
+ Register scratch = a3;
+ Register extra = t0;
+ Register extra2 = t1;
+ Register extra3 = t2;
+
+ // 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(v0));
}
+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(), a1);
V(StringCompareAndBranch) \
V(SubI) \
V(TaggedToI) \
+ V(TailCallThroughMegamorphicCache) \
V(ThisFunction) \
V(ToFastProperties) \
V(TransitionElementsKind) \
};
+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 {
#include "src/code-stubs.h"
#include "src/hydrogen-osr.h"
+#include "src/ic/stub-cache.h"
#include "src/mips64/lithium-codegen-mips64.h"
#include "src/mips64/lithium-gap-resolver-mips64.h"
}
+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(a1));
+ DCHECK(name.is(a2));
+
+ Register scratch = a3;
+ Register extra = a4;
+ Register extra2 = a5;
+ Register extra3 = a6;
+
+ // 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(v0));
}
+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(), a1);
V(StringCompareAndBranch) \
V(SubI) \
V(TaggedToI) \
+ V(TailCallThroughMegamorphicCache) \
V(ThisFunction) \
V(ToFastProperties) \
V(TransitionElementsKind) \
};
+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 {