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) {
|
LInstruction* LChunkBuilder::DoInvokeFunction(HInvokeFunction* instr) {
|
||||||
LOperand* context = UseFixed(instr->context(), cp);
|
LOperand* context = UseFixed(instr->context(), cp);
|
||||||
LOperand* function = UseFixed(instr->function(), r1);
|
LOperand* function = UseFixed(instr->function(), r1);
|
||||||
|
@ -154,6 +154,7 @@ class LCodeGen;
|
|||||||
V(SubI) \
|
V(SubI) \
|
||||||
V(RSubI) \
|
V(RSubI) \
|
||||||
V(TaggedToI) \
|
V(TaggedToI) \
|
||||||
|
V(TailCallThroughMegamorphicCache) \
|
||||||
V(ThisFunction) \
|
V(ThisFunction) \
|
||||||
V(ToFastProperties) \
|
V(ToFastProperties) \
|
||||||
V(TransitionElementsKind) \
|
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> {
|
class LUnknownOSRValue FINAL : public LTemplateInstruction<1, 0, 0> {
|
||||||
public:
|
public:
|
||||||
virtual bool HasInterestingComment(LCodeGen* gen) const OVERRIDE {
|
virtual bool HasInterestingComment(LCodeGen* gen) const OVERRIDE {
|
||||||
|
@ -9,6 +9,7 @@
|
|||||||
#include "src/base/bits.h"
|
#include "src/base/bits.h"
|
||||||
#include "src/code-stubs.h"
|
#include "src/code-stubs.h"
|
||||||
#include "src/hydrogen-osr.h"
|
#include "src/hydrogen-osr.h"
|
||||||
|
#include "src/ic/stub-cache.h"
|
||||||
|
|
||||||
namespace v8 {
|
namespace v8 {
|
||||||
namespace internal {
|
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) {
|
void LCodeGen::DoCallWithDescriptor(LCallWithDescriptor* instr) {
|
||||||
DCHECK(ToRegister(instr->result()).is(r0));
|
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) {
|
LInstruction* LChunkBuilder::DoInvokeFunction(HInvokeFunction* instr) {
|
||||||
LOperand* context = UseFixed(instr->context(), cp);
|
LOperand* context = UseFixed(instr->context(), cp);
|
||||||
// The function is required (by MacroAssembler::InvokeFunction) to be in x1.
|
// The function is required (by MacroAssembler::InvokeFunction) to be in x1.
|
||||||
|
@ -165,6 +165,7 @@ class LCodeGen;
|
|||||||
V(SubI) \
|
V(SubI) \
|
||||||
V(SubS) \
|
V(SubS) \
|
||||||
V(TaggedToI) \
|
V(TaggedToI) \
|
||||||
|
V(TailCallThroughMegamorphicCache) \
|
||||||
V(ThisFunction) \
|
V(ThisFunction) \
|
||||||
V(ToFastProperties) \
|
V(ToFastProperties) \
|
||||||
V(TransitionElementsKind) \
|
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> {
|
class LUnknownOSRValue FINAL : public LTemplateInstruction<1, 0, 0> {
|
||||||
public:
|
public:
|
||||||
virtual bool HasInterestingComment(LCodeGen* gen) const OVERRIDE {
|
virtual bool HasInterestingComment(LCodeGen* gen) const OVERRIDE {
|
||||||
|
@ -9,6 +9,7 @@
|
|||||||
#include "src/base/bits.h"
|
#include "src/base/bits.h"
|
||||||
#include "src/code-stubs.h"
|
#include "src/code-stubs.h"
|
||||||
#include "src/hydrogen-osr.h"
|
#include "src/hydrogen-osr.h"
|
||||||
|
#include "src/ic/stub-cache.h"
|
||||||
|
|
||||||
namespace v8 {
|
namespace v8 {
|
||||||
namespace internal {
|
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) {
|
void LCodeGen::DoCallWithDescriptor(LCallWithDescriptor* instr) {
|
||||||
DCHECK(instr->IsMarkedAsCall());
|
DCHECK(instr->IsMarkedAsCall());
|
||||||
DCHECK(ToRegister(instr->result()).Is(x0));
|
DCHECK(ToRegister(instr->result()).Is(x0));
|
||||||
|
@ -1808,4 +1808,25 @@ HValue* CodeStubGraphBuilder<VectorKeyedLoadStub>::BuildCodeStub() {
|
|||||||
Handle<Code> VectorKeyedLoadStub::GenerateCode() {
|
Handle<Code> VectorKeyedLoadStub::GenerateCode() {
|
||||||
return DoGenerateCode(this);
|
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
|
} } // 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(
|
void FastNewClosureStub::InitializeInterfaceDescriptor(
|
||||||
CodeStubInterfaceDescriptor* descriptor) {
|
CodeStubInterfaceDescriptor* descriptor) {
|
||||||
FastNewClosureDescriptor call_descriptor(isolate());
|
FastNewClosureDescriptor call_descriptor(isolate());
|
||||||
|
@ -67,6 +67,7 @@ namespace internal {
|
|||||||
V(KeyedLoadGeneric) \
|
V(KeyedLoadGeneric) \
|
||||||
V(LoadDictionaryElement) \
|
V(LoadDictionaryElement) \
|
||||||
V(LoadFastElement) \
|
V(LoadFastElement) \
|
||||||
|
V(MegamorphicLoad) \
|
||||||
V(NameDictionaryLookup) \
|
V(NameDictionaryLookup) \
|
||||||
V(NumberToString) \
|
V(NumberToString) \
|
||||||
V(RegExpConstructResult) \
|
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 {
|
class VectorLoadStub : public HydrogenCodeStub {
|
||||||
public:
|
public:
|
||||||
explicit VectorLoadStub(Isolate* isolate, const LoadIC::State& state)
|
explicit VectorLoadStub(Isolate* isolate, const LoadIC::State& state)
|
||||||
|
@ -846,6 +846,7 @@ bool HInstruction::CanDeoptimize() {
|
|||||||
case HValue::kStoreNamedGeneric:
|
case HValue::kStoreNamedGeneric:
|
||||||
case HValue::kStringCharCodeAt:
|
case HValue::kStringCharCodeAt:
|
||||||
case HValue::kStringCharFromCode:
|
case HValue::kStringCharFromCode:
|
||||||
|
case HValue::kTailCallThroughMegamorphicCache:
|
||||||
case HValue::kThisFunction:
|
case HValue::kThisFunction:
|
||||||
case HValue::kTypeofIsAndBranch:
|
case HValue::kTypeofIsAndBranch:
|
||||||
case HValue::kUnknownOSRValue:
|
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
|
OStream& HUnknownOSRValue::PrintDataTo(OStream& os) const { // NOLINT
|
||||||
const char* type = "expression";
|
const char* type = "expression";
|
||||||
if (environment_->is_local_index(index_)) type = "local";
|
if (environment_->is_local_index(index_)) type = "local";
|
||||||
|
@ -37,133 +37,134 @@ class LInstruction;
|
|||||||
class LChunkBuilder;
|
class LChunkBuilder;
|
||||||
class OStream;
|
class OStream;
|
||||||
|
|
||||||
#define HYDROGEN_ABSTRACT_INSTRUCTION_LIST(V) \
|
#define HYDROGEN_ABSTRACT_INSTRUCTION_LIST(V) \
|
||||||
V(ArithmeticBinaryOperation) \
|
V(ArithmeticBinaryOperation) \
|
||||||
V(BinaryOperation) \
|
V(BinaryOperation) \
|
||||||
V(BitwiseBinaryOperation) \
|
V(BitwiseBinaryOperation) \
|
||||||
V(ControlInstruction) \
|
V(ControlInstruction) \
|
||||||
V(Instruction) \
|
V(Instruction)
|
||||||
|
|
||||||
|
|
||||||
#define HYDROGEN_CONCRETE_INSTRUCTION_LIST(V) \
|
#define HYDROGEN_CONCRETE_INSTRUCTION_LIST(V) \
|
||||||
V(AbnormalExit) \
|
V(AbnormalExit) \
|
||||||
V(AccessArgumentsAt) \
|
V(AccessArgumentsAt) \
|
||||||
V(Add) \
|
V(Add) \
|
||||||
V(AllocateBlockContext) \
|
V(AllocateBlockContext) \
|
||||||
V(Allocate) \
|
V(Allocate) \
|
||||||
V(ApplyArguments) \
|
V(ApplyArguments) \
|
||||||
V(ArgumentsElements) \
|
V(ArgumentsElements) \
|
||||||
V(ArgumentsLength) \
|
V(ArgumentsLength) \
|
||||||
V(ArgumentsObject) \
|
V(ArgumentsObject) \
|
||||||
V(Bitwise) \
|
V(Bitwise) \
|
||||||
V(BlockEntry) \
|
V(BlockEntry) \
|
||||||
V(BoundsCheck) \
|
V(BoundsCheck) \
|
||||||
V(BoundsCheckBaseIndexInformation) \
|
V(BoundsCheckBaseIndexInformation) \
|
||||||
V(Branch) \
|
V(Branch) \
|
||||||
V(CallWithDescriptor) \
|
V(CallWithDescriptor) \
|
||||||
V(CallJSFunction) \
|
V(CallJSFunction) \
|
||||||
V(CallFunction) \
|
V(CallFunction) \
|
||||||
V(CallNew) \
|
V(CallNew) \
|
||||||
V(CallNewArray) \
|
V(CallNewArray) \
|
||||||
V(CallRuntime) \
|
V(CallRuntime) \
|
||||||
V(CallStub) \
|
V(CallStub) \
|
||||||
V(CapturedObject) \
|
V(CapturedObject) \
|
||||||
V(Change) \
|
V(Change) \
|
||||||
V(CheckHeapObject) \
|
V(CheckHeapObject) \
|
||||||
V(CheckInstanceType) \
|
V(CheckInstanceType) \
|
||||||
V(CheckMaps) \
|
V(CheckMaps) \
|
||||||
V(CheckMapValue) \
|
V(CheckMapValue) \
|
||||||
V(CheckSmi) \
|
V(CheckSmi) \
|
||||||
V(CheckValue) \
|
V(CheckValue) \
|
||||||
V(ClampToUint8) \
|
V(ClampToUint8) \
|
||||||
V(ClassOfTestAndBranch) \
|
V(ClassOfTestAndBranch) \
|
||||||
V(CompareNumericAndBranch) \
|
V(CompareNumericAndBranch) \
|
||||||
V(CompareHoleAndBranch) \
|
V(CompareHoleAndBranch) \
|
||||||
V(CompareGeneric) \
|
V(CompareGeneric) \
|
||||||
V(CompareMinusZeroAndBranch) \
|
V(CompareMinusZeroAndBranch) \
|
||||||
V(CompareObjectEqAndBranch) \
|
V(CompareObjectEqAndBranch) \
|
||||||
V(CompareMap) \
|
V(CompareMap) \
|
||||||
V(Constant) \
|
V(Constant) \
|
||||||
V(ConstructDouble) \
|
V(ConstructDouble) \
|
||||||
V(Context) \
|
V(Context) \
|
||||||
V(DateField) \
|
V(DateField) \
|
||||||
V(DebugBreak) \
|
V(DebugBreak) \
|
||||||
V(DeclareGlobals) \
|
V(DeclareGlobals) \
|
||||||
V(Deoptimize) \
|
V(Deoptimize) \
|
||||||
V(Div) \
|
V(Div) \
|
||||||
V(DoubleBits) \
|
V(DoubleBits) \
|
||||||
V(DummyUse) \
|
V(DummyUse) \
|
||||||
V(EnterInlined) \
|
V(EnterInlined) \
|
||||||
V(EnvironmentMarker) \
|
V(EnvironmentMarker) \
|
||||||
V(ForceRepresentation) \
|
V(ForceRepresentation) \
|
||||||
V(ForInCacheArray) \
|
V(ForInCacheArray) \
|
||||||
V(ForInPrepareMap) \
|
V(ForInPrepareMap) \
|
||||||
V(FunctionLiteral) \
|
V(FunctionLiteral) \
|
||||||
V(GetCachedArrayIndex) \
|
V(GetCachedArrayIndex) \
|
||||||
V(Goto) \
|
V(Goto) \
|
||||||
V(HasCachedArrayIndexAndBranch) \
|
V(HasCachedArrayIndexAndBranch) \
|
||||||
V(HasInstanceTypeAndBranch) \
|
V(HasInstanceTypeAndBranch) \
|
||||||
V(InnerAllocatedObject) \
|
V(InnerAllocatedObject) \
|
||||||
V(InstanceOf) \
|
V(InstanceOf) \
|
||||||
V(InstanceOfKnownGlobal) \
|
V(InstanceOfKnownGlobal) \
|
||||||
V(InvokeFunction) \
|
V(InvokeFunction) \
|
||||||
V(IsConstructCallAndBranch) \
|
V(IsConstructCallAndBranch) \
|
||||||
V(IsObjectAndBranch) \
|
V(IsObjectAndBranch) \
|
||||||
V(IsStringAndBranch) \
|
V(IsStringAndBranch) \
|
||||||
V(IsSmiAndBranch) \
|
V(IsSmiAndBranch) \
|
||||||
V(IsUndetectableAndBranch) \
|
V(IsUndetectableAndBranch) \
|
||||||
V(LeaveInlined) \
|
V(LeaveInlined) \
|
||||||
V(LoadContextSlot) \
|
V(LoadContextSlot) \
|
||||||
V(LoadFieldByIndex) \
|
V(LoadFieldByIndex) \
|
||||||
V(LoadFunctionPrototype) \
|
V(LoadFunctionPrototype) \
|
||||||
V(LoadGlobalCell) \
|
V(LoadGlobalCell) \
|
||||||
V(LoadGlobalGeneric) \
|
V(LoadGlobalGeneric) \
|
||||||
V(LoadKeyed) \
|
V(LoadKeyed) \
|
||||||
V(LoadKeyedGeneric) \
|
V(LoadKeyedGeneric) \
|
||||||
V(LoadNamedField) \
|
V(LoadNamedField) \
|
||||||
V(LoadNamedGeneric) \
|
V(LoadNamedGeneric) \
|
||||||
V(LoadRoot) \
|
V(LoadRoot) \
|
||||||
V(MapEnumLength) \
|
V(MapEnumLength) \
|
||||||
V(MathFloorOfDiv) \
|
V(MathFloorOfDiv) \
|
||||||
V(MathMinMax) \
|
V(MathMinMax) \
|
||||||
V(Mod) \
|
V(Mod) \
|
||||||
V(Mul) \
|
V(Mul) \
|
||||||
V(OsrEntry) \
|
V(OsrEntry) \
|
||||||
V(Parameter) \
|
V(Parameter) \
|
||||||
V(Power) \
|
V(Power) \
|
||||||
V(PushArguments) \
|
V(PushArguments) \
|
||||||
V(RegExpLiteral) \
|
V(RegExpLiteral) \
|
||||||
V(Return) \
|
V(Return) \
|
||||||
V(Ror) \
|
V(Ror) \
|
||||||
V(Sar) \
|
V(Sar) \
|
||||||
V(SeqStringGetChar) \
|
V(SeqStringGetChar) \
|
||||||
V(SeqStringSetChar) \
|
V(SeqStringSetChar) \
|
||||||
V(Shl) \
|
V(Shl) \
|
||||||
V(Shr) \
|
V(Shr) \
|
||||||
V(Simulate) \
|
V(Simulate) \
|
||||||
V(StackCheck) \
|
V(StackCheck) \
|
||||||
V(StoreCodeEntry) \
|
V(StoreCodeEntry) \
|
||||||
V(StoreContextSlot) \
|
V(StoreContextSlot) \
|
||||||
V(StoreFrameContext) \
|
V(StoreFrameContext) \
|
||||||
V(StoreGlobalCell) \
|
V(StoreGlobalCell) \
|
||||||
V(StoreKeyed) \
|
V(StoreKeyed) \
|
||||||
V(StoreKeyedGeneric) \
|
V(StoreKeyedGeneric) \
|
||||||
V(StoreNamedField) \
|
V(StoreNamedField) \
|
||||||
V(StoreNamedGeneric) \
|
V(StoreNamedGeneric) \
|
||||||
V(StringAdd) \
|
V(StringAdd) \
|
||||||
V(StringCharCodeAt) \
|
V(StringCharCodeAt) \
|
||||||
V(StringCharFromCode) \
|
V(StringCharFromCode) \
|
||||||
V(StringCompareAndBranch) \
|
V(StringCompareAndBranch) \
|
||||||
V(Sub) \
|
V(Sub) \
|
||||||
V(ThisFunction) \
|
V(TailCallThroughMegamorphicCache) \
|
||||||
V(ToFastProperties) \
|
V(ThisFunction) \
|
||||||
V(TransitionElementsKind) \
|
V(ToFastProperties) \
|
||||||
V(TrapAllocationMemento) \
|
V(TransitionElementsKind) \
|
||||||
V(Typeof) \
|
V(TrapAllocationMemento) \
|
||||||
V(TypeofIsAndBranch) \
|
V(Typeof) \
|
||||||
V(UnaryMathOperation) \
|
V(TypeofIsAndBranch) \
|
||||||
V(UnknownOSRValue) \
|
V(UnaryMathOperation) \
|
||||||
V(UseConst) \
|
V(UnknownOSRValue) \
|
||||||
|
V(UseConst) \
|
||||||
V(WrapReceiver)
|
V(WrapReceiver)
|
||||||
|
|
||||||
#define GVN_TRACKED_FLAG_LIST(V) \
|
#define GVN_TRACKED_FLAG_LIST(V) \
|
||||||
@ -2324,9 +2325,8 @@ class HCallWithDescriptor FINAL : public HInstruction {
|
|||||||
CallInterfaceDescriptor descriptor,
|
CallInterfaceDescriptor descriptor,
|
||||||
const Vector<HValue*>& operands) {
|
const Vector<HValue*>& operands) {
|
||||||
DCHECK(operands.length() == descriptor.GetEnvironmentLength());
|
DCHECK(operands.length() == descriptor.GetEnvironmentLength());
|
||||||
HCallWithDescriptor* res =
|
HCallWithDescriptor* res = new (zone)
|
||||||
new(zone) HCallWithDescriptor(target, argument_count,
|
HCallWithDescriptor(target, argument_count, descriptor, operands, zone);
|
||||||
descriptor, operands, zone);
|
|
||||||
return res;
|
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> {
|
class HUnknownOSRValue FINAL : public HTemplateInstruction<0> {
|
||||||
public:
|
public:
|
||||||
DECLARE_INSTRUCTION_FACTORY_P2(HUnknownOSRValue, HEnvironment*, int);
|
DECLARE_INSTRUCTION_FACTORY_P2(HUnknownOSRValue, HEnvironment*, int);
|
||||||
|
@ -12,6 +12,7 @@
|
|||||||
#include "src/deoptimizer.h"
|
#include "src/deoptimizer.h"
|
||||||
#include "src/hydrogen-osr.h"
|
#include "src/hydrogen-osr.h"
|
||||||
#include "src/ia32/lithium-codegen-ia32.h"
|
#include "src/ia32/lithium-codegen-ia32.h"
|
||||||
|
#include "src/ic/stub-cache.h"
|
||||||
|
|
||||||
namespace v8 {
|
namespace v8 {
|
||||||
namespace internal {
|
namespace internal {
|
||||||
@ -3147,11 +3148,9 @@ void LCodeGen::DoLoadKeyedFixedArray(LLoadKeyed* instr) {
|
|||||||
|
|
||||||
// Load the result.
|
// Load the result.
|
||||||
__ mov(result,
|
__ mov(result,
|
||||||
BuildFastArrayOperand(instr->elements(),
|
BuildFastArrayOperand(instr->elements(), instr->key(),
|
||||||
instr->key(),
|
|
||||||
instr->hydrogen()->key()->representation(),
|
instr->hydrogen()->key()->representation(),
|
||||||
FAST_ELEMENTS,
|
FAST_ELEMENTS, instr->base_offset()));
|
||||||
instr->base_offset()));
|
|
||||||
|
|
||||||
// Check for the hole value.
|
// Check for the hole value.
|
||||||
if (instr->hydrogen()->RequiresHoleCheck()) {
|
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) {
|
void LCodeGen::DoCallWithDescriptor(LCallWithDescriptor* instr) {
|
||||||
DCHECK(ToRegister(instr->result()).is(eax));
|
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) {
|
LInstruction* LChunkBuilder::DoInvokeFunction(HInvokeFunction* instr) {
|
||||||
LOperand* context = UseFixed(instr->context(), esi);
|
LOperand* context = UseFixed(instr->context(), esi);
|
||||||
LOperand* function = UseFixed(instr->function(), edi);
|
LOperand* function = UseFixed(instr->function(), edi);
|
||||||
|
@ -155,6 +155,7 @@ class LCodeGen;
|
|||||||
V(StringCompareAndBranch) \
|
V(StringCompareAndBranch) \
|
||||||
V(SubI) \
|
V(SubI) \
|
||||||
V(TaggedToI) \
|
V(TaggedToI) \
|
||||||
|
V(TailCallThroughMegamorphicCache) \
|
||||||
V(ThisFunction) \
|
V(ThisFunction) \
|
||||||
V(ToFastProperties) \
|
V(ToFastProperties) \
|
||||||
V(TransitionElementsKind) \
|
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> {
|
class LUnknownOSRValue FINAL : public LTemplateInstruction<1, 0, 0> {
|
||||||
public:
|
public:
|
||||||
virtual bool HasInterestingComment(LCodeGen* gen) const OVERRIDE {
|
virtual bool HasInterestingComment(LCodeGen* gen) const OVERRIDE {
|
||||||
@ -1900,9 +1922,10 @@ class LCallWithDescriptor FINAL : public LTemplateResultInstruction<1> {
|
|||||||
|
|
||||||
LOperand* target() const { return inputs_[0]; }
|
LOperand* target() const { return inputs_[0]; }
|
||||||
|
|
||||||
|
DECLARE_HYDROGEN_ACCESSOR(CallWithDescriptor)
|
||||||
|
|
||||||
private:
|
private:
|
||||||
DECLARE_CONCRETE_INSTRUCTION(CallWithDescriptor, "call-with-descriptor")
|
DECLARE_CONCRETE_INSTRUCTION(CallWithDescriptor, "call-with-descriptor")
|
||||||
DECLARE_HYDROGEN_ACCESSOR(CallWithDescriptor)
|
|
||||||
|
|
||||||
virtual void PrintDataTo(StringStream* stream) OVERRIDE;
|
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) {
|
void LoadIC::GenerateNormal(MacroAssembler* masm) {
|
||||||
Register dictionary = r0;
|
Register dictionary = r0;
|
||||||
DCHECK(!dictionary.is(LoadDescriptor::ReceiverRegister()));
|
DCHECK(!dictionary.is(LoadDescriptor::ReceiverRegister()));
|
||||||
@ -963,8 +945,8 @@ void StoreIC::GenerateMegamorphic(MacroAssembler* masm) {
|
|||||||
Code::Flags flags = Code::RemoveTypeAndHolderFromFlags(
|
Code::Flags flags = Code::RemoveTypeAndHolderFromFlags(
|
||||||
Code::ComputeHandlerFlags(Code::STORE_IC));
|
Code::ComputeHandlerFlags(Code::STORE_IC));
|
||||||
|
|
||||||
masm->isolate()->stub_cache()->GenerateProbe(masm, flags, receiver, name, r3,
|
masm->isolate()->stub_cache()->GenerateProbe(masm, flags, false, receiver,
|
||||||
r4, r5, r6);
|
name, r3, r4, r5, r6);
|
||||||
|
|
||||||
// Cache miss: Jump to runtime.
|
// Cache miss: Jump to runtime.
|
||||||
GenerateMiss(masm);
|
GenerateMiss(masm);
|
||||||
|
@ -16,8 +16,8 @@ namespace internal {
|
|||||||
|
|
||||||
|
|
||||||
static void ProbeTable(Isolate* isolate, MacroAssembler* masm,
|
static void ProbeTable(Isolate* isolate, MacroAssembler* masm,
|
||||||
Code::Flags flags, StubCache::Table table,
|
Code::Flags flags, bool leave_frame,
|
||||||
Register receiver, Register name,
|
StubCache::Table table, Register receiver, Register name,
|
||||||
// Number of the cache entry, not scaled.
|
// Number of the cache entry, not scaled.
|
||||||
Register offset, Register scratch, Register scratch2,
|
Register offset, Register scratch, Register scratch2,
|
||||||
Register offset_scratch) {
|
Register offset_scratch) {
|
||||||
@ -84,6 +84,8 @@ static void ProbeTable(Isolate* isolate, MacroAssembler* masm,
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
if (leave_frame) __ LeaveFrame(StackFrame::INTERNAL);
|
||||||
|
|
||||||
// Jump to the first instruction in the code stub.
|
// Jump to the first instruction in the code stub.
|
||||||
__ add(pc, code, Operand(Code::kHeaderSize - kHeapObjectTag));
|
__ 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,
|
void StubCache::GenerateProbe(MacroAssembler* masm, Code::Flags flags,
|
||||||
Register receiver, Register name,
|
bool leave_frame, Register receiver,
|
||||||
Register scratch, Register extra, Register extra2,
|
Register name, Register scratch, Register extra,
|
||||||
Register extra3) {
|
Register extra2, Register extra3) {
|
||||||
Isolate* isolate = masm->isolate();
|
Isolate* isolate = masm->isolate();
|
||||||
Label miss;
|
Label miss;
|
||||||
|
|
||||||
@ -145,8 +147,8 @@ void StubCache::GenerateProbe(MacroAssembler* masm, Code::Flags flags,
|
|||||||
__ and_(scratch, scratch, Operand(mask));
|
__ and_(scratch, scratch, Operand(mask));
|
||||||
|
|
||||||
// Probe the primary table.
|
// Probe the primary table.
|
||||||
ProbeTable(isolate, masm, flags, kPrimary, receiver, name, scratch, extra,
|
ProbeTable(isolate, masm, flags, leave_frame, kPrimary, receiver, name,
|
||||||
extra2, extra3);
|
scratch, extra, extra2, extra3);
|
||||||
|
|
||||||
// Primary miss: Compute hash for secondary probe.
|
// Primary miss: Compute hash for secondary probe.
|
||||||
__ sub(scratch, scratch, Operand(name, LSR, kCacheIndexShift));
|
__ sub(scratch, scratch, Operand(name, LSR, kCacheIndexShift));
|
||||||
@ -155,8 +157,8 @@ void StubCache::GenerateProbe(MacroAssembler* masm, Code::Flags flags,
|
|||||||
__ and_(scratch, scratch, Operand(mask2));
|
__ and_(scratch, scratch, Operand(mask2));
|
||||||
|
|
||||||
// Probe the secondary table.
|
// Probe the secondary table.
|
||||||
ProbeTable(isolate, masm, flags, kSecondary, receiver, name, scratch, extra,
|
ProbeTable(isolate, masm, flags, leave_frame, kSecondary, receiver, name,
|
||||||
extra2, extra3);
|
scratch, extra, extra2, extra3);
|
||||||
|
|
||||||
// Cache miss: Fall-through and let caller handle the miss by
|
// Cache miss: Fall-through and let caller handle the miss by
|
||||||
// entering the runtime system.
|
// 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) {
|
void LoadIC::GenerateNormal(MacroAssembler* masm) {
|
||||||
Register dictionary = x0;
|
Register dictionary = x0;
|
||||||
DCHECK(!dictionary.is(LoadDescriptor::ReceiverRegister()));
|
DCHECK(!dictionary.is(LoadDescriptor::ReceiverRegister()));
|
||||||
@ -994,8 +976,8 @@ void StoreIC::GenerateMegamorphic(MacroAssembler* masm) {
|
|||||||
// Probe the stub cache.
|
// Probe the stub cache.
|
||||||
Code::Flags flags = Code::RemoveTypeAndHolderFromFlags(
|
Code::Flags flags = Code::RemoveTypeAndHolderFromFlags(
|
||||||
Code::ComputeHandlerFlags(Code::STORE_IC));
|
Code::ComputeHandlerFlags(Code::STORE_IC));
|
||||||
masm->isolate()->stub_cache()->GenerateProbe(masm, flags, receiver, name, x3,
|
masm->isolate()->stub_cache()->GenerateProbe(masm, flags, false, receiver,
|
||||||
x4, x5, x6);
|
name, x3, x4, x5, x6);
|
||||||
|
|
||||||
// Cache miss: Jump to runtime.
|
// Cache miss: Jump to runtime.
|
||||||
GenerateMiss(masm);
|
GenerateMiss(masm);
|
||||||
|
@ -23,9 +23,10 @@ namespace internal {
|
|||||||
//
|
//
|
||||||
// 'receiver', 'name' and 'offset' registers are preserved on miss.
|
// 'receiver', 'name' and 'offset' registers are preserved on miss.
|
||||||
static void ProbeTable(Isolate* isolate, MacroAssembler* masm,
|
static void ProbeTable(Isolate* isolate, MacroAssembler* masm,
|
||||||
Code::Flags flags, StubCache::Table table,
|
Code::Flags flags, bool leave_frame,
|
||||||
Register receiver, Register name, Register offset,
|
StubCache::Table table, Register receiver, Register name,
|
||||||
Register scratch, Register scratch2, Register scratch3) {
|
Register offset, Register scratch, Register scratch2,
|
||||||
|
Register scratch3) {
|
||||||
// Some code below relies on the fact that the Entry struct contains
|
// Some code below relies on the fact that the Entry struct contains
|
||||||
// 3 pointers (name, code, map).
|
// 3 pointers (name, code, map).
|
||||||
STATIC_ASSERT(sizeof(StubCache::Entry) == (3 * kPointerSize));
|
STATIC_ASSERT(sizeof(StubCache::Entry) == (3 * kPointerSize));
|
||||||
@ -78,6 +79,8 @@ static void ProbeTable(Isolate* isolate, MacroAssembler* masm,
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
if (leave_frame) __ LeaveFrame(StackFrame::INTERNAL);
|
||||||
|
|
||||||
// Jump to the first instruction in the code stub.
|
// Jump to the first instruction in the code stub.
|
||||||
__ Add(scratch, scratch, Code::kHeaderSize - kHeapObjectTag);
|
__ Add(scratch, scratch, Code::kHeaderSize - kHeapObjectTag);
|
||||||
__ Br(scratch);
|
__ Br(scratch);
|
||||||
@ -88,9 +91,9 @@ static void ProbeTable(Isolate* isolate, MacroAssembler* masm,
|
|||||||
|
|
||||||
|
|
||||||
void StubCache::GenerateProbe(MacroAssembler* masm, Code::Flags flags,
|
void StubCache::GenerateProbe(MacroAssembler* masm, Code::Flags flags,
|
||||||
Register receiver, Register name,
|
bool leave_frame, Register receiver,
|
||||||
Register scratch, Register extra, Register extra2,
|
Register name, Register scratch, Register extra,
|
||||||
Register extra3) {
|
Register extra2, Register extra3) {
|
||||||
Isolate* isolate = masm->isolate();
|
Isolate* isolate = masm->isolate();
|
||||||
Label miss;
|
Label miss;
|
||||||
|
|
||||||
@ -122,8 +125,8 @@ void StubCache::GenerateProbe(MacroAssembler* masm, Code::Flags flags,
|
|||||||
CountTrailingZeros(kPrimaryTableSize, 64));
|
CountTrailingZeros(kPrimaryTableSize, 64));
|
||||||
|
|
||||||
// Probe the primary table.
|
// Probe the primary table.
|
||||||
ProbeTable(isolate, masm, flags, kPrimary, receiver, name, scratch, extra,
|
ProbeTable(isolate, masm, flags, leave_frame, kPrimary, receiver, name,
|
||||||
extra2, extra3);
|
scratch, extra, extra2, extra3);
|
||||||
|
|
||||||
// Primary miss: Compute hash for secondary table.
|
// Primary miss: Compute hash for secondary table.
|
||||||
__ Sub(scratch, scratch, Operand(name, LSR, kCacheIndexShift));
|
__ Sub(scratch, scratch, Operand(name, LSR, kCacheIndexShift));
|
||||||
@ -131,8 +134,8 @@ void StubCache::GenerateProbe(MacroAssembler* masm, Code::Flags flags,
|
|||||||
__ And(scratch, scratch, kSecondaryTableSize - 1);
|
__ And(scratch, scratch, kSecondaryTableSize - 1);
|
||||||
|
|
||||||
// Probe the secondary table.
|
// Probe the secondary table.
|
||||||
ProbeTable(isolate, masm, flags, kSecondary, receiver, name, scratch, extra,
|
ProbeTable(isolate, masm, flags, leave_frame, kSecondary, receiver, name,
|
||||||
extra2, extra3);
|
scratch, extra, extra2, extra3);
|
||||||
|
|
||||||
// Cache miss: Fall-through and let caller handle the miss by
|
// Cache miss: Fall-through and let caller handle the miss by
|
||||||
// entering the runtime system.
|
// 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) {
|
void LoadIC::GenerateNormal(MacroAssembler* masm) {
|
||||||
Register dictionary = eax;
|
Register dictionary = eax;
|
||||||
DCHECK(!dictionary.is(LoadDescriptor::ReceiverRegister()));
|
DCHECK(!dictionary.is(LoadDescriptor::ReceiverRegister()));
|
||||||
@ -922,7 +904,7 @@ void StoreIC::GenerateMegamorphic(MacroAssembler* masm) {
|
|||||||
Code::Flags flags = Code::RemoveTypeAndHolderFromFlags(
|
Code::Flags flags = Code::RemoveTypeAndHolderFromFlags(
|
||||||
Code::ComputeHandlerFlags(Code::STORE_IC));
|
Code::ComputeHandlerFlags(Code::STORE_IC));
|
||||||
masm->isolate()->stub_cache()->GenerateProbe(
|
masm->isolate()->stub_cache()->GenerateProbe(
|
||||||
masm, flags, StoreDescriptor::ReceiverRegister(),
|
masm, flags, false, StoreDescriptor::ReceiverRegister(),
|
||||||
StoreDescriptor::NameRegister(), ebx, no_reg);
|
StoreDescriptor::NameRegister(), ebx, no_reg);
|
||||||
|
|
||||||
// Cache miss: Jump to runtime.
|
// Cache miss: Jump to runtime.
|
||||||
|
@ -16,8 +16,8 @@ namespace internal {
|
|||||||
|
|
||||||
|
|
||||||
static void ProbeTable(Isolate* isolate, MacroAssembler* masm,
|
static void ProbeTable(Isolate* isolate, MacroAssembler* masm,
|
||||||
Code::Flags flags, StubCache::Table table, Register name,
|
Code::Flags flags, bool leave_frame,
|
||||||
Register receiver,
|
StubCache::Table table, Register name, Register receiver,
|
||||||
// Number of the cache entry pointer-size scaled.
|
// Number of the cache entry pointer-size scaled.
|
||||||
Register offset, Register extra) {
|
Register offset, Register extra) {
|
||||||
ExternalReference key_offset(isolate->stub_cache()->key_reference(table));
|
ExternalReference key_offset(isolate->stub_cache()->key_reference(table));
|
||||||
@ -56,6 +56,8 @@ static void ProbeTable(Isolate* isolate, MacroAssembler* masm,
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
if (leave_frame) __ leave();
|
||||||
|
|
||||||
// Jump to the first instruction in the code stub.
|
// Jump to the first instruction in the code stub.
|
||||||
__ add(extra, Immediate(Code::kHeaderSize - kHeapObjectTag));
|
__ add(extra, Immediate(Code::kHeaderSize - kHeapObjectTag));
|
||||||
__ jmp(extra);
|
__ jmp(extra);
|
||||||
@ -98,6 +100,8 @@ static void ProbeTable(Isolate* isolate, MacroAssembler* masm,
|
|||||||
__ pop(offset);
|
__ pop(offset);
|
||||||
__ mov(offset, Operand::StaticArray(offset, times_1, value_offset));
|
__ mov(offset, Operand::StaticArray(offset, times_1, value_offset));
|
||||||
|
|
||||||
|
if (leave_frame) __ leave();
|
||||||
|
|
||||||
// Jump to the first instruction in the code stub.
|
// Jump to the first instruction in the code stub.
|
||||||
__ add(offset, Immediate(Code::kHeaderSize - kHeapObjectTag));
|
__ add(offset, Immediate(Code::kHeaderSize - kHeapObjectTag));
|
||||||
__ jmp(offset);
|
__ jmp(offset);
|
||||||
@ -110,9 +114,9 @@ static void ProbeTable(Isolate* isolate, MacroAssembler* masm,
|
|||||||
|
|
||||||
|
|
||||||
void StubCache::GenerateProbe(MacroAssembler* masm, Code::Flags flags,
|
void StubCache::GenerateProbe(MacroAssembler* masm, Code::Flags flags,
|
||||||
Register receiver, Register name,
|
bool leave_frame, Register receiver,
|
||||||
Register scratch, Register extra, Register extra2,
|
Register name, Register scratch, Register extra,
|
||||||
Register extra3) {
|
Register extra2, Register extra3) {
|
||||||
Label miss;
|
Label miss;
|
||||||
|
|
||||||
// Assert that code is valid. The multiplying code relies on the entry size
|
// 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);
|
DCHECK(kCacheIndexShift == kPointerSizeLog2);
|
||||||
|
|
||||||
// Probe the primary table.
|
// 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.
|
// Primary miss: Compute hash for secondary probe.
|
||||||
__ mov(offset, FieldOperand(name, Name::kHashFieldOffset));
|
__ mov(offset, FieldOperand(name, Name::kHashFieldOffset));
|
||||||
@ -167,7 +172,8 @@ void StubCache::GenerateProbe(MacroAssembler* masm, Code::Flags flags,
|
|||||||
__ and_(offset, (kSecondaryTableSize - 1) << kCacheIndexShift);
|
__ and_(offset, (kSecondaryTableSize - 1) << kCacheIndexShift);
|
||||||
|
|
||||||
// Probe the secondary table.
|
// 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
|
// Cache miss: Fall-through and let caller handle the miss by
|
||||||
// entering the runtime system.
|
// entering the runtime system.
|
||||||
|
@ -178,8 +178,6 @@ Handle<Code> PropertyICCompiler::ComputeLoad(Isolate* isolate,
|
|||||||
code = compiler.CompileLoadInitialize(flags);
|
code = compiler.CompileLoadInitialize(flags);
|
||||||
} else if (ic_state == PREMONOMORPHIC) {
|
} else if (ic_state == PREMONOMORPHIC) {
|
||||||
code = compiler.CompileLoadPreMonomorphic(flags);
|
code = compiler.CompileLoadPreMonomorphic(flags);
|
||||||
} else if (ic_state == MEGAMORPHIC) {
|
|
||||||
code = compiler.CompileLoadMegamorphic(flags);
|
|
||||||
} else {
|
} else {
|
||||||
UNREACHABLE();
|
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) {
|
Handle<Code> PropertyICCompiler::CompileStoreInitialize(Code::Flags flags) {
|
||||||
StoreIC::GenerateInitialize(masm());
|
StoreIC::GenerateInitialize(masm());
|
||||||
Handle<Code> code = GetCodeWithFlags(flags, "CompileStoreInitialize");
|
Handle<Code> code = GetCodeWithFlags(flags, "CompileStoreInitialize");
|
||||||
|
@ -72,7 +72,6 @@ class PropertyICCompiler : public PropertyAccessCompiler {
|
|||||||
|
|
||||||
Handle<Code> CompileLoadInitialize(Code::Flags flags);
|
Handle<Code> CompileLoadInitialize(Code::Flags flags);
|
||||||
Handle<Code> CompileLoadPreMonomorphic(Code::Flags flags);
|
Handle<Code> CompileLoadPreMonomorphic(Code::Flags flags);
|
||||||
Handle<Code> CompileLoadMegamorphic(Code::Flags flags);
|
|
||||||
Handle<Code> CompileStoreInitialize(Code::Flags flags);
|
Handle<Code> CompileStoreInitialize(Code::Flags flags);
|
||||||
Handle<Code> CompileStorePreMonomorphic(Code::Flags flags);
|
Handle<Code> CompileStorePreMonomorphic(Code::Flags flags);
|
||||||
Handle<Code> CompileStoreGeneric(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() {
|
Handle<Code> LoadIC::megamorphic_stub() {
|
||||||
if (kind() == Code::LOAD_IC) {
|
if (kind() == Code::LOAD_IC) {
|
||||||
return PropertyICCompiler::ComputeLoad(isolate(), MEGAMORPHIC,
|
MegamorphicLoadStub stub(isolate(), State(extra_ic_state()));
|
||||||
extra_ic_state());
|
return stub.GetCode();
|
||||||
} else {
|
} else {
|
||||||
DCHECK_EQ(Code::KEYED_LOAD_IC, kind());
|
DCHECK_EQ(Code::KEYED_LOAD_IC, kind());
|
||||||
return KeyedLoadIC::generic_stub(isolate());
|
return KeyedLoadIC::generic_stub(isolate());
|
||||||
|
@ -405,7 +405,6 @@ class LoadIC : public IC {
|
|||||||
GenerateMiss(masm);
|
GenerateMiss(masm);
|
||||||
}
|
}
|
||||||
static void GenerateMiss(MacroAssembler* masm);
|
static void GenerateMiss(MacroAssembler* masm);
|
||||||
static void GenerateMegamorphic(MacroAssembler* masm);
|
|
||||||
static void GenerateNormal(MacroAssembler* masm);
|
static void GenerateNormal(MacroAssembler* masm);
|
||||||
static void GenerateRuntimeGetProperty(MacroAssembler* masm);
|
static void GenerateRuntimeGetProperty(MacroAssembler* masm);
|
||||||
|
|
||||||
|
@ -51,9 +51,11 @@ class StubCache {
|
|||||||
// Generate code for probing the stub cache table.
|
// Generate code for probing the stub cache table.
|
||||||
// Arguments extra, extra2 and extra3 may be used to pass additional scratch
|
// Arguments extra, extra2 and extra3 may be used to pass additional scratch
|
||||||
// registers. Set to no_reg if not needed.
|
// registers. Set to no_reg if not needed.
|
||||||
void GenerateProbe(MacroAssembler* masm, Code::Flags flags, Register receiver,
|
// If leave_frame is true, then exit a frame before the tail call.
|
||||||
Register name, Register scratch, Register extra,
|
void GenerateProbe(MacroAssembler* masm, Code::Flags flags, bool leave_frame,
|
||||||
Register extra2 = no_reg, Register extra3 = no_reg);
|
Register receiver, Register name, Register scratch,
|
||||||
|
Register extra, Register extra2 = no_reg,
|
||||||
|
Register extra3 = no_reg);
|
||||||
|
|
||||||
enum Table { kPrimary, kSecondary };
|
enum Table { kPrimary, kSecondary };
|
||||||
|
|
||||||
@ -153,6 +155,7 @@ class StubCache {
|
|||||||
static const int kSecondaryTableBits = 9;
|
static const int kSecondaryTableBits = 9;
|
||||||
static const int kSecondaryTableSize = (1 << kSecondaryTableBits);
|
static const int kSecondaryTableSize = (1 << kSecondaryTableBits);
|
||||||
|
|
||||||
|
private:
|
||||||
Entry primary_[kPrimaryTableSize];
|
Entry primary_[kPrimaryTableSize];
|
||||||
Entry secondary_[kSecondaryTableSize];
|
Entry secondary_[kSecondaryTableSize];
|
||||||
Isolate* isolate_;
|
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) {
|
void LoadIC::GenerateNormal(MacroAssembler* masm) {
|
||||||
Register dictionary = rax;
|
Register dictionary = rax;
|
||||||
DCHECK(!dictionary.is(LoadDescriptor::ReceiverRegister()));
|
DCHECK(!dictionary.is(LoadDescriptor::ReceiverRegister()));
|
||||||
@ -934,7 +917,7 @@ void StoreIC::GenerateMegamorphic(MacroAssembler* masm) {
|
|||||||
Code::Flags flags = Code::RemoveTypeAndHolderFromFlags(
|
Code::Flags flags = Code::RemoveTypeAndHolderFromFlags(
|
||||||
Code::ComputeHandlerFlags(Code::STORE_IC));
|
Code::ComputeHandlerFlags(Code::STORE_IC));
|
||||||
masm->isolate()->stub_cache()->GenerateProbe(
|
masm->isolate()->stub_cache()->GenerateProbe(
|
||||||
masm, flags, StoreDescriptor::ReceiverRegister(),
|
masm, flags, false, StoreDescriptor::ReceiverRegister(),
|
||||||
StoreDescriptor::NameRegister(), rbx, no_reg);
|
StoreDescriptor::NameRegister(), rbx, no_reg);
|
||||||
|
|
||||||
// Cache miss: Jump to runtime.
|
// Cache miss: Jump to runtime.
|
||||||
|
@ -16,8 +16,8 @@ namespace internal {
|
|||||||
|
|
||||||
|
|
||||||
static void ProbeTable(Isolate* isolate, MacroAssembler* masm,
|
static void ProbeTable(Isolate* isolate, MacroAssembler* masm,
|
||||||
Code::Flags flags, StubCache::Table table,
|
Code::Flags flags, bool leave_frame,
|
||||||
Register receiver, Register name,
|
StubCache::Table table, Register receiver, Register name,
|
||||||
// The offset is scaled by 4, based on
|
// The offset is scaled by 4, based on
|
||||||
// kCacheIndexShift, which is two bits
|
// kCacheIndexShift, which is two bits
|
||||||
Register offset) {
|
Register offset) {
|
||||||
@ -72,6 +72,8 @@ static void ProbeTable(Isolate* isolate, MacroAssembler* masm,
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
if (leave_frame) __ leave();
|
||||||
|
|
||||||
// Jump to the first instruction in the code stub.
|
// Jump to the first instruction in the code stub.
|
||||||
__ addp(kScratchRegister, Immediate(Code::kHeaderSize - kHeapObjectTag));
|
__ addp(kScratchRegister, Immediate(Code::kHeaderSize - kHeapObjectTag));
|
||||||
__ jmp(kScratchRegister);
|
__ jmp(kScratchRegister);
|
||||||
@ -81,9 +83,9 @@ static void ProbeTable(Isolate* isolate, MacroAssembler* masm,
|
|||||||
|
|
||||||
|
|
||||||
void StubCache::GenerateProbe(MacroAssembler* masm, Code::Flags flags,
|
void StubCache::GenerateProbe(MacroAssembler* masm, Code::Flags flags,
|
||||||
Register receiver, Register name,
|
bool leave_frame, Register receiver,
|
||||||
Register scratch, Register extra, Register extra2,
|
Register name, Register scratch, Register extra,
|
||||||
Register extra3) {
|
Register extra2, Register extra3) {
|
||||||
Isolate* isolate = masm->isolate();
|
Isolate* isolate = masm->isolate();
|
||||||
Label miss;
|
Label miss;
|
||||||
USE(extra); // The register extra is not used on the X64 platform.
|
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));
|
__ andp(scratch, Immediate((kPrimaryTableSize - 1) << kCacheIndexShift));
|
||||||
|
|
||||||
// Probe the primary table.
|
// 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.
|
// Primary miss: Compute hash for secondary probe.
|
||||||
__ movl(scratch, FieldOperand(name, Name::kHashFieldOffset));
|
__ movl(scratch, FieldOperand(name, Name::kHashFieldOffset));
|
||||||
@ -133,7 +136,8 @@ void StubCache::GenerateProbe(MacroAssembler* masm, Code::Flags flags,
|
|||||||
__ andp(scratch, Immediate((kSecondaryTableSize - 1) << kCacheIndexShift));
|
__ andp(scratch, Immediate((kSecondaryTableSize - 1) << kCacheIndexShift));
|
||||||
|
|
||||||
// Probe the secondary table.
|
// 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
|
// Cache miss: Fall-through and let caller handle the miss by
|
||||||
// entering the runtime system.
|
// entering the runtime system.
|
||||||
|
@ -9,6 +9,7 @@
|
|||||||
#include "src/base/bits.h"
|
#include "src/base/bits.h"
|
||||||
#include "src/code-stubs.h"
|
#include "src/code-stubs.h"
|
||||||
#include "src/hydrogen-osr.h"
|
#include "src/hydrogen-osr.h"
|
||||||
|
#include "src/ic/stub-cache.h"
|
||||||
#include "src/x64/lithium-codegen-x64.h"
|
#include "src/x64/lithium-codegen-x64.h"
|
||||||
|
|
||||||
namespace v8 {
|
namespace v8 {
|
||||||
@ -3227,11 +3228,9 @@ void LCodeGen::DoLoadKeyedFixedArray(LLoadKeyed* instr) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
__ Load(result,
|
__ Load(result,
|
||||||
BuildFastArrayOperand(instr->elements(),
|
BuildFastArrayOperand(instr->elements(), key,
|
||||||
key,
|
|
||||||
instr->hydrogen()->key()->representation(),
|
instr->hydrogen()->key()->representation(),
|
||||||
FAST_ELEMENTS,
|
FAST_ELEMENTS, offset),
|
||||||
offset),
|
|
||||||
representation);
|
representation);
|
||||||
|
|
||||||
// Check for the hole value.
|
// 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) {
|
void LCodeGen::DoCallWithDescriptor(LCallWithDescriptor* instr) {
|
||||||
DCHECK(ToRegister(instr->result()).is(rax));
|
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) {
|
LInstruction* LChunkBuilder::DoInvokeFunction(HInvokeFunction* instr) {
|
||||||
LOperand* context = UseFixed(instr->context(), rsi);
|
LOperand* context = UseFixed(instr->context(), rsi);
|
||||||
LOperand* function = UseFixed(instr->function(), rdi);
|
LOperand* function = UseFixed(instr->function(), rdi);
|
||||||
|
@ -151,6 +151,7 @@ class LCodeGen;
|
|||||||
V(StringCompareAndBranch) \
|
V(StringCompareAndBranch) \
|
||||||
V(SubI) \
|
V(SubI) \
|
||||||
V(TaggedToI) \
|
V(TaggedToI) \
|
||||||
|
V(TailCallThroughMegamorphicCache) \
|
||||||
V(ThisFunction) \
|
V(ThisFunction) \
|
||||||
V(ToFastProperties) \
|
V(ToFastProperties) \
|
||||||
V(TransitionElementsKind) \
|
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> {
|
class LUnknownOSRValue FINAL : public LTemplateInstruction<1, 0, 0> {
|
||||||
public:
|
public:
|
||||||
virtual bool HasInterestingComment(LCodeGen* gen) const OVERRIDE {
|
virtual bool HasInterestingComment(LCodeGen* gen) const OVERRIDE {
|
||||||
@ -1886,9 +1908,10 @@ class LCallWithDescriptor FINAL : public LTemplateResultInstruction<1> {
|
|||||||
|
|
||||||
LOperand* target() const { return inputs_[0]; }
|
LOperand* target() const { return inputs_[0]; }
|
||||||
|
|
||||||
|
DECLARE_HYDROGEN_ACCESSOR(CallWithDescriptor)
|
||||||
|
|
||||||
private:
|
private:
|
||||||
DECLARE_CONCRETE_INSTRUCTION(CallWithDescriptor, "call-with-descriptor")
|
DECLARE_CONCRETE_INSTRUCTION(CallWithDescriptor, "call-with-descriptor")
|
||||||
DECLARE_HYDROGEN_ACCESSOR(CallWithDescriptor)
|
|
||||||
|
|
||||||
virtual void PrintDataTo(StringStream* stream) OVERRIDE;
|
virtual void PrintDataTo(StringStream* stream) OVERRIDE;
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user