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:
verwaest@chromium.org 2014-01-14 12:04:10 +00:00
parent c30421677d
commit f2245a9cf9
37 changed files with 315 additions and 488 deletions

View File

@ -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);

View File

@ -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);
}

View File

@ -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);

View File

@ -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);
}

View File

@ -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());

View File

@ -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);

View File

@ -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) {

View File

@ -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()) {

View File

@ -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");
}

View File

@ -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;
}

View File

@ -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()) {

View File

@ -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);

View File

@ -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_;
};

View File

@ -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);

View File

@ -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_;

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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);
}

View File

@ -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);

View File

@ -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());

View File

@ -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) {

View File

@ -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);

View File

@ -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());

View File

@ -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,

View File

@ -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
};

View File

@ -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);

View File

@ -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();

View File

@ -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);

View File

@ -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);
}

View File

@ -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);

View File

@ -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());

View File

@ -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) {

View File

@ -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);
}

View File

@ -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;

View File

@ -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 ({}) {