To aid vector-based load ic work, we need to be able to handle
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
This commit is contained in:
parent
4ad3760dff
commit
6e1ebdcbc3
@ -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);
|
||||
|
@ -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 {
|
||||
|
@ -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));
|
||||
|
||||
|
@ -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.
|
||||
|
@ -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 {
|
||||
|
@ -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));
|
||||
|
@ -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
|
||||
|
@ -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());
|
||||
|
@ -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)
|
||||
|
@ -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";
|
||||
|
@ -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_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_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);
|
||||
|
@ -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));
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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.
|
||||
|
@ -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);
|
||||
|
@ -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.
|
||||
|
@ -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.
|
||||
|
@ -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.
|
||||
|
@ -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");
|
||||
|
@ -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);
|
||||
|
@ -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());
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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_;
|
||||
|
@ -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.
|
||||
|
@ -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.
|
||||
|
@ -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));
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user