void FastCodeGenerator::Generate(FunctionLiteral* fun) {
function_ = fun;
SetFunctionPosition(fun);
+ int locals_count = fun->scope()->num_stack_slots();
__ stm(db_w, sp, r1.bit() | cp.bit() | fp.bit() | lr.bit());
+ if (locals_count > 0) {
+ // Load undefined value here, so the value is ready for the loop below.
+ __ LoadRoot(ip, Heap::kUndefinedValueRootIndex);
+ }
// Adjust fp to point to caller's fp.
__ add(fp, sp, Operand(2 * kPointerSize));
{ Comment cmnt(masm_, "[ Allocate locals");
- int locals_count = fun->scope()->num_stack_slots();
- if (locals_count > 0) {
- __ LoadRoot(ip, Heap::kUndefinedValueRootIndex);
- }
- __ LoadRoot(r2, Heap::kStackLimitRootIndex);
for (int i = 0; i < locals_count; i++) {
__ push(ip);
}
}
+ bool function_in_register = true;
+
+ Variable* arguments = fun->scope()->arguments()->AsVariable();
+ if (arguments != NULL) {
+ // Function uses arguments object.
+ Comment cmnt(masm_, "[ Allocate arguments object");
+ __ mov(r3, r1);
+ // Receiver is just before the parameters on the caller's stack.
+ __ add(r2, fp, Operand(StandardFrameConstants::kCallerSPOffset +
+ fun->num_parameters() * kPointerSize));
+ __ mov(r1, Operand(Smi::FromInt(fun->num_parameters())));
+ __ stm(db_w, sp, r1.bit() | r2.bit() | r3.bit());
+
+ // Arguments to ArgumentsAccessStub:
+ // function, receiver address, parameter count.
+ // The stub will rewrite receiever and parameter count if the previous
+ // stack frame was an arguments adapter frame.
+ ArgumentsAccessStub stub(ArgumentsAccessStub::NEW_OBJECT);
+ __ CallStub(&stub);
+ __ str(r0, MemOperand(fp, SlotOffset(arguments->slot())));
+ Slot* dot_arguments_slot =
+ fun->scope()->arguments_shadow()->AsVariable()->slot();
+ __ str(r0, MemOperand(fp, SlotOffset(dot_arguments_slot)));
+ function_in_register = false;
+ }
+
// Possibly allocate a local context.
if (fun->scope()->num_heap_slots() > 0) {
Comment cmnt(masm_, "[ Allocate local context");
- // Argument to NewContext is the function, still in r1.
+ if (!function_in_register) {
+ // Load this again, if it's used by the local context below.
+ __ ldr(r1, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
+ }
+ // Argument to NewContext is the function, which is in r1.
__ push(r1);
__ CallRuntime(Runtime::kNewContext, 1);
// Context is returned in both r0 and cp. It replaces the context
// added to the implicit 8 byte offset that always applies to operations
// with pc and gives a return address 12 bytes down.
Comment cmnt(masm_, "[ Stack check");
+ __ LoadRoot(r2, Heap::kStackLimitRootIndex);
__ add(lr, pc, Operand(Assembler::kInstrSize));
__ cmp(sp, Operand(r2));
StackCheckStub stub;
Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize));
__ Call(ic, RelocInfo::CODE_TARGET_CONTEXT);
DropAndMove(expr->context(), r0);
- } else {
+ } else if (rewrite->AsSlot() != NULL) {
Slot* slot = rewrite->AsSlot();
ASSERT_NE(NULL, slot);
switch (slot->type()) {
UNREACHABLE();
break;
}
+ } else {
+ // The parameter variable has been rewritten into an explict access to
+ // the arguments object.
+ Property* property = rewrite->AsProperty();
+ ASSERT_NOT_NULL(property);
+ ASSERT_EQ(expr->context(), property->context());
+ Visit(property);
}
}
}
}
- if (scope->arguments() != NULL) {
- if (FLAG_trace_bailout) PrintF("function uses 'arguments'\n");
- return NORMAL;
- }
-
has_supported_syntax_ = true;
VisitDeclarations(scope->declarations());
if (!has_supported_syntax_) return NORMAL;
if (rewrite != NULL) {
// Non-global.
Slot* slot = rewrite->AsSlot();
- if (slot == NULL) {
- // This is a variable rewritten to an explicit property access
- // on the arguments object.
- BAILOUT("non-global/non-slot variable reference");
- }
-
- Slot::Type type = slot->type();
- // When LOOKUP slots are enabled, some currently dead code
- // implementing unary typeof will become live.
- if (type == Slot::LOOKUP) {
- BAILOUT("Lookup slot");
+ if (slot != NULL) {
+ Slot::Type type = slot->type();
+ // When LOOKUP slots are enabled, some currently dead code
+ // implementing unary typeof will become live.
+ if (type == Slot::LOOKUP) {
+ BAILOUT("Lookup slot");
+ }
+ } else {
+ Property* property = rewrite->AsProperty();
+ // In the presence of an arguments object, parameter variables
+ // are rewritten into property accesses on that object.
+ ASSERT_NOT_NULL(property);
+ ASSERT_NE(Expression::kUninitialized, context_);
+ Visit(property);
+ property->set_context(context_);
}
}
}
}
}
+ bool function_in_register = true;
+
+ Variable* arguments = fun->scope()->arguments()->AsVariable();
+ if (arguments != NULL) {
+ // Function uses arguments object.
+ Comment cmnt(masm_, "[ Allocate arguments object");
+ __ push(edi);
+ // Receiver is just before the parameters on the caller's stack.
+ __ lea(edx, Operand(ebp, StandardFrameConstants::kCallerSPOffset +
+ fun->num_parameters() * kPointerSize));
+ __ push(edx);
+ __ push(Immediate(Smi::FromInt(fun->num_parameters())));
+ // Arguments to ArgumentsAccessStub:
+ // function, receiver address, parameter count.
+ // The stub will rewrite receiever and parameter count if the previous
+ // stack frame was an arguments adapter frame.
+ ArgumentsAccessStub stub(ArgumentsAccessStub::NEW_OBJECT);
+ __ CallStub(&stub);
+ __ mov(Operand(ebp, SlotOffset(arguments->slot())), eax);
+ Slot* dot_arguments_slot =
+ fun->scope()->arguments_shadow()->AsVariable()->slot();
+ __ mov(Operand(ebp, SlotOffset(dot_arguments_slot)), eax);
+
+ function_in_register = false;
+ }
+
// Possibly allocate a local context.
if (fun->scope()->num_heap_slots() > 0) {
Comment cmnt(masm_, "[ Allocate local context");
- // Argument to NewContext is the function, still in edi.
- __ push(edi);
+ if (function_in_register) {
+ // Argument to NewContext is the function, still in edi.
+ __ push(edi);
+ } else {
+ // Argument to NewContext is the function, no longer in edi.
+ __ push(Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
+ }
__ CallRuntime(Runtime::kNewContext, 1);
// Context is returned in both eax and esi. It replaces the context
// passed to us. It's saved in the stack and kept live in esi.
__ nop();
DropAndMove(expr->context(), eax);
- } else {
+ } else if (rewrite->AsSlot() != NULL) {
Slot* slot = rewrite->AsSlot();
- ASSERT_NE(NULL, slot);
switch (slot->type()) {
case Slot::LOCAL:
case Slot::PARAMETER: {
UNREACHABLE();
break;
}
+ } else {
+ // The parameter variable has been rewritten into an explict access to
+ // the arguments object.
+ Property* property = rewrite->AsProperty();
+ ASSERT_NOT_NULL(property);
+ ASSERT_EQ(expr->context(), property->context());
+ Visit(property);
}
}
{ Comment cmnt(masm_, "[ Allocate locals");
int locals_count = fun->scope()->num_stack_slots();
- for (int i = 0; i < locals_count; i++) {
- __ PushRoot(Heap::kUndefinedValueRootIndex);
+ if (locals_count <= 1) {
+ if (locals_count > 0) {
+ __ PushRoot(Heap::kUndefinedValueRootIndex);
+ }
+ } else {
+ __ LoadRoot(rdx, Heap::kUndefinedValueRootIndex);
+ for (int i = 0; i < locals_count; i++) {
+ __ push(rdx);
+ }
}
}
+ bool function_in_register = true;
+
+ Variable* arguments = fun->scope()->arguments()->AsVariable();
+ if (arguments != NULL) {
+ // Function uses arguments object.
+ Comment cmnt(masm_, "[ Allocate arguments object");
+ __ push(rdi);
+ // The receiver is just before the parameters on the caller's stack.
+ __ lea(rdx, Operand(rbp, StandardFrameConstants::kCallerSPOffset +
+ fun->num_parameters() * kPointerSize));
+ __ push(rdx);
+ __ Push(Smi::FromInt(fun->num_parameters()));
+ // Arguments to ArgumentsAccessStub:
+ // function, receiver address, parameter count.
+ // The stub will rewrite receiver and parameter count if the previous
+ // stack frame was an arguments adapter frame.
+ ArgumentsAccessStub stub(ArgumentsAccessStub::NEW_OBJECT);
+ __ CallStub(&stub);
+ // Store new arguments object in both "arguments" and ".arguments" slots.
+ __ movq(Operand(rbp, SlotOffset(arguments->slot())), rax);
+ Slot* dot_arguments_slot =
+ fun->scope()->arguments_shadow()->AsVariable()->slot();
+ __ movq(Operand(rbp, SlotOffset(dot_arguments_slot)), rax);
+ function_in_register = false;
+ }
+
// Possibly allocate a local context.
if (fun->scope()->num_heap_slots() > 0) {
Comment cmnt(masm_, "[ Allocate local context");
- // Argument to NewContext is the function, still in rdi.
- __ push(rdi);
+ if (function_in_register) {
+ // Argument to NewContext is the function, still in rdi.
+ __ push(rdi);
+ } else {
+ // Argument to NewContext is the function, no longer in rdi.
+ __ push(Operand(rbp, JavaScriptFrameConstants::kFunctionOffset));
+ }
__ CallRuntime(Runtime::kNewContext, 1);
// Context is returned in both rax and rsi. It replaces the context
// passed to us. It's saved in the stack and kept live in rsi.
__ nop();
DropAndMove(expr->context(), rax);
- } else {
+ } else if (rewrite->AsSlot() != NULL) {
Slot* slot = rewrite->AsSlot();
- ASSERT_NE(NULL, slot);
switch (slot->type()) {
case Slot::LOCAL:
case Slot::PARAMETER: {
UNREACHABLE();
break;
}
+ } else {
+ // The parameter variable has been rewritten into an explict access to
+ // the arguments object.
+ Property* property = rewrite->AsProperty();
+ ASSERT_NOT_NULL(property);
+ ASSERT_EQ(expr->context(), property->context());
+ Visit(property);
}
}