This is a preview of a first step towards unification of the hydrogen

call machinery.  The change replaces CallNamed, CallKeyed,
CallConstantFunction and CallKnownGlobal hydrogen instructions with two
new instructions with a more lower level semantics:

1. CallJSFunction for direct calls of JSFunction objects (no
   argument adaptation)

2. CallWithDescriptor for calls of a given Code object according to
   the supplied calling convention.

Details:

CallJSFunction should be straightforward, the main difference from the
existing InvokeFunction instruction is the absence of argument adaptor
handling. (As a next step, we will replace InvokeFunction with an
equivalent hydrogen code.)

For CallWithDescriptor, the calling conventions are represented by a
tweaked version of CallStubInterfaceDescriptor. In addition to the
parameter-register mapping, we also define parameter-representation
mapping there. The CallWithDescriptor instruction has variable number of
parameters now - this required some simple tweaks in Lithium, which
assumed fixed number of arguments in some places.

The calling conventions used in the calls are initialized in the
CallDescriptors class (code-stubs.h, <arch>/code-stubs-<arch>.cc), and
they live in a new table in the Isolate class. I should say I am not
quite sure about Representation::Integer32() representation for some of
the params of ArgumentAdaptorCall - it is not clear to me wether the
params could not end up on the stack and thus confuse the GC.

The change also includes an earlier small change to argument adaptor
(https://codereview.chromium.org/98463007) that avoids passing a naked
pointer to the code entry as a parameter. I am sorry for packaging that
with an already biggish change.

Performance implications:

Locally, I see a small regression (.2% or so). It is hard to say where
exactly it comes from, but I do see inefficient call sequences to the
adaptor trampoline. For example:

;;; <@78,#24> constant-t
bf85aa515a     mov edi,0x5a51aa85          ;; debug: position 29
;;; <@72,#53> load-named-field
8b7717         mov esi,[edi+0x17]          ;; debug: position 195
;;; <@80,#51> constant-s
b902000000     mov ecx,0x2                 ;; debug: position 195
;;; <@81,#51> gap
894df0         mov [ebp+0xf0],ecx
;;; <@82,#103> constant-i
bb01000000     mov ebx,0x1
;;; <@84,#102> constant-i
b902000000     mov ecx,0x2
;;; <@85,#102> gap
89d8           mov eax,ebx
89cb           mov ebx,ecx
8b4df0         mov ecx,[ebp+0xf0]
;;; <@86,#58> call-with-descriptor
e8ef57fcff     call ArgumentsAdaptorTrampoline  (0x2d80e6e0)    ;; code: BUILTIN

Note the silly handling of ecx; the hydrogen for this code is:

0 4 s27 Constant 1  range:1_1 <|@
0 3 t30 Constant 0x5bc1aa85 <JS Function xyz (SharedFunctionInfo 0x5bc1a919)> type:object <|@
0 1 t36 LoadNamedField t30.[in-object]@24 <|@
0 1 t38 Constant 0x2300e6a1 <Code> <|@
0 1 i102 Constant 2  range:2_2 <|@
0 1 i103 Constant 1  range:1_1 <|@
0 2 t41 CallWithDescriptor t38 t30 t36 s27 i103 i102 #2 changes[*] <|@

BUG=
R=verwaest@chromium.org, danno@chromium.org

Review URL: https://codereview.chromium.org/104663004

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@18626 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
jarin@chromium.org 2014-01-15 17:00:35 +00:00
parent c45304752e
commit 19d832719e
29 changed files with 1033 additions and 786 deletions

View File

@ -605,9 +605,7 @@ static void Generate_JSConstructStubHelper(MacroAssembler* masm,
__ ldr(cp, FieldMemOperand(r1, JSFunction::kContextOffset));
Handle<Code> code =
masm->isolate()->builtins()->HandleApiCallConstruct();
ParameterCount expected(0);
__ InvokeCode(code, expected, expected,
RelocInfo::CODE_TARGET, CALL_FUNCTION);
__ Call(code, RelocInfo::CODE_TARGET);
} else {
ParameterCount actual(r0);
__ InvokeFunction(r1, actual, CALL_FUNCTION, NullCallWrapper());
@ -1150,12 +1148,12 @@ void Builtins::Generate_FunctionCall(MacroAssembler* masm) {
__ push(r1); // re-add proxy object as additional argument
__ add(r0, r0, Operand(1));
__ GetBuiltinEntry(r3, Builtins::CALL_FUNCTION_PROXY);
__ GetBuiltinFunction(r1, Builtins::CALL_FUNCTION_PROXY);
__ Jump(masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(),
RelocInfo::CODE_TARGET);
__ bind(&non_proxy);
__ GetBuiltinEntry(r3, Builtins::CALL_NON_FUNCTION);
__ GetBuiltinFunction(r1, Builtins::CALL_NON_FUNCTION);
__ Jump(masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(),
RelocInfo::CODE_TARGET);
__ bind(&function);
@ -1170,12 +1168,12 @@ void Builtins::Generate_FunctionCall(MacroAssembler* masm) {
__ ldr(r2,
FieldMemOperand(r3, SharedFunctionInfo::kFormalParameterCountOffset));
__ SmiUntag(r2);
__ ldr(r3, FieldMemOperand(r1, JSFunction::kCodeEntryOffset));
__ cmp(r2, r0); // Check formal and actual parameter counts.
__ Jump(masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(),
RelocInfo::CODE_TARGET,
ne);
__ ldr(r3, FieldMemOperand(r1, JSFunction::kCodeEntryOffset));
ParameterCount expected(0);
__ InvokeCode(r3, expected, expected, JUMP_FUNCTION, NullCallWrapper());
}
@ -1326,7 +1324,7 @@ void Builtins::Generate_FunctionApply(MacroAssembler* masm) {
__ push(r1); // add function proxy as last argument
__ add(r0, r0, Operand(1));
__ mov(r2, Operand::Zero());
__ GetBuiltinEntry(r3, Builtins::CALL_FUNCTION_PROXY);
__ GetBuiltinFunction(r1, Builtins::CALL_FUNCTION_PROXY);
__ Call(masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(),
RelocInfo::CODE_TARGET);
@ -1368,12 +1366,12 @@ void Builtins::Generate_ArgumentsAdaptorTrampoline(MacroAssembler* masm) {
// -- r0 : actual number of arguments
// -- r1 : function (passed through to callee)
// -- r2 : expected number of arguments
// -- r3 : code entry to call
// -----------------------------------
Label invoke, dont_adapt_arguments;
Label enough, too_few;
__ ldr(r3, FieldMemOperand(r1, JSFunction::kCodeEntryOffset));
__ cmp(r0, r2);
__ b(lt, &too_few);
__ cmp(r2, Operand(SharedFunctionInfo::kDontAdaptArgumentsSentinel));

View File

@ -361,6 +361,65 @@ void NewStringAddStub::InitializeInterfaceDescriptor(
}
void CallDescriptors::InitializeForIsolate(Isolate* isolate) {
static PlatformCallInterfaceDescriptor default_descriptor =
PlatformCallInterfaceDescriptor(CAN_INLINE_TARGET_ADDRESS);
static PlatformCallInterfaceDescriptor noInlineDescriptor =
PlatformCallInterfaceDescriptor(NEVER_INLINE_TARGET_ADDRESS);
{
CallInterfaceDescriptor* descriptor =
isolate->call_descriptor(Isolate::ArgumentAdaptorCall);
static Register registers[] = { r1, // JSFunction
cp, // context
r0, // actual number of arguments
r2, // expected number of arguments
};
static Representation representations[] = {
Representation::Tagged(), // JSFunction
Representation::Tagged(), // context
Representation::Integer32(), // actual number of arguments
Representation::Integer32(), // expected number of arguments
};
descriptor->register_param_count_ = 4;
descriptor->register_params_ = registers;
descriptor->param_representations_ = representations;
descriptor->platform_specific_descriptor_ = &default_descriptor;
}
{
CallInterfaceDescriptor* descriptor =
isolate->call_descriptor(Isolate::KeyedCall);
static Register registers[] = { cp, // context
r2, // key
};
static Representation representations[] = {
Representation::Tagged(), // context
Representation::Tagged(), // key
};
descriptor->register_param_count_ = 2;
descriptor->register_params_ = registers;
descriptor->param_representations_ = representations;
descriptor->platform_specific_descriptor_ = &noInlineDescriptor;
}
{
CallInterfaceDescriptor* descriptor =
isolate->call_descriptor(Isolate::NamedCall);
static Register registers[] = { cp, // context
r2, // name
};
static Representation representations[] = {
Representation::Tagged(), // context
Representation::Tagged(), // name
};
descriptor->register_param_count_ = 2;
descriptor->register_params_ = registers;
descriptor->param_representations_ = representations;
descriptor->platform_specific_descriptor_ = &noInlineDescriptor;
}
}
#define __ ACCESS_MASM(masm)
@ -3217,7 +3276,7 @@ void CallFunctionStub::Generate(MacroAssembler* masm) {
__ push(r1); // put proxy as additional argument
__ mov(r0, Operand(argc_ + 1, RelocInfo::NONE32));
__ mov(r2, Operand::Zero());
__ GetBuiltinEntry(r3, Builtins::CALL_FUNCTION_PROXY);
__ GetBuiltinFunction(r1, Builtins::CALL_FUNCTION_PROXY);
{
Handle<Code> adaptor =
masm->isolate()->builtins()->ArgumentsAdaptorTrampoline();
@ -3230,7 +3289,7 @@ void CallFunctionStub::Generate(MacroAssembler* masm) {
__ str(r1, MemOperand(sp, argc_ * kPointerSize));
__ mov(r0, Operand(argc_)); // Set up the number of arguments.
__ mov(r2, Operand::Zero());
__ GetBuiltinEntry(r3, Builtins::CALL_NON_FUNCTION);
__ GetBuiltinFunction(r1, Builtins::CALL_NON_FUNCTION);
__ Jump(masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(),
RelocInfo::CODE_TARGET);
}
@ -3266,11 +3325,11 @@ void CallConstructStub::Generate(MacroAssembler* masm) {
__ bind(&slow);
__ cmp(r3, Operand(JS_FUNCTION_PROXY_TYPE));
__ b(ne, &non_function_call);
__ GetBuiltinEntry(r3, Builtins::CALL_FUNCTION_PROXY_AS_CONSTRUCTOR);
__ GetBuiltinFunction(r1, Builtins::CALL_FUNCTION_PROXY_AS_CONSTRUCTOR);
__ jmp(&do_call);
__ bind(&non_function_call);
__ GetBuiltinEntry(r3, Builtins::CALL_NON_FUNCTION_AS_CONSTRUCTOR);
__ GetBuiltinFunction(r1, Builtins::CALL_NON_FUNCTION_AS_CONSTRUCTOR);
__ bind(&do_call);
// Set expected number of arguments to zero (not changing r0).
__ mov(r2, Operand::Zero());

View File

@ -480,6 +480,18 @@ class NameDictionaryLookupStub: public PlatformCodeStub {
};
struct PlatformCallInterfaceDescriptor {
explicit PlatformCallInterfaceDescriptor(
TargetAddressStorageMode storage_mode)
: storage_mode_(storage_mode) { }
TargetAddressStorageMode storage_mode() { return storage_mode_; }
private:
TargetAddressStorageMode storage_mode_;
};
} } // namespace v8::internal
#endif // V8_ARM_CODE_STUBS_ARM_H_

View File

@ -277,7 +277,18 @@ void LInnerAllocatedObject::PrintDataTo(StringStream* stream) {
}
void LCallConstantFunction::PrintDataTo(StringStream* stream) {
void LCallJSFunction::PrintDataTo(StringStream* stream) {
stream->Add("= ");
function()->PrintTo(stream);
stream->Add("#%d / ", arity());
}
void LCallWithDescriptor::PrintDataTo(StringStream* stream) {
for (int i = 0; i < InputCount(); i++) {
InputAt(i)->PrintTo(stream);
stream->Add(" ");
}
stream->Add("#%d / ", arity());
}
@ -302,22 +313,6 @@ void LInvokeFunction::PrintDataTo(StringStream* stream) {
}
void LCallKeyed::PrintDataTo(StringStream* stream) {
stream->Add("[r2] #%d / ", arity());
}
void LCallNamed::PrintDataTo(StringStream* stream) {
SmartArrayPointer<char> name_string = name()->ToCString();
stream->Add("%s #%d / ", name_string.get(), arity());
}
void LCallKnownGlobal::PrintDataTo(StringStream* stream) {
stream->Add("#%d / ", arity());
}
void LCallNew::PrintDataTo(StringStream* stream) {
stream->Add("= ");
constructor()->PrintTo(stream);
@ -557,8 +552,7 @@ LOperand* LChunkBuilder::Use(HValue* value, LUnallocated* operand) {
}
template<int I, int T>
LInstruction* LChunkBuilder::Define(LTemplateInstruction<1, I, T>* instr,
LInstruction* LChunkBuilder::Define(LTemplateResultInstruction<1>* instr,
LUnallocated* result) {
result->set_virtual_register(current_instruction_->id());
instr->set_result(result);
@ -566,40 +560,35 @@ LInstruction* LChunkBuilder::Define(LTemplateInstruction<1, I, T>* instr,
}
template<int I, int T>
LInstruction* LChunkBuilder::DefineAsRegister(
LTemplateInstruction<1, I, T>* instr) {
LTemplateResultInstruction<1>* instr) {
return Define(instr,
new(zone()) LUnallocated(LUnallocated::MUST_HAVE_REGISTER));
}
template<int I, int T>
LInstruction* LChunkBuilder::DefineAsSpilled(
LTemplateInstruction<1, I, T>* instr, int index) {
LTemplateResultInstruction<1>* instr, int index) {
return Define(instr,
new(zone()) LUnallocated(LUnallocated::FIXED_SLOT, index));
}
template<int I, int T>
LInstruction* LChunkBuilder::DefineSameAsFirst(
LTemplateInstruction<1, I, T>* instr) {
LTemplateResultInstruction<1>* instr) {
return Define(instr,
new(zone()) LUnallocated(LUnallocated::SAME_AS_FIRST_INPUT));
}
template<int I, int T>
LInstruction* LChunkBuilder::DefineFixed(
LTemplateInstruction<1, I, T>* instr, Register reg) {
LTemplateResultInstruction<1>* instr, Register reg) {
return Define(instr, ToUnallocated(reg));
}
template<int I, int T>
LInstruction* LChunkBuilder::DefineFixedDouble(
LTemplateInstruction<1, I, T>* instr, DoubleRegister reg) {
LTemplateResultInstruction<1>* instr, DoubleRegister reg) {
return Define(instr, ToUnallocated(reg));
}
@ -1077,9 +1066,32 @@ LInstruction* LChunkBuilder::DoGlobalReceiver(HGlobalReceiver* instr) {
}
LInstruction* LChunkBuilder::DoCallConstantFunction(
HCallConstantFunction* instr) {
return MarkAsCall(DefineFixed(new(zone()) LCallConstantFunction, r0), instr);
LInstruction* LChunkBuilder::DoCallJSFunction(
HCallJSFunction* instr) {
LOperand* function = UseFixed(instr->function(), r1);
LCallJSFunction* result = new(zone()) LCallJSFunction(function);
return MarkAsCall(DefineFixed(result, r0), instr);
}
LInstruction* LChunkBuilder::DoCallWithDescriptor(
HCallWithDescriptor* instr) {
const CallInterfaceDescriptor* descriptor = instr->descriptor();
LOperand* target = UseRegisterOrConstantAtStart(instr->target());
ZoneList<LOperand*> ops(instr->OperandCount(), zone());
ops.Add(target, zone());
for (int i = 1; i < instr->OperandCount(); i++) {
LOperand* op = UseFixed(instr->OperandAt(i),
descriptor->GetParameterRegister(i - 1));
ops.Add(op, zone());
}
LCallWithDescriptor* result = new(zone()) LCallWithDescriptor(
descriptor, ops, zone());
return MarkAsCall(DefineFixed(result, r0), instr);
}
@ -1167,26 +1179,6 @@ LInstruction* LChunkBuilder::DoMathPowHalf(HUnaryMathOperation* instr) {
}
LInstruction* LChunkBuilder::DoCallKeyed(HCallKeyed* instr) {
ASSERT(instr->key()->representation().IsTagged());
LOperand* context = UseFixed(instr->context(), cp);
LOperand* key = UseFixed(instr->key(), r2);
return MarkAsCall(
DefineFixed(new(zone()) LCallKeyed(context, key), r0), instr);
}
LInstruction* LChunkBuilder::DoCallNamed(HCallNamed* instr) {
LOperand* context = UseFixed(instr->context(), cp);
return MarkAsCall(DefineFixed(new(zone()) LCallNamed(context), r0), instr);
}
LInstruction* LChunkBuilder::DoCallKnownGlobal(HCallKnownGlobal* instr) {
return MarkAsCall(DefineFixed(new(zone()) LCallKnownGlobal, r0), instr);
}
LInstruction* LChunkBuilder::DoCallNew(HCallNew* instr) {
LOperand* context = UseFixed(instr->context(), cp);
LOperand* constructor = UseFixed(instr->constructor(), r1);

View File

@ -52,11 +52,9 @@ class LCodeGen;
V(BitI) \
V(BoundsCheck) \
V(Branch) \
V(CallConstantFunction) \
V(CallJSFunction) \
V(CallWithDescriptor) \
V(CallFunction) \
V(CallKeyed) \
V(CallKnownGlobal) \
V(CallNamed) \
V(CallNew) \
V(CallNewArray) \
V(CallRuntime) \
@ -302,10 +300,8 @@ class LInstruction : public ZoneObject {
// R = number of result operands (0 or 1).
// I = number of input operands.
// T = number of temporary operands.
template<int R, int I, int T>
class LTemplateInstruction : public LInstruction {
template<int R>
class LTemplateResultInstruction : public LInstruction {
public:
// Allow 0 or 1 output operands.
STATIC_ASSERT(R == 0 || R == 1);
@ -317,10 +313,20 @@ class LTemplateInstruction : public LInstruction {
protected:
EmbeddedContainer<LOperand*, R> results_;
};
// R = number of result operands (0 or 1).
// I = number of input operands.
// T = number of temporary operands.
template<int R, int I, int T>
class LTemplateInstruction : public LTemplateResultInstruction<R> {
protected:
EmbeddedContainer<LOperand*, I> inputs_;
EmbeddedContainer<LOperand*, T> temps_;
private:
// Iterator support.
virtual int InputCount() V8_FINAL V8_OVERRIDE { return I; }
virtual LOperand* InputAt(int i) V8_FINAL V8_OVERRIDE { return inputs_[i]; }
@ -1833,18 +1839,63 @@ class LGlobalReceiver V8_FINAL : public LTemplateInstruction<1, 1, 0> {
};
class LCallConstantFunction V8_FINAL : public LTemplateInstruction<1, 0, 0> {
class LCallJSFunction V8_FINAL : public LTemplateInstruction<1, 1, 0> {
public:
DECLARE_CONCRETE_INSTRUCTION(CallConstantFunction, "call-constant-function")
DECLARE_HYDROGEN_ACCESSOR(CallConstantFunction)
explicit LCallJSFunction(LOperand* function) {
inputs_[0] = function;
}
LOperand* function() { return inputs_[0]; }
DECLARE_CONCRETE_INSTRUCTION(CallJSFunction, "call-js-function")
DECLARE_HYDROGEN_ACCESSOR(CallJSFunction)
virtual void PrintDataTo(StringStream* stream) V8_OVERRIDE;
Handle<JSFunction> function() { return hydrogen()->function(); }
int arity() const { return hydrogen()->argument_count() - 1; }
};
class LCallWithDescriptor V8_FINAL : public LTemplateResultInstruction<1> {
public:
LCallWithDescriptor(const CallInterfaceDescriptor* descriptor,
ZoneList<LOperand*>& operands,
Zone* zone)
: descriptor_(descriptor),
inputs_(descriptor->environment_length() + 1, zone) {
ASSERT(descriptor->environment_length() + 1 == operands.length());
inputs_.AddAll(operands, zone);
}
LOperand* target() const { return inputs_[0]; }
const CallInterfaceDescriptor* descriptor() { return descriptor_; }
private:
DECLARE_CONCRETE_INSTRUCTION(CallWithDescriptor, "call-with-descriptor")
DECLARE_HYDROGEN_ACCESSOR(CallWithDescriptor)
virtual void PrintDataTo(StringStream* stream) V8_OVERRIDE;
int arity() const { return hydrogen()->argument_count() - 1; }
const CallInterfaceDescriptor* descriptor_;
ZoneList<LOperand*> inputs_;
virtual void InternalSetOperandAt(int index,
LOperand* value) V8_FINAL V8_OVERRIDE {
inputs_[index] = value;
}
// Iterator support.
virtual int InputCount() V8_FINAL V8_OVERRIDE { return inputs_.length(); }
virtual LOperand* InputAt(int i) V8_FINAL V8_OVERRIDE { return inputs_[i]; }
virtual int TempCount() V8_FINAL V8_OVERRIDE { return 0; }
virtual LOperand* TempAt(int i) V8_FINAL V8_OVERRIDE { return NULL; }
};
class LInvokeFunction V8_FINAL : public LTemplateInstruction<1, 2, 0> {
public:
LInvokeFunction(LOperand* context, LOperand* function) {
@ -1864,44 +1915,6 @@ class LInvokeFunction V8_FINAL : public LTemplateInstruction<1, 2, 0> {
};
class LCallKeyed V8_FINAL : public LTemplateInstruction<1, 2, 0> {
public:
LCallKeyed(LOperand* context, LOperand* key) {
inputs_[0] = context;
inputs_[1] = key;
}
LOperand* context() { return inputs_[0]; }
LOperand* key() { return inputs_[1]; }
DECLARE_CONCRETE_INSTRUCTION(CallKeyed, "call-keyed")
DECLARE_HYDROGEN_ACCESSOR(CallKeyed)
virtual void PrintDataTo(StringStream* stream) V8_OVERRIDE;
int arity() const { return hydrogen()->argument_count() - 1; }
};
class LCallNamed V8_FINAL : public LTemplateInstruction<1, 1, 0> {
public:
explicit LCallNamed(LOperand* context) {
inputs_[0] = context;
}
LOperand* context() { return inputs_[0]; }
DECLARE_CONCRETE_INSTRUCTION(CallNamed, "call-named")
DECLARE_HYDROGEN_ACCESSOR(CallNamed)
virtual void PrintDataTo(StringStream* stream) V8_OVERRIDE;
Handle<String> name() const { return hydrogen()->name(); }
int arity() const { return hydrogen()->argument_count() - 1; }
};
class LCallFunction V8_FINAL : public LTemplateInstruction<1, 2, 0> {
public:
LCallFunction(LOperand* context, LOperand* function) {
@ -1919,17 +1932,6 @@ class LCallFunction V8_FINAL : public LTemplateInstruction<1, 2, 0> {
};
class LCallKnownGlobal V8_FINAL : public LTemplateInstruction<1, 0, 0> {
public:
DECLARE_CONCRETE_INSTRUCTION(CallKnownGlobal, "call-known-global")
DECLARE_HYDROGEN_ACCESSOR(CallKnownGlobal)
virtual void PrintDataTo(StringStream* stream) V8_OVERRIDE;
int arity() const { return hydrogen()->argument_count() - 1; }
};
class LCallNew V8_FINAL : public LTemplateInstruction<1, 2, 0> {
public:
LCallNew(LOperand* context, LOperand* constructor) {
@ -2788,22 +2790,16 @@ class LChunkBuilder V8_FINAL : public LChunkBuilderBase {
// Methods for setting up define-use relationships.
// Return the same instruction that they are passed.
template<int I, int T>
LInstruction* Define(LTemplateInstruction<1, I, T>* instr,
LUnallocated* result);
template<int I, int T>
LInstruction* DefineAsRegister(LTemplateInstruction<1, I, T>* instr);
template<int I, int T>
LInstruction* DefineAsSpilled(LTemplateInstruction<1, I, T>* instr,
int index);
template<int I, int T>
LInstruction* DefineSameAsFirst(LTemplateInstruction<1, I, T>* instr);
template<int I, int T>
LInstruction* DefineFixed(LTemplateInstruction<1, I, T>* instr,
Register reg);
template<int I, int T>
LInstruction* DefineFixedDouble(LTemplateInstruction<1, I, T>* instr,
DoubleRegister reg);
LInstruction* Define(LTemplateResultInstruction<1>* instr,
LUnallocated* result);
LInstruction* DefineAsRegister(LTemplateResultInstruction<1>* instr);
LInstruction* DefineAsSpilled(LTemplateResultInstruction<1>* instr,
int index);
LInstruction* DefineSameAsFirst(LTemplateResultInstruction<1>* instr);
LInstruction* DefineFixed(LTemplateResultInstruction<1>* instr,
Register reg);
LInstruction* DefineFixedDouble(LTemplateResultInstruction<1>* instr,
DoubleRegister reg);
LInstruction* AssignEnvironment(LInstruction* instr);
LInstruction* AssignPointerMap(LInstruction* instr);

View File

@ -3676,16 +3676,6 @@ void LCodeGen::CallKnownFunction(Handle<JSFunction> function,
}
void LCodeGen::DoCallConstantFunction(LCallConstantFunction* instr) {
ASSERT(ToRegister(instr->result()).is(r0));
CallKnownFunction(instr->hydrogen()->function(),
instr->hydrogen()->formal_parameter_count(),
instr->arity(),
instr,
R1_UNINITIALIZED);
}
void LCodeGen::DoDeferredMathAbsTaggedHeapNumber(LMathAbs* instr) {
ASSERT(instr->context() != NULL);
ASSERT(ToRegister(instr->context()).is(cp));
@ -3970,25 +3960,47 @@ void LCodeGen::DoInvokeFunction(LInvokeFunction* instr) {
}
void LCodeGen::DoCallKeyed(LCallKeyed* instr) {
ASSERT(ToRegister(instr->context()).is(cp));
void LCodeGen::DoCallWithDescriptor(LCallWithDescriptor* instr) {
ASSERT(ToRegister(instr->result()).is(r0));
int arity = instr->arity();
Handle<Code> ic =
isolate()->stub_cache()->ComputeKeyedCallInitialize(arity);
CallCode(ic, RelocInfo::CODE_TARGET, instr, NEVER_INLINE_TARGET_ADDRESS);
LPointerMap* pointers = instr->pointer_map();
SafepointGenerator generator(this, pointers, Safepoint::kLazyDeopt);
if (instr->target()->IsConstantOperand()) {
LConstantOperand* target = LConstantOperand::cast(instr->target());
Handle<Code> code = Handle<Code>::cast(ToHandle(target));
generator.BeforeCall(__ CallSize(code, RelocInfo::CODE_TARGET));
PlatformCallInterfaceDescriptor* call_descriptor =
instr->descriptor()->platform_specific_descriptor();
__ Call(code, RelocInfo::CODE_TARGET, TypeFeedbackId::None(), al,
call_descriptor->storage_mode());
} else {
ASSERT(instr->target()->IsRegister());
Register target = ToRegister(instr->target());
generator.BeforeCall(__ CallSize(target));
__ add(target, target, Operand(Code::kHeaderSize - kHeapObjectTag));
__ Call(target);
}
generator.AfterCall();
}
void LCodeGen::DoCallNamed(LCallNamed* instr) {
ASSERT(ToRegister(instr->context()).is(cp));
void LCodeGen::DoCallJSFunction(LCallJSFunction* instr) {
ASSERT(ToRegister(instr->function()).is(r1));
ASSERT(ToRegister(instr->result()).is(r0));
int arity = instr->arity();
Handle<Code> ic = isolate()->stub_cache()->ComputeCallInitialize(arity);
__ mov(r2, Operand(instr->name()));
CallCode(ic, RelocInfo::CODE_TARGET, instr, NEVER_INLINE_TARGET_ADDRESS);
if (instr->hydrogen()->pass_argument_count()) {
__ mov(r0, Operand(instr->arity()));
}
// Change context.
__ ldr(cp, FieldMemOperand(r1, JSFunction::kContextOffset));
// Load the code entry address
__ ldr(ip, FieldMemOperand(r1, JSFunction::kCodeEntryOffset));
__ Call(ip);
RecordSafepointWithLazyDeopt(instr, RECORD_SIMPLE_SAFEPOINT);
}
@ -4008,16 +4020,6 @@ void LCodeGen::DoCallFunction(LCallFunction* instr) {
}
void LCodeGen::DoCallKnownGlobal(LCallKnownGlobal* instr) {
ASSERT(ToRegister(instr->result()).is(r0));
CallKnownFunction(instr->hydrogen()->target(),
instr->hydrogen()->formal_parameter_count(),
instr->arity(),
instr,
R1_UNINITIALIZED);
}
void LCodeGen::DoCallNew(LCallNew* instr) {
ASSERT(ToRegister(instr->context()).is(cp));
ASSERT(ToRegister(instr->constructor()).is(r1));

View File

@ -1113,7 +1113,6 @@ void MacroAssembler::InvokePrologue(const ParameterCount& expected,
// r0: actual arguments count
// r1: function (passed through to callee)
// r2: expected arguments count
// r3: callee code entry
// The code below is made a lot easier because the calling code already sets
// up actual and expected registers according to the contract if values are
@ -1204,33 +1203,6 @@ void MacroAssembler::InvokeCode(Register code,
}
void MacroAssembler::InvokeCode(Handle<Code> code,
const ParameterCount& expected,
const ParameterCount& actual,
RelocInfo::Mode rmode,
InvokeFlag flag) {
// You can't call a function without a valid frame.
ASSERT(flag == JUMP_FUNCTION || has_frame());
Label done;
bool definitely_mismatches = false;
InvokePrologue(expected, actual, code, no_reg,
&done, &definitely_mismatches, flag,
NullCallWrapper());
if (!definitely_mismatches) {
if (flag == CALL_FUNCTION) {
Call(code, rmode);
} else {
Jump(code, rmode);
}
// Continue here if InvokePrologue does handle the invocation due to
// mismatched parameter counts.
bind(&done);
}
}
void MacroAssembler::InvokeFunction(Register fun,
const ParameterCount& actual,
InvokeFlag flag,

View File

@ -601,12 +601,6 @@ class MacroAssembler: public Assembler {
InvokeFlag flag,
const CallWrapper& call_wrapper);
void InvokeCode(Handle<Code> code,
const ParameterCount& expected,
const ParameterCount& actual,
RelocInfo::Mode rmode,
InvokeFlag flag);
// Invoke the JavaScript function in the given register. Changes the
// current context to the context in the function before invoking.
void InvokeFunction(Register function,

View File

@ -319,7 +319,7 @@ struct CodeStubInterfaceDescriptor {
return has_miss_handler_;
}
Register GetParameterRegister(int index) {
Register GetParameterRegister(int index) const {
return register_params_[index];
}
@ -341,6 +341,41 @@ struct CodeStubInterfaceDescriptor {
};
struct PlatformCallInterfaceDescriptor;
struct CallInterfaceDescriptor {
CallInterfaceDescriptor()
: register_param_count_(-1),
register_params_(NULL),
param_representations_(NULL),
platform_specific_descriptor_(NULL) { }
bool initialized() const { return register_param_count_ >= 0; }
int environment_length() const {
return register_param_count_;
}
Representation GetParameterRepresentation(int index) const {
return param_representations_[index];
}
Register GetParameterRegister(int index) const {
return register_params_[index];
}
PlatformCallInterfaceDescriptor* platform_specific_descriptor() const {
return platform_specific_descriptor_;
}
int register_param_count_;
Register* register_params_;
Representation* param_representations_;
PlatformCallInterfaceDescriptor* platform_specific_descriptor_;
};
class HydrogenCodeStub : public CodeStub {
public:
enum InitializationState {
@ -2432,6 +2467,12 @@ class ProfileEntryHookStub : public PlatformCodeStub {
DISALLOW_COPY_AND_ASSIGN(ProfileEntryHookStub);
};
class CallDescriptors {
public:
static void InitializeForIsolate(Isolate* isolate);
};
} } // namespace v8::internal
#endif // V8_CODE_STUBS_H_

View File

@ -841,6 +841,39 @@ void HUnaryCall::PrintDataTo(StringStream* stream) {
}
void HCallJSFunction::PrintDataTo(StringStream* stream) {
OperandAt(0)->PrintNameTo(stream);
stream->Add(" ");
OperandAt(1)->PrintNameTo(stream);
stream->Add(" ");
stream->Add("#%d", argument_count());
}
HCallJSFunction* HCallJSFunction::New(
Zone* zone,
HValue* context,
HValue* function,
int argument_count,
bool pass_argument_count) {
bool has_stack_check = false;
if (function->IsConstant()) {
HConstant* fun_const = HConstant::cast(function);
Handle<JSFunction> jsfun =
Handle<JSFunction>::cast(fun_const->handle(zone->isolate()));
has_stack_check = !jsfun.is_null() &&
(jsfun->code()->kind() == Code::FUNCTION ||
jsfun->code()->kind() == Code::OPTIMIZED_FUNCTION);
}
return new(zone) HCallJSFunction(
function, argument_count, pass_argument_count,
has_stack_check);
}
void HBinaryCall::PrintDataTo(StringStream* stream) {
first()->PrintNameTo(stream);
stream->Add(" ");
@ -966,28 +999,15 @@ void HBoundsCheckBaseIndexInformation::PrintDataTo(StringStream* stream) {
}
void HCallConstantFunction::PrintDataTo(StringStream* stream) {
if (IsApplyFunction()) {
stream->Add("optimized apply ");
} else {
stream->Add("%o ", function()->shared()->DebugName());
void HCallWithDescriptor::PrintDataTo(StringStream* stream) {
for (int i = 0; i < OperandCount(); i++) {
OperandAt(i)->PrintNameTo(stream);
stream->Add(" ");
}
stream->Add("#%d", argument_count());
}
void HCallNamed::PrintDataTo(StringStream* stream) {
stream->Add("%o ", *name());
HUnaryCall::PrintDataTo(stream);
}
void HCallKnownGlobal::PrintDataTo(StringStream* stream) {
stream->Add("%o ", target()->shared()->DebugName());
stream->Add("#%d", argument_count());
}
void HCallNewArray::PrintDataTo(StringStream* stream) {
stream->Add(ElementsKindToString(elements_kind()));
stream->Add(" ");

View File

@ -77,11 +77,9 @@ class LChunkBuilder;
V(BoundsCheck) \
V(BoundsCheckBaseIndexInformation) \
V(Branch) \
V(CallConstantFunction) \
V(CallWithDescriptor) \
V(CallJSFunction) \
V(CallFunction) \
V(CallKeyed) \
V(CallKnownGlobal) \
V(CallNamed) \
V(CallNew) \
V(CallNewArray) \
V(CallRuntime) \
@ -2279,6 +2277,139 @@ class HBinaryCall : public HCall<2> {
};
class HCallJSFunction V8_FINAL : public HCall<1> {
public:
static HCallJSFunction* New(Zone* zone,
HValue* context,
HValue* function,
int argument_count,
bool pass_argument_count);
HValue* function() { return OperandAt(0); }
virtual void PrintDataTo(StringStream* stream) V8_OVERRIDE;
virtual Representation RequiredInputRepresentation(
int index) V8_FINAL V8_OVERRIDE {
ASSERT(index == 0);
return Representation::Tagged();
}
bool pass_argument_count() const { return pass_argument_count_; }
virtual bool HasStackCheck() V8_FINAL V8_OVERRIDE {
return has_stack_check_;
}
DECLARE_CONCRETE_INSTRUCTION(CallJSFunction)
private:
// The argument count includes the receiver.
HCallJSFunction(HValue* function,
int argument_count,
bool pass_argument_count,
bool has_stack_check)
: HCall<1>(argument_count),
pass_argument_count_(pass_argument_count),
has_stack_check_(has_stack_check) {
SetOperandAt(0, function);
}
bool pass_argument_count_;
bool has_stack_check_;
};
class HCallWithDescriptor V8_FINAL : public HInstruction {
public:
static HCallWithDescriptor* New(Zone* zone, HValue* context,
HValue* target,
int argument_count,
const CallInterfaceDescriptor* descriptor,
Vector<HValue*>& operands) {
ASSERT(operands.length() == descriptor->environment_length());
HCallWithDescriptor* res =
new(zone) HCallWithDescriptor(target, argument_count,
descriptor, operands, zone);
return res;
}
virtual int OperandCount() V8_FINAL V8_OVERRIDE { return values_.length(); }
virtual HValue* OperandAt(int index) const V8_FINAL V8_OVERRIDE {
return values_[index];
}
virtual Representation RequiredInputRepresentation(
int index) V8_FINAL V8_OVERRIDE {
if (index == 0) {
return Representation::Tagged();
} else {
int par_index = index - 1;
ASSERT(par_index < descriptor_->environment_length());
return descriptor_->GetParameterRepresentation(par_index);
}
}
DECLARE_CONCRETE_INSTRUCTION(CallWithDescriptor)
virtual HType CalculateInferredType() V8_FINAL V8_OVERRIDE {
return HType::Tagged();
}
virtual int argument_count() const {
return argument_count_;
}
virtual int argument_delta() const V8_OVERRIDE {
return -argument_count_;
}
const CallInterfaceDescriptor* descriptor() const {
return descriptor_;
}
HValue* target() {
return OperandAt(0);
}
virtual bool IsCall() V8_FINAL V8_OVERRIDE { return true; }
virtual void PrintDataTo(StringStream* stream) V8_OVERRIDE;
private:
// The argument count includes the receiver.
HCallWithDescriptor(HValue* target,
int argument_count,
const CallInterfaceDescriptor* descriptor,
Vector<HValue*>& operands,
Zone* zone)
: descriptor_(descriptor),
values_(descriptor->environment_length() + 1, zone) {
argument_count_ = argument_count;
AddOperand(target, zone);
for (int i = 0; i < operands.length(); i++) {
AddOperand(operands[i], zone);
}
this->set_representation(Representation::Tagged());
this->SetAllSideEffects();
}
void AddOperand(HValue* v, Zone* zone) {
values_.Add(NULL, zone);
SetOperandAt(values_.length() - 1, v);
}
void InternalSetOperandAt(int index,
HValue* value) V8_FINAL V8_OVERRIDE {
values_[index] = value;
}
const CallInterfaceDescriptor* descriptor_;
ZoneList<HValue*> values_;
int argument_count_;
};
class HInvokeFunction V8_FINAL : public HBinaryCall {
public:
DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P2(HInvokeFunction, HValue*, int);
@ -2328,83 +2459,6 @@ class HInvokeFunction V8_FINAL : public HBinaryCall {
};
class HCallConstantFunction V8_FINAL : public HCall<0> {
public:
DECLARE_INSTRUCTION_FACTORY_P2(HCallConstantFunction,
Handle<JSFunction>,
int);
Handle<JSFunction> function() const { return function_; }
int formal_parameter_count() const { return formal_parameter_count_; }
bool IsApplyFunction() const {
return function_->code() ==
function_->GetIsolate()->builtins()->builtin(Builtins::kFunctionApply);
}
virtual void PrintDataTo(StringStream* stream) V8_OVERRIDE;
virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
return Representation::None();
}
virtual bool HasStackCheck() V8_FINAL V8_OVERRIDE {
return has_stack_check_;
}
DECLARE_CONCRETE_INSTRUCTION(CallConstantFunction)
private:
HCallConstantFunction(Handle<JSFunction> function, int argument_count)
: HCall<0>(argument_count),
function_(function),
formal_parameter_count_(function->shared()->formal_parameter_count()),
has_stack_check_(
function->code()->kind() == Code::FUNCTION ||
function->code()->kind() == Code::OPTIMIZED_FUNCTION) {}
Handle<JSFunction> function_;
int formal_parameter_count_;
bool has_stack_check_;
};
class HCallKeyed V8_FINAL : public HBinaryCall {
public:
DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P2(HCallKeyed, HValue*, int);
HValue* context() { return first(); }
HValue* key() { return second(); }
DECLARE_CONCRETE_INSTRUCTION(CallKeyed)
private:
HCallKeyed(HValue* context, HValue* key, int argument_count)
: HBinaryCall(context, key, argument_count) {
}
};
class HCallNamed V8_FINAL : public HUnaryCall {
public:
DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P2(HCallNamed, Handle<String>, int);
virtual void PrintDataTo(StringStream* stream) V8_OVERRIDE;
HValue* context() { return value(); }
Handle<String> name() const { return name_; }
DECLARE_CONCRETE_INSTRUCTION(CallNamed)
private:
HCallNamed(HValue* context, Handle<String> name, int argument_count)
: HUnaryCall(context, argument_count), name_(name) {
}
Handle<String> name_;
};
enum CallMode {
NORMAL_CALL,
TAIL_CALL,
@ -2441,40 +2495,6 @@ class HCallFunction V8_FINAL : public HBinaryCall {
};
class HCallKnownGlobal V8_FINAL : public HCall<0> {
public:
DECLARE_INSTRUCTION_FACTORY_P2(HCallKnownGlobal, Handle<JSFunction>, int);
virtual void PrintDataTo(StringStream* stream) V8_OVERRIDE;
Handle<JSFunction> target() const { return target_; }
int formal_parameter_count() const { return formal_parameter_count_; }
virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
return Representation::None();
}
virtual bool HasStackCheck() V8_FINAL V8_OVERRIDE {
return has_stack_check_;
}
DECLARE_CONCRETE_INSTRUCTION(CallKnownGlobal)
private:
HCallKnownGlobal(Handle<JSFunction> target, int argument_count)
: HCall<0>(argument_count),
target_(target),
formal_parameter_count_(target->shared()->formal_parameter_count()),
has_stack_check_(
target->code()->kind() == Code::FUNCTION ||
target->code()->kind() == Code::OPTIMIZED_FUNCTION) {}
Handle<JSFunction> target_;
int formal_parameter_count_;
bool has_stack_check_;
};
class HCallNew V8_FINAL : public HBinaryCall {
public:
DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P2(HCallNew, HValue*, int);

View File

@ -3917,9 +3917,7 @@ void HGraph::RestoreActualValues() {
}
template <class Instruction>
HInstruction* HOptimizedGraphBuilder::PreProcessCall(Instruction* call) {
int count = call->argument_count();
void HOptimizedGraphBuilder::PushArgumentsFromEnvironment(int count) {
ZoneList<HValue*> arguments(count, zone());
for (int i = 0; i < count; ++i) {
arguments.Add(Pop(), zone());
@ -3928,6 +3926,12 @@ HInstruction* HOptimizedGraphBuilder::PreProcessCall(Instruction* call) {
while (!arguments.is_empty()) {
Add<HPushArgument>(arguments.RemoveLast());
}
}
template <class Instruction>
HInstruction* HOptimizedGraphBuilder::PreProcessCall(Instruction* call) {
PushArgumentsFromEnvironment(call->argument_count());
return call;
}
@ -5499,7 +5503,7 @@ HInstruction* HOptimizedGraphBuilder::BuildLoadMonomorphic(
return NULL;
}
Add<HPushArgument>(Pop());
return New<HCallConstantFunction>(info->accessor(), 1);
return BuildCallConstantFunction(info->accessor(), 1);
}
ASSERT(info->lookup()->IsConstant());
@ -5784,7 +5788,7 @@ void HOptimizedGraphBuilder::BuildStore(Expression* expr,
Drop(2);
Add<HPushArgument>(object);
Add<HPushArgument>(value);
instr = New<HCallConstantFunction>(setter, 2);
instr = BuildCallConstantFunction(setter, 2);
} else {
Drop(2);
CHECK_ALIVE(instr = BuildStoreNamedMonomorphic(object,
@ -6746,6 +6750,86 @@ void HOptimizedGraphBuilder::AddCheckConstantFunction(
}
HInstruction* HOptimizedGraphBuilder::NewPlainFunctionCall(
HValue* fun, int argument_count, bool pass_argument_count) {
return New<HCallJSFunction>(
fun, argument_count, pass_argument_count);
}
HInstruction* HOptimizedGraphBuilder::NewArgumentAdaptorCall(
HValue* fun, HValue* context,
int argument_count, HValue* expected_param_count) {
CallInterfaceDescriptor* descriptor =
isolate()->call_descriptor(Isolate::ArgumentAdaptorCall);
HValue* arity = Add<HConstant>(argument_count - 1);
HValue* op_vals[] = { fun, context, arity, expected_param_count };
Handle<Code> adaptor =
isolate()->builtins()->ArgumentsAdaptorTrampoline();
HConstant* adaptor_value = Add<HConstant>(adaptor);
return New<HCallWithDescriptor>(
adaptor_value, argument_count, descriptor,
Vector<HValue*>(op_vals, descriptor->environment_length()));
}
HInstruction* HOptimizedGraphBuilder::BuildCallConstantFunction(
Handle<JSFunction> jsfun, int argument_count) {
HValue* target = Add<HConstant>(jsfun);
// For constant functions, we try to avoid calling the
// argument adaptor and instead call the function directly
int formal_parameter_count = jsfun->shared()->formal_parameter_count();
bool dont_adapt_arguments =
(formal_parameter_count ==
SharedFunctionInfo::kDontAdaptArgumentsSentinel);
int arity = argument_count - 1;
bool can_invoke_directly =
dont_adapt_arguments || formal_parameter_count == arity;
if (can_invoke_directly) {
return NewPlainFunctionCall(target, argument_count, dont_adapt_arguments);
} else {
HValue* param_count_value = Add<HConstant>(formal_parameter_count);
HValue* context = Add<HLoadNamedField>(target,
HObjectAccess::ForFunctionContextPointer());
return NewArgumentAdaptorCall(target, context,
argument_count, param_count_value);
}
UNREACHABLE();
return NULL;
}
HInstruction* HOptimizedGraphBuilder::NewCallNamed(
Handle<String> name, int argument_count) {
CallInterfaceDescriptor* descriptor =
isolate()->call_descriptor(Isolate::NamedCall);
HValue* op_vals[] = { context(), Add<HConstant>(name) };
int arity = argument_count - 1;
Handle<Code> ic = isolate()->stub_cache()->ComputeCallInitialize(arity);
return New<HCallWithDescriptor>(
Add<HConstant>(ic), argument_count, descriptor,
Vector<HValue*>(op_vals, descriptor->environment_length()));
}
HInstruction* HOptimizedGraphBuilder::NewCallKeyed(
HValue* key, int argument_count) {
CallInterfaceDescriptor* descriptor =
isolate()->call_descriptor(Isolate::KeyedCall);
HValue* op_vals[] = { context(), key };
int arity = argument_count - 1;
Handle<Code> ic = isolate()->stub_cache()->ComputeKeyedCallInitialize(arity);
return New<HCallWithDescriptor>(
Add<HConstant>(ic), argument_count, descriptor,
Vector<HValue*>(op_vals, descriptor->environment_length()));
}
class FunctionSorter {
public:
FunctionSorter() : index_(0), ticks_(0), ast_length_(0), src_length_(0) { }
@ -6801,9 +6885,9 @@ bool HOptimizedGraphBuilder::TryCallPolymorphicAsMonomorphic(
if (!TryInlineCall(expr)) {
int argument_count = expr->arguments()->length() + 1; // Includes receiver.
HCallConstantFunction* call =
New<HCallConstantFunction>(expr->target(), argument_count);
PreProcessCall(call);
HInstruction* call = BuildCallConstantFunction(
expr->target(), argument_count);
PushArgumentsFromEnvironment(argument_count);
AddInstruction(call);
if (!ast_context()->IsEffect()) Push(call);
Add<HSimulate>(expr->id(), REMOVABLE_SIMULATE);
@ -6917,9 +7001,9 @@ void HOptimizedGraphBuilder::HandlePolymorphicCallNamed(
// entire compilation by setting stack overflow on the visitor.
if (HasStackOverflow()) return;
} else {
HCallConstantFunction* call =
New<HCallConstantFunction>(expr->target(), argument_count);
PreProcessCall(call);
HInstruction* call = BuildCallConstantFunction(
expr->target(), argument_count);
PushArgumentsFromEnvironment(argument_count);
AddInstruction(call);
if (!ast_context()->IsEffect()) Push(call);
}
@ -6939,8 +7023,8 @@ void HOptimizedGraphBuilder::HandlePolymorphicCallNamed(
if (!ast_context()->IsEffect()) Push(graph()->GetConstant0());
FinishExitWithHardDeoptimization("Unknown map in polymorphic call", join);
} else {
HCallNamed* call = New<HCallNamed>(name, argument_count);
PreProcessCall(call);
HInstruction* call = NewCallNamed(name, argument_count);
PushArgumentsFromEnvironment(argument_count);
if (join != NULL) {
AddInstruction(call);
@ -7664,7 +7748,7 @@ void HOptimizedGraphBuilder::VisitCall(Call* expr) {
call = New<HCallFunction>(function, argument_count);
} else {
call = New<HCallKeyed>(key, argument_count);
call = NewCallKeyed(key, argument_count);
}
Drop(argument_count + 1); // 1 is the key.
return ast_context()->ReturnInstruction(call, expr->id());
@ -7703,13 +7787,14 @@ void HOptimizedGraphBuilder::VisitCall(Call* expr) {
// When the target has a custom call IC generator, use the IC,
// because it is likely to generate better code. Also use the IC
// when a primitive receiver check is required.
call = PreProcessCall(New<HCallNamed>(name, argument_count));
call = NewCallNamed(name, argument_count);
PushArgumentsFromEnvironment(argument_count);
} else {
AddCheckConstantFunction(expr->holder(), receiver, map);
if (TryInlineCall(expr)) return;
call = PreProcessCall(
New<HCallConstantFunction>(expr->target(), argument_count));
call = BuildCallConstantFunction(expr->target(), argument_count);
PushArgumentsFromEnvironment(argument_count);
}
} else if (types != NULL && types->length() > 1) {
ASSERT(expr->check_type() == RECEIVER_MAP_CHECK);
@ -7717,7 +7802,8 @@ void HOptimizedGraphBuilder::VisitCall(Call* expr) {
return;
} else {
call = PreProcessCall(New<HCallNamed>(name, argument_count));
call = NewCallNamed(name, argument_count);
PushArgumentsFromEnvironment(argument_count);
}
} else {
VariableProxy* proxy = expr->expression()->AsVariableProxy();
@ -7778,17 +7864,18 @@ void HOptimizedGraphBuilder::VisitCall(Call* expr) {
environment()->SetExpressionStackAt(receiver_index, global_object);
// When the target has a custom call IC generator, use the IC,
// because it is likely to generate better code.
call = PreProcessCall(New<HCallNamed>(var->name(), argument_count));
call = NewCallNamed(var->name(), argument_count);
PushArgumentsFromEnvironment(argument_count);
} else {
call = PreProcessCall(New<HCallKnownGlobal>(
expr->target(), argument_count));
call = BuildCallConstantFunction(expr->target(), argument_count);
PushArgumentsFromEnvironment(argument_count);
}
} else {
HGlobalObject* receiver = Add<HGlobalObject>();
Push(Add<HPushArgument>(receiver));
CHECK_ALIVE(VisitArgumentList(expr->arguments()));
call = New<HCallNamed>(var->name(), argument_count);
call = NewCallNamed(var->name(), argument_count);
Drop(argument_count);
}

View File

@ -2170,6 +2170,7 @@ class HOptimizedGraphBuilder : public HGraphBuilder, public AstVisitor {
// Remove the arguments from the bailout environment and emit instructions
// to push them as outgoing parameters.
template <class Instruction> HInstruction* PreProcessCall(Instruction* call);
void PushArgumentsFromEnvironment(int count);
void SetUpScope(Scope* scope);
virtual void VisitStatements(ZoneList<Statement*>* statements) V8_OVERRIDE;
@ -2496,6 +2497,21 @@ class HOptimizedGraphBuilder : public HGraphBuilder, public AstVisitor {
HValue* receiver,
Handle<Map> receiver_map);
HInstruction* NewPlainFunctionCall(HValue* fun,
int argument_count,
bool pass_argument_count);
HInstruction* NewArgumentAdaptorCall(HValue* fun, HValue* context,
int argument_count,
HValue* expected_param_count);
HInstruction* BuildCallConstantFunction(Handle<JSFunction> target,
int argument_count);
HInstruction* NewCallKeyed(HValue* key, int argument_count);
HInstruction* NewCallNamed(Handle<String> name, int argument_count);
// The translation state of the currently-being-translated function.
FunctionState* function_state_;

View File

@ -364,9 +364,7 @@ static void Generate_JSConstructStubHelper(MacroAssembler* masm,
__ mov(esi, FieldOperand(edi, JSFunction::kContextOffset));
Handle<Code> code =
masm->isolate()->builtins()->HandleApiCallConstruct();
ParameterCount expected(0);
__ InvokeCode(code, expected, expected, RelocInfo::CODE_TARGET,
CALL_FUNCTION, NullCallWrapper());
__ call(code, RelocInfo::CODE_TARGET);
} else {
ParameterCount actual(eax);
__ InvokeFunction(edi, actual, CALL_FUNCTION,
@ -1231,13 +1229,14 @@ void Builtins::Generate_ArgumentsAdaptorTrampoline(MacroAssembler* masm) {
// ----------- S t a t e -------------
// -- eax : actual number of arguments
// -- ebx : expected number of arguments
// -- edx : code entry to call
// -- edi : function (passed through to callee)
// -----------------------------------
Label invoke, dont_adapt_arguments;
__ IncrementCounter(masm->isolate()->counters()->arguments_adaptors(), 1);
Label enough, too_few;
__ mov(edx, FieldOperand(edi, JSFunction::kCodeEntryOffset));
__ cmp(eax, ebx);
__ j(less, &too_few);
__ cmp(ebx, SharedFunctionInfo::kDontAdaptArgumentsSentinel);

View File

@ -364,6 +364,56 @@ void NewStringAddStub::InitializeInterfaceDescriptor(
}
void CallDescriptors::InitializeForIsolate(Isolate* isolate) {
{
CallInterfaceDescriptor* descriptor =
isolate->call_descriptor(Isolate::ArgumentAdaptorCall);
static Register registers[] = { edi, // JSFunction
esi, // context
eax, // actual number of arguments
ebx, // expected number of arguments
};
static Representation representations[] = {
Representation::Tagged(), // JSFunction
Representation::Tagged(), // context
Representation::Integer32(), // actual number of arguments
Representation::Integer32(), // expected number of arguments
};
descriptor->register_param_count_ = 4;
descriptor->register_params_ = registers;
descriptor->param_representations_ = representations;
}
{
CallInterfaceDescriptor* descriptor =
isolate->call_descriptor(Isolate::KeyedCall);
static Register registers[] = { esi, // context
ecx, // key
};
static Representation representations[] = {
Representation::Tagged(), // context
Representation::Tagged(), // key
};
descriptor->register_param_count_ = 2;
descriptor->register_params_ = registers;
descriptor->param_representations_ = representations;
}
{
CallInterfaceDescriptor* descriptor =
isolate->call_descriptor(Isolate::NamedCall);
static Register registers[] = { esi, // context
ecx, // name
};
static Representation representations[] = {
Representation::Tagged(), // context
Representation::Tagged(), // name
};
descriptor->register_param_count_ = 2;
descriptor->register_params_ = registers;
descriptor->param_representations_ = representations;
}
}
#define __ ACCESS_MASM(masm)

View File

@ -3835,13 +3835,54 @@ void LCodeGen::CallKnownFunction(Handle<JSFunction> function,
}
void LCodeGen::DoCallConstantFunction(LCallConstantFunction* instr) {
void LCodeGen::DoCallWithDescriptor(LCallWithDescriptor* instr) {
ASSERT(ToRegister(instr->result()).is(eax));
CallKnownFunction(instr->hydrogen()->function(),
instr->hydrogen()->formal_parameter_count(),
instr->arity(),
instr,
EDI_UNINITIALIZED);
LPointerMap* pointers = instr->pointer_map();
SafepointGenerator generator(this, pointers, Safepoint::kLazyDeopt);
if (instr->target()->IsConstantOperand()) {
LConstantOperand* target = LConstantOperand::cast(instr->target());
Handle<Code> code = Handle<Code>::cast(ToHandle(target));
generator.BeforeCall(__ CallSize(code, RelocInfo::CODE_TARGET));
__ call(code, RelocInfo::CODE_TARGET);
} else {
ASSERT(instr->target()->IsRegister());
Register target = ToRegister(instr->target());
generator.BeforeCall(__ CallSize(Operand(target)));
__ add(target, Immediate(Code::kHeaderSize - kHeapObjectTag));
__ call(target);
}
generator.AfterCall();
}
void LCodeGen::DoCallJSFunction(LCallJSFunction* instr) {
ASSERT(ToRegister(instr->function()).is(edi));
ASSERT(ToRegister(instr->result()).is(eax));
if (instr->hydrogen()->pass_argument_count()) {
__ mov(eax, instr->arity());
}
// Change context.
__ mov(esi, FieldOperand(edi, JSFunction::kContextOffset));
bool is_self_call = false;
if (instr->hydrogen()->function()->IsConstant()) {
HConstant* fun_const = HConstant::cast(instr->hydrogen()->function());
Handle<JSFunction> jsfun =
Handle<JSFunction>::cast(fun_const->handle(isolate()));
is_self_call = jsfun.is_identical_to(info()->closure());
}
if (is_self_call) {
__ CallSelf();
} else {
__ call(FieldOperand(edi, JSFunction::kCodeEntryOffset));
}
RecordSafepointWithLazyDeopt(instr, RECORD_SIMPLE_SAFEPOINT);
}
@ -4212,29 +4253,6 @@ void LCodeGen::DoInvokeFunction(LInvokeFunction* instr) {
}
void LCodeGen::DoCallKeyed(LCallKeyed* instr) {
ASSERT(ToRegister(instr->context()).is(esi));
ASSERT(ToRegister(instr->key()).is(ecx));
ASSERT(ToRegister(instr->result()).is(eax));
int arity = instr->arity();
Handle<Code> ic =
isolate()->stub_cache()->ComputeKeyedCallInitialize(arity);
CallCode(ic, RelocInfo::CODE_TARGET, instr);
}
void LCodeGen::DoCallNamed(LCallNamed* instr) {
ASSERT(ToRegister(instr->context()).is(esi));
ASSERT(ToRegister(instr->result()).is(eax));
int arity = instr->arity();
Handle<Code> ic = isolate()->stub_cache()->ComputeCallInitialize(arity);
__ mov(ecx, instr->name());
CallCode(ic, RelocInfo::CODE_TARGET, instr);
}
void LCodeGen::DoCallFunction(LCallFunction* instr) {
ASSERT(ToRegister(instr->context()).is(esi));
ASSERT(ToRegister(instr->function()).is(edi));
@ -4251,16 +4269,6 @@ void LCodeGen::DoCallFunction(LCallFunction* instr) {
}
void LCodeGen::DoCallKnownGlobal(LCallKnownGlobal* instr) {
ASSERT(ToRegister(instr->result()).is(eax));
CallKnownFunction(instr->hydrogen()->target(),
instr->hydrogen()->formal_parameter_count(),
instr->arity(),
instr,
EDI_UNINITIALIZED);
}
void LCodeGen::DoCallNew(LCallNew* instr) {
ASSERT(ToRegister(instr->context()).is(esi));
ASSERT(ToRegister(instr->constructor()).is(edi));

View File

@ -307,7 +307,18 @@ void LInnerAllocatedObject::PrintDataTo(StringStream* stream) {
}
void LCallConstantFunction::PrintDataTo(StringStream* stream) {
void LCallJSFunction::PrintDataTo(StringStream* stream) {
stream->Add("= ");
function()->PrintTo(stream);
stream->Add("#%d / ", arity());
}
void LCallWithDescriptor::PrintDataTo(StringStream* stream) {
for (int i = 0; i < InputCount(); i++) {
InputAt(i)->PrintTo(stream);
stream->Add(" ");
}
stream->Add("#%d / ", arity());
}
@ -334,22 +345,6 @@ void LInvokeFunction::PrintDataTo(StringStream* stream) {
}
void LCallKeyed::PrintDataTo(StringStream* stream) {
stream->Add("[ecx] #%d / ", arity());
}
void LCallNamed::PrintDataTo(StringStream* stream) {
SmartArrayPointer<char> name_string = name()->ToCString();
stream->Add("%s #%d / ", name_string.get(), arity());
}
void LCallKnownGlobal::PrintDataTo(StringStream* stream) {
stream->Add("#%d / ", arity());
}
void LCallNew::PrintDataTo(StringStream* stream) {
stream->Add("= ");
context()->PrintTo(stream);
@ -619,8 +614,7 @@ LOperand* LChunkBuilder::Use(HValue* value, LUnallocated* operand) {
}
template<int I, int T>
LInstruction* LChunkBuilder::Define(LTemplateInstruction<1, I, T>* instr,
LInstruction* LChunkBuilder::Define(LTemplateResultInstruction<1>* instr,
LUnallocated* result) {
result->set_virtual_register(current_instruction_->id());
instr->set_result(result);
@ -628,41 +622,36 @@ LInstruction* LChunkBuilder::Define(LTemplateInstruction<1, I, T>* instr,
}
template<int I, int T>
LInstruction* LChunkBuilder::DefineAsRegister(
LTemplateInstruction<1, I, T>* instr) {
LTemplateResultInstruction<1>* instr) {
return Define(instr,
new(zone()) LUnallocated(LUnallocated::MUST_HAVE_REGISTER));
}
template<int I, int T>
LInstruction* LChunkBuilder::DefineAsSpilled(
LTemplateInstruction<1, I, T>* instr,
LTemplateResultInstruction<1>* instr,
int index) {
return Define(instr,
new(zone()) LUnallocated(LUnallocated::FIXED_SLOT, index));
}
template<int I, int T>
LInstruction* LChunkBuilder::DefineSameAsFirst(
LTemplateInstruction<1, I, T>* instr) {
LTemplateResultInstruction<1>* instr) {
return Define(instr,
new(zone()) LUnallocated(LUnallocated::SAME_AS_FIRST_INPUT));
}
template<int I, int T>
LInstruction* LChunkBuilder::DefineFixed(LTemplateInstruction<1, I, T>* instr,
LInstruction* LChunkBuilder::DefineFixed(LTemplateResultInstruction<1>* instr,
Register reg) {
return Define(instr, ToUnallocated(reg));
}
template<int I, int T>
LInstruction* LChunkBuilder::DefineFixedDouble(
LTemplateInstruction<1, I, T>* instr,
LTemplateResultInstruction<1>* instr,
XMMRegister reg) {
return Define(instr, ToUnallocated(reg));
}
@ -1162,9 +1151,32 @@ LInstruction* LChunkBuilder::DoGlobalReceiver(HGlobalReceiver* instr) {
}
LInstruction* LChunkBuilder::DoCallConstantFunction(
HCallConstantFunction* instr) {
return MarkAsCall(DefineFixed(new(zone()) LCallConstantFunction, eax), instr);
LInstruction* LChunkBuilder::DoCallJSFunction(
HCallJSFunction* instr) {
LOperand* function = UseFixed(instr->function(), edi);
LCallJSFunction* result = new(zone()) LCallJSFunction(function);
return MarkAsCall(DefineFixed(result, eax), instr, CANNOT_DEOPTIMIZE_EAGERLY);
}
LInstruction* LChunkBuilder::DoCallWithDescriptor(
HCallWithDescriptor* instr) {
const CallInterfaceDescriptor* descriptor = instr->descriptor();
LOperand* target = UseRegisterOrConstantAtStart(instr->target());
ZoneList<LOperand*> ops(instr->OperandCount(), zone());
ops.Add(target, zone());
for (int i = 1; i < instr->OperandCount(); i++) {
LOperand* op = UseFixed(instr->OperandAt(i),
descriptor->GetParameterRegister(i - 1));
ops.Add(op, zone());
}
LCallWithDescriptor* result = new(zone()) LCallWithDescriptor(
descriptor, ops, zone());
return MarkAsCall(DefineFixed(result, eax), instr, CANNOT_DEOPTIMIZE_EAGERLY);
}
@ -1249,27 +1261,6 @@ LInstruction* LChunkBuilder::DoMathPowHalf(HUnaryMathOperation* instr) {
}
LInstruction* LChunkBuilder::DoCallKeyed(HCallKeyed* instr) {
ASSERT(instr->key()->representation().IsTagged());
LOperand* context = UseFixed(instr->context(), esi);
LOperand* key = UseFixed(instr->key(), ecx);
LCallKeyed* result = new(zone()) LCallKeyed(context, key);
return MarkAsCall(DefineFixed(result, eax), instr);
}
LInstruction* LChunkBuilder::DoCallNamed(HCallNamed* instr) {
LOperand* context = UseFixed(instr->context(), esi);
LCallNamed* result = new(zone()) LCallNamed(context);
return MarkAsCall(DefineFixed(result, eax), instr);
}
LInstruction* LChunkBuilder::DoCallKnownGlobal(HCallKnownGlobal* instr) {
return MarkAsCall(DefineFixed(new(zone()) LCallKnownGlobal, eax), instr);
}
LInstruction* LChunkBuilder::DoCallNew(HCallNew* instr) {
LOperand* context = UseFixed(instr->context(), esi);
LOperand* constructor = UseFixed(instr->constructor(), edi);

View File

@ -52,11 +52,9 @@ class LCodeGen;
V(BitI) \
V(BoundsCheck) \
V(Branch) \
V(CallConstantFunction) \
V(CallJSFunction) \
V(CallWithDescriptor) \
V(CallFunction) \
V(CallKeyed) \
V(CallKnownGlobal) \
V(CallNamed) \
V(CallNew) \
V(CallNewArray) \
V(CallRuntime) \
@ -307,10 +305,8 @@ class LInstruction : public ZoneObject {
// R = number of result operands (0 or 1).
// I = number of input operands.
// T = number of temporary operands.
template<int R, int I, int T>
class LTemplateInstruction : public LInstruction {
template<int R>
class LTemplateResultInstruction : public LInstruction {
public:
// Allow 0 or 1 output operands.
STATIC_ASSERT(R == 0 || R == 1);
@ -322,6 +318,15 @@ class LTemplateInstruction : public LInstruction {
protected:
EmbeddedContainer<LOperand*, R> results_;
};
// R = number of result operands (0 or 1).
// I = number of input operands.
// T = number of temporary operands.
template<int R, int I, int T>
class LTemplateInstruction : public LTemplateResultInstruction<R> {
protected:
EmbeddedContainer<LOperand*, I> inputs_;
EmbeddedContainer<LOperand*, T> temps_;
@ -1836,18 +1841,62 @@ class LGlobalReceiver V8_FINAL : public LTemplateInstruction<1, 1, 0> {
};
class LCallConstantFunction V8_FINAL : public LTemplateInstruction<1, 0, 0> {
class LCallJSFunction V8_FINAL : public LTemplateInstruction<1, 1, 0> {
public:
DECLARE_CONCRETE_INSTRUCTION(CallConstantFunction, "call-constant-function")
DECLARE_HYDROGEN_ACCESSOR(CallConstantFunction)
explicit LCallJSFunction(LOperand* function) {
inputs_[0] = function;
}
LOperand* function() { return inputs_[0]; }
DECLARE_CONCRETE_INSTRUCTION(CallJSFunction, "call-js-function")
DECLARE_HYDROGEN_ACCESSOR(CallJSFunction)
virtual void PrintDataTo(StringStream* stream) V8_OVERRIDE;
Handle<JSFunction> function() { return hydrogen()->function(); }
int arity() const { return hydrogen()->argument_count() - 1; }
};
class LCallWithDescriptor V8_FINAL : public LTemplateResultInstruction<1> {
public:
LCallWithDescriptor(const CallInterfaceDescriptor* descriptor,
ZoneList<LOperand*>& operands,
Zone* zone)
: descriptor_(descriptor),
inputs_(descriptor->environment_length() + 1, zone) {
ASSERT(descriptor->environment_length() + 1 == operands.length());
inputs_.AddAll(operands, zone);
}
LOperand* target() const { return inputs_[0]; }
private:
DECLARE_CONCRETE_INSTRUCTION(CallWithDescriptor, "call-with-descriptor")
DECLARE_HYDROGEN_ACCESSOR(CallWithDescriptor)
virtual void PrintDataTo(StringStream* stream) V8_OVERRIDE;
int arity() const { return hydrogen()->argument_count() - 1; }
const CallInterfaceDescriptor* descriptor_;
ZoneList<LOperand*> inputs_;
virtual void InternalSetOperandAt(int index,
LOperand* value) V8_FINAL V8_OVERRIDE {
inputs_[index] = value;
}
// Iterator support.
virtual int InputCount() V8_FINAL V8_OVERRIDE { return inputs_.length(); }
virtual LOperand* InputAt(int i) V8_FINAL V8_OVERRIDE { return inputs_[i]; }
virtual int TempCount() V8_FINAL V8_OVERRIDE { return 0; }
virtual LOperand* TempAt(int i) V8_FINAL V8_OVERRIDE { return NULL; }
};
class LInvokeFunction V8_FINAL : public LTemplateInstruction<1, 2, 0> {
public:
LInvokeFunction(LOperand* context, LOperand* function) {
@ -1867,43 +1916,6 @@ class LInvokeFunction V8_FINAL : public LTemplateInstruction<1, 2, 0> {
};
class LCallKeyed V8_FINAL : public LTemplateInstruction<1, 2, 0> {
public:
LCallKeyed(LOperand* context, LOperand* key) {
inputs_[0] = context;
inputs_[1] = key;
}
LOperand* context() { return inputs_[0]; }
LOperand* key() { return inputs_[1]; }
DECLARE_CONCRETE_INSTRUCTION(CallKeyed, "call-keyed")
DECLARE_HYDROGEN_ACCESSOR(CallKeyed)
virtual void PrintDataTo(StringStream* stream) V8_OVERRIDE;
int arity() const { return hydrogen()->argument_count() - 1; }
};
class LCallNamed V8_FINAL : public LTemplateInstruction<1, 1, 0> {
public:
explicit LCallNamed(LOperand* context) {
inputs_[0] = context;
}
LOperand* context() { return inputs_[0]; }
DECLARE_CONCRETE_INSTRUCTION(CallNamed, "call-named")
DECLARE_HYDROGEN_ACCESSOR(CallNamed)
virtual void PrintDataTo(StringStream* stream) V8_OVERRIDE;
Handle<String> name() const { return hydrogen()->name(); }
int arity() const { return hydrogen()->argument_count() - 1; }
};
class LCallFunction V8_FINAL : public LTemplateInstruction<1, 2, 0> {
public:
explicit LCallFunction(LOperand* context, LOperand* function) {
@ -1921,17 +1933,6 @@ class LCallFunction V8_FINAL : public LTemplateInstruction<1, 2, 0> {
};
class LCallKnownGlobal V8_FINAL : public LTemplateInstruction<1, 0, 0> {
public:
DECLARE_CONCRETE_INSTRUCTION(CallKnownGlobal, "call-known-global")
DECLARE_HYDROGEN_ACCESSOR(CallKnownGlobal)
virtual void PrintDataTo(StringStream* stream) V8_OVERRIDE;
int arity() const { return hydrogen()->argument_count() - 1; }
};
class LCallNew V8_FINAL : public LTemplateInstruction<1, 2, 0> {
public:
LCallNew(LOperand* context, LOperand* constructor) {
@ -2802,24 +2803,17 @@ class LChunkBuilder V8_FINAL : public LChunkBuilderBase {
// Methods for setting up define-use relationships.
// Return the same instruction that they are passed.
template<int I, int T>
LInstruction* Define(LTemplateInstruction<1, I, T>* instr,
LUnallocated* result);
template<int I, int T>
LInstruction* DefineAsRegister(LTemplateInstruction<1, I, T>* instr);
template<int I, int T>
LInstruction* DefineAsSpilled(LTemplateInstruction<1, I, T>* instr,
int index);
template<int I, int T>
LInstruction* DefineSameAsFirst(LTemplateInstruction<1, I, T>* instr);
template<int I, int T>
LInstruction* DefineFixed(LTemplateInstruction<1, I, T>* instr,
Register reg);
template<int I, int T>
LInstruction* DefineFixedDouble(LTemplateInstruction<1, I, T>* instr,
XMMRegister reg);
template<int I, int T>
LInstruction* DefineX87TOS(LTemplateInstruction<1, I, T>* instr);
LInstruction* Define(LTemplateResultInstruction<1>* instr,
LUnallocated* result);
LInstruction* DefineAsRegister(LTemplateResultInstruction<1>* instr);
LInstruction* DefineAsSpilled(LTemplateResultInstruction<1>* instr,
int index);
LInstruction* DefineSameAsFirst(LTemplateResultInstruction<1>* instr);
LInstruction* DefineFixed(LTemplateResultInstruction<1>* instr,
Register reg);
LInstruction* DefineFixedDouble(LTemplateResultInstruction<1>* instr,
XMMRegister reg);
LInstruction* DefineX87TOS(LTemplateResultInstruction<1>* instr);
// Assigns an environment to an instruction. An instruction which can
// deoptimize must have an environment.
LInstruction* AssignEnvironment(LInstruction* instr);

View File

@ -2556,34 +2556,6 @@ void MacroAssembler::InvokeCode(const Operand& code,
}
void MacroAssembler::InvokeCode(Handle<Code> code,
const ParameterCount& expected,
const ParameterCount& actual,
RelocInfo::Mode rmode,
InvokeFlag flag,
const CallWrapper& call_wrapper) {
// You can't call a function without a valid frame.
ASSERT(flag == JUMP_FUNCTION || has_frame());
Label done;
Operand dummy(eax, 0);
bool definitely_mismatches = false;
InvokePrologue(expected, actual, code, dummy, &done, &definitely_mismatches,
flag, Label::kNear, call_wrapper);
if (!definitely_mismatches) {
if (flag == CALL_FUNCTION) {
call_wrapper.BeforeCall(CallSize(code, rmode));
call(code, rmode);
call_wrapper.AfterCall();
} else {
ASSERT(flag == JUMP_FUNCTION);
jmp(code, rmode);
}
bind(&done);
}
}
void MacroAssembler::InvokeFunction(Register fun,
const ParameterCount& actual,
InvokeFlag flag,

View File

@ -326,13 +326,6 @@ class MacroAssembler: public Assembler {
InvokeFlag flag,
const CallWrapper& call_wrapper);
void InvokeCode(Handle<Code> code,
const ParameterCount& expected,
const ParameterCount& actual,
RelocInfo::Mode rmode,
InvokeFlag flag,
const CallWrapper& call_wrapper);
// Invoke the JavaScript function in the given register. Changes the
// current context to the context in the function before invoking.
void InvokeFunction(Register function,

View File

@ -1550,6 +1550,7 @@ Isolate::Isolate()
regexp_stack_(NULL),
date_cache_(NULL),
code_stub_interface_descriptors_(NULL),
call_descriptors_(NULL),
// TODO(bmeurer) Initialized lazily because it depends on flags; can
// be fixed once the default isolate cleanup is done.
random_number_generator_(NULL),
@ -1758,6 +1759,9 @@ Isolate::~Isolate() {
delete[] code_stub_interface_descriptors_;
code_stub_interface_descriptors_ = NULL;
delete[] call_descriptors_;
call_descriptors_ = NULL;
delete regexp_stack_;
regexp_stack_ = NULL;
@ -1948,6 +1952,8 @@ bool Isolate::Init(Deserializer* des) {
date_cache_ = new DateCache();
code_stub_interface_descriptors_ =
new CodeStubInterfaceDescriptor[CodeStub::NUMBER_OF_IDS];
call_descriptors_ =
new CallInterfaceDescriptor[NUMBER_OF_CALL_DESCRIPTORS];
cpu_profiler_ = new CpuProfiler(this);
heap_profiler_ = new HeapProfiler(heap());
@ -2109,6 +2115,8 @@ bool Isolate::Init(Deserializer* des) {
NewStringAddStub::InstallDescriptors(this);
}
CallDescriptors::InitializeForIsolate(this);
initialized_from_snapshot_ = (des != NULL);
return true;
@ -2286,6 +2294,13 @@ CodeStubInterfaceDescriptor*
}
CallInterfaceDescriptor*
Isolate::call_descriptor(CallDescriptorKey index) {
ASSERT(0 <= index && index < NUMBER_OF_CALL_DESCRIPTORS);
return &call_descriptors_[index];
}
Object* Isolate::FindCodeObject(Address a) {
return inner_pointer_to_code_cache()->GcSafeFindCodeForInnerPointer(a);
}

View File

@ -55,6 +55,7 @@ class Bootstrapper;
class CodeGenerator;
class CodeRange;
struct CodeStubInterfaceDescriptor;
struct CallInterfaceDescriptor;
class CodeTracer;
class CompilationCache;
class ContextSlotCache;
@ -1074,6 +1075,15 @@ class Isolate {
CodeStubInterfaceDescriptor*
code_stub_interface_descriptor(int index);
enum CallDescriptorKey {
KeyedCall,
NamedCall,
ArgumentAdaptorCall,
NUMBER_OF_CALL_DESCRIPTORS
};
CallInterfaceDescriptor* call_descriptor(CallDescriptorKey index);
void IterateDeferredHandles(ObjectVisitor* visitor);
void LinkDeferredHandles(DeferredHandles* deferred_handles);
void UnlinkDeferredHandles(DeferredHandles* deferred_handles);
@ -1299,6 +1309,7 @@ class Isolate {
DateCache* date_cache_;
unibrow::Mapping<unibrow::Ecma262Canonicalize> interp_canonicalize_mapping_;
CodeStubInterfaceDescriptor* code_stub_interface_descriptors_;
CallInterfaceDescriptor* call_descriptors_;
RandomNumberGenerator* random_number_generator_;
// True if fatal error has been signaled for this isolate.

View File

@ -369,9 +369,7 @@ static void Generate_JSConstructStubHelper(MacroAssembler* masm,
__ movq(rsi, FieldOperand(rdi, JSFunction::kContextOffset));
Handle<Code> code =
masm->isolate()->builtins()->HandleApiCallConstruct();
ParameterCount expected(0);
__ InvokeCode(code, expected, expected, RelocInfo::CODE_TARGET,
CALL_FUNCTION, NullCallWrapper());
__ Call(code, RelocInfo::CODE_TARGET);
} else {
ParameterCount actual(rax);
__ InvokeFunction(rdi, actual, CALL_FUNCTION, NullCallWrapper());
@ -1303,7 +1301,7 @@ void Builtins::Generate_ArgumentsAdaptorTrampoline(MacroAssembler* masm) {
// ----------- S t a t e -------------
// -- rax : actual number of arguments
// -- rbx : expected number of arguments
// -- rdx : code entry to call
// -- rdi: function (passed through to callee)
// -----------------------------------
Label invoke, dont_adapt_arguments;
@ -1311,6 +1309,7 @@ void Builtins::Generate_ArgumentsAdaptorTrampoline(MacroAssembler* masm) {
__ IncrementCounter(counters->arguments_adaptors(), 1);
Label enough, too_few;
__ movq(rdx, FieldOperand(rdi, JSFunction::kCodeEntryOffset));
__ cmpq(rax, rbx);
__ j(less, &too_few);
__ cmpq(rbx, Immediate(SharedFunctionInfo::kDontAdaptArgumentsSentinel));

View File

@ -361,6 +361,56 @@ void NewStringAddStub::InitializeInterfaceDescriptor(
}
void CallDescriptors::InitializeForIsolate(Isolate* isolate) {
{
CallInterfaceDescriptor* descriptor =
isolate->call_descriptor(Isolate::ArgumentAdaptorCall);
static Register registers[] = { rdi, // JSFunction
rsi, // context
rax, // actual number of arguments
rbx, // expected number of arguments
};
static Representation representations[] = {
Representation::Tagged(), // JSFunction
Representation::Tagged(), // context
Representation::Integer32(), // actual number of arguments
Representation::Integer32(), // expected number of arguments
};
descriptor->register_param_count_ = 4;
descriptor->register_params_ = registers;
descriptor->param_representations_ = representations;
}
{
CallInterfaceDescriptor* descriptor =
isolate->call_descriptor(Isolate::KeyedCall);
static Register registers[] = { rsi, // context
rcx, // key
};
static Representation representations[] = {
Representation::Tagged(), // context
Representation::Tagged(), // key
};
descriptor->register_param_count_ = 2;
descriptor->register_params_ = registers;
descriptor->param_representations_ = representations;
}
{
CallInterfaceDescriptor* descriptor =
isolate->call_descriptor(Isolate::NamedCall);
static Register registers[] = { rsi, // context
rcx, // name
};
static Representation representations[] = {
Representation::Tagged(), // context
Representation::Tagged(), // name
};
descriptor->register_param_count_ = 2;
descriptor->register_params_ = registers;
descriptor->param_representations_ = representations;
}
}
#define __ ACCESS_MASM(masm)

View File

@ -3409,13 +3409,58 @@ void LCodeGen::CallKnownFunction(Handle<JSFunction> function,
}
void LCodeGen::DoCallConstantFunction(LCallConstantFunction* instr) {
void LCodeGen::DoCallWithDescriptor(LCallWithDescriptor* instr) {
ASSERT(ToRegister(instr->result()).is(rax));
CallKnownFunction(instr->hydrogen()->function(),
instr->hydrogen()->formal_parameter_count(),
instr->arity(),
instr,
RDI_UNINITIALIZED);
LPointerMap* pointers = instr->pointer_map();
SafepointGenerator generator(this, pointers, Safepoint::kLazyDeopt);
if (instr->target()->IsConstantOperand()) {
LConstantOperand* target = LConstantOperand::cast(instr->target());
Handle<Code> code = Handle<Code>::cast(ToHandle(target));
generator.BeforeCall(__ CallSize(code));
__ call(code, RelocInfo::CODE_TARGET);
} else {
ASSERT(instr->target()->IsRegister());
Register target = ToRegister(instr->target());
generator.BeforeCall(__ CallSize(target));
__ addq(target, Immediate(Code::kHeaderSize - kHeapObjectTag));
__ call(target);
}
generator.AfterCall();
}
void LCodeGen::DoCallJSFunction(LCallJSFunction* instr) {
ASSERT(ToRegister(instr->function()).is(rdi));
ASSERT(ToRegister(instr->result()).is(rax));
if (instr->hydrogen()->pass_argument_count()) {
__ Set(rax, instr->arity());
}
// Change context.
__ movq(rsi, FieldOperand(rdi, JSFunction::kContextOffset));
LPointerMap* pointers = instr->pointer_map();
SafepointGenerator generator(this, pointers, Safepoint::kLazyDeopt);
bool is_self_call = false;
if (instr->hydrogen()->function()->IsConstant()) {
Handle<JSFunction> jsfun = Handle<JSFunction>::null();
HConstant* fun_const = HConstant::cast(instr->hydrogen()->function());
jsfun = Handle<JSFunction>::cast(fun_const->handle(isolate()));
is_self_call = jsfun.is_identical_to(info()->closure());
}
if (is_self_call) {
__ CallSelf();
} else {
Operand target = FieldOperand(rdi, JSFunction::kCodeEntryOffset);
generator.BeforeCall(__ CallSize(target));
__ call(target);
}
generator.AfterCall();
}
@ -3784,29 +3829,6 @@ void LCodeGen::DoInvokeFunction(LInvokeFunction* instr) {
}
void LCodeGen::DoCallKeyed(LCallKeyed* instr) {
ASSERT(ToRegister(instr->context()).is(rsi));
ASSERT(ToRegister(instr->key()).is(rcx));
ASSERT(ToRegister(instr->result()).is(rax));
int arity = instr->arity();
Handle<Code> ic =
isolate()->stub_cache()->ComputeKeyedCallInitialize(arity);
CallCode(ic, RelocInfo::CODE_TARGET, instr);
}
void LCodeGen::DoCallNamed(LCallNamed* instr) {
ASSERT(ToRegister(instr->context()).is(rsi));
ASSERT(ToRegister(instr->result()).is(rax));
int arity = instr->arity();
Handle<Code> ic = isolate()->stub_cache()->ComputeCallInitialize(arity);
__ Move(rcx, instr->name());
CallCode(ic, RelocInfo::CODE_TARGET, instr);
}
void LCodeGen::DoCallFunction(LCallFunction* instr) {
ASSERT(ToRegister(instr->context()).is(rsi));
ASSERT(ToRegister(instr->function()).is(rdi));
@ -3823,16 +3845,6 @@ void LCodeGen::DoCallFunction(LCallFunction* instr) {
}
void LCodeGen::DoCallKnownGlobal(LCallKnownGlobal* instr) {
ASSERT(ToRegister(instr->result()).is(rax));
CallKnownFunction(instr->hydrogen()->target(),
instr->hydrogen()->formal_parameter_count(),
instr->arity(),
instr,
RDI_UNINITIALIZED);
}
void LCodeGen::DoCallNew(LCallNew* instr) {
ASSERT(ToRegister(instr->context()).is(rsi));
ASSERT(ToRegister(instr->constructor()).is(rdi));

View File

@ -280,7 +280,18 @@ void LInnerAllocatedObject::PrintDataTo(StringStream* stream) {
}
void LCallConstantFunction::PrintDataTo(StringStream* stream) {
void LCallJSFunction::PrintDataTo(StringStream* stream) {
stream->Add("= ");
function()->PrintTo(stream);
stream->Add("#%d / ", arity());
}
void LCallWithDescriptor::PrintDataTo(StringStream* stream) {
for (int i = 0; i < InputCount(); i++) {
InputAt(i)->PrintTo(stream);
stream->Add(" ");
}
stream->Add("#%d / ", arity());
}
@ -305,22 +316,6 @@ void LInvokeFunction::PrintDataTo(StringStream* stream) {
}
void LCallKeyed::PrintDataTo(StringStream* stream) {
stream->Add("[rcx] #%d / ", arity());
}
void LCallNamed::PrintDataTo(StringStream* stream) {
SmartArrayPointer<char> name_string = name()->ToCString();
stream->Add("%s #%d / ", name_string.get(), arity());
}
void LCallKnownGlobal::PrintDataTo(StringStream* stream) {
stream->Add("#%d / ", arity());
}
void LCallNew::PrintDataTo(StringStream* stream) {
stream->Add("= ");
constructor()->PrintTo(stream);
@ -570,8 +565,7 @@ LOperand* LChunkBuilder::Use(HValue* value, LUnallocated* operand) {
}
template<int I, int T>
LInstruction* LChunkBuilder::Define(LTemplateInstruction<1, I, T>* instr,
LInstruction* LChunkBuilder::Define(LTemplateResultInstruction<1>* instr,
LUnallocated* result) {
result->set_virtual_register(current_instruction_->id());
instr->set_result(result);
@ -579,41 +573,36 @@ LInstruction* LChunkBuilder::Define(LTemplateInstruction<1, I, T>* instr,
}
template<int I, int T>
LInstruction* LChunkBuilder::DefineAsRegister(
LTemplateInstruction<1, I, T>* instr) {
LTemplateResultInstruction<1>* instr) {
return Define(instr,
new(zone()) LUnallocated(LUnallocated::MUST_HAVE_REGISTER));
}
template<int I, int T>
LInstruction* LChunkBuilder::DefineAsSpilled(
LTemplateInstruction<1, I, T>* instr,
LTemplateResultInstruction<1>* instr,
int index) {
return Define(instr,
new(zone()) LUnallocated(LUnallocated::FIXED_SLOT, index));
}
template<int I, int T>
LInstruction* LChunkBuilder::DefineSameAsFirst(
LTemplateInstruction<1, I, T>* instr) {
LTemplateResultInstruction<1>* instr) {
return Define(instr,
new(zone()) LUnallocated(LUnallocated::SAME_AS_FIRST_INPUT));
}
template<int I, int T>
LInstruction* LChunkBuilder::DefineFixed(LTemplateInstruction<1, I, T>* instr,
LInstruction* LChunkBuilder::DefineFixed(LTemplateResultInstruction<1>* instr,
Register reg) {
return Define(instr, ToUnallocated(reg));
}
template<int I, int T>
LInstruction* LChunkBuilder::DefineFixedDouble(
LTemplateInstruction<1, I, T>* instr,
LTemplateResultInstruction<1>* instr,
XMMRegister reg) {
return Define(instr, ToUnallocated(reg));
}
@ -1084,9 +1073,32 @@ LInstruction* LChunkBuilder::DoGlobalReceiver(HGlobalReceiver* instr) {
}
LInstruction* LChunkBuilder::DoCallConstantFunction(
HCallConstantFunction* instr) {
return MarkAsCall(DefineFixed(new(zone()) LCallConstantFunction, rax), instr);
LInstruction* LChunkBuilder::DoCallJSFunction(
HCallJSFunction* instr) {
LOperand* function = UseFixed(instr->function(), rdi);
LCallJSFunction* result = new(zone()) LCallJSFunction(function);
return MarkAsCall(DefineFixed(result, rax), instr);
}
LInstruction* LChunkBuilder::DoCallWithDescriptor(
HCallWithDescriptor* instr) {
const CallInterfaceDescriptor* descriptor = instr->descriptor();
LOperand* target = UseRegisterOrConstantAtStart(instr->target());
ZoneList<LOperand*> ops(instr->OperandCount(), zone());
ops.Add(target, zone());
for (int i = 1; i < instr->OperandCount(); i++) {
LOperand* op = UseFixed(instr->OperandAt(i),
descriptor->GetParameterRegister(i - 1));
ops.Add(op, zone());
}
LCallWithDescriptor* result = new(zone()) LCallWithDescriptor(
descriptor, ops, zone());
return MarkAsCall(DefineFixed(result, rax), instr);
}
@ -1169,27 +1181,6 @@ LInstruction* LChunkBuilder::DoMathPowHalf(HUnaryMathOperation* instr) {
}
LInstruction* LChunkBuilder::DoCallKeyed(HCallKeyed* instr) {
ASSERT(instr->key()->representation().IsTagged());
LOperand* context = UseFixed(instr->context(), rsi);
LOperand* key = UseFixed(instr->key(), rcx);
LCallKeyed* result = new(zone()) LCallKeyed(context, key);
return MarkAsCall(DefineFixed(result, rax), instr);
}
LInstruction* LChunkBuilder::DoCallNamed(HCallNamed* instr) {
LOperand* context = UseFixed(instr->context(), rsi);
LCallNamed* result = new(zone()) LCallNamed(context);
return MarkAsCall(DefineFixed(result, rax), instr);
}
LInstruction* LChunkBuilder::DoCallKnownGlobal(HCallKnownGlobal* instr) {
return MarkAsCall(DefineFixed(new(zone()) LCallKnownGlobal, rax), instr);
}
LInstruction* LChunkBuilder::DoCallNew(HCallNew* instr) {
LOperand* context = UseFixed(instr->context(), rsi);
LOperand* constructor = UseFixed(instr->constructor(), rdi);

View File

@ -52,11 +52,9 @@ class LCodeGen;
V(BitI) \
V(BoundsCheck) \
V(Branch) \
V(CallConstantFunction) \
V(CallJSFunction) \
V(CallWithDescriptor) \
V(CallFunction) \
V(CallKeyed) \
V(CallKnownGlobal) \
V(CallNamed) \
V(CallNew) \
V(CallNewArray) \
V(CallRuntime) \
@ -299,10 +297,8 @@ class LInstruction : public ZoneObject {
// R = number of result operands (0 or 1).
// I = number of input operands.
// T = number of temporary operands.
template<int R, int I, int T>
class LTemplateInstruction : public LInstruction {
template<int R>
class LTemplateResultInstruction : public LInstruction {
public:
// Allow 0 or 1 output operands.
STATIC_ASSERT(R == 0 || R == 1);
@ -314,6 +310,15 @@ class LTemplateInstruction : public LInstruction {
protected:
EmbeddedContainer<LOperand*, R> results_;
};
// R = number of result operands (0 or 1).
// I = number of input operands.
// T = number of temporary operands.
template<int R, int I, int T>
class LTemplateInstruction : public LTemplateResultInstruction<R> {
protected:
EmbeddedContainer<LOperand*, I> inputs_;
EmbeddedContainer<LOperand*, T> temps_;
@ -1781,18 +1786,62 @@ class LGlobalReceiver V8_FINAL : public LTemplateInstruction<1, 1, 0> {
};
class LCallConstantFunction V8_FINAL : public LTemplateInstruction<1, 0, 0> {
class LCallJSFunction V8_FINAL : public LTemplateInstruction<1, 1, 0> {
public:
DECLARE_CONCRETE_INSTRUCTION(CallConstantFunction, "call-constant-function")
DECLARE_HYDROGEN_ACCESSOR(CallConstantFunction)
explicit LCallJSFunction(LOperand* function) {
inputs_[0] = function;
}
virtual void PrintDataTo(StringStream* stream);
LOperand* function() { return inputs_[0]; }
DECLARE_CONCRETE_INSTRUCTION(CallJSFunction, "call-js-function")
DECLARE_HYDROGEN_ACCESSOR(CallJSFunction)
virtual void PrintDataTo(StringStream* stream) V8_OVERRIDE;
Handle<JSFunction> function() { return hydrogen()->function(); }
int arity() const { return hydrogen()->argument_count() - 1; }
};
class LCallWithDescriptor V8_FINAL : public LTemplateResultInstruction<1> {
public:
LCallWithDescriptor(const CallInterfaceDescriptor* descriptor,
ZoneList<LOperand*>& operands,
Zone* zone)
: descriptor_(descriptor),
inputs_(descriptor->environment_length() + 1, zone) {
ASSERT(descriptor->environment_length() + 1 == operands.length());
inputs_.AddAll(operands, zone);
}
LOperand* target() const { return inputs_[0]; }
private:
DECLARE_CONCRETE_INSTRUCTION(CallWithDescriptor, "call-with-descriptor")
DECLARE_HYDROGEN_ACCESSOR(CallWithDescriptor)
virtual void PrintDataTo(StringStream* stream) V8_OVERRIDE;
int arity() const { return hydrogen()->argument_count() - 1; }
const CallInterfaceDescriptor* descriptor_;
ZoneList<LOperand*> inputs_;
virtual void InternalSetOperandAt(int index,
LOperand* value) V8_FINAL V8_OVERRIDE {
inputs_[index] = value;
}
// Iterator support.
virtual int InputCount() V8_FINAL V8_OVERRIDE { return inputs_.length(); }
virtual LOperand* InputAt(int i) V8_FINAL V8_OVERRIDE { return inputs_[i]; }
virtual int TempCount() V8_FINAL V8_OVERRIDE { return 0; }
virtual LOperand* TempAt(int i) V8_FINAL V8_OVERRIDE { return NULL; }
};
class LInvokeFunction V8_FINAL : public LTemplateInstruction<1, 2, 0> {
public:
LInvokeFunction(LOperand* context, LOperand* function) {
@ -1812,43 +1861,6 @@ class LInvokeFunction V8_FINAL : public LTemplateInstruction<1, 2, 0> {
};
class LCallKeyed V8_FINAL : public LTemplateInstruction<1, 2, 0> {
public:
LCallKeyed(LOperand* context, LOperand* key) {
inputs_[0] = context;
inputs_[1] = key;
}
DECLARE_CONCRETE_INSTRUCTION(CallKeyed, "call-keyed")
DECLARE_HYDROGEN_ACCESSOR(CallKeyed)
LOperand* context() { return inputs_[0]; }
LOperand* key() { return inputs_[1]; }
virtual void PrintDataTo(StringStream* stream) V8_OVERRIDE;
int arity() const { return hydrogen()->argument_count() - 1; }
};
class LCallNamed V8_FINAL : public LTemplateInstruction<1, 1, 0> {
public:
explicit LCallNamed(LOperand* context) {
inputs_[0] = context;
}
LOperand* context() { return inputs_[0]; }
DECLARE_CONCRETE_INSTRUCTION(CallNamed, "call-named")
DECLARE_HYDROGEN_ACCESSOR(CallNamed)
virtual void PrintDataTo(StringStream* stream) V8_OVERRIDE;
Handle<String> name() const { return hydrogen()->name(); }
int arity() const { return hydrogen()->argument_count() - 1; }
};
class LCallFunction V8_FINAL : public LTemplateInstruction<1, 2, 0> {
public:
LCallFunction(LOperand* context, LOperand* function) {
@ -1865,17 +1877,6 @@ class LCallFunction V8_FINAL : public LTemplateInstruction<1, 2, 0> {
};
class LCallKnownGlobal V8_FINAL : public LTemplateInstruction<1, 0, 0> {
public:
DECLARE_CONCRETE_INSTRUCTION(CallKnownGlobal, "call-known-global")
DECLARE_HYDROGEN_ACCESSOR(CallKnownGlobal)
virtual void PrintDataTo(StringStream* stream) V8_OVERRIDE;
int arity() const { return hydrogen()->argument_count() - 1; }
};
class LCallNew V8_FINAL : public LTemplateInstruction<1, 2, 0> {
public:
LCallNew(LOperand* context, LOperand* constructor) {
@ -2718,22 +2719,16 @@ class LChunkBuilder V8_FINAL : public LChunkBuilderBase {
// Methods for setting up define-use relationships.
// Return the same instruction that they are passed.
template<int I, int T>
LInstruction* Define(LTemplateInstruction<1, I, T>* instr,
LUnallocated* result);
template<int I, int T>
LInstruction* DefineAsRegister(LTemplateInstruction<1, I, T>* instr);
template<int I, int T>
LInstruction* DefineAsSpilled(LTemplateInstruction<1, I, T>* instr,
int index);
template<int I, int T>
LInstruction* DefineSameAsFirst(LTemplateInstruction<1, I, T>* instr);
template<int I, int T>
LInstruction* DefineFixed(LTemplateInstruction<1, I, T>* instr,
Register reg);
template<int I, int T>
LInstruction* DefineFixedDouble(LTemplateInstruction<1, I, T>* instr,
XMMRegister reg);
LInstruction* Define(LTemplateResultInstruction<1>* instr,
LUnallocated* result);
LInstruction* DefineAsRegister(LTemplateResultInstruction<1>* instr);
LInstruction* DefineAsSpilled(LTemplateResultInstruction<1>* instr,
int index);
LInstruction* DefineSameAsFirst(LTemplateResultInstruction<1>* instr);
LInstruction* DefineFixed(LTemplateResultInstruction<1>* instr,
Register reg);
LInstruction* DefineFixedDouble(LTemplateResultInstruction<1>* instr,
XMMRegister reg);
// Assigns an environment to an instruction. An instruction which can
// deoptimize must have an environment.
LInstruction* AssignEnvironment(LInstruction* instr);

View File

@ -3505,41 +3505,6 @@ void MacroAssembler::InvokeCode(Register code,
}
void MacroAssembler::InvokeCode(Handle<Code> code,
const ParameterCount& expected,
const ParameterCount& actual,
RelocInfo::Mode rmode,
InvokeFlag flag,
const CallWrapper& call_wrapper) {
// You can't call a function without a valid frame.
ASSERT(flag == JUMP_FUNCTION || has_frame());
Label done;
bool definitely_mismatches = false;
Register dummy = rax;
InvokePrologue(expected,
actual,
code,
dummy,
&done,
&definitely_mismatches,
flag,
Label::kNear,
call_wrapper);
if (!definitely_mismatches) {
if (flag == CALL_FUNCTION) {
call_wrapper.BeforeCall(CallSize(code));
Call(code, rmode);
call_wrapper.AfterCall();
} else {
ASSERT(flag == JUMP_FUNCTION);
Jump(code, rmode);
}
bind(&done);
}
}
void MacroAssembler::InvokeFunction(Register function,
const ParameterCount& actual,
InvokeFlag flag,

View File

@ -349,13 +349,6 @@ class MacroAssembler: public Assembler {
InvokeFlag flag,
const CallWrapper& call_wrapper);
void InvokeCode(Handle<Code> code,
const ParameterCount& expected,
const ParameterCount& actual,
RelocInfo::Mode rmode,
InvokeFlag flag,
const CallWrapper& call_wrapper);
// Invoke the JavaScript function in the given register. Changes the
// current context to the context in the function before invoking.
void InvokeFunction(Register function,