Make the strict-mode calling convention for contextual calls the default one.
BUG= R=dcarney@chromium.org Review URL: https://codereview.chromium.org/131663003 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@18581 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
parent
c30421677d
commit
f2245a9cf9
@ -1089,8 +1089,6 @@ void Builtins::Generate_FunctionCall(MacroAssembler* masm) {
|
||||
__ mov(r4, Operand::Zero());
|
||||
__ jmp(&patch_receiver);
|
||||
|
||||
// Use the global receiver object from the called function as the
|
||||
// receiver.
|
||||
__ bind(&use_global_receiver);
|
||||
__ ldr(r2, ContextOperand(cp, Context::GLOBAL_OBJECT_INDEX));
|
||||
__ ldr(r2, FieldMemOperand(r2, GlobalObject::kGlobalReceiverOffset));
|
||||
@ -1180,7 +1178,7 @@ void Builtins::Generate_FunctionCall(MacroAssembler* masm) {
|
||||
FieldMemOperand(r3, SharedFunctionInfo::kFormalParameterCountOffset));
|
||||
__ SmiUntag(r2);
|
||||
__ ldr(r3, FieldMemOperand(r1, JSFunction::kCodeEntryOffset));
|
||||
__ SetCallKind(r5, CALL_AS_METHOD);
|
||||
__ SetCallKind(r5, CALL_AS_FUNCTION);
|
||||
__ cmp(r2, r0); // Check formal and actual parameter counts.
|
||||
__ Jump(masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(),
|
||||
RelocInfo::CODE_TARGET,
|
||||
@ -1188,7 +1186,7 @@ void Builtins::Generate_FunctionCall(MacroAssembler* masm) {
|
||||
|
||||
ParameterCount expected(0);
|
||||
__ InvokeCode(r3, expected, expected, JUMP_FUNCTION,
|
||||
NullCallWrapper(), CALL_AS_METHOD);
|
||||
NullCallWrapper(), CALL_AS_FUNCTION);
|
||||
}
|
||||
|
||||
|
||||
@ -1282,7 +1280,6 @@ void Builtins::Generate_FunctionApply(MacroAssembler* masm) {
|
||||
__ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION);
|
||||
__ b(&push_receiver);
|
||||
|
||||
// Use the current global receiver object as the receiver.
|
||||
__ bind(&use_global_receiver);
|
||||
__ ldr(r0, ContextOperand(cp, Context::GLOBAL_OBJECT_INDEX));
|
||||
__ ldr(r0, FieldMemOperand(r0, GlobalObject::kGlobalReceiverOffset));
|
||||
@ -1320,7 +1317,7 @@ void Builtins::Generate_FunctionApply(MacroAssembler* masm) {
|
||||
__ cmp(r0, r1);
|
||||
__ b(ne, &loop);
|
||||
|
||||
// Invoke the function.
|
||||
// Call the function.
|
||||
Label call_proxy;
|
||||
ParameterCount actual(r0);
|
||||
__ SmiUntag(r0);
|
||||
@ -1328,18 +1325,18 @@ void Builtins::Generate_FunctionApply(MacroAssembler* masm) {
|
||||
__ CompareObjectType(r1, r2, r2, JS_FUNCTION_TYPE);
|
||||
__ b(ne, &call_proxy);
|
||||
__ InvokeFunction(r1, actual, CALL_FUNCTION,
|
||||
NullCallWrapper(), CALL_AS_METHOD);
|
||||
NullCallWrapper(), CALL_AS_FUNCTION);
|
||||
|
||||
frame_scope.GenerateLeaveFrame();
|
||||
__ add(sp, sp, Operand(3 * kPointerSize));
|
||||
__ Jump(lr);
|
||||
|
||||
// Invoke the function proxy.
|
||||
// Call the function proxy.
|
||||
__ bind(&call_proxy);
|
||||
__ push(r1); // add function proxy as last argument
|
||||
__ add(r0, r0, Operand(1));
|
||||
__ mov(r2, Operand::Zero());
|
||||
__ SetCallKind(r5, CALL_AS_METHOD);
|
||||
__ SetCallKind(r5, CALL_AS_FUNCTION);
|
||||
__ GetBuiltinEntry(r3, Builtins::CALL_FUNCTION_PROXY);
|
||||
__ Call(masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(),
|
||||
RelocInfo::CODE_TARGET);
|
||||
|
@ -3186,43 +3186,9 @@ void CallFunctionStub::Generate(MacroAssembler* masm) {
|
||||
// r1: pushed function (to be verified)
|
||||
__ JumpIfSmi(r1, &non_function);
|
||||
|
||||
// The receiver might implicitly be the global object. This is
|
||||
// indicated by passing the hole as the receiver to the call
|
||||
// function stub.
|
||||
if (ReceiverMightBeImplicit() || ReceiverIsImplicit()) {
|
||||
Label try_call, call, patch_current_context;
|
||||
if (ReceiverMightBeImplicit()) {
|
||||
// Get the receiver from the stack.
|
||||
// function, receiver [, arguments]
|
||||
__ ldr(r4, MemOperand(sp, argc_ * kPointerSize));
|
||||
// Call as function is indicated with the hole.
|
||||
__ CompareRoot(r4, Heap::kTheHoleValueRootIndex);
|
||||
__ b(ne, &try_call);
|
||||
}
|
||||
// Patch the receiver on the stack with the global receiver object.
|
||||
// Goto slow case if we do not have a function.
|
||||
__ CompareObjectType(r1, r3, r3, JS_FUNCTION_TYPE);
|
||||
__ b(ne, &patch_current_context);
|
||||
CallStubCompiler::FetchGlobalProxy(masm, r3, r1);
|
||||
__ str(r3, MemOperand(sp, argc_ * kPointerSize));
|
||||
__ jmp(&call);
|
||||
|
||||
__ bind(&patch_current_context);
|
||||
__ LoadRoot(r4, Heap::kUndefinedValueRootIndex);
|
||||
__ str(r4, MemOperand(sp, argc_ * kPointerSize));
|
||||
__ jmp(&slow);
|
||||
|
||||
__ bind(&try_call);
|
||||
// Get the map of the function object.
|
||||
__ CompareObjectType(r1, r3, r3, JS_FUNCTION_TYPE);
|
||||
__ b(ne, &slow);
|
||||
|
||||
__ bind(&call);
|
||||
} else {
|
||||
// Get the map of the function object.
|
||||
__ CompareObjectType(r1, r3, r3, JS_FUNCTION_TYPE);
|
||||
__ b(ne, &slow);
|
||||
}
|
||||
// Goto slow case if we do not have a function.
|
||||
__ CompareObjectType(r1, r3, r3, JS_FUNCTION_TYPE);
|
||||
__ b(ne, &slow);
|
||||
|
||||
if (RecordCallTarget()) {
|
||||
GenerateRecordCallTarget(masm);
|
||||
@ -3232,17 +3198,6 @@ void CallFunctionStub::Generate(MacroAssembler* masm) {
|
||||
// r1: pushed function
|
||||
ParameterCount actual(argc_);
|
||||
|
||||
if (ReceiverMightBeImplicit()) {
|
||||
Label call_as_function;
|
||||
__ CompareRoot(r4, Heap::kTheHoleValueRootIndex);
|
||||
__ b(eq, &call_as_function);
|
||||
__ InvokeFunction(r1,
|
||||
actual,
|
||||
JUMP_FUNCTION,
|
||||
NullCallWrapper(),
|
||||
CALL_AS_METHOD);
|
||||
__ bind(&call_as_function);
|
||||
}
|
||||
__ InvokeFunction(r1,
|
||||
actual,
|
||||
JUMP_FUNCTION,
|
||||
@ -3281,7 +3236,7 @@ void CallFunctionStub::Generate(MacroAssembler* masm) {
|
||||
__ mov(r0, Operand(argc_)); // Set up the number of arguments.
|
||||
__ mov(r2, Operand::Zero());
|
||||
__ GetBuiltinEntry(r3, Builtins::CALL_NON_FUNCTION);
|
||||
__ SetCallKind(r5, CALL_AS_METHOD);
|
||||
__ SetCallKind(r5, CALL_AS_FUNCTION);
|
||||
__ Jump(masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(),
|
||||
RelocInfo::CODE_TARGET);
|
||||
}
|
||||
|
@ -144,15 +144,25 @@ void FullCodeGenerator::Generate() {
|
||||
}
|
||||
#endif
|
||||
|
||||
// Strict mode functions and builtins need to replace the receiver
|
||||
// with undefined when called as functions (without an explicit
|
||||
// receiver object). r5 is zero for method calls and non-zero for
|
||||
// function calls.
|
||||
if (!info->is_classic_mode() || info->is_native()) {
|
||||
// Classic mode functions and builtins need to replace the receiver with the
|
||||
// global proxy when called as functions (without an explicit receiver
|
||||
// object).
|
||||
if (info->is_classic_mode() && !info->is_native()) {
|
||||
Label ok;
|
||||
__ cmp(r5, Operand::Zero());
|
||||
__ b(eq, &ok);
|
||||
|
||||
int receiver_offset = info->scope()->num_parameters() * kPointerSize;
|
||||
__ LoadRoot(r2, Heap::kUndefinedValueRootIndex);
|
||||
__ str(r2, MemOperand(sp, receiver_offset), ne);
|
||||
__ ldr(r2, MemOperand(sp, receiver_offset));
|
||||
__ CompareRoot(r2, Heap::kUndefinedValueRootIndex);
|
||||
__ b(ne, &ok);
|
||||
|
||||
__ ldr(r2, GlobalObjectOperand());
|
||||
__ ldr(r2, FieldMemOperand(r2, GlobalObject::kGlobalReceiverOffset));
|
||||
|
||||
__ str(r2, MemOperand(sp, receiver_offset));
|
||||
|
||||
__ bind(&ok);
|
||||
}
|
||||
|
||||
// Open a frame scope to indicate that there is a frame on the stack. The
|
||||
@ -2734,7 +2744,7 @@ void FullCodeGenerator::VisitCall(Call* expr) {
|
||||
|
||||
// Record source position for debugger.
|
||||
SetSourcePosition(expr->position());
|
||||
CallFunctionStub stub(arg_count, RECEIVER_MIGHT_BE_IMPLICIT);
|
||||
CallFunctionStub stub(arg_count, NO_CALL_FUNCTION_FLAGS);
|
||||
__ ldr(r1, MemOperand(sp, (arg_count + 1) * kPointerSize));
|
||||
__ CallStub(&stub);
|
||||
RecordJSReturnSite(expr);
|
||||
@ -2776,15 +2786,14 @@ void FullCodeGenerator::VisitCall(Call* expr) {
|
||||
__ push(r0);
|
||||
// The receiver is implicitly the global receiver. Indicate this
|
||||
// by passing the hole to the call function stub.
|
||||
__ LoadRoot(r1, Heap::kTheHoleValueRootIndex);
|
||||
__ LoadRoot(r1, Heap::kUndefinedValueRootIndex);
|
||||
__ push(r1);
|
||||
__ bind(&call);
|
||||
}
|
||||
|
||||
// The receiver is either the global receiver or an object found
|
||||
// by LoadContextSlot. That object could be the hole if the
|
||||
// receiver is implicitly the global object.
|
||||
EmitCallWithStub(expr, RECEIVER_MIGHT_BE_IMPLICIT);
|
||||
// by LoadContextSlot.
|
||||
EmitCallWithStub(expr, NO_CALL_FUNCTION_FLAGS);
|
||||
} else if (property != NULL) {
|
||||
{ PreservePositionScope scope(masm()->positions_recorder());
|
||||
VisitForStackValue(property->obj());
|
||||
@ -2801,12 +2810,10 @@ void FullCodeGenerator::VisitCall(Call* expr) {
|
||||
{ PreservePositionScope scope(masm()->positions_recorder());
|
||||
VisitForStackValue(callee);
|
||||
}
|
||||
// Push the hole as receiver.
|
||||
// It will be correctly replaced in the call stub.
|
||||
__ LoadRoot(r1, Heap::kTheHoleValueRootIndex);
|
||||
__ LoadRoot(r1, Heap::kUndefinedValueRootIndex);
|
||||
__ push(r1);
|
||||
// Emit function call.
|
||||
EmitCallWithStub(expr, RECEIVER_IS_IMPLICIT);
|
||||
EmitCallWithStub(expr, NO_CALL_FUNCTION_FLAGS);
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
@ -3723,7 +3730,7 @@ void FullCodeGenerator::EmitCallFunction(CallRuntime* expr) {
|
||||
__ mov(r1, result_register());
|
||||
ParameterCount count(arg_count);
|
||||
__ InvokeFunction(r1, count, CALL_FUNCTION,
|
||||
NullCallWrapper(), CALL_AS_METHOD);
|
||||
NullCallWrapper(), CALL_AS_FUNCTION);
|
||||
__ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
|
||||
__ jmp(&done);
|
||||
|
||||
|
@ -491,7 +491,7 @@ void CallICBase::GenerateMiss(MacroAssembler* masm,
|
||||
|
||||
// Patch the receiver on the stack.
|
||||
__ bind(&global);
|
||||
CallStubCompiler::FetchGlobalProxy(masm, r2, r1);
|
||||
__ LoadRoot(r2, Heap::kUndefinedValueRootIndex);
|
||||
__ str(r2, MemOperand(sp, argc * kPointerSize));
|
||||
__ bind(&invoke);
|
||||
}
|
||||
|
@ -2511,8 +2511,7 @@ LInstruction* LChunkBuilder::DoEnterInlined(HEnterInlined* instr) {
|
||||
instr->arguments_count(),
|
||||
instr->function(),
|
||||
undefined,
|
||||
instr->inlining_kind(),
|
||||
instr->undefined_receiver());
|
||||
instr->inlining_kind());
|
||||
// Only replay binding of arguments object if it wasn't removed from graph.
|
||||
if (instr->arguments_var() != NULL && instr->arguments_object()->IsLinked()) {
|
||||
inner->Bind(instr->arguments_var(), instr->arguments_object());
|
||||
|
@ -147,15 +147,27 @@ bool LCodeGen::GeneratePrologue() {
|
||||
// fp: Caller's frame pointer.
|
||||
// lr: Caller's pc.
|
||||
|
||||
// Strict mode functions and builtins need to replace the receiver
|
||||
// with undefined when called as functions (without an explicit
|
||||
// receiver object). r5 is zero for method calls and non-zero for
|
||||
// function calls.
|
||||
if (!info_->is_classic_mode() || info_->is_native()) {
|
||||
// Classic mode functions and builtins need to replace the receiver with the
|
||||
// global proxy when called as functions (without an explicit receiver
|
||||
// object).
|
||||
if (info_->this_has_uses() &&
|
||||
info_->is_classic_mode() &&
|
||||
!info_->is_native()) {
|
||||
Label ok;
|
||||
__ cmp(r5, Operand::Zero());
|
||||
int receiver_offset = scope()->num_parameters() * kPointerSize;
|
||||
__ LoadRoot(r2, Heap::kUndefinedValueRootIndex);
|
||||
__ str(r2, MemOperand(sp, receiver_offset), ne);
|
||||
__ b(eq, &ok);
|
||||
|
||||
int receiver_offset = info_->scope()->num_parameters() * kPointerSize;
|
||||
__ ldr(r2, MemOperand(sp, receiver_offset));
|
||||
__ CompareRoot(r2, Heap::kUndefinedValueRootIndex);
|
||||
__ b(ne, &ok);
|
||||
|
||||
__ ldr(r2, GlobalObjectOperand());
|
||||
__ ldr(r2, FieldMemOperand(r2, GlobalObject::kGlobalReceiverOffset));
|
||||
|
||||
__ str(r2, MemOperand(sp, receiver_offset));
|
||||
|
||||
__ bind(&ok);
|
||||
}
|
||||
}
|
||||
|
||||
@ -3494,7 +3506,12 @@ void LCodeGen::DoWrapReceiver(LWrapReceiver* instr) {
|
||||
__ b(&result_in_receiver);
|
||||
|
||||
__ bind(&global_object);
|
||||
CallStubCompiler::FetchGlobalProxy(masm(), receiver, function);
|
||||
__ ldr(receiver, FieldMemOperand(function, JSFunction::kContextOffset));
|
||||
__ ldr(receiver,
|
||||
ContextOperand(receiver,
|
||||
Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX)));
|
||||
__ ldr(receiver,
|
||||
FieldMemOperand(receiver, GlobalObject::kGlobalReceiverOffset));
|
||||
|
||||
if (result.is(receiver)) {
|
||||
__ bind(&result_in_receiver);
|
||||
@ -3552,7 +3569,7 @@ void LCodeGen::DoApplyArguments(LApplyArguments* instr) {
|
||||
// by InvokeFunction.
|
||||
ParameterCount actual(receiver);
|
||||
__ InvokeFunction(function, actual, CALL_FUNCTION,
|
||||
safepoint_generator, CALL_AS_METHOD);
|
||||
safepoint_generator, CALL_AS_FUNCTION);
|
||||
}
|
||||
|
||||
|
||||
@ -3673,7 +3690,7 @@ void LCodeGen::DoCallConstantFunction(LCallConstantFunction* instr) {
|
||||
instr->hydrogen()->formal_parameter_count(),
|
||||
instr->arity(),
|
||||
instr,
|
||||
CALL_AS_METHOD,
|
||||
CALL_AS_FUNCTION,
|
||||
R1_UNINITIALIZED);
|
||||
}
|
||||
|
||||
@ -3951,13 +3968,13 @@ void LCodeGen::DoInvokeFunction(LInvokeFunction* instr) {
|
||||
LPointerMap* pointers = instr->pointer_map();
|
||||
SafepointGenerator generator(this, pointers, Safepoint::kLazyDeopt);
|
||||
ParameterCount count(instr->arity());
|
||||
__ InvokeFunction(r1, count, CALL_FUNCTION, generator, CALL_AS_METHOD);
|
||||
__ InvokeFunction(r1, count, CALL_FUNCTION, generator, CALL_AS_FUNCTION);
|
||||
} else {
|
||||
CallKnownFunction(known_function,
|
||||
instr->hydrogen()->formal_parameter_count(),
|
||||
instr->arity(),
|
||||
instr,
|
||||
CALL_AS_METHOD,
|
||||
CALL_AS_FUNCTION,
|
||||
R1_CONTAINS_TARGET);
|
||||
}
|
||||
}
|
||||
@ -3992,10 +4009,7 @@ void LCodeGen::DoCallFunction(LCallFunction* instr) {
|
||||
ASSERT(ToRegister(instr->result()).is(r0));
|
||||
|
||||
int arity = instr->arity();
|
||||
CallFunctionFlags flags =
|
||||
instr->hydrogen()->IsContextualCall() ?
|
||||
RECEIVER_IS_IMPLICIT : NO_CALL_FUNCTION_FLAGS;
|
||||
CallFunctionStub stub(arity, flags);
|
||||
CallFunctionStub stub(arity, NO_CALL_FUNCTION_FLAGS);
|
||||
if (instr->hydrogen()->IsTailCall()) {
|
||||
if (NeedsEagerFrame()) __ mov(sp, fp);
|
||||
__ Jump(stub.GetCode(isolate()), RelocInfo::CODE_TARGET);
|
||||
|
@ -2341,23 +2341,11 @@ void StubCompiler::GenerateBooleanCheck(Register object, Label* miss) {
|
||||
}
|
||||
|
||||
|
||||
void CallStubCompiler::PatchGlobalProxy(Handle<Object> object,
|
||||
Handle<JSFunction> function) {
|
||||
void CallStubCompiler::PatchImplicitReceiver(Handle<Object> object) {
|
||||
if (object->IsGlobalObject()) {
|
||||
const int argc = arguments().immediate();
|
||||
const int receiver_offset = argc * kPointerSize;
|
||||
__ Move(r3, handle(function->context()->global_proxy()));
|
||||
__ str(r3, MemOperand(sp, receiver_offset));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void CallStubCompiler::PatchGlobalProxy(Handle<Object> object,
|
||||
Register function) {
|
||||
if (object->IsGlobalObject()) {
|
||||
FetchGlobalProxy(masm(), r3, function);
|
||||
const int argc = arguments().immediate();
|
||||
const int receiver_offset = argc * kPointerSize;
|
||||
__ LoadRoot(r3, Heap::kUndefinedValueRootIndex);
|
||||
__ str(r3, MemOperand(sp, receiver_offset));
|
||||
}
|
||||
}
|
||||
@ -2456,7 +2444,7 @@ void CallStubCompiler::GenerateJumpFunction(Handle<Object> object,
|
||||
ASSERT(function.is(r1));
|
||||
// Check that the function really is a function.
|
||||
GenerateFunctionCheck(function, r3, miss);
|
||||
PatchGlobalProxy(object, function);
|
||||
PatchImplicitReceiver(object);
|
||||
|
||||
// Invoke the function.
|
||||
__ InvokeFunction(r1, arguments(), JUMP_FUNCTION,
|
||||
@ -2574,15 +2562,6 @@ Handle<Code> StoreStubCompiler::CompileStoreCallback(
|
||||
#define __ ACCESS_MASM(masm)
|
||||
|
||||
|
||||
void CallStubCompiler::FetchGlobalProxy(MacroAssembler* masm,
|
||||
Register target,
|
||||
Register function) {
|
||||
__ ldr(target, FieldMemOperand(function, JSFunction::kContextOffset));
|
||||
__ ldr(target, ContextOperand(target, Context::GLOBAL_OBJECT_INDEX));
|
||||
__ ldr(target, FieldMemOperand(target, GlobalObject::kGlobalReceiverOffset));
|
||||
}
|
||||
|
||||
|
||||
void StoreStubCompiler::GenerateStoreViaSetter(
|
||||
MacroAssembler* masm,
|
||||
Handle<JSFunction> setter) {
|
||||
|
@ -1173,6 +1173,15 @@ MUST_USE_RESULT static MaybeObject* HandleApiCallHelper(
|
||||
fun_data = *desc;
|
||||
}
|
||||
|
||||
SharedFunctionInfo* shared = function->shared();
|
||||
if (shared->is_classic_mode() && !shared->native()) {
|
||||
Object* recv = args[0];
|
||||
ASSERT(!recv->IsNull());
|
||||
if (recv->IsUndefined()) {
|
||||
args[0] = function->context()->global_object()->global_receiver();
|
||||
}
|
||||
}
|
||||
|
||||
Object* raw_holder = TypeCheck(heap, args.length(), &args[0], fun_data);
|
||||
|
||||
if (raw_holder->IsNull()) {
|
||||
|
@ -595,7 +595,6 @@ void ArgumentsAccessStub::PrintName(StringStream* stream) {
|
||||
|
||||
void CallFunctionStub::PrintName(StringStream* stream) {
|
||||
stream->Add("CallFunctionStub_Args%d", argc_);
|
||||
if (ReceiverMightBeImplicit()) stream->Add("_Implicit");
|
||||
if (RecordCallTarget()) stream->Add("_Recording");
|
||||
}
|
||||
|
||||
|
@ -1553,8 +1553,8 @@ class CallFunctionStub: public PlatformCodeStub {
|
||||
virtual void PrintName(StringStream* stream);
|
||||
|
||||
// Minor key encoding in 32 bits with Bitfield <Type, shift, size>.
|
||||
class FlagBits: public BitField<CallFunctionFlags, 0, 3> {};
|
||||
class ArgcBits: public BitField<unsigned, 3, 32 - 3> {};
|
||||
class FlagBits: public BitField<CallFunctionFlags, 0, 1> {};
|
||||
class ArgcBits: public BitField<unsigned, 1, 32 - 1> {};
|
||||
|
||||
Major MajorKey() { return CallFunction; }
|
||||
int MinorKey() {
|
||||
@ -1562,14 +1562,6 @@ class CallFunctionStub: public PlatformCodeStub {
|
||||
return FlagBits::encode(flags_) | ArgcBits::encode(argc_);
|
||||
}
|
||||
|
||||
bool ReceiverMightBeImplicit() {
|
||||
return (flags_ & RECEIVER_MIGHT_BE_IMPLICIT) != 0;
|
||||
}
|
||||
|
||||
bool ReceiverIsImplicit() {
|
||||
return (flags_ & RECEIVER_IS_IMPLICIT) != 0;
|
||||
}
|
||||
|
||||
bool RecordCallTarget() {
|
||||
return (flags_ & RECORD_CALL_TARGET) != 0;
|
||||
}
|
||||
|
@ -59,7 +59,8 @@ CompilationInfo::CompilationInfo(Handle<Script> script,
|
||||
: flags_(LanguageModeField::encode(CLASSIC_MODE)),
|
||||
script_(script),
|
||||
osr_ast_id_(BailoutId::None()),
|
||||
parameter_count_(0) {
|
||||
parameter_count_(0),
|
||||
this_has_uses_(true) {
|
||||
Initialize(script->GetIsolate(), BASE, zone);
|
||||
}
|
||||
|
||||
@ -70,7 +71,8 @@ CompilationInfo::CompilationInfo(Handle<SharedFunctionInfo> shared_info,
|
||||
shared_info_(shared_info),
|
||||
script_(Handle<Script>(Script::cast(shared_info->script()))),
|
||||
osr_ast_id_(BailoutId::None()),
|
||||
parameter_count_(0) {
|
||||
parameter_count_(0),
|
||||
this_has_uses_(true) {
|
||||
Initialize(script_->GetIsolate(), BASE, zone);
|
||||
}
|
||||
|
||||
@ -83,7 +85,8 @@ CompilationInfo::CompilationInfo(Handle<JSFunction> closure,
|
||||
script_(Handle<Script>(Script::cast(shared_info_->script()))),
|
||||
context_(closure->context()),
|
||||
osr_ast_id_(BailoutId::None()),
|
||||
parameter_count_(0) {
|
||||
parameter_count_(0),
|
||||
this_has_uses_(true) {
|
||||
Initialize(script_->GetIsolate(), BASE, zone);
|
||||
}
|
||||
|
||||
@ -94,7 +97,8 @@ CompilationInfo::CompilationInfo(HydrogenCodeStub* stub,
|
||||
: flags_(LanguageModeField::encode(CLASSIC_MODE) |
|
||||
IsLazy::encode(true)),
|
||||
osr_ast_id_(BailoutId::None()),
|
||||
parameter_count_(0) {
|
||||
parameter_count_(0),
|
||||
this_has_uses_(true) {
|
||||
Initialize(isolate, STUB, zone);
|
||||
code_stub_ = stub;
|
||||
}
|
||||
@ -399,6 +403,7 @@ OptimizedCompileJob::Status OptimizedCompileJob::CreateGraph() {
|
||||
: new(info()->zone()) HOptimizedGraphBuilder(info());
|
||||
|
||||
Timer t(this, &time_taken_to_create_graph_);
|
||||
info()->set_this_has_uses(false);
|
||||
graph_ = graph_builder_->CreateGraph();
|
||||
|
||||
if (isolate()->has_pending_exception()) {
|
||||
|
@ -102,6 +102,13 @@ class CompilationInfo {
|
||||
ASSERT(IsStub());
|
||||
parameter_count_ = parameter_count;
|
||||
}
|
||||
|
||||
void set_this_has_uses(bool has_no_uses) {
|
||||
this_has_uses_ = has_no_uses;
|
||||
}
|
||||
bool this_has_uses() {
|
||||
return this_has_uses_;
|
||||
}
|
||||
void SetLanguageMode(LanguageMode language_mode) {
|
||||
ASSERT(this->language_mode() == CLASSIC_MODE ||
|
||||
this->language_mode() == language_mode ||
|
||||
@ -441,6 +448,8 @@ class CompilationInfo {
|
||||
// Number of parameters used for compilation of stubs that require arguments.
|
||||
int parameter_count_;
|
||||
|
||||
bool this_has_uses_;
|
||||
|
||||
Handle<Foreign> object_wrapper_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(CompilationInfo);
|
||||
|
@ -1993,11 +1993,10 @@ class HEnterInlined V8_FINAL : public HTemplateInstruction<0> {
|
||||
FunctionLiteral* function,
|
||||
InliningKind inlining_kind,
|
||||
Variable* arguments_var,
|
||||
HArgumentsObject* arguments_object,
|
||||
bool undefined_receiver) {
|
||||
HArgumentsObject* arguments_object) {
|
||||
return new(zone) HEnterInlined(closure, arguments_count, function,
|
||||
inlining_kind, arguments_var,
|
||||
arguments_object, undefined_receiver, zone);
|
||||
arguments_object, zone);
|
||||
}
|
||||
|
||||
void RegisterReturnTarget(HBasicBlock* return_target, Zone* zone);
|
||||
@ -2011,7 +2010,6 @@ class HEnterInlined V8_FINAL : public HTemplateInstruction<0> {
|
||||
void set_arguments_pushed() { arguments_pushed_ = true; }
|
||||
FunctionLiteral* function() const { return function_; }
|
||||
InliningKind inlining_kind() const { return inlining_kind_; }
|
||||
bool undefined_receiver() const { return undefined_receiver_; }
|
||||
|
||||
virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
|
||||
return Representation::None();
|
||||
@ -2029,7 +2027,6 @@ class HEnterInlined V8_FINAL : public HTemplateInstruction<0> {
|
||||
InliningKind inlining_kind,
|
||||
Variable* arguments_var,
|
||||
HArgumentsObject* arguments_object,
|
||||
bool undefined_receiver,
|
||||
Zone* zone)
|
||||
: closure_(closure),
|
||||
arguments_count_(arguments_count),
|
||||
@ -2038,7 +2035,6 @@ class HEnterInlined V8_FINAL : public HTemplateInstruction<0> {
|
||||
inlining_kind_(inlining_kind),
|
||||
arguments_var_(arguments_var),
|
||||
arguments_object_(arguments_object),
|
||||
undefined_receiver_(undefined_receiver),
|
||||
return_targets_(2, zone) {
|
||||
}
|
||||
|
||||
@ -2049,7 +2045,6 @@ class HEnterInlined V8_FINAL : public HTemplateInstruction<0> {
|
||||
InliningKind inlining_kind_;
|
||||
Variable* arguments_var_;
|
||||
HArgumentsObject* arguments_object_;
|
||||
bool undefined_receiver_;
|
||||
ZoneList<HBasicBlock*> return_targets_;
|
||||
};
|
||||
|
||||
|
@ -4687,6 +4687,10 @@ HValue* HOptimizedGraphBuilder::BuildContextChainWalk(Variable* var) {
|
||||
|
||||
|
||||
void HOptimizedGraphBuilder::VisitVariableProxy(VariableProxy* expr) {
|
||||
if (expr->is_this()) {
|
||||
current_info()->set_this_has_uses(true);
|
||||
}
|
||||
|
||||
ASSERT(!HasStackOverflow());
|
||||
ASSERT(current_block() != NULL);
|
||||
ASSERT(current_block()->HasPredecessor());
|
||||
@ -7210,15 +7214,13 @@ bool HOptimizedGraphBuilder::TryInline(CallKind call_kind,
|
||||
this, &target_info, inlining_kind);
|
||||
|
||||
HConstant* undefined = graph()->GetConstantUndefined();
|
||||
bool undefined_receiver = HEnvironment::UseUndefinedReceiver(
|
||||
target, function, call_kind, inlining_kind);
|
||||
|
||||
HEnvironment* inner_env =
|
||||
environment()->CopyForInlining(target,
|
||||
arguments_count,
|
||||
function,
|
||||
undefined,
|
||||
function_state()->inlining_kind(),
|
||||
undefined_receiver);
|
||||
function_state()->inlining_kind());
|
||||
|
||||
HConstant* context = Add<HConstant>(Handle<Context>(target->context()));
|
||||
inner_env->BindContext(context);
|
||||
@ -7244,7 +7246,7 @@ bool HOptimizedGraphBuilder::TryInline(CallKind call_kind,
|
||||
Add<HEnterInlined>(target, arguments_count, function,
|
||||
function_state()->inlining_kind(),
|
||||
function->scope()->arguments(),
|
||||
arguments_object, undefined_receiver);
|
||||
arguments_object);
|
||||
function_state()->set_entry(enter_inlined);
|
||||
|
||||
VisitDeclarations(target_info.scope()->declarations());
|
||||
@ -7667,24 +7669,22 @@ bool HOptimizedGraphBuilder::TryCallApply(Call* expr) {
|
||||
}
|
||||
|
||||
|
||||
void HOptimizedGraphBuilder::InstallGlobalReceiverInExpressionStack(
|
||||
int receiver_index,
|
||||
Handle<JSFunction> function) {
|
||||
// TODO(dcarney): Fix deserializer to be able to hookup the global receiver
|
||||
// and object during deserialization and embed the global receiver here
|
||||
// directly.
|
||||
// Install global receiver on stack.
|
||||
HValue* function_constant = Add<HConstant>(function);
|
||||
HValue* context = Add<HLoadNamedField>(
|
||||
function_constant,
|
||||
HObjectAccess::ForJSObjectOffset(JSFunction::kContextOffset));
|
||||
HValue* global_object = Add<HLoadNamedField>(
|
||||
context,
|
||||
HObjectAccess::ForContextSlot(Context::GLOBAL_OBJECT_INDEX));
|
||||
HValue* global_receiver = Add<HLoadNamedField>(
|
||||
global_object,
|
||||
HObjectAccess::ForJSObjectOffset(GlobalObject::kGlobalReceiverOffset));
|
||||
environment()->SetExpressionStackAt(receiver_index, global_receiver);
|
||||
HValue* HOptimizedGraphBuilder::ImplicitReceiverFor(HValue* function,
|
||||
Handle<JSFunction> target) {
|
||||
SharedFunctionInfo* shared = target->shared();
|
||||
if (shared->is_classic_mode() && !shared->native()) {
|
||||
HValue* context = Add<HLoadNamedField>(
|
||||
function,
|
||||
HObjectAccess::ForJSObjectOffset(JSFunction::kContextOffset));
|
||||
HValue* global_object = Add<HLoadNamedField>(
|
||||
context,
|
||||
HObjectAccess::ForContextSlot(Context::GLOBAL_OBJECT_INDEX));
|
||||
return Add<HLoadNamedField>(
|
||||
global_object,
|
||||
HObjectAccess::ForJSObjectOffset(
|
||||
GlobalObject::kGlobalReceiverOffset));
|
||||
}
|
||||
return graph()->GetConstantUndefined();
|
||||
}
|
||||
|
||||
|
||||
@ -7802,17 +7802,17 @@ void HOptimizedGraphBuilder::VisitCall(Call* expr) {
|
||||
// code generated by the full code generator expects it.
|
||||
HGlobalObject* global_object = Add<HGlobalObject>();
|
||||
Push(global_object);
|
||||
|
||||
CHECK_ALIVE(VisitExpressions(expr->arguments()));
|
||||
|
||||
CHECK_ALIVE(VisitForValue(expr->expression()));
|
||||
HValue* function = Pop();
|
||||
Add<HCheckValue>(function, expr->target());
|
||||
|
||||
// Install global receiver on stack.
|
||||
// Patch the global object on the stack by the expected receiver.
|
||||
HValue* receiver = ImplicitReceiverFor(function, expr->target());
|
||||
const int receiver_index = argument_count - 1;
|
||||
ASSERT(environment()->ExpressionStackAt(receiver_index)->
|
||||
IsGlobalObject());
|
||||
InstallGlobalReceiverInExpressionStack(receiver_index, expr->target());
|
||||
environment()->SetExpressionStackAt(receiver_index, receiver);
|
||||
|
||||
if (TryInlineBuiltinFunctionCall(expr, false)) { // Nothing to drop.
|
||||
if (FLAG_trace_inlining) {
|
||||
@ -7831,6 +7831,8 @@ void HOptimizedGraphBuilder::VisitCall(Call* expr) {
|
||||
if (CallStubCompiler::HasCustomCallGenerator(expr->target())) {
|
||||
// We're about to install a contextual IC, which expects the global
|
||||
// object as receiver rather than the global proxy.
|
||||
HGlobalObject* global_object = Add<HGlobalObject>();
|
||||
const int receiver_index = argument_count - 1;
|
||||
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.
|
||||
@ -7853,17 +7855,13 @@ void HOptimizedGraphBuilder::VisitCall(Call* expr) {
|
||||
// evaluation of the arguments.
|
||||
CHECK_ALIVE(VisitForValue(expr->expression()));
|
||||
HValue* function = Top();
|
||||
HGlobalObject* global = Add<HGlobalObject>();
|
||||
HGlobalReceiver* receiver = Add<HGlobalReceiver>(global);
|
||||
Push(receiver);
|
||||
CHECK_ALIVE(VisitExpressions(expr->arguments()));
|
||||
|
||||
Add<HCheckValue>(function, expr->target());
|
||||
|
||||
// Install global receiver on stack.
|
||||
const int receiver_index = argument_count - 1;
|
||||
ASSERT(environment()->ExpressionStackAt(receiver_index)->
|
||||
IsGlobalReceiver());
|
||||
InstallGlobalReceiverInExpressionStack(receiver_index, expr->target());
|
||||
HValue* receiver = ImplicitReceiverFor(function, expr->target());
|
||||
Push(receiver);
|
||||
|
||||
CHECK_ALIVE(VisitExpressions(expr->arguments()));
|
||||
|
||||
if (TryInlineBuiltinFunctionCall(expr, true)) { // Drop the function.
|
||||
if (FLAG_trace_inlining) {
|
||||
@ -7885,7 +7883,7 @@ void HOptimizedGraphBuilder::VisitCall(Call* expr) {
|
||||
} else {
|
||||
CHECK_ALIVE(VisitForValue(expr->expression()));
|
||||
HValue* function = Top();
|
||||
HValue* receiver = graph()->GetConstantHole();
|
||||
HValue* receiver = graph()->GetConstantUndefined();
|
||||
Push(Add<HPushArgument>(receiver));
|
||||
CHECK_ALIVE(VisitArgumentList(expr->arguments()));
|
||||
call = New<HCallFunction>(
|
||||
@ -10571,8 +10569,7 @@ HEnvironment* HEnvironment::CopyForInlining(
|
||||
int arguments,
|
||||
FunctionLiteral* function,
|
||||
HConstant* undefined,
|
||||
InliningKind inlining_kind,
|
||||
bool undefined_receiver) const {
|
||||
InliningKind inlining_kind) const {
|
||||
ASSERT(frame_type() == JS_FUNCTION);
|
||||
|
||||
// Outer environment is a copy of this one without the arguments.
|
||||
@ -10610,12 +10607,6 @@ HEnvironment* HEnvironment::CopyForInlining(
|
||||
ExpressionStackAt(arguments - i) : undefined;
|
||||
inner->SetValueAt(i, push);
|
||||
}
|
||||
// If the function we are inlining is a strict mode function or a
|
||||
// builtin function, pass undefined as the receiver for function
|
||||
// calls (instead of the global receiver).
|
||||
if (undefined_receiver) {
|
||||
inner->SetValueAt(0, undefined);
|
||||
}
|
||||
inner->SetValueAt(arity + 1, context());
|
||||
for (int i = arity + 2; i < inner->length(); ++i) {
|
||||
inner->SetValueAt(i, undefined);
|
||||
|
@ -640,16 +640,7 @@ class HEnvironment V8_FINAL : public ZoneObject {
|
||||
int arguments,
|
||||
FunctionLiteral* function,
|
||||
HConstant* undefined,
|
||||
InliningKind inlining_kind,
|
||||
bool undefined_receiver) const;
|
||||
|
||||
static bool UseUndefinedReceiver(Handle<JSFunction> closure,
|
||||
FunctionLiteral* function,
|
||||
CallKind call_kind,
|
||||
InliningKind inlining_kind) {
|
||||
return (closure->shared()->native() || !function->is_classic_mode()) &&
|
||||
call_kind == CALL_AS_FUNCTION && inlining_kind != CONSTRUCT_CALL_RETURN;
|
||||
}
|
||||
InliningKind inlining_kind) const;
|
||||
|
||||
HEnvironment* DiscardInlined(bool drop_extra) {
|
||||
HEnvironment* outer = outer_;
|
||||
@ -2203,6 +2194,9 @@ class HOptimizedGraphBuilder : public HGraphBuilder, public AstVisitor {
|
||||
// Try to optimize fun.apply(receiver, arguments) pattern.
|
||||
bool TryCallApply(Call* expr);
|
||||
|
||||
HValue* ImplicitReceiverFor(HValue* function,
|
||||
Handle<JSFunction> target);
|
||||
|
||||
int InliningAstSize(Handle<JSFunction> target);
|
||||
bool TryInline(CallKind call_kind,
|
||||
Handle<JSFunction> target,
|
||||
@ -2503,9 +2497,6 @@ class HOptimizedGraphBuilder : public HGraphBuilder, public AstVisitor {
|
||||
HValue* receiver,
|
||||
Handle<Map> receiver_map);
|
||||
|
||||
void InstallGlobalReceiverInExpressionStack(int index,
|
||||
Handle<JSFunction> function);
|
||||
|
||||
// The translation state of the currently-being-translated function.
|
||||
FunctionState* function_state_;
|
||||
|
||||
|
@ -781,10 +781,10 @@ void Builtins::Generate_FunctionCall(MacroAssembler* masm) {
|
||||
__ mov(edi, Operand(esp, eax, times_4, 1 * kPointerSize));
|
||||
__ jmp(&patch_receiver);
|
||||
|
||||
// Use the global receiver object from the called function as the
|
||||
// receiver.
|
||||
__ bind(&use_global_receiver);
|
||||
CallStubCompiler::FetchGlobalProxy(masm, ebx, edi);
|
||||
__ mov(ebx,
|
||||
Operand(esi, Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX)));
|
||||
__ mov(ebx, FieldOperand(ebx, GlobalObject::kGlobalReceiverOffset));
|
||||
|
||||
__ bind(&patch_receiver);
|
||||
__ mov(Operand(esp, eax, times_4, 0), ebx);
|
||||
@ -855,14 +855,14 @@ void Builtins::Generate_FunctionCall(MacroAssembler* masm) {
|
||||
FieldOperand(edx, SharedFunctionInfo::kFormalParameterCountOffset));
|
||||
__ mov(edx, FieldOperand(edi, JSFunction::kCodeEntryOffset));
|
||||
__ SmiUntag(ebx);
|
||||
__ SetCallKind(ecx, CALL_AS_METHOD);
|
||||
__ SetCallKind(ecx, CALL_AS_FUNCTION);
|
||||
__ cmp(eax, ebx);
|
||||
__ j(not_equal,
|
||||
masm->isolate()->builtins()->ArgumentsAdaptorTrampoline());
|
||||
|
||||
ParameterCount expected(0);
|
||||
__ InvokeCode(edx, expected, expected, JUMP_FUNCTION, NullCallWrapper(),
|
||||
CALL_AS_METHOD);
|
||||
CALL_AS_FUNCTION);
|
||||
}
|
||||
|
||||
|
||||
@ -914,7 +914,7 @@ void Builtins::Generate_FunctionApply(MacroAssembler* masm) {
|
||||
__ mov(ebx, Operand(ebp, kReceiverOffset));
|
||||
|
||||
// Check that the function is a JS function (otherwise it must be a proxy).
|
||||
Label push_receiver;
|
||||
Label push_receiver, use_global_receiver;
|
||||
__ mov(edi, Operand(ebp, kFunctionOffset));
|
||||
__ CmpObjectType(edi, JS_FUNCTION_TYPE, ecx);
|
||||
__ j(not_equal, &push_receiver);
|
||||
@ -924,7 +924,7 @@ void Builtins::Generate_FunctionApply(MacroAssembler* masm) {
|
||||
|
||||
// Compute the receiver.
|
||||
// Do not transform the receiver for strict mode functions.
|
||||
Label call_to_object, use_global_receiver;
|
||||
Label call_to_object;
|
||||
__ mov(ecx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset));
|
||||
__ test_b(FieldOperand(ecx, SharedFunctionInfo::kStrictModeByteOffset),
|
||||
1 << SharedFunctionInfo::kStrictModeBitWithinByte);
|
||||
@ -955,9 +955,10 @@ void Builtins::Generate_FunctionApply(MacroAssembler* masm) {
|
||||
__ mov(ebx, eax);
|
||||
__ jmp(&push_receiver);
|
||||
|
||||
// Use the current global receiver object as the receiver.
|
||||
__ bind(&use_global_receiver);
|
||||
CallStubCompiler::FetchGlobalProxy(masm, ebx, edi);
|
||||
__ mov(ebx,
|
||||
Operand(esi, Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX)));
|
||||
__ mov(ebx, FieldOperand(ebx, GlobalObject::kGlobalReceiverOffset));
|
||||
|
||||
// Push the receiver.
|
||||
__ bind(&push_receiver);
|
||||
@ -990,7 +991,7 @@ void Builtins::Generate_FunctionApply(MacroAssembler* masm) {
|
||||
__ cmp(ecx, Operand(ebp, kLimitOffset));
|
||||
__ j(not_equal, &loop);
|
||||
|
||||
// Invoke the function.
|
||||
// Call the function.
|
||||
Label call_proxy;
|
||||
__ mov(eax, ecx);
|
||||
ParameterCount actual(eax);
|
||||
@ -999,17 +1000,17 @@ void Builtins::Generate_FunctionApply(MacroAssembler* masm) {
|
||||
__ CmpObjectType(edi, JS_FUNCTION_TYPE, ecx);
|
||||
__ j(not_equal, &call_proxy);
|
||||
__ InvokeFunction(edi, actual, CALL_FUNCTION,
|
||||
NullCallWrapper(), CALL_AS_METHOD);
|
||||
NullCallWrapper(), CALL_AS_FUNCTION);
|
||||
|
||||
frame_scope.GenerateLeaveFrame();
|
||||
__ ret(3 * kPointerSize); // remove this, receiver, and arguments
|
||||
|
||||
// Invoke the function proxy.
|
||||
// Call the function proxy.
|
||||
__ bind(&call_proxy);
|
||||
__ push(edi); // add function proxy as last argument
|
||||
__ inc(eax);
|
||||
__ Set(ebx, Immediate(0));
|
||||
__ SetCallKind(ecx, CALL_AS_METHOD);
|
||||
__ SetCallKind(ecx, CALL_AS_FUNCTION);
|
||||
__ GetBuiltinEntry(edx, Builtins::CALL_FUNCTION_PROXY);
|
||||
__ call(masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(),
|
||||
RelocInfo::CODE_TARGET);
|
||||
|
@ -2520,43 +2520,9 @@ void CallFunctionStub::Generate(MacroAssembler* masm) {
|
||||
// Check that the function really is a JavaScript function.
|
||||
__ JumpIfSmi(edi, &non_function);
|
||||
|
||||
// The receiver might implicitly be the global object. This is
|
||||
// indicated by passing the hole as the receiver to the call
|
||||
// function stub.
|
||||
if (ReceiverMightBeImplicit() || ReceiverIsImplicit()) {
|
||||
Label try_call, call, patch_current_context;
|
||||
if (ReceiverMightBeImplicit()) {
|
||||
// Get the receiver from the stack.
|
||||
// +1 ~ return address
|
||||
__ mov(eax, Operand(esp, (argc_ + 1) * kPointerSize));
|
||||
// Call as function is indicated with the hole.
|
||||
__ cmp(eax, isolate->factory()->the_hole_value());
|
||||
__ j(not_equal, &try_call, Label::kNear);
|
||||
}
|
||||
// Patch the receiver on the stack with the global receiver object.
|
||||
// Goto slow case if we do not have a function.
|
||||
__ CmpObjectType(edi, JS_FUNCTION_TYPE, ecx);
|
||||
__ j(not_equal, &patch_current_context);
|
||||
CallStubCompiler::FetchGlobalProxy(masm, ecx, edi);
|
||||
__ mov(Operand(esp, (argc_ + 1) * kPointerSize), ecx);
|
||||
__ jmp(&call, Label::kNear);
|
||||
|
||||
__ bind(&patch_current_context);
|
||||
__ mov(edx, isolate->factory()->undefined_value());
|
||||
__ mov(Operand(esp, (argc_ + 1) * kPointerSize), edx);
|
||||
__ jmp(&slow);
|
||||
|
||||
__ bind(&try_call);
|
||||
// Goto slow case if we do not have a function.
|
||||
__ CmpObjectType(edi, JS_FUNCTION_TYPE, ecx);
|
||||
__ j(not_equal, &slow);
|
||||
|
||||
__ bind(&call);
|
||||
} else {
|
||||
// Goto slow case if we do not have a function.
|
||||
__ CmpObjectType(edi, JS_FUNCTION_TYPE, ecx);
|
||||
__ j(not_equal, &slow);
|
||||
}
|
||||
// Goto slow case if we do not have a function.
|
||||
__ CmpObjectType(edi, JS_FUNCTION_TYPE, ecx);
|
||||
__ j(not_equal, &slow);
|
||||
|
||||
if (RecordCallTarget()) {
|
||||
GenerateRecordCallTarget(masm);
|
||||
@ -2565,17 +2531,6 @@ void CallFunctionStub::Generate(MacroAssembler* masm) {
|
||||
// Fast-case: Just invoke the function.
|
||||
ParameterCount actual(argc_);
|
||||
|
||||
if (ReceiverMightBeImplicit()) {
|
||||
Label call_as_function;
|
||||
__ cmp(eax, isolate->factory()->the_hole_value());
|
||||
__ j(equal, &call_as_function);
|
||||
__ InvokeFunction(edi,
|
||||
actual,
|
||||
JUMP_FUNCTION,
|
||||
NullCallWrapper(),
|
||||
CALL_AS_METHOD);
|
||||
__ bind(&call_as_function);
|
||||
}
|
||||
__ InvokeFunction(edi,
|
||||
actual,
|
||||
JUMP_FUNCTION,
|
||||
@ -2612,7 +2567,7 @@ void CallFunctionStub::Generate(MacroAssembler* masm) {
|
||||
__ mov(Operand(esp, (argc_ + 1) * kPointerSize), edi);
|
||||
__ Set(eax, Immediate(argc_));
|
||||
__ Set(ebx, Immediate(0));
|
||||
__ SetCallKind(ecx, CALL_AS_METHOD);
|
||||
__ SetCallKind(ecx, CALL_AS_FUNCTION);
|
||||
__ GetBuiltinEntry(edx, Builtins::CALL_NON_FUNCTION);
|
||||
Handle<Code> adaptor = isolate->builtins()->ArgumentsAdaptorTrampoline();
|
||||
__ jmp(adaptor, RelocInfo::CODE_TARGET);
|
||||
|
@ -133,22 +133,26 @@ void FullCodeGenerator::Generate() {
|
||||
}
|
||||
#endif
|
||||
|
||||
// Strict mode functions and builtins need to replace the receiver
|
||||
// with undefined when called as functions (without an explicit
|
||||
// receiver object). ecx is zero for method calls and non-zero for
|
||||
// function calls.
|
||||
if (!info->is_classic_mode() || info->is_native()) {
|
||||
// Classic mode functions and builtins need to replace the receiver with the
|
||||
// global proxy when called as functions (without an explicit receiver
|
||||
// object).
|
||||
if (info->is_classic_mode() && !info->is_native()) {
|
||||
Label ok;
|
||||
__ test(ecx, ecx);
|
||||
__ j(zero, &ok, Label::kNear);
|
||||
|
||||
// +1 for return address.
|
||||
int receiver_offset = (info->scope()->num_parameters() + 1) * kPointerSize;
|
||||
__ mov(ecx, Operand(esp, receiver_offset));
|
||||
__ JumpIfSmi(ecx, &ok);
|
||||
__ CmpObjectType(ecx, JS_GLOBAL_PROXY_TYPE, ecx);
|
||||
|
||||
__ cmp(ecx, isolate()->factory()->undefined_value());
|
||||
__ j(not_equal, &ok, Label::kNear);
|
||||
__ mov(Operand(esp, receiver_offset),
|
||||
Immediate(isolate()->factory()->undefined_value()));
|
||||
|
||||
__ mov(ecx, GlobalObjectOperand());
|
||||
__ mov(ecx, FieldOperand(ecx, GlobalObject::kGlobalReceiverOffset));
|
||||
|
||||
__ mov(Operand(esp, receiver_offset), ecx);
|
||||
|
||||
__ bind(&ok);
|
||||
}
|
||||
|
||||
@ -2688,7 +2692,7 @@ void FullCodeGenerator::VisitCall(Call* expr) {
|
||||
}
|
||||
// Record source position for debugger.
|
||||
SetSourcePosition(expr->position());
|
||||
CallFunctionStub stub(arg_count, RECEIVER_MIGHT_BE_IMPLICIT);
|
||||
CallFunctionStub stub(arg_count, NO_CALL_FUNCTION_FLAGS);
|
||||
__ mov(edi, Operand(esp, (arg_count + 1) * kPointerSize));
|
||||
__ CallStub(&stub);
|
||||
RecordJSReturnSite(expr);
|
||||
@ -2727,14 +2731,13 @@ void FullCodeGenerator::VisitCall(Call* expr) {
|
||||
__ push(eax);
|
||||
// The receiver is implicitly the global receiver. Indicate this by
|
||||
// passing the hole to the call function stub.
|
||||
__ push(Immediate(isolate()->factory()->the_hole_value()));
|
||||
__ push(Immediate(isolate()->factory()->undefined_value()));
|
||||
__ bind(&call);
|
||||
}
|
||||
|
||||
// The receiver is either the global receiver or an object found by
|
||||
// LoadContextSlot. That object could be the hole if the receiver is
|
||||
// implicitly the global object.
|
||||
EmitCallWithStub(expr, RECEIVER_MIGHT_BE_IMPLICIT);
|
||||
// LoadContextSlot.
|
||||
EmitCallWithStub(expr, NO_CALL_FUNCTION_FLAGS);
|
||||
|
||||
} else if (property != NULL) {
|
||||
{ PreservePositionScope scope(masm()->positions_recorder());
|
||||
@ -2753,11 +2756,9 @@ void FullCodeGenerator::VisitCall(Call* expr) {
|
||||
{ PreservePositionScope scope(masm()->positions_recorder());
|
||||
VisitForStackValue(callee);
|
||||
}
|
||||
// Push the hole as receiver.
|
||||
// It will be correctly replaced in the call stub.
|
||||
__ push(Immediate(isolate()->factory()->the_hole_value()));
|
||||
__ push(Immediate(isolate()->factory()->undefined_value()));
|
||||
// Emit function call.
|
||||
EmitCallWithStub(expr, RECEIVER_IS_IMPLICIT);
|
||||
EmitCallWithStub(expr, NO_CALL_FUNCTION_FLAGS);
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
@ -3693,7 +3694,7 @@ void FullCodeGenerator::EmitCallFunction(CallRuntime* expr) {
|
||||
__ mov(edi, result_register());
|
||||
ParameterCount count(arg_count);
|
||||
__ InvokeFunction(edi, count, CALL_FUNCTION,
|
||||
NullCallWrapper(), CALL_AS_METHOD);
|
||||
NullCallWrapper(), CALL_AS_FUNCTION);
|
||||
__ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
|
||||
__ jmp(&done);
|
||||
|
||||
|
@ -1112,8 +1112,8 @@ void CallICBase::GenerateMiss(MacroAssembler* masm,
|
||||
|
||||
// Patch the receiver on the stack.
|
||||
__ bind(&global);
|
||||
CallStubCompiler::FetchGlobalProxy(masm, edx, edi);
|
||||
__ mov(Operand(esp, (argc + 1) * kPointerSize), edx);
|
||||
__ mov(Operand(esp, (argc + 1) * kPointerSize),
|
||||
masm->isolate()->factory()->undefined_value());
|
||||
|
||||
__ bind(&invoke);
|
||||
}
|
||||
|
@ -175,18 +175,28 @@ bool LCodeGen::GeneratePrologue() {
|
||||
}
|
||||
#endif
|
||||
|
||||
// Strict mode functions and builtins need to replace the receiver
|
||||
// with undefined when called as functions (without an explicit
|
||||
// receiver object). ecx is zero for method calls and non-zero for
|
||||
// function calls.
|
||||
if (!info_->is_classic_mode() || info_->is_native()) {
|
||||
// Classic mode functions and builtins need to replace the receiver with the
|
||||
// global proxy when called as functions (without an explicit receiver
|
||||
// object).
|
||||
if (info_->this_has_uses() &&
|
||||
info_->is_classic_mode() &&
|
||||
!info_->is_native()) {
|
||||
Label ok;
|
||||
__ test(ecx, Operand(ecx));
|
||||
__ test(ecx, ecx);
|
||||
__ j(zero, &ok, Label::kNear);
|
||||
|
||||
// +1 for return address.
|
||||
int receiver_offset = (scope()->num_parameters() + 1) * kPointerSize;
|
||||
__ mov(Operand(esp, receiver_offset),
|
||||
Immediate(isolate()->factory()->undefined_value()));
|
||||
__ mov(ecx, Operand(esp, receiver_offset));
|
||||
|
||||
__ cmp(ecx, isolate()->factory()->undefined_value());
|
||||
__ j(not_equal, &ok, Label::kNear);
|
||||
|
||||
__ mov(ecx, GlobalObjectOperand());
|
||||
__ mov(ecx, FieldOperand(ecx, GlobalObject::kGlobalReceiverOffset));
|
||||
|
||||
__ mov(Operand(esp, receiver_offset), ecx);
|
||||
|
||||
__ bind(&ok);
|
||||
}
|
||||
|
||||
@ -3641,7 +3651,7 @@ void LCodeGen::DoWrapReceiver(LWrapReceiver* instr) {
|
||||
// If the receiver is null or undefined, we have to pass the global
|
||||
// object as a receiver to normal functions. Values have to be
|
||||
// passed unchanged to builtins and strict-mode functions.
|
||||
Label global_object, receiver_ok;
|
||||
Label receiver_ok, global_object;
|
||||
Label::Distance dist = DeoptEveryNTimes() ? Label::kFar : Label::kNear;
|
||||
|
||||
// Do not transform the receiver to object for strict mode
|
||||
@ -3671,10 +3681,11 @@ void LCodeGen::DoWrapReceiver(LWrapReceiver* instr) {
|
||||
__ jmp(&receiver_ok, Label::kNear);
|
||||
|
||||
__ bind(&global_object);
|
||||
// TODO(kmillikin): We have a hydrogen value for the global object. See
|
||||
// if it's better to use it than to explicitly fetch it from the context
|
||||
// here.
|
||||
CallStubCompiler::FetchGlobalProxy(masm(), receiver, function);
|
||||
__ mov(receiver, FieldOperand(function, JSFunction::kContextOffset));
|
||||
__ mov(receiver,
|
||||
Operand(receiver, Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX)));
|
||||
__ mov(receiver, FieldOperand(receiver, GlobalObject::kGlobalReceiverOffset));
|
||||
|
||||
__ bind(&receiver_ok);
|
||||
}
|
||||
|
||||
@ -3716,7 +3727,7 @@ void LCodeGen::DoApplyArguments(LApplyArguments* instr) {
|
||||
this, pointers, Safepoint::kLazyDeopt);
|
||||
ParameterCount actual(eax);
|
||||
__ InvokeFunction(function, actual, CALL_FUNCTION,
|
||||
safepoint_generator, CALL_AS_METHOD);
|
||||
safepoint_generator, CALL_AS_FUNCTION);
|
||||
}
|
||||
|
||||
|
||||
@ -3837,7 +3848,7 @@ void LCodeGen::DoCallConstantFunction(LCallConstantFunction* instr) {
|
||||
instr->hydrogen()->formal_parameter_count(),
|
||||
instr->arity(),
|
||||
instr,
|
||||
CALL_AS_METHOD,
|
||||
CALL_AS_FUNCTION,
|
||||
EDI_UNINITIALIZED);
|
||||
}
|
||||
|
||||
@ -4198,13 +4209,13 @@ void LCodeGen::DoInvokeFunction(LInvokeFunction* instr) {
|
||||
SafepointGenerator generator(
|
||||
this, pointers, Safepoint::kLazyDeopt);
|
||||
ParameterCount count(instr->arity());
|
||||
__ InvokeFunction(edi, count, CALL_FUNCTION, generator, CALL_AS_METHOD);
|
||||
__ InvokeFunction(edi, count, CALL_FUNCTION, generator, CALL_AS_FUNCTION);
|
||||
} else {
|
||||
CallKnownFunction(known_function,
|
||||
instr->hydrogen()->formal_parameter_count(),
|
||||
instr->arity(),
|
||||
instr,
|
||||
CALL_AS_METHOD,
|
||||
CALL_AS_FUNCTION,
|
||||
EDI_CONTAINS_TARGET);
|
||||
}
|
||||
}
|
||||
@ -4240,10 +4251,7 @@ void LCodeGen::DoCallFunction(LCallFunction* instr) {
|
||||
ASSERT(ToRegister(instr->result()).is(eax));
|
||||
|
||||
int arity = instr->arity();
|
||||
CallFunctionFlags flags =
|
||||
instr->hydrogen()->IsContextualCall() ?
|
||||
RECEIVER_IS_IMPLICIT : NO_CALL_FUNCTION_FLAGS;
|
||||
CallFunctionStub stub(arity, flags);
|
||||
CallFunctionStub stub(arity, NO_CALL_FUNCTION_FLAGS);
|
||||
if (instr->hydrogen()->IsTailCall()) {
|
||||
if (NeedsEagerFrame()) __ leave();
|
||||
__ jmp(stub.GetCode(isolate()), RelocInfo::CODE_TARGET);
|
||||
|
@ -2624,8 +2624,7 @@ LInstruction* LChunkBuilder::DoEnterInlined(HEnterInlined* instr) {
|
||||
instr->arguments_count(),
|
||||
instr->function(),
|
||||
undefined,
|
||||
instr->inlining_kind(),
|
||||
instr->undefined_receiver());
|
||||
instr->inlining_kind());
|
||||
// Only replay binding of arguments object if it wasn't removed from graph.
|
||||
if (instr->arguments_var() != NULL && instr->arguments_object()->IsLinked()) {
|
||||
inner->Bind(instr->arguments_var(), instr->arguments_object());
|
||||
|
@ -2468,24 +2468,12 @@ void StubCompiler::GenerateBooleanCheck(Register object, Label* miss) {
|
||||
}
|
||||
|
||||
|
||||
void CallStubCompiler::PatchGlobalProxy(Handle<Object> object,
|
||||
Handle<JSFunction> function) {
|
||||
void CallStubCompiler::PatchImplicitReceiver(Handle<Object> object) {
|
||||
if (object->IsGlobalObject()) {
|
||||
const int argc = arguments().immediate();
|
||||
const int receiver_offset = (argc + 1) * kPointerSize;
|
||||
__ LoadHeapObject(edx, handle(function->context()->global_proxy()));
|
||||
__ mov(Operand(esp, receiver_offset), edx);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void CallStubCompiler::PatchGlobalProxy(Handle<Object> object,
|
||||
Register function) {
|
||||
if (object->IsGlobalObject()) {
|
||||
FetchGlobalProxy(masm(), edx, function);
|
||||
const int argc = arguments().immediate();
|
||||
const int receiver_offset = (argc + 1) * kPointerSize;
|
||||
__ mov(Operand(esp, receiver_offset), edx);
|
||||
__ mov(Operand(esp, receiver_offset),
|
||||
isolate()->factory()->undefined_value());
|
||||
}
|
||||
}
|
||||
|
||||
@ -2578,7 +2566,7 @@ void CallStubCompiler::GenerateJumpFunction(Handle<Object> object,
|
||||
GenerateFunctionCheck(function, ebx, miss);
|
||||
|
||||
if (!function.is(edi)) __ mov(edi, function);
|
||||
PatchGlobalProxy(object, function);
|
||||
PatchImplicitReceiver(object);
|
||||
|
||||
// Invoke the function.
|
||||
__ InvokeFunction(edi, arguments(), JUMP_FUNCTION,
|
||||
@ -2693,15 +2681,6 @@ Handle<Code> StoreStubCompiler::CompileStoreCallback(
|
||||
#define __ ACCESS_MASM(masm)
|
||||
|
||||
|
||||
void CallStubCompiler::FetchGlobalProxy(MacroAssembler* masm,
|
||||
Register target,
|
||||
Register function) {
|
||||
__ mov(target, FieldOperand(function, JSFunction::kContextOffset));
|
||||
__ mov(target, ContextOperand(target, Context::GLOBAL_OBJECT_INDEX));
|
||||
__ mov(target, FieldOperand(target, GlobalObject::kGlobalReceiverOffset));
|
||||
}
|
||||
|
||||
|
||||
void StoreStubCompiler::GenerateStoreViaSetter(
|
||||
MacroAssembler* masm,
|
||||
Handle<JSFunction> setter) {
|
||||
|
@ -9170,9 +9170,8 @@ static Object* ComputeReceiverForNonGlobal(Isolate* isolate,
|
||||
if (constructor != context_extension_function) return holder;
|
||||
// Fall back to using the global object as the implicit receiver if
|
||||
// the property turns out to be a local variable allocated in a
|
||||
// context extension object - introduced via eval. Implicit global
|
||||
// receivers are indicated with the hole value.
|
||||
return isolate->heap()->the_hole_value();
|
||||
// context extension object - introduced via eval.
|
||||
return isolate->heap()->undefined_value();
|
||||
}
|
||||
|
||||
|
||||
@ -9206,11 +9205,7 @@ static ObjectPair LoadContextSlotHelper(Arguments args,
|
||||
ASSERT(holder->IsContext());
|
||||
// If the "property" we were looking for is a local variable, the
|
||||
// receiver is the global object; see ECMA-262, 3rd., 10.1.6 and 10.2.3.
|
||||
//
|
||||
// Use the hole as the receiver to signal that the receiver is implicit
|
||||
// and that the global receiver should be used (as distinguished from an
|
||||
// explicit receiver that happens to be a global object).
|
||||
Handle<Object> receiver = isolate->factory()->the_hole_value();
|
||||
Handle<Object> receiver = isolate->factory()->undefined_value();
|
||||
Object* value = Context::cast(*holder)->get(index);
|
||||
// Check for uninitialized bindings.
|
||||
switch (binding_flags) {
|
||||
@ -9245,7 +9240,7 @@ static ObjectPair LoadContextSlotHelper(Arguments args,
|
||||
// GetProperty below can cause GC.
|
||||
Handle<Object> receiver_handle(
|
||||
object->IsGlobalObject()
|
||||
? Object::cast(isolate->heap()->the_hole_value())
|
||||
? Object::cast(isolate->heap()->undefined_value())
|
||||
: object->IsJSProxy() ? static_cast<Object*>(*object)
|
||||
: ComputeReceiverForNonGlobal(isolate, JSObject::cast(*object)),
|
||||
isolate);
|
||||
@ -9744,7 +9739,7 @@ RUNTIME_FUNCTION(ObjectPair, Runtime_ResolvePossiblyDirectEval) {
|
||||
// the first argument without doing anything).
|
||||
if (*callee != isolate->native_context()->global_eval_fun() ||
|
||||
!args[1]->IsString()) {
|
||||
return MakePair(*callee, isolate->heap()->the_hole_value());
|
||||
return MakePair(*callee, isolate->heap()->undefined_value());
|
||||
}
|
||||
|
||||
CONVERT_LANGUAGE_MODE_ARG(language_mode, 3);
|
||||
@ -11336,11 +11331,15 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFrameDetails) {
|
||||
// by creating correct wrapper object based on the calling frame's
|
||||
// native context.
|
||||
it.Advance();
|
||||
Handle<Context> calling_frames_native_context(
|
||||
Context::cast(Context::cast(it.frame()->context())->native_context()));
|
||||
ASSERT(!receiver->IsUndefined() && !receiver->IsNull());
|
||||
receiver =
|
||||
isolate->factory()->ToObject(receiver, calling_frames_native_context);
|
||||
if (receiver->IsUndefined()) {
|
||||
Context* context = function->context();
|
||||
receiver = handle(context->global_object()->global_receiver());
|
||||
} else {
|
||||
ASSERT(!receiver->IsNull());
|
||||
Context* context = Context::cast(it.frame()->context());
|
||||
Handle<Context> native_context(Context::cast(context->native_context()));
|
||||
receiver = isolate->factory()->ToObject(receiver, native_context);
|
||||
}
|
||||
}
|
||||
details->set(kFrameDetailsReceiverIndex, *receiver);
|
||||
|
||||
|
@ -1291,7 +1291,7 @@ void CallStubCompiler::GenerateJumpFunctionIgnoreReceiver(
|
||||
|
||||
void CallStubCompiler::GenerateJumpFunction(Handle<Object> object,
|
||||
Handle<JSFunction> function) {
|
||||
PatchGlobalProxy(object, function);
|
||||
PatchImplicitReceiver(object);
|
||||
GenerateJumpFunctionIgnoreReceiver(function);
|
||||
}
|
||||
|
||||
@ -1299,7 +1299,7 @@ void CallStubCompiler::GenerateJumpFunction(Handle<Object> object,
|
||||
void CallStubCompiler::GenerateJumpFunction(Handle<Object> object,
|
||||
Register actual_closure,
|
||||
Handle<JSFunction> function) {
|
||||
PatchGlobalProxy(object, function);
|
||||
PatchImplicitReceiver(object);
|
||||
ParameterCount expected(function);
|
||||
__ InvokeFunction(actual_closure, expected, arguments(),
|
||||
JUMP_FUNCTION, NullCallWrapper(), call_kind());
|
||||
|
@ -929,13 +929,9 @@ class CallStubCompiler: public StubCompiler {
|
||||
PropertyIndex index,
|
||||
Handle<Name> name);
|
||||
|
||||
// Patch the global proxy over the global object if the global object is the
|
||||
// receiver.
|
||||
static void FetchGlobalProxy(MacroAssembler* masm,
|
||||
Register target,
|
||||
Register function);
|
||||
void PatchGlobalProxy(Handle<Object> object, Register function);
|
||||
void PatchGlobalProxy(Handle<Object> object, Handle<JSFunction> function);
|
||||
// Patch the implicit receiver over the global object if the global object is
|
||||
// the receiver.
|
||||
void PatchImplicitReceiver(Handle<Object> object);
|
||||
|
||||
// Returns the register containing the holder of |name|.
|
||||
Register HandlerFrontendHeader(Handle<Object> object,
|
||||
|
@ -289,14 +289,9 @@ enum CheckType {
|
||||
|
||||
|
||||
enum CallFunctionFlags {
|
||||
NO_CALL_FUNCTION_FLAGS = 0,
|
||||
// Receiver might implicitly be the global objects. If it is, the
|
||||
// hole is passed to the call function stub.
|
||||
RECEIVER_MIGHT_BE_IMPLICIT = 1 << 0,
|
||||
// Receiver is implicit and the hole has been passed to the stub.
|
||||
RECEIVER_IS_IMPLICIT = 1 << 1,
|
||||
NO_CALL_FUNCTION_FLAGS,
|
||||
// The call target is cached in the instruction stream.
|
||||
RECORD_CALL_TARGET = 1 << 2
|
||||
RECORD_CALL_TARGET
|
||||
};
|
||||
|
||||
|
||||
|
@ -844,10 +844,10 @@ void Builtins::Generate_FunctionCall(MacroAssembler* masm) {
|
||||
__ movq(rdi, args.GetReceiverOperand());
|
||||
__ jmp(&patch_receiver, Label::kNear);
|
||||
|
||||
// Use the global receiver object from the called function as the
|
||||
// receiver.
|
||||
__ bind(&use_global_receiver);
|
||||
CallStubCompiler::FetchGlobalProxy(masm, rbx, rdi);
|
||||
__ movq(rbx,
|
||||
Operand(rsi, Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX)));
|
||||
__ movq(rbx, FieldOperand(rbx, GlobalObject::kGlobalReceiverOffset));
|
||||
|
||||
__ bind(&patch_receiver);
|
||||
__ movq(args.GetArgumentOperand(1), rbx);
|
||||
@ -917,7 +917,7 @@ void Builtins::Generate_FunctionCall(MacroAssembler* masm) {
|
||||
FieldOperand(rdx,
|
||||
SharedFunctionInfo::kFormalParameterCountOffset));
|
||||
__ movq(rdx, FieldOperand(rdi, JSFunction::kCodeEntryOffset));
|
||||
__ SetCallKind(rcx, CALL_AS_METHOD);
|
||||
__ SetCallKind(rcx, CALL_AS_FUNCTION);
|
||||
__ cmpq(rax, rbx);
|
||||
__ j(not_equal,
|
||||
masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(),
|
||||
@ -925,7 +925,7 @@ void Builtins::Generate_FunctionCall(MacroAssembler* masm) {
|
||||
|
||||
ParameterCount expected(0);
|
||||
__ InvokeCode(rdx, expected, expected, JUMP_FUNCTION,
|
||||
NullCallWrapper(), CALL_AS_METHOD);
|
||||
NullCallWrapper(), CALL_AS_FUNCTION);
|
||||
}
|
||||
|
||||
|
||||
@ -1025,9 +1025,11 @@ void Builtins::Generate_FunctionApply(MacroAssembler* masm) {
|
||||
__ movq(rbx, rax);
|
||||
__ jmp(&push_receiver, Label::kNear);
|
||||
|
||||
// Use the current global receiver object as the receiver.
|
||||
__ bind(&use_global_receiver);
|
||||
CallStubCompiler::FetchGlobalProxy(masm, rbx, rdi);
|
||||
__ movq(rbx,
|
||||
Operand(rsi, Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX)));
|
||||
__ movq(rbx, FieldOperand(rbx, GlobalObject::kGlobalReceiverOffset));
|
||||
|
||||
// Push the receiver.
|
||||
__ bind(&push_receiver);
|
||||
__ push(rbx);
|
||||
@ -1060,7 +1062,7 @@ void Builtins::Generate_FunctionApply(MacroAssembler* masm) {
|
||||
__ cmpq(rax, Operand(rbp, kLimitOffset));
|
||||
__ j(not_equal, &loop);
|
||||
|
||||
// Invoke the function.
|
||||
// Call the function.
|
||||
Label call_proxy;
|
||||
ParameterCount actual(rax);
|
||||
__ SmiToInteger32(rax, rax);
|
||||
@ -1068,17 +1070,17 @@ void Builtins::Generate_FunctionApply(MacroAssembler* masm) {
|
||||
__ CmpObjectType(rdi, JS_FUNCTION_TYPE, rcx);
|
||||
__ j(not_equal, &call_proxy);
|
||||
__ InvokeFunction(rdi, actual, CALL_FUNCTION,
|
||||
NullCallWrapper(), CALL_AS_METHOD);
|
||||
NullCallWrapper(), CALL_AS_FUNCTION);
|
||||
|
||||
frame_scope.GenerateLeaveFrame();
|
||||
__ ret(3 * kPointerSize); // remove this, receiver, and arguments
|
||||
|
||||
// Invoke the function proxy.
|
||||
// Call the function proxy.
|
||||
__ bind(&call_proxy);
|
||||
__ push(rdi); // add function proxy as last argument
|
||||
__ incq(rax);
|
||||
__ Set(rbx, 0);
|
||||
__ SetCallKind(rcx, CALL_AS_METHOD);
|
||||
__ SetCallKind(rcx, CALL_AS_FUNCTION);
|
||||
__ GetBuiltinEntry(rdx, Builtins::CALL_FUNCTION_PROXY);
|
||||
__ call(masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(),
|
||||
RelocInfo::CODE_TARGET);
|
||||
|
@ -2353,42 +2353,9 @@ void CallFunctionStub::Generate(MacroAssembler* masm) {
|
||||
// Check that the function really is a JavaScript function.
|
||||
__ JumpIfSmi(rdi, &non_function);
|
||||
|
||||
// The receiver might implicitly be the global object. This is
|
||||
// indicated by passing the hole as the receiver to the call
|
||||
// function stub.
|
||||
if (ReceiverMightBeImplicit() || ReceiverIsImplicit()) {
|
||||
Label try_call, call, patch_current_context;
|
||||
if (ReceiverMightBeImplicit()) {
|
||||
// Get the receiver from the stack.
|
||||
__ movq(rax, args.GetReceiverOperand());
|
||||
// Call as function is indicated with the hole.
|
||||
__ CompareRoot(rax, Heap::kTheHoleValueRootIndex);
|
||||
__ j(not_equal, &try_call, Label::kNear);
|
||||
}
|
||||
// Patch the receiver on the stack with the global receiver object.
|
||||
// Goto slow case if we do not have a function.
|
||||
__ CmpObjectType(rdi, JS_FUNCTION_TYPE, rcx);
|
||||
__ j(not_equal, &patch_current_context);
|
||||
CallStubCompiler::FetchGlobalProxy(masm, rcx, rdi);
|
||||
__ movq(args.GetReceiverOperand(), rcx);
|
||||
__ jmp(&call, Label::kNear);
|
||||
|
||||
__ bind(&patch_current_context);
|
||||
__ LoadRoot(kScratchRegister, Heap::kUndefinedValueRootIndex);
|
||||
__ movq(args.GetReceiverOperand(), kScratchRegister);
|
||||
__ jmp(&slow);
|
||||
|
||||
__ bind(&try_call);
|
||||
// Goto slow case if we do not have a function.
|
||||
__ CmpObjectType(rdi, JS_FUNCTION_TYPE, rcx);
|
||||
__ j(not_equal, &slow);
|
||||
|
||||
__ bind(&call);
|
||||
} else {
|
||||
// Goto slow case if we do not have a function.
|
||||
__ CmpObjectType(rdi, JS_FUNCTION_TYPE, rcx);
|
||||
__ j(not_equal, &slow);
|
||||
}
|
||||
// Goto slow case if we do not have a function.
|
||||
__ CmpObjectType(rdi, JS_FUNCTION_TYPE, rcx);
|
||||
__ j(not_equal, &slow);
|
||||
|
||||
if (RecordCallTarget()) {
|
||||
GenerateRecordCallTarget(masm);
|
||||
@ -2397,17 +2364,6 @@ void CallFunctionStub::Generate(MacroAssembler* masm) {
|
||||
// Fast-case: Just invoke the function.
|
||||
ParameterCount actual(argc_);
|
||||
|
||||
if (ReceiverMightBeImplicit()) {
|
||||
Label call_as_function;
|
||||
__ CompareRoot(rax, Heap::kTheHoleValueRootIndex);
|
||||
__ j(equal, &call_as_function);
|
||||
__ InvokeFunction(rdi,
|
||||
actual,
|
||||
JUMP_FUNCTION,
|
||||
NullCallWrapper(),
|
||||
CALL_AS_METHOD);
|
||||
__ bind(&call_as_function);
|
||||
}
|
||||
__ InvokeFunction(rdi,
|
||||
actual,
|
||||
JUMP_FUNCTION,
|
||||
@ -2445,7 +2401,7 @@ void CallFunctionStub::Generate(MacroAssembler* masm) {
|
||||
__ movq(args.GetReceiverOperand(), rdi);
|
||||
__ Set(rax, argc_);
|
||||
__ Set(rbx, 0);
|
||||
__ SetCallKind(rcx, CALL_AS_METHOD);
|
||||
__ SetCallKind(rcx, CALL_AS_FUNCTION);
|
||||
__ GetBuiltinEntry(rdx, Builtins::CALL_NON_FUNCTION);
|
||||
Handle<Code> adaptor =
|
||||
isolate->builtins()->ArgumentsAdaptorTrampoline();
|
||||
|
@ -132,17 +132,26 @@ void FullCodeGenerator::Generate() {
|
||||
}
|
||||
#endif
|
||||
|
||||
// Strict mode functions and builtins need to replace the receiver
|
||||
// with undefined when called as functions (without an explicit
|
||||
// receiver object). rcx is zero for method calls and non-zero for
|
||||
// function calls.
|
||||
if (!info->is_classic_mode() || info->is_native()) {
|
||||
// Classic mode functions and builtins need to replace the receiver with the
|
||||
// global proxy when called as functions (without an explicit receiver
|
||||
// object).
|
||||
if (info->is_classic_mode() && !info->is_native()) {
|
||||
Label ok;
|
||||
__ testq(rcx, rcx);
|
||||
__ j(zero, &ok, Label::kNear);
|
||||
|
||||
// +1 for return address.
|
||||
StackArgumentsAccessor args(rsp, info->scope()->num_parameters());
|
||||
__ LoadRoot(kScratchRegister, Heap::kUndefinedValueRootIndex);
|
||||
__ movq(args.GetReceiverOperand(), kScratchRegister);
|
||||
__ movq(rcx, args.GetReceiverOperand());
|
||||
|
||||
__ CompareRoot(rcx, Heap::kUndefinedValueRootIndex);
|
||||
__ j(not_equal, &ok, Label::kNear);
|
||||
|
||||
__ movq(rcx, GlobalObjectOperand());
|
||||
__ movq(rcx, FieldOperand(rcx, GlobalObject::kGlobalReceiverOffset));
|
||||
|
||||
__ movq(args.GetReceiverOperand(), rcx);
|
||||
|
||||
__ bind(&ok);
|
||||
}
|
||||
|
||||
@ -2668,7 +2677,7 @@ void FullCodeGenerator::VisitCall(Call* expr) {
|
||||
}
|
||||
// Record source position for debugger.
|
||||
SetSourcePosition(expr->position());
|
||||
CallFunctionStub stub(arg_count, RECEIVER_MIGHT_BE_IMPLICIT);
|
||||
CallFunctionStub stub(arg_count, NO_CALL_FUNCTION_FLAGS);
|
||||
__ movq(rdi, Operand(rsp, (arg_count + 1) * kPointerSize));
|
||||
__ CallStub(&stub);
|
||||
RecordJSReturnSite(expr);
|
||||
@ -2708,14 +2717,13 @@ void FullCodeGenerator::VisitCall(Call* expr) {
|
||||
__ push(rax);
|
||||
// The receiver is implicitly the global receiver. Indicate this by
|
||||
// passing the hole to the call function stub.
|
||||
__ PushRoot(Heap::kTheHoleValueRootIndex);
|
||||
__ PushRoot(Heap::kUndefinedValueRootIndex);
|
||||
__ bind(&call);
|
||||
}
|
||||
|
||||
// The receiver is either the global receiver or an object found by
|
||||
// LoadContextSlot. That object could be the hole if the receiver is
|
||||
// implicitly the global object.
|
||||
EmitCallWithStub(expr, RECEIVER_MIGHT_BE_IMPLICIT);
|
||||
// LoadContextSlot.
|
||||
EmitCallWithStub(expr, NO_CALL_FUNCTION_FLAGS);
|
||||
} else if (property != NULL) {
|
||||
{ PreservePositionScope scope(masm()->positions_recorder());
|
||||
VisitForStackValue(property->obj());
|
||||
@ -2732,11 +2740,9 @@ void FullCodeGenerator::VisitCall(Call* expr) {
|
||||
{ PreservePositionScope scope(masm()->positions_recorder());
|
||||
VisitForStackValue(callee);
|
||||
}
|
||||
// Push the hole as receiver.
|
||||
// It will be correctly replaced in the call stub.
|
||||
__ PushRoot(Heap::kTheHoleValueRootIndex);
|
||||
__ PushRoot(Heap::kUndefinedValueRootIndex);
|
||||
// Emit function call.
|
||||
EmitCallWithStub(expr, RECEIVER_IS_IMPLICIT);
|
||||
EmitCallWithStub(expr, NO_CALL_FUNCTION_FLAGS);
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
@ -3662,7 +3668,7 @@ void FullCodeGenerator::EmitCallFunction(CallRuntime* expr) {
|
||||
__ movq(rdi, result_register());
|
||||
ParameterCount count(arg_count);
|
||||
__ InvokeFunction(rdi, count, CALL_FUNCTION,
|
||||
NullCallWrapper(), CALL_AS_METHOD);
|
||||
NullCallWrapper(), CALL_AS_FUNCTION);
|
||||
__ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
|
||||
__ jmp(&done);
|
||||
|
||||
|
@ -998,7 +998,7 @@ void CallICBase::GenerateMiss(MacroAssembler* masm,
|
||||
|
||||
// Patch the receiver on the stack.
|
||||
__ bind(&global);
|
||||
CallStubCompiler::FetchGlobalProxy(masm, rdx, rdi);
|
||||
__ LoadRoot(rdx, Heap::kUndefinedValueRootIndex);
|
||||
__ movq(args.GetReceiverOperand(), rdx);
|
||||
__ bind(&invoke);
|
||||
}
|
||||
|
@ -156,17 +156,26 @@ bool LCodeGen::GeneratePrologue() {
|
||||
}
|
||||
#endif
|
||||
|
||||
// Strict mode functions need to replace the receiver with undefined
|
||||
// when called as functions (without an explicit receiver
|
||||
// object). rcx is zero for method calls and non-zero for function
|
||||
// calls.
|
||||
if (!info_->is_classic_mode() || info_->is_native()) {
|
||||
// Classic mode functions need to replace the receiver with the global proxy
|
||||
// when called as functions (without an explicit receiver object).
|
||||
if (info_->this_has_uses() &&
|
||||
info_->is_classic_mode() &&
|
||||
!info_->is_native()) {
|
||||
Label ok;
|
||||
__ testq(rcx, rcx);
|
||||
__ j(zero, &ok, Label::kNear);
|
||||
|
||||
StackArgumentsAccessor args(rsp, scope()->num_parameters());
|
||||
__ LoadRoot(kScratchRegister, Heap::kUndefinedValueRootIndex);
|
||||
__ movq(args.GetReceiverOperand(), kScratchRegister);
|
||||
__ movq(rcx, args.GetReceiverOperand());
|
||||
|
||||
__ CompareRoot(rcx, Heap::kUndefinedValueRootIndex);
|
||||
__ j(not_equal, &ok, Label::kNear);
|
||||
|
||||
__ movq(rcx, GlobalObjectOperand());
|
||||
__ movq(rcx, FieldOperand(rcx, GlobalObject::kGlobalReceiverOffset));
|
||||
|
||||
__ movq(args.GetReceiverOperand(), rcx);
|
||||
|
||||
__ bind(&ok);
|
||||
}
|
||||
}
|
||||
@ -3246,10 +3255,11 @@ void LCodeGen::DoWrapReceiver(LWrapReceiver* instr) {
|
||||
__ jmp(&receiver_ok, Label::kNear);
|
||||
|
||||
__ bind(&global_object);
|
||||
// TODO(kmillikin): We have a hydrogen value for the global object. See
|
||||
// if it's better to use it than to explicitly fetch it from the context
|
||||
// here.
|
||||
CallStubCompiler::FetchGlobalProxy(masm(), receiver, function);
|
||||
__ movq(receiver, FieldOperand(function, JSFunction::kContextOffset));
|
||||
__ movq(receiver,
|
||||
Operand(receiver, Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX)));
|
||||
__ movq(receiver,
|
||||
FieldOperand(receiver, GlobalObject::kGlobalReceiverOffset));
|
||||
__ bind(&receiver_ok);
|
||||
}
|
||||
|
||||
@ -3293,7 +3303,7 @@ void LCodeGen::DoApplyArguments(LApplyArguments* instr) {
|
||||
this, pointers, Safepoint::kLazyDeopt);
|
||||
ParameterCount actual(rax);
|
||||
__ InvokeFunction(function, actual, CALL_FUNCTION,
|
||||
safepoint_generator, CALL_AS_METHOD);
|
||||
safepoint_generator, CALL_AS_FUNCTION);
|
||||
}
|
||||
|
||||
|
||||
@ -3412,7 +3422,7 @@ void LCodeGen::DoCallConstantFunction(LCallConstantFunction* instr) {
|
||||
instr->hydrogen()->formal_parameter_count(),
|
||||
instr->arity(),
|
||||
instr,
|
||||
CALL_AS_METHOD,
|
||||
CALL_AS_FUNCTION,
|
||||
RDI_UNINITIALIZED);
|
||||
}
|
||||
|
||||
@ -3771,13 +3781,13 @@ void LCodeGen::DoInvokeFunction(LInvokeFunction* instr) {
|
||||
LPointerMap* pointers = instr->pointer_map();
|
||||
SafepointGenerator generator(this, pointers, Safepoint::kLazyDeopt);
|
||||
ParameterCount count(instr->arity());
|
||||
__ InvokeFunction(rdi, count, CALL_FUNCTION, generator, CALL_AS_METHOD);
|
||||
__ InvokeFunction(rdi, count, CALL_FUNCTION, generator, CALL_AS_FUNCTION);
|
||||
} else {
|
||||
CallKnownFunction(known_function,
|
||||
instr->hydrogen()->formal_parameter_count(),
|
||||
instr->arity(),
|
||||
instr,
|
||||
CALL_AS_METHOD,
|
||||
CALL_AS_FUNCTION,
|
||||
RDI_CONTAINS_TARGET);
|
||||
}
|
||||
}
|
||||
@ -3813,10 +3823,7 @@ void LCodeGen::DoCallFunction(LCallFunction* instr) {
|
||||
ASSERT(ToRegister(instr->result()).is(rax));
|
||||
|
||||
int arity = instr->arity();
|
||||
CallFunctionFlags flags =
|
||||
instr->hydrogen()->IsContextualCall() ?
|
||||
RECEIVER_IS_IMPLICIT : NO_CALL_FUNCTION_FLAGS;
|
||||
CallFunctionStub stub(arity, flags);
|
||||
CallFunctionStub stub(arity, NO_CALL_FUNCTION_FLAGS);
|
||||
if (instr->hydrogen()->IsTailCall()) {
|
||||
if (NeedsEagerFrame()) __ leave();
|
||||
__ jmp(stub.GetCode(isolate()), RelocInfo::CODE_TARGET);
|
||||
|
@ -2468,8 +2468,7 @@ LInstruction* LChunkBuilder::DoEnterInlined(HEnterInlined* instr) {
|
||||
instr->arguments_count(),
|
||||
instr->function(),
|
||||
undefined,
|
||||
instr->inlining_kind(),
|
||||
instr->undefined_receiver());
|
||||
instr->inlining_kind());
|
||||
// Only replay binding of arguments object if it wasn't removed from graph.
|
||||
if (instr->arguments_var() != NULL && instr->arguments_object()->IsLinked()) {
|
||||
inner->Bind(instr->arguments_var(), instr->arguments_object());
|
||||
|
@ -2375,21 +2375,10 @@ void StubCompiler::GenerateBooleanCheck(Register object, Label* miss) {
|
||||
}
|
||||
|
||||
|
||||
void CallStubCompiler::PatchGlobalProxy(Handle<Object> object,
|
||||
Handle<JSFunction> function) {
|
||||
void CallStubCompiler::PatchImplicitReceiver(Handle<Object> object) {
|
||||
if (object->IsGlobalObject()) {
|
||||
StackArgumentsAccessor args(rsp, arguments());
|
||||
__ MoveHeapObject(rdx, handle(function->context()->global_proxy()));
|
||||
__ movq(args.GetReceiverOperand(), rdx);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void CallStubCompiler::PatchGlobalProxy(Handle<Object> object,
|
||||
Register function) {
|
||||
if (object->IsGlobalObject()) {
|
||||
FetchGlobalProxy(masm(), rdx, function);
|
||||
StackArgumentsAccessor args(rsp, arguments().immediate());
|
||||
__ LoadRoot(rdx, Heap::kUndefinedValueRootIndex);
|
||||
__ movq(args.GetReceiverOperand(), rdx);
|
||||
}
|
||||
}
|
||||
@ -2483,7 +2472,7 @@ void CallStubCompiler::GenerateJumpFunction(Handle<Object> object,
|
||||
GenerateFunctionCheck(function, rbx, miss);
|
||||
|
||||
if (!function.is(rdi)) __ movq(rdi, function);
|
||||
PatchGlobalProxy(object, function);
|
||||
PatchImplicitReceiver(object);
|
||||
|
||||
// Invoke the function.
|
||||
__ InvokeFunction(rdi, arguments(), JUMP_FUNCTION,
|
||||
@ -2596,15 +2585,6 @@ Handle<Code> StoreStubCompiler::CompileStoreCallback(
|
||||
#define __ ACCESS_MASM(masm)
|
||||
|
||||
|
||||
void CallStubCompiler::FetchGlobalProxy(MacroAssembler* masm,
|
||||
Register target,
|
||||
Register function) {
|
||||
__ movq(target, FieldOperand(function, JSFunction::kContextOffset));
|
||||
__ movq(target, ContextOperand(target, Context::GLOBAL_OBJECT_INDEX));
|
||||
__ movq(target, FieldOperand(target, GlobalObject::kGlobalReceiverOffset));
|
||||
}
|
||||
|
||||
|
||||
void StoreStubCompiler::GenerateStoreViaSetter(
|
||||
MacroAssembler* masm,
|
||||
Handle<JSFunction> setter) {
|
||||
|
@ -53,9 +53,10 @@ function TestGenerator(g, expected_values_for_next,
|
||||
function testNext(thunk) {
|
||||
var iter = thunk();
|
||||
for (var i = 0; i < expected_values_for_next.length; i++) {
|
||||
assertIteratorResult(expected_values_for_next[i],
|
||||
i == expected_values_for_next.length - 1,
|
||||
iter.next());
|
||||
var v1 = expected_values_for_next[i];
|
||||
var v2 = i == expected_values_for_next.length - 1;
|
||||
// var v3 = iter.next();
|
||||
assertIteratorResult(v1, v2, iter.next());
|
||||
}
|
||||
assertThrows(function() { iter.next(); }, Error);
|
||||
}
|
||||
|
@ -147,8 +147,9 @@ assertThrows(function() { notifier.performChange(1, function(){}); }, TypeError)
|
||||
assertThrows(function() { notifier.performChange(undefined, function(){}); }, TypeError);
|
||||
assertThrows(function() { notifier.performChange('foo', undefined); }, TypeError);
|
||||
assertThrows(function() { notifier.performChange('foo', 'bar'); }, TypeError);
|
||||
var global = this;
|
||||
notifier.performChange('foo', function() {
|
||||
assertEquals(undefined, this);
|
||||
assertEquals(global, this);
|
||||
});
|
||||
|
||||
var notify = notifier.notify;
|
||||
|
@ -763,8 +763,8 @@ for (var i = 0; i < 10; i++) {
|
||||
assertEquals(Realm.shared.gg, gp());
|
||||
|
||||
with (this) {
|
||||
assertEquals(Realm.shared.fg, fp());
|
||||
assertEquals(Realm.shared.gg, gp());
|
||||
assertEquals(this, fp());
|
||||
assertEquals(this, gp());
|
||||
}
|
||||
|
||||
with ({}) {
|
||||
|
Loading…
Reference in New Issue
Block a user