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:
mvstanton@chromium.org 2014-09-08 12:51:29 +00:00
parent 4ad3760dff
commit 6e1ebdcbc3
30 changed files with 538 additions and 265 deletions

View File

@ -1099,6 +1099,19 @@ LInstruction* LChunkBuilder::DoCallWithDescriptor(
}
LInstruction* LChunkBuilder::DoTailCallThroughMegamorphicCache(
HTailCallThroughMegamorphicCache* instr) {
LOperand* context = UseFixed(instr->context(), cp);
LOperand* receiver_register =
UseFixed(instr->receiver(), LoadDescriptor::ReceiverRegister());
LOperand* name_register =
UseFixed(instr->name(), LoadDescriptor::NameRegister());
// Not marked as call. It can't deoptimize, and it never returns.
return new (zone()) LTailCallThroughMegamorphicCache(
context, receiver_register, name_register);
}
LInstruction* LChunkBuilder::DoInvokeFunction(HInvokeFunction* instr) {
LOperand* context = UseFixed(instr->context(), cp);
LOperand* function = UseFixed(instr->function(), r1);

View File

@ -154,6 +154,7 @@ class LCodeGen;
V(SubI) \
V(RSubI) \
V(TaggedToI) \
V(TailCallThroughMegamorphicCache) \
V(ThisFunction) \
V(ToFastProperties) \
V(TransitionElementsKind) \
@ -482,6 +483,26 @@ class LCallStub FINAL : public LTemplateInstruction<1, 1, 0> {
};
class LTailCallThroughMegamorphicCache FINAL
: public LTemplateInstruction<0, 3, 0> {
public:
explicit LTailCallThroughMegamorphicCache(LOperand* context,
LOperand* receiver,
LOperand* name) {
inputs_[0] = context;
inputs_[1] = receiver;
inputs_[2] = name;
}
LOperand* context() { return inputs_[0]; }
LOperand* receiver() { return inputs_[1]; }
LOperand* name() { return inputs_[2]; }
DECLARE_CONCRETE_INSTRUCTION(TailCallThroughMegamorphicCache,
"tail-call-through-megamorphic-cache")
DECLARE_HYDROGEN_ACCESSOR(TailCallThroughMegamorphicCache)
};
class LUnknownOSRValue FINAL : public LTemplateInstruction<1, 0, 0> {
public:
virtual bool HasInterestingComment(LCodeGen* gen) const OVERRIDE {

View File

@ -9,6 +9,7 @@
#include "src/base/bits.h"
#include "src/code-stubs.h"
#include "src/hydrogen-osr.h"
#include "src/ic/stub-cache.h"
namespace v8 {
namespace internal {
@ -3969,6 +3970,34 @@ void LCodeGen::DoInvokeFunction(LInvokeFunction* instr) {
}
void LCodeGen::DoTailCallThroughMegamorphicCache(
LTailCallThroughMegamorphicCache* instr) {
Register receiver = ToRegister(instr->receiver());
Register name = ToRegister(instr->name());
DCHECK(receiver.is(LoadDescriptor::ReceiverRegister()));
DCHECK(name.is(LoadDescriptor::NameRegister()));
DCHECK(receiver.is(r1));
DCHECK(name.is(r2));
Register scratch = r3;
Register extra = r4;
Register extra2 = r5;
Register extra3 = r6;
// Important for the tail-call.
bool must_teardown_frame = NeedsEagerFrame();
// The probe will tail call to a handler if found.
isolate()->stub_cache()->GenerateProbe(masm(), instr->hydrogen()->flags(),
must_teardown_frame, receiver, name,
scratch, extra, extra2, extra3);
// Tail call to miss if we ended up here.
if (must_teardown_frame) __ LeaveFrame(StackFrame::INTERNAL);
LoadIC::GenerateMiss(masm());
}
void LCodeGen::DoCallWithDescriptor(LCallWithDescriptor* instr) {
DCHECK(ToRegister(instr->result()).is(r0));

View File

@ -1562,6 +1562,19 @@ LInstruction* LChunkBuilder::DoInstanceOfKnownGlobal(
}
LInstruction* LChunkBuilder::DoTailCallThroughMegamorphicCache(
HTailCallThroughMegamorphicCache* instr) {
LOperand* context = UseFixed(instr->context(), cp);
LOperand* receiver_register =
UseFixed(instr->receiver(), LoadDescriptor::ReceiverRegister());
LOperand* name_register =
UseFixed(instr->name(), LoadDescriptor::NameRegister());
// Not marked as call. It can't deoptimize, and it never returns.
return new (zone()) LTailCallThroughMegamorphicCache(
context, receiver_register, name_register);
}
LInstruction* LChunkBuilder::DoInvokeFunction(HInvokeFunction* instr) {
LOperand* context = UseFixed(instr->context(), cp);
// The function is required (by MacroAssembler::InvokeFunction) to be in x1.

View File

@ -165,6 +165,7 @@ class LCodeGen;
V(SubI) \
V(SubS) \
V(TaggedToI) \
V(TailCallThroughMegamorphicCache) \
V(ThisFunction) \
V(ToFastProperties) \
V(TransitionElementsKind) \
@ -324,6 +325,27 @@ class LTemplateInstruction : public LTemplateResultInstruction<R> {
};
class LTailCallThroughMegamorphicCache FINAL
: public LTemplateInstruction<0, 3, 0> {
public:
explicit LTailCallThroughMegamorphicCache(LOperand* context,
LOperand* receiver,
LOperand* name) {
inputs_[0] = context;
inputs_[1] = receiver;
inputs_[2] = name;
}
LOperand* context() { return inputs_[0]; }
LOperand* receiver() { return inputs_[1]; }
LOperand* name() { return inputs_[2]; }
DECLARE_CONCRETE_INSTRUCTION(TailCallThroughMegamorphicCache,
"tail-call-through-megamorphic-cache")
DECLARE_HYDROGEN_ACCESSOR(TailCallThroughMegamorphicCache)
};
class LUnknownOSRValue FINAL : public LTemplateInstruction<1, 0, 0> {
public:
virtual bool HasInterestingComment(LCodeGen* gen) const OVERRIDE {

View File

@ -9,6 +9,7 @@
#include "src/base/bits.h"
#include "src/code-stubs.h"
#include "src/hydrogen-osr.h"
#include "src/ic/stub-cache.h"
namespace v8 {
namespace internal {
@ -2037,6 +2038,34 @@ void LCodeGen::CallKnownFunction(Handle<JSFunction> function,
}
void LCodeGen::DoTailCallThroughMegamorphicCache(
LTailCallThroughMegamorphicCache* instr) {
Register receiver = ToRegister(instr->receiver());
Register name = ToRegister(instr->name());
DCHECK(receiver.is(LoadDescriptor::ReceiverRegister()));
DCHECK(name.is(LoadDescriptor::NameRegister()));
DCHECK(receiver.is(x1));
DCHECK(name.is(x2));
Register scratch = x3;
Register extra = x4;
Register extra2 = x5;
Register extra3 = x6;
// Important for the tail-call.
bool must_teardown_frame = NeedsEagerFrame();
// The probe will tail call to a handler if found.
isolate()->stub_cache()->GenerateProbe(masm(), instr->hydrogen()->flags(),
must_teardown_frame, receiver, name,
scratch, extra, extra2, extra3);
// Tail call to miss if we ended up here.
if (must_teardown_frame) __ LeaveFrame(StackFrame::INTERNAL);
LoadIC::GenerateMiss(masm());
}
void LCodeGen::DoCallWithDescriptor(LCallWithDescriptor* instr) {
DCHECK(instr->IsMarkedAsCall());
DCHECK(ToRegister(instr->result()).Is(x0));

View File

@ -1808,4 +1808,25 @@ HValue* CodeStubGraphBuilder<VectorKeyedLoadStub>::BuildCodeStub() {
Handle<Code> VectorKeyedLoadStub::GenerateCode() {
return DoGenerateCode(this);
}
Handle<Code> MegamorphicLoadStub::GenerateCode() {
return DoGenerateCode(this);
}
template <>
HValue* CodeStubGraphBuilder<MegamorphicLoadStub>::BuildCodeStub() {
// The return address is on the stack.
HValue* receiver = GetParameter(LoadDescriptor::kReceiverIndex);
HValue* name = GetParameter(LoadDescriptor::kNameIndex);
// Probe the stub cache.
Code::Flags flags = Code::RemoveTypeAndHolderFromFlags(
Code::ComputeHandlerFlags(Code::LOAD_IC));
Add<HTailCallThroughMegamorphicCache>(receiver, name, flags);
// We never continue.
return graph()->GetConstant0();
}
} } // namespace v8::internal

View File

@ -619,6 +619,13 @@ void VectorKeyedLoadStub::InitializeInterfaceDescriptor(
}
void MegamorphicLoadStub::InitializeInterfaceDescriptor(
CodeStubInterfaceDescriptor* descriptor) {
LoadDescriptor call_descriptor(isolate());
descriptor->Initialize(MajorKey(), call_descriptor);
}
void FastNewClosureStub::InitializeInterfaceDescriptor(
CodeStubInterfaceDescriptor* descriptor) {
FastNewClosureDescriptor call_descriptor(isolate());

View File

@ -67,6 +67,7 @@ namespace internal {
V(KeyedLoadGeneric) \
V(LoadDictionaryElement) \
V(LoadFastElement) \
V(MegamorphicLoad) \
V(NameDictionaryLookup) \
V(NumberToString) \
V(RegExpConstructResult) \
@ -1733,6 +1734,27 @@ class KeyedLoadICTrampolineStub : public LoadICTrampolineStub {
};
class MegamorphicLoadStub : public HydrogenCodeStub {
public:
MegamorphicLoadStub(Isolate* isolate, const LoadIC::State& state)
: HydrogenCodeStub(isolate) {
set_sub_minor_key(state.GetExtraICState());
}
virtual Code::Kind GetCodeKind() const OVERRIDE { return Code::LOAD_IC; }
virtual InlineCacheState GetICState() const FINAL OVERRIDE {
return MEGAMORPHIC;
}
virtual ExtraICState GetExtraICState() const FINAL OVERRIDE {
return static_cast<ExtraICState>(sub_minor_key());
}
DEFINE_HYDROGEN_CODE_STUB(MegamorphicLoad, HydrogenCodeStub);
};
class VectorLoadStub : public HydrogenCodeStub {
public:
explicit VectorLoadStub(Isolate* isolate, const LoadIC::State& state)

View File

@ -846,6 +846,7 @@ bool HInstruction::CanDeoptimize() {
case HValue::kStoreNamedGeneric:
case HValue::kStringCharCodeAt:
case HValue::kStringCharFromCode:
case HValue::kTailCallThroughMegamorphicCache:
case HValue::kThisFunction:
case HValue::kTypeofIsAndBranch:
case HValue::kUnknownOSRValue:
@ -1702,6 +1703,15 @@ OStream& HCallStub::PrintDataTo(OStream& os) const { // NOLINT
}
OStream& HTailCallThroughMegamorphicCache::PrintDataTo(
OStream& os) const { // NOLINT
for (int i = 0; i < OperandCount(); i++) {
os << NameOf(OperandAt(i)) << " ";
}
return os << "flags: " << flags();
}
OStream& HUnknownOSRValue::PrintDataTo(OStream& os) const { // NOLINT
const char* type = "expression";
if (environment_->is_local_index(index_)) type = "local";

View File

@ -37,133 +37,134 @@ class LInstruction;
class LChunkBuilder;
class OStream;
#define HYDROGEN_ABSTRACT_INSTRUCTION_LIST(V) \
V(ArithmeticBinaryOperation) \
V(BinaryOperation) \
V(BitwiseBinaryOperation) \
V(ControlInstruction) \
V(Instruction) \
#define HYDROGEN_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);

View File

@ -12,6 +12,7 @@
#include "src/deoptimizer.h"
#include "src/hydrogen-osr.h"
#include "src/ia32/lithium-codegen-ia32.h"
#include "src/ic/stub-cache.h"
namespace v8 {
namespace internal {
@ -3147,11 +3148,9 @@ void LCodeGen::DoLoadKeyedFixedArray(LLoadKeyed* instr) {
// Load the result.
__ mov(result,
BuildFastArrayOperand(instr->elements(),
instr->key(),
BuildFastArrayOperand(instr->elements(), instr->key(),
instr->hydrogen()->key()->representation(),
FAST_ELEMENTS,
instr->base_offset()));
FAST_ELEMENTS, instr->base_offset()));
// Check for the hole value.
if (instr->hydrogen()->RequiresHoleCheck()) {
@ -3447,6 +3446,32 @@ void LCodeGen::CallKnownFunction(Handle<JSFunction> function,
}
void LCodeGen::DoTailCallThroughMegamorphicCache(
LTailCallThroughMegamorphicCache* instr) {
Register receiver = ToRegister(instr->receiver());
Register name = ToRegister(instr->name());
DCHECK(receiver.is(LoadDescriptor::ReceiverRegister()));
DCHECK(name.is(LoadDescriptor::NameRegister()));
Register scratch = ebx;
Register extra = eax;
DCHECK(!scratch.is(receiver) && !scratch.is(name));
DCHECK(!extra.is(receiver) && !extra.is(name));
// Important for the tail-call.
bool must_teardown_frame = NeedsEagerFrame();
// The probe will tail call to a handler if found.
isolate()->stub_cache()->GenerateProbe(masm(), instr->hydrogen()->flags(),
must_teardown_frame, receiver, name,
scratch, extra);
// Tail call to miss if we ended up here.
if (must_teardown_frame) __ leave();
LoadIC::GenerateMiss(masm());
}
void LCodeGen::DoCallWithDescriptor(LCallWithDescriptor* instr) {
DCHECK(ToRegister(instr->result()).is(eax));

View File

@ -1139,6 +1139,19 @@ LInstruction* LChunkBuilder::DoCallWithDescriptor(
}
LInstruction* LChunkBuilder::DoTailCallThroughMegamorphicCache(
HTailCallThroughMegamorphicCache* instr) {
LOperand* context = UseFixed(instr->context(), esi);
LOperand* receiver_register =
UseFixed(instr->receiver(), LoadDescriptor::ReceiverRegister());
LOperand* name_register =
UseFixed(instr->name(), LoadDescriptor::NameRegister());
// Not marked as call. It can't deoptimize, and it never returns.
return new (zone()) LTailCallThroughMegamorphicCache(
context, receiver_register, name_register);
}
LInstruction* LChunkBuilder::DoInvokeFunction(HInvokeFunction* instr) {
LOperand* context = UseFixed(instr->context(), esi);
LOperand* function = UseFixed(instr->function(), edi);

View File

@ -155,6 +155,7 @@ class LCodeGen;
V(StringCompareAndBranch) \
V(SubI) \
V(TaggedToI) \
V(TailCallThroughMegamorphicCache) \
V(ThisFunction) \
V(ToFastProperties) \
V(TransitionElementsKind) \
@ -479,6 +480,27 @@ class LCallStub FINAL : public LTemplateInstruction<1, 1, 0> {
};
class LTailCallThroughMegamorphicCache FINAL
: public LTemplateInstruction<0, 3, 0> {
public:
explicit LTailCallThroughMegamorphicCache(LOperand* context,
LOperand* receiver,
LOperand* name) {
inputs_[0] = context;
inputs_[1] = receiver;
inputs_[2] = name;
}
LOperand* context() { return inputs_[0]; }
LOperand* receiver() { return inputs_[1]; }
LOperand* name() { return inputs_[2]; }
DECLARE_CONCRETE_INSTRUCTION(TailCallThroughMegamorphicCache,
"tail-call-through-megamorphic-cache")
DECLARE_HYDROGEN_ACCESSOR(TailCallThroughMegamorphicCache)
};
class LUnknownOSRValue FINAL : public LTemplateInstruction<1, 0, 0> {
public:
virtual bool HasInterestingComment(LCodeGen* gen) const OVERRIDE {
@ -1900,9 +1922,10 @@ class LCallWithDescriptor FINAL : public LTemplateResultInstruction<1> {
LOperand* target() const { return inputs_[0]; }
DECLARE_HYDROGEN_ACCESSOR(CallWithDescriptor)
private:
DECLARE_CONCRETE_INSTRUCTION(CallWithDescriptor, "call-with-descriptor")
DECLARE_HYDROGEN_ACCESSOR(CallWithDescriptor)
virtual void PrintDataTo(StringStream* stream) OVERRIDE;

View File

@ -242,24 +242,6 @@ static void GenerateKeyNameCheck(MacroAssembler* masm, Register key,
}
void LoadIC::GenerateMegamorphic(MacroAssembler* masm) {
// The return address is in lr.
Register receiver = LoadDescriptor::ReceiverRegister();
Register name = LoadDescriptor::NameRegister();
DCHECK(receiver.is(r1));
DCHECK(name.is(r2));
// Probe the stub cache.
Code::Flags flags = Code::RemoveTypeAndHolderFromFlags(
Code::ComputeHandlerFlags(Code::LOAD_IC));
masm->isolate()->stub_cache()->GenerateProbe(masm, flags, receiver, name, r3,
r4, r5, r6);
// Cache miss: Jump to runtime.
GenerateMiss(masm);
}
void LoadIC::GenerateNormal(MacroAssembler* masm) {
Register dictionary = r0;
DCHECK(!dictionary.is(LoadDescriptor::ReceiverRegister()));
@ -963,8 +945,8 @@ void StoreIC::GenerateMegamorphic(MacroAssembler* masm) {
Code::Flags flags = Code::RemoveTypeAndHolderFromFlags(
Code::ComputeHandlerFlags(Code::STORE_IC));
masm->isolate()->stub_cache()->GenerateProbe(masm, flags, receiver, name, r3,
r4, r5, r6);
masm->isolate()->stub_cache()->GenerateProbe(masm, flags, false, receiver,
name, r3, r4, r5, r6);
// Cache miss: Jump to runtime.
GenerateMiss(masm);

View File

@ -16,8 +16,8 @@ namespace internal {
static void ProbeTable(Isolate* isolate, MacroAssembler* masm,
Code::Flags flags, StubCache::Table table,
Register receiver, Register name,
Code::Flags flags, bool leave_frame,
StubCache::Table table, Register receiver, Register name,
// Number of the cache entry, not scaled.
Register offset, Register scratch, Register scratch2,
Register offset_scratch) {
@ -84,6 +84,8 @@ static void ProbeTable(Isolate* isolate, MacroAssembler* masm,
}
#endif
if (leave_frame) __ LeaveFrame(StackFrame::INTERNAL);
// Jump to the first instruction in the code stub.
__ add(pc, code, Operand(Code::kHeaderSize - kHeapObjectTag));
@ -93,9 +95,9 @@ static void ProbeTable(Isolate* isolate, MacroAssembler* masm,
void StubCache::GenerateProbe(MacroAssembler* masm, Code::Flags flags,
Register receiver, Register name,
Register scratch, Register extra, Register extra2,
Register extra3) {
bool leave_frame, Register receiver,
Register name, Register scratch, Register extra,
Register extra2, Register extra3) {
Isolate* isolate = masm->isolate();
Label miss;
@ -145,8 +147,8 @@ void StubCache::GenerateProbe(MacroAssembler* masm, Code::Flags flags,
__ and_(scratch, scratch, Operand(mask));
// Probe the primary table.
ProbeTable(isolate, masm, flags, kPrimary, receiver, name, scratch, extra,
extra2, extra3);
ProbeTable(isolate, masm, flags, leave_frame, kPrimary, receiver, name,
scratch, extra, extra2, extra3);
// Primary miss: Compute hash for secondary probe.
__ sub(scratch, scratch, Operand(name, LSR, kCacheIndexShift));
@ -155,8 +157,8 @@ void StubCache::GenerateProbe(MacroAssembler* masm, Code::Flags flags,
__ and_(scratch, scratch, Operand(mask2));
// Probe the secondary table.
ProbeTable(isolate, masm, flags, kSecondary, receiver, name, scratch, extra,
extra2, extra3);
ProbeTable(isolate, masm, flags, leave_frame, kSecondary, receiver, name,
scratch, extra, extra2, extra3);
// Cache miss: Fall-through and let caller handle the miss by
// entering the runtime system.

View File

@ -331,24 +331,6 @@ static MemOperand GenerateUnmappedArgumentsLookup(MacroAssembler* masm,
}
void LoadIC::GenerateMegamorphic(MacroAssembler* masm) {
// The return address is in lr.
Register receiver = LoadDescriptor::ReceiverRegister();
Register name = LoadDescriptor::NameRegister();
DCHECK(receiver.is(x1));
DCHECK(name.is(x2));
// Probe the stub cache.
Code::Flags flags = Code::RemoveTypeAndHolderFromFlags(
Code::ComputeHandlerFlags(Code::LOAD_IC));
masm->isolate()->stub_cache()->GenerateProbe(masm, flags, receiver, name, x3,
x4, x5, x6);
// Cache miss: Jump to runtime.
GenerateMiss(masm);
}
void LoadIC::GenerateNormal(MacroAssembler* masm) {
Register dictionary = x0;
DCHECK(!dictionary.is(LoadDescriptor::ReceiverRegister()));
@ -994,8 +976,8 @@ void StoreIC::GenerateMegamorphic(MacroAssembler* masm) {
// Probe the stub cache.
Code::Flags flags = Code::RemoveTypeAndHolderFromFlags(
Code::ComputeHandlerFlags(Code::STORE_IC));
masm->isolate()->stub_cache()->GenerateProbe(masm, flags, receiver, name, x3,
x4, x5, x6);
masm->isolate()->stub_cache()->GenerateProbe(masm, flags, false, receiver,
name, x3, x4, x5, x6);
// Cache miss: Jump to runtime.
GenerateMiss(masm);

View File

@ -23,9 +23,10 @@ namespace internal {
//
// 'receiver', 'name' and 'offset' registers are preserved on miss.
static void ProbeTable(Isolate* isolate, MacroAssembler* masm,
Code::Flags flags, StubCache::Table table,
Register receiver, Register name, Register offset,
Register scratch, Register scratch2, Register scratch3) {
Code::Flags flags, bool leave_frame,
StubCache::Table table, Register receiver, Register name,
Register offset, Register scratch, Register scratch2,
Register scratch3) {
// Some code below relies on the fact that the Entry struct contains
// 3 pointers (name, code, map).
STATIC_ASSERT(sizeof(StubCache::Entry) == (3 * kPointerSize));
@ -78,6 +79,8 @@ static void ProbeTable(Isolate* isolate, MacroAssembler* masm,
}
#endif
if (leave_frame) __ LeaveFrame(StackFrame::INTERNAL);
// Jump to the first instruction in the code stub.
__ Add(scratch, scratch, Code::kHeaderSize - kHeapObjectTag);
__ Br(scratch);
@ -88,9 +91,9 @@ static void ProbeTable(Isolate* isolate, MacroAssembler* masm,
void StubCache::GenerateProbe(MacroAssembler* masm, Code::Flags flags,
Register receiver, Register name,
Register scratch, Register extra, Register extra2,
Register extra3) {
bool leave_frame, Register receiver,
Register name, Register scratch, Register extra,
Register extra2, Register extra3) {
Isolate* isolate = masm->isolate();
Label miss;
@ -122,8 +125,8 @@ void StubCache::GenerateProbe(MacroAssembler* masm, Code::Flags flags,
CountTrailingZeros(kPrimaryTableSize, 64));
// Probe the primary table.
ProbeTable(isolate, masm, flags, kPrimary, receiver, name, scratch, extra,
extra2, extra3);
ProbeTable(isolate, masm, flags, leave_frame, kPrimary, receiver, name,
scratch, extra, extra2, extra3);
// Primary miss: Compute hash for secondary table.
__ Sub(scratch, scratch, Operand(name, LSR, kCacheIndexShift));
@ -131,8 +134,8 @@ void StubCache::GenerateProbe(MacroAssembler* masm, Code::Flags flags,
__ And(scratch, scratch, kSecondaryTableSize - 1);
// Probe the secondary table.
ProbeTable(isolate, masm, flags, kSecondary, receiver, name, scratch, extra,
extra2, extra3);
ProbeTable(isolate, masm, flags, leave_frame, kSecondary, receiver, name,
scratch, extra, extra2, extra3);
// Cache miss: Fall-through and let caller handle the miss by
// entering the runtime system.

View File

@ -824,24 +824,6 @@ void KeyedStoreIC::GenerateGeneric(MacroAssembler* masm,
}
void LoadIC::GenerateMegamorphic(MacroAssembler* masm) {
// The return address is on the stack.
Register receiver = LoadDescriptor::ReceiverRegister();
Register name = LoadDescriptor::NameRegister();
DCHECK(receiver.is(edx));
DCHECK(name.is(ecx));
// Probe the stub cache.
Code::Flags flags = Code::RemoveTypeAndHolderFromFlags(
Code::ComputeHandlerFlags(Code::LOAD_IC));
masm->isolate()->stub_cache()->GenerateProbe(masm, flags, receiver, name, ebx,
eax);
// Cache miss: Jump to runtime.
GenerateMiss(masm);
}
void LoadIC::GenerateNormal(MacroAssembler* masm) {
Register dictionary = eax;
DCHECK(!dictionary.is(LoadDescriptor::ReceiverRegister()));
@ -922,7 +904,7 @@ void StoreIC::GenerateMegamorphic(MacroAssembler* masm) {
Code::Flags flags = Code::RemoveTypeAndHolderFromFlags(
Code::ComputeHandlerFlags(Code::STORE_IC));
masm->isolate()->stub_cache()->GenerateProbe(
masm, flags, StoreDescriptor::ReceiverRegister(),
masm, flags, false, StoreDescriptor::ReceiverRegister(),
StoreDescriptor::NameRegister(), ebx, no_reg);
// Cache miss: Jump to runtime.

View File

@ -16,8 +16,8 @@ namespace internal {
static void ProbeTable(Isolate* isolate, MacroAssembler* masm,
Code::Flags flags, StubCache::Table table, Register name,
Register receiver,
Code::Flags flags, bool leave_frame,
StubCache::Table table, Register name, Register receiver,
// Number of the cache entry pointer-size scaled.
Register offset, Register extra) {
ExternalReference key_offset(isolate->stub_cache()->key_reference(table));
@ -56,6 +56,8 @@ static void ProbeTable(Isolate* isolate, MacroAssembler* masm,
}
#endif
if (leave_frame) __ leave();
// Jump to the first instruction in the code stub.
__ add(extra, Immediate(Code::kHeaderSize - kHeapObjectTag));
__ jmp(extra);
@ -98,6 +100,8 @@ static void ProbeTable(Isolate* isolate, MacroAssembler* masm,
__ pop(offset);
__ mov(offset, Operand::StaticArray(offset, times_1, value_offset));
if (leave_frame) __ leave();
// Jump to the first instruction in the code stub.
__ add(offset, Immediate(Code::kHeaderSize - kHeapObjectTag));
__ jmp(offset);
@ -110,9 +114,9 @@ static void ProbeTable(Isolate* isolate, MacroAssembler* masm,
void StubCache::GenerateProbe(MacroAssembler* masm, Code::Flags flags,
Register receiver, Register name,
Register scratch, Register extra, Register extra2,
Register extra3) {
bool leave_frame, Register receiver,
Register name, Register scratch, Register extra,
Register extra2, Register extra3) {
Label miss;
// Assert that code is valid. The multiplying code relies on the entry size
@ -155,7 +159,8 @@ void StubCache::GenerateProbe(MacroAssembler* masm, Code::Flags flags,
DCHECK(kCacheIndexShift == kPointerSizeLog2);
// Probe the primary table.
ProbeTable(isolate(), masm, flags, kPrimary, name, receiver, offset, extra);
ProbeTable(isolate(), masm, flags, leave_frame, kPrimary, name, receiver,
offset, extra);
// Primary miss: Compute hash for secondary probe.
__ mov(offset, FieldOperand(name, Name::kHashFieldOffset));
@ -167,7 +172,8 @@ void StubCache::GenerateProbe(MacroAssembler* masm, Code::Flags flags,
__ and_(offset, (kSecondaryTableSize - 1) << kCacheIndexShift);
// Probe the secondary table.
ProbeTable(isolate(), masm, flags, kSecondary, name, receiver, offset, extra);
ProbeTable(isolate(), masm, flags, leave_frame, kSecondary, name, receiver,
offset, extra);
// Cache miss: Fall-through and let caller handle the miss by
// entering the runtime system.

View File

@ -178,8 +178,6 @@ Handle<Code> PropertyICCompiler::ComputeLoad(Isolate* isolate,
code = compiler.CompileLoadInitialize(flags);
} else if (ic_state == PREMONOMORPHIC) {
code = compiler.CompileLoadPreMonomorphic(flags);
} else if (ic_state == MEGAMORPHIC) {
code = compiler.CompileLoadMegamorphic(flags);
} else {
UNREACHABLE();
}
@ -320,14 +318,6 @@ Handle<Code> PropertyICCompiler::CompileLoadPreMonomorphic(Code::Flags flags) {
}
Handle<Code> PropertyICCompiler::CompileLoadMegamorphic(Code::Flags flags) {
LoadIC::GenerateMegamorphic(masm());
Handle<Code> code = GetCodeWithFlags(flags, "CompileLoadMegamorphic");
PROFILE(isolate(), CodeCreateEvent(Logger::LOAD_MEGAMORPHIC_TAG, *code, 0));
return code;
}
Handle<Code> PropertyICCompiler::CompileStoreInitialize(Code::Flags flags) {
StoreIC::GenerateInitialize(masm());
Handle<Code> code = GetCodeWithFlags(flags, "CompileStoreInitialize");

View File

@ -72,7 +72,6 @@ class PropertyICCompiler : public PropertyAccessCompiler {
Handle<Code> CompileLoadInitialize(Code::Flags flags);
Handle<Code> CompileLoadPreMonomorphic(Code::Flags flags);
Handle<Code> CompileLoadMegamorphic(Code::Flags flags);
Handle<Code> CompileStoreInitialize(Code::Flags flags);
Handle<Code> CompileStorePreMonomorphic(Code::Flags flags);
Handle<Code> CompileStoreGeneric(Code::Flags flags);

View File

@ -815,8 +815,8 @@ Handle<Code> LoadIC::initialize_stub(Isolate* isolate,
Handle<Code> LoadIC::megamorphic_stub() {
if (kind() == Code::LOAD_IC) {
return PropertyICCompiler::ComputeLoad(isolate(), MEGAMORPHIC,
extra_ic_state());
MegamorphicLoadStub stub(isolate(), State(extra_ic_state()));
return stub.GetCode();
} else {
DCHECK_EQ(Code::KEYED_LOAD_IC, kind());
return KeyedLoadIC::generic_stub(isolate());

View File

@ -405,7 +405,6 @@ class LoadIC : public IC {
GenerateMiss(masm);
}
static void GenerateMiss(MacroAssembler* masm);
static void GenerateMegamorphic(MacroAssembler* masm);
static void GenerateNormal(MacroAssembler* masm);
static void GenerateRuntimeGetProperty(MacroAssembler* masm);

View File

@ -51,9 +51,11 @@ class StubCache {
// Generate code for probing the stub cache table.
// Arguments extra, extra2 and extra3 may be used to pass additional scratch
// registers. Set to no_reg if not needed.
void GenerateProbe(MacroAssembler* masm, Code::Flags flags, Register receiver,
Register name, Register scratch, Register extra,
Register extra2 = no_reg, Register extra3 = no_reg);
// If leave_frame is true, then exit a frame before the tail call.
void GenerateProbe(MacroAssembler* masm, Code::Flags flags, bool leave_frame,
Register receiver, Register name, Register scratch,
Register extra, Register extra2 = no_reg,
Register extra3 = no_reg);
enum Table { kPrimary, kSecondary };
@ -153,6 +155,7 @@ class StubCache {
static const int kSecondaryTableBits = 9;
static const int kSecondaryTableSize = (1 << kSecondaryTableBits);
private:
Entry primary_[kPrimaryTableSize];
Entry secondary_[kSecondaryTableSize];
Isolate* isolate_;

View File

@ -823,23 +823,6 @@ void KeyedStoreIC::GenerateSloppyArguments(MacroAssembler* masm) {
}
void LoadIC::GenerateMegamorphic(MacroAssembler* masm) {
// The return address is on the stack.
Register receiver = LoadDescriptor::ReceiverRegister();
Register name = LoadDescriptor::NameRegister();
DCHECK(receiver.is(rdx));
DCHECK(name.is(rcx));
// Probe the stub cache.
Code::Flags flags = Code::RemoveTypeAndHolderFromFlags(
Code::ComputeHandlerFlags(Code::LOAD_IC));
masm->isolate()->stub_cache()->GenerateProbe(masm, flags, receiver, name, rbx,
rax);
GenerateMiss(masm);
}
void LoadIC::GenerateNormal(MacroAssembler* masm) {
Register dictionary = rax;
DCHECK(!dictionary.is(LoadDescriptor::ReceiverRegister()));
@ -934,7 +917,7 @@ void StoreIC::GenerateMegamorphic(MacroAssembler* masm) {
Code::Flags flags = Code::RemoveTypeAndHolderFromFlags(
Code::ComputeHandlerFlags(Code::STORE_IC));
masm->isolate()->stub_cache()->GenerateProbe(
masm, flags, StoreDescriptor::ReceiverRegister(),
masm, flags, false, StoreDescriptor::ReceiverRegister(),
StoreDescriptor::NameRegister(), rbx, no_reg);
// Cache miss: Jump to runtime.

View File

@ -16,8 +16,8 @@ namespace internal {
static void ProbeTable(Isolate* isolate, MacroAssembler* masm,
Code::Flags flags, StubCache::Table table,
Register receiver, Register name,
Code::Flags flags, bool leave_frame,
StubCache::Table table, Register receiver, Register name,
// The offset is scaled by 4, based on
// kCacheIndexShift, which is two bits
Register offset) {
@ -72,6 +72,8 @@ static void ProbeTable(Isolate* isolate, MacroAssembler* masm,
}
#endif
if (leave_frame) __ leave();
// Jump to the first instruction in the code stub.
__ addp(kScratchRegister, Immediate(Code::kHeaderSize - kHeapObjectTag));
__ jmp(kScratchRegister);
@ -81,9 +83,9 @@ static void ProbeTable(Isolate* isolate, MacroAssembler* masm,
void StubCache::GenerateProbe(MacroAssembler* masm, Code::Flags flags,
Register receiver, Register name,
Register scratch, Register extra, Register extra2,
Register extra3) {
bool leave_frame, Register receiver,
Register name, Register scratch, Register extra,
Register extra2, Register extra3) {
Isolate* isolate = masm->isolate();
Label miss;
USE(extra); // The register extra is not used on the X64 platform.
@ -121,7 +123,8 @@ void StubCache::GenerateProbe(MacroAssembler* masm, Code::Flags flags,
__ andp(scratch, Immediate((kPrimaryTableSize - 1) << kCacheIndexShift));
// Probe the primary table.
ProbeTable(isolate, masm, flags, kPrimary, receiver, name, scratch);
ProbeTable(isolate, masm, flags, leave_frame, kPrimary, receiver, name,
scratch);
// Primary miss: Compute hash for secondary probe.
__ movl(scratch, FieldOperand(name, Name::kHashFieldOffset));
@ -133,7 +136,8 @@ void StubCache::GenerateProbe(MacroAssembler* masm, Code::Flags flags,
__ andp(scratch, Immediate((kSecondaryTableSize - 1) << kCacheIndexShift));
// Probe the secondary table.
ProbeTable(isolate, masm, flags, kSecondary, receiver, name, scratch);
ProbeTable(isolate, masm, flags, leave_frame, kSecondary, receiver, name,
scratch);
// Cache miss: Fall-through and let caller handle the miss by
// entering the runtime system.

View File

@ -9,6 +9,7 @@
#include "src/base/bits.h"
#include "src/code-stubs.h"
#include "src/hydrogen-osr.h"
#include "src/ic/stub-cache.h"
#include "src/x64/lithium-codegen-x64.h"
namespace v8 {
@ -3227,11 +3228,9 @@ void LCodeGen::DoLoadKeyedFixedArray(LLoadKeyed* instr) {
}
__ Load(result,
BuildFastArrayOperand(instr->elements(),
key,
BuildFastArrayOperand(instr->elements(), key,
instr->hydrogen()->key()->representation(),
FAST_ELEMENTS,
offset),
FAST_ELEMENTS, offset),
representation);
// Check for the hole value.
@ -3531,6 +3530,30 @@ void LCodeGen::CallKnownFunction(Handle<JSFunction> function,
}
void LCodeGen::DoTailCallThroughMegamorphicCache(
LTailCallThroughMegamorphicCache* instr) {
Register receiver = ToRegister(instr->receiver());
Register name = ToRegister(instr->name());
DCHECK(receiver.is(LoadDescriptor::ReceiverRegister()));
DCHECK(name.is(LoadDescriptor::NameRegister()));
Register scratch = rbx;
DCHECK(!scratch.is(receiver) && !scratch.is(name));
// Important for the tail-call.
bool must_teardown_frame = NeedsEagerFrame();
// The probe will tail call to a handler if found.
isolate()->stub_cache()->GenerateProbe(masm(), instr->hydrogen()->flags(),
must_teardown_frame, receiver, name,
scratch, no_reg);
// Tail call to miss if we ended up here.
if (must_teardown_frame) __ leave();
LoadIC::GenerateMiss(masm());
}
void LCodeGen::DoCallWithDescriptor(LCallWithDescriptor* instr) {
DCHECK(ToRegister(instr->result()).is(rax));

View File

@ -1119,6 +1119,19 @@ LInstruction* LChunkBuilder::DoCallWithDescriptor(
}
LInstruction* LChunkBuilder::DoTailCallThroughMegamorphicCache(
HTailCallThroughMegamorphicCache* instr) {
LOperand* context = UseFixed(instr->context(), rsi);
LOperand* receiver_register =
UseFixed(instr->receiver(), LoadDescriptor::ReceiverRegister());
LOperand* name_register =
UseFixed(instr->name(), LoadDescriptor::NameRegister());
// Not marked as call. It can't deoptimize, and it never returns.
return new (zone()) LTailCallThroughMegamorphicCache(
context, receiver_register, name_register);
}
LInstruction* LChunkBuilder::DoInvokeFunction(HInvokeFunction* instr) {
LOperand* context = UseFixed(instr->context(), rsi);
LOperand* function = UseFixed(instr->function(), rdi);

View File

@ -151,6 +151,7 @@ class LCodeGen;
V(StringCompareAndBranch) \
V(SubI) \
V(TaggedToI) \
V(TailCallThroughMegamorphicCache) \
V(ThisFunction) \
V(ToFastProperties) \
V(TransitionElementsKind) \
@ -489,6 +490,27 @@ class LCallStub FINAL : public LTemplateInstruction<1, 1, 0> {
};
class LTailCallThroughMegamorphicCache FINAL
: public LTemplateInstruction<0, 3, 0> {
public:
explicit LTailCallThroughMegamorphicCache(LOperand* context,
LOperand* receiver,
LOperand* name) {
inputs_[0] = context;
inputs_[1] = receiver;
inputs_[2] = name;
}
LOperand* context() { return inputs_[0]; }
LOperand* receiver() { return inputs_[1]; }
LOperand* name() { return inputs_[2]; }
DECLARE_CONCRETE_INSTRUCTION(TailCallThroughMegamorphicCache,
"tail-call-through-megamorphic-cache")
DECLARE_HYDROGEN_ACCESSOR(TailCallThroughMegamorphicCache)
};
class LUnknownOSRValue FINAL : public LTemplateInstruction<1, 0, 0> {
public:
virtual bool HasInterestingComment(LCodeGen* gen) const OVERRIDE {
@ -1886,9 +1908,10 @@ class LCallWithDescriptor FINAL : public LTemplateResultInstruction<1> {
LOperand* target() const { return inputs_[0]; }
DECLARE_HYDROGEN_ACCESSOR(CallWithDescriptor)
private:
DECLARE_CONCRETE_INSTRUCTION(CallWithDescriptor, "call-with-descriptor")
DECLARE_HYDROGEN_ACCESSOR(CallWithDescriptor)
virtual void PrintDataTo(StringStream* stream) OVERRIDE;