}
+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);
V(SubI) \
V(RSubI) \
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/base/bits.h"
#include "src/code-stubs.h"
#include "src/hydrogen-osr.h"
+#include "src/ic/stub-cache.h"
namespace v8 {
namespace internal {
}
+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));
}
+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.
V(SubI) \
V(SubS) \
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/base/bits.h"
#include "src/code-stubs.h"
#include "src/hydrogen-osr.h"
+#include "src/ic/stub-cache.h"
namespace v8 {
namespace internal {
}
+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));
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
}
+void MegamorphicLoadStub::InitializeInterfaceDescriptor(
+ CodeStubInterfaceDescriptor* descriptor) {
+ LoadDescriptor call_descriptor(isolate());
+ descriptor->Initialize(MajorKey(), call_descriptor);
+}
+
+
void FastNewClosureStub::InitializeInterfaceDescriptor(
CodeStubInterfaceDescriptor* descriptor) {
FastNewClosureDescriptor call_descriptor(isolate());
V(KeyedLoadGeneric) \
V(LoadDictionaryElement) \
V(LoadFastElement) \
+ V(MegamorphicLoad) \
V(NameDictionaryLookup) \
V(NumberToString) \
V(RegExpConstructResult) \
};
+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)
case HValue::kStoreNamedGeneric:
case HValue::kStringCharCodeAt:
case HValue::kStringCharFromCode:
+ case HValue::kTailCallThroughMegamorphicCache:
case HValue::kThisFunction:
case HValue::kTypeofIsAndBranch:
case HValue::kUnknownOSRValue:
}
+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";
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) \
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;
}
};
+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);
#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 {
// 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()) {
}
+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));
}
+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);
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 {
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;
}
-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()));
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);
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.
__ add(pc, code, Operand(Code::kHeaderSize - kHeapObjectTag));
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.
__ sub(scratch, scratch, Operand(name, LSR, 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(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()));
// 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);
//
// '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));
}
#endif
+ if (leave_frame) __ LeaveFrame(StackFrame::INTERNAL);
+
// Jump to the first instruction in the code stub.
__ Add(scratch, scratch, Code::kHeaderSize - kHeapObjectTag);
__ Br(scratch);
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;
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));
__ 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.
}
-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()));
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.
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));
}
#endif
+ if (leave_frame) __ leave();
+
// Jump to the first instruction in the code stub.
__ add(extra, Immediate(Code::kHeaderSize - kHeapObjectTag));
__ jmp(extra);
__ 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);
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
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));
__ 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.
code = compiler.CompileLoadInitialize(flags);
} else if (ic_state == PREMONOMORPHIC) {
code = compiler.CompileLoadPreMonomorphic(flags);
- } else if (ic_state == MEGAMORPHIC) {
- code = compiler.CompileLoadMegamorphic(flags);
} else {
UNREACHABLE();
}
}
-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");
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);
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());
GenerateMiss(masm);
}
static void GenerateMiss(MacroAssembler* masm);
- static void GenerateMegamorphic(MacroAssembler* masm);
static void GenerateNormal(MacroAssembler* masm);
static void GenerateRuntimeGetProperty(MacroAssembler* masm);
// 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 };
static const int kSecondaryTableBits = 9;
static const int kSecondaryTableSize = (1 << kSecondaryTableBits);
+ private:
Entry primary_[kPrimaryTableSize];
Entry secondary_[kSecondaryTableSize];
Isolate* isolate_;
}
-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()));
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.
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) {
}
#endif
+ if (leave_frame) __ leave();
+
// Jump to the first instruction in the code stub.
__ addp(kScratchRegister, Immediate(Code::kHeaderSize - kHeapObjectTag));
__ jmp(kScratchRegister);
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.
__ 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));
__ 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.
#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 {
}
__ 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.
}
+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));
}
+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);
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 {
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;