OLD | NEW |
1 // Copyright 2009 the V8 project authors. All rights reserved. | 1 // Copyright 2009 the V8 project authors. All rights reserved. |
2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
4 // met: | 4 // met: |
5 // | 5 // |
6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
45 // | 45 // |
46 // The live registers are: | 46 // The live registers are: |
47 // o r1: the JS function object being called (ie, ourselves) | 47 // o r1: the JS function object being called (ie, ourselves) |
48 // o cp: our context | 48 // o cp: our context |
49 // o fp: our caller's frame pointer | 49 // o fp: our caller's frame pointer |
50 // o sp: stack pointer | 50 // o sp: stack pointer |
51 // o lr: return address | 51 // o lr: return address |
52 // | 52 // |
53 // The function builds a JS frame. Please see JavaScriptFrameConstants in | 53 // The function builds a JS frame. Please see JavaScriptFrameConstants in |
54 // frames-arm.h for its layout. | 54 // frames-arm.h for its layout. |
55 void FullCodeGenerator::Generate(FunctionLiteral* fun, Mode mode) { | 55 void FullCodeGenerator::Generate(CompilationInfo* info, Mode mode) { |
56 function_ = fun; | 56 ASSERT(info_ == NULL); |
57 SetFunctionPosition(fun); | 57 info_ = info; |
| 58 SetFunctionPosition(function()); |
58 | 59 |
59 if (mode == PRIMARY) { | 60 if (mode == PRIMARY) { |
60 int locals_count = fun->scope()->num_stack_slots(); | 61 int locals_count = scope()->num_stack_slots(); |
61 | 62 |
62 __ stm(db_w, sp, r1.bit() | cp.bit() | fp.bit() | lr.bit()); | 63 __ stm(db_w, sp, r1.bit() | cp.bit() | fp.bit() | lr.bit()); |
63 if (locals_count > 0) { | 64 if (locals_count > 0) { |
64 // Load undefined value here, so the value is ready for the loop | 65 // Load undefined value here, so the value is ready for the loop |
65 // below. | 66 // below. |
66 __ LoadRoot(ip, Heap::kUndefinedValueRootIndex); | 67 __ LoadRoot(ip, Heap::kUndefinedValueRootIndex); |
67 } | 68 } |
68 // Adjust fp to point to caller's fp. | 69 // Adjust fp to point to caller's fp. |
69 __ add(fp, sp, Operand(2 * kPointerSize)); | 70 __ add(fp, sp, Operand(2 * kPointerSize)); |
70 | 71 |
71 { Comment cmnt(masm_, "[ Allocate locals"); | 72 { Comment cmnt(masm_, "[ Allocate locals"); |
72 for (int i = 0; i < locals_count; i++) { | 73 for (int i = 0; i < locals_count; i++) { |
73 __ push(ip); | 74 __ push(ip); |
74 } | 75 } |
75 } | 76 } |
76 | 77 |
77 bool function_in_register = true; | 78 bool function_in_register = true; |
78 | 79 |
79 // Possibly allocate a local context. | 80 // Possibly allocate a local context. |
80 if (fun->scope()->num_heap_slots() > 0) { | 81 if (scope()->num_heap_slots() > 0) { |
81 Comment cmnt(masm_, "[ Allocate local context"); | 82 Comment cmnt(masm_, "[ Allocate local context"); |
82 // Argument to NewContext is the function, which is in r1. | 83 // Argument to NewContext is the function, which is in r1. |
83 __ push(r1); | 84 __ push(r1); |
84 __ CallRuntime(Runtime::kNewContext, 1); | 85 __ CallRuntime(Runtime::kNewContext, 1); |
85 function_in_register = false; | 86 function_in_register = false; |
86 // Context is returned in both r0 and cp. It replaces the context | 87 // Context is returned in both r0 and cp. It replaces the context |
87 // passed to us. It's saved in the stack and kept live in cp. | 88 // passed to us. It's saved in the stack and kept live in cp. |
88 __ str(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); | 89 __ str(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); |
89 // Copy any necessary parameters into the context. | 90 // Copy any necessary parameters into the context. |
90 int num_parameters = fun->scope()->num_parameters(); | 91 int num_parameters = scope()->num_parameters(); |
91 for (int i = 0; i < num_parameters; i++) { | 92 for (int i = 0; i < num_parameters; i++) { |
92 Slot* slot = fun->scope()->parameter(i)->slot(); | 93 Slot* slot = scope()->parameter(i)->slot(); |
93 if (slot != NULL && slot->type() == Slot::CONTEXT) { | 94 if (slot != NULL && slot->type() == Slot::CONTEXT) { |
94 int parameter_offset = StandardFrameConstants::kCallerSPOffset + | 95 int parameter_offset = StandardFrameConstants::kCallerSPOffset + |
95 (num_parameters - 1 - i) * kPointerSize; | 96 (num_parameters - 1 - i) * kPointerSize; |
96 // Load parameter from stack. | 97 // Load parameter from stack. |
97 __ ldr(r0, MemOperand(fp, parameter_offset)); | 98 __ ldr(r0, MemOperand(fp, parameter_offset)); |
98 // Store it in the context. | 99 // Store it in the context. |
99 __ mov(r1, Operand(Context::SlotOffset(slot->index()))); | 100 __ mov(r1, Operand(Context::SlotOffset(slot->index()))); |
100 __ str(r0, MemOperand(cp, r1)); | 101 __ str(r0, MemOperand(cp, r1)); |
101 // Update the write barrier. This clobbers all involved | 102 // Update the write barrier. This clobbers all involved |
102 // registers, so we have use a third register to avoid | 103 // registers, so we have use a third register to avoid |
103 // clobbering cp. | 104 // clobbering cp. |
104 __ mov(r2, Operand(cp)); | 105 __ mov(r2, Operand(cp)); |
105 __ RecordWrite(r2, r1, r0); | 106 __ RecordWrite(r2, r1, r0); |
106 } | 107 } |
107 } | 108 } |
108 } | 109 } |
109 | 110 |
110 Variable* arguments = fun->scope()->arguments()->AsVariable(); | 111 Variable* arguments = scope()->arguments()->AsVariable(); |
111 if (arguments != NULL) { | 112 if (arguments != NULL) { |
112 // Function uses arguments object. | 113 // Function uses arguments object. |
113 Comment cmnt(masm_, "[ Allocate arguments object"); | 114 Comment cmnt(masm_, "[ Allocate arguments object"); |
114 if (!function_in_register) { | 115 if (!function_in_register) { |
115 // Load this again, if it's used by the local context below. | 116 // Load this again, if it's used by the local context below. |
116 __ ldr(r3, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset)); | 117 __ ldr(r3, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset)); |
117 } else { | 118 } else { |
118 __ mov(r3, r1); | 119 __ mov(r3, r1); |
119 } | 120 } |
120 // Receiver is just before the parameters on the caller's stack. | 121 // Receiver is just before the parameters on the caller's stack. |
121 __ add(r2, fp, Operand(StandardFrameConstants::kCallerSPOffset + | 122 int offset = scope()->num_parameters() * kPointerSize; |
122 fun->num_parameters() * kPointerSize)); | 123 __ add(r2, fp, |
123 __ mov(r1, Operand(Smi::FromInt(fun->num_parameters()))); | 124 Operand(StandardFrameConstants::kCallerSPOffset + offset)); |
| 125 __ mov(r1, Operand(Smi::FromInt(scope()->num_parameters()))); |
124 __ stm(db_w, sp, r3.bit() | r2.bit() | r1.bit()); | 126 __ stm(db_w, sp, r3.bit() | r2.bit() | r1.bit()); |
125 | 127 |
126 // Arguments to ArgumentsAccessStub: | 128 // Arguments to ArgumentsAccessStub: |
127 // function, receiver address, parameter count. | 129 // function, receiver address, parameter count. |
128 // The stub will rewrite receiever and parameter count if the previous | 130 // The stub will rewrite receiever and parameter count if the previous |
129 // stack frame was an arguments adapter frame. | 131 // stack frame was an arguments adapter frame. |
130 ArgumentsAccessStub stub(ArgumentsAccessStub::NEW_OBJECT); | 132 ArgumentsAccessStub stub(ArgumentsAccessStub::NEW_OBJECT); |
131 __ CallStub(&stub); | 133 __ CallStub(&stub); |
132 // Duplicate the value; move-to-slot operation might clobber registers. | 134 // Duplicate the value; move-to-slot operation might clobber registers. |
133 __ mov(r3, r0); | 135 __ mov(r3, r0); |
134 Move(arguments->slot(), r0, r1, r2); | 136 Move(arguments->slot(), r0, r1, r2); |
135 Slot* dot_arguments_slot = | 137 Slot* dot_arguments_slot = |
136 fun->scope()->arguments_shadow()->AsVariable()->slot(); | 138 scope()->arguments_shadow()->AsVariable()->slot(); |
137 Move(dot_arguments_slot, r3, r1, r2); | 139 Move(dot_arguments_slot, r3, r1, r2); |
138 } | 140 } |
139 } | 141 } |
140 | 142 |
141 // Check the stack for overflow or break request. | 143 // Check the stack for overflow or break request. |
142 // Put the lr setup instruction in the delay slot. The kInstrSize is | 144 // Put the lr setup instruction in the delay slot. The kInstrSize is |
143 // added to the implicit 8 byte offset that always applies to operations | 145 // added to the implicit 8 byte offset that always applies to operations |
144 // with pc and gives a return address 12 bytes down. | 146 // with pc and gives a return address 12 bytes down. |
145 { Comment cmnt(masm_, "[ Stack check"); | 147 { Comment cmnt(masm_, "[ Stack check"); |
146 __ LoadRoot(r2, Heap::kStackLimitRootIndex); | 148 __ LoadRoot(r2, Heap::kStackLimitRootIndex); |
147 __ add(lr, pc, Operand(Assembler::kInstrSize)); | 149 __ add(lr, pc, Operand(Assembler::kInstrSize)); |
148 __ cmp(sp, Operand(r2)); | 150 __ cmp(sp, Operand(r2)); |
149 StackCheckStub stub; | 151 StackCheckStub stub; |
150 __ mov(pc, | 152 __ mov(pc, |
151 Operand(reinterpret_cast<intptr_t>(stub.GetCode().location()), | 153 Operand(reinterpret_cast<intptr_t>(stub.GetCode().location()), |
152 RelocInfo::CODE_TARGET), | 154 RelocInfo::CODE_TARGET), |
153 LeaveCC, | 155 LeaveCC, |
154 lo); | 156 lo); |
155 } | 157 } |
156 | 158 |
157 { Comment cmnt(masm_, "[ Declarations"); | 159 { Comment cmnt(masm_, "[ Declarations"); |
158 VisitDeclarations(fun->scope()->declarations()); | 160 VisitDeclarations(scope()->declarations()); |
159 } | 161 } |
160 | 162 |
161 if (FLAG_trace) { | 163 if (FLAG_trace) { |
162 __ CallRuntime(Runtime::kTraceEnter, 0); | 164 __ CallRuntime(Runtime::kTraceEnter, 0); |
163 } | 165 } |
164 | 166 |
165 { Comment cmnt(masm_, "[ Body"); | 167 { Comment cmnt(masm_, "[ Body"); |
166 ASSERT(loop_depth() == 0); | 168 ASSERT(loop_depth() == 0); |
167 VisitStatements(fun->body()); | 169 VisitStatements(function()->body()); |
168 ASSERT(loop_depth() == 0); | 170 ASSERT(loop_depth() == 0); |
169 } | 171 } |
170 | 172 |
171 { Comment cmnt(masm_, "[ return <undefined>;"); | 173 { Comment cmnt(masm_, "[ return <undefined>;"); |
172 // Emit a 'return undefined' in case control fell off the end of the | 174 // Emit a 'return undefined' in case control fell off the end of the |
173 // body. | 175 // body. |
174 __ LoadRoot(r0, Heap::kUndefinedValueRootIndex); | 176 __ LoadRoot(r0, Heap::kUndefinedValueRootIndex); |
175 } | 177 } |
176 EmitReturnSequence(function_->end_position()); | 178 EmitReturnSequence(function()->end_position()); |
177 } | 179 } |
178 | 180 |
179 | 181 |
180 void FullCodeGenerator::EmitReturnSequence(int position) { | 182 void FullCodeGenerator::EmitReturnSequence(int position) { |
181 Comment cmnt(masm_, "[ Return sequence"); | 183 Comment cmnt(masm_, "[ Return sequence"); |
182 if (return_label_.is_bound()) { | 184 if (return_label_.is_bound()) { |
183 __ b(&return_label_); | 185 __ b(&return_label_); |
184 } else { | 186 } else { |
185 __ bind(&return_label_); | 187 __ bind(&return_label_); |
186 if (FLAG_trace) { | 188 if (FLAG_trace) { |
187 // Push the return value on the stack as the parameter. | 189 // Push the return value on the stack as the parameter. |
188 // Runtime::TraceExit returns its parameter in r0. | 190 // Runtime::TraceExit returns its parameter in r0. |
189 __ push(r0); | 191 __ push(r0); |
190 __ CallRuntime(Runtime::kTraceExit, 1); | 192 __ CallRuntime(Runtime::kTraceExit, 1); |
191 } | 193 } |
192 | 194 |
193 // Add a label for checking the size of the code used for returning. | 195 // Add a label for checking the size of the code used for returning. |
194 Label check_exit_codesize; | 196 Label check_exit_codesize; |
195 masm_->bind(&check_exit_codesize); | 197 masm_->bind(&check_exit_codesize); |
196 | 198 |
197 // Calculate the exact length of the return sequence and make sure that | 199 // Calculate the exact length of the return sequence and make sure that |
198 // the constant pool is not emitted inside of the return sequence. | 200 // the constant pool is not emitted inside of the return sequence. |
199 int num_parameters = function_->scope()->num_parameters(); | 201 int num_parameters = scope()->num_parameters(); |
200 int32_t sp_delta = (num_parameters + 1) * kPointerSize; | 202 int32_t sp_delta = (num_parameters + 1) * kPointerSize; |
201 int return_sequence_length = Assembler::kJSReturnSequenceLength; | 203 int return_sequence_length = Assembler::kJSReturnSequenceLength; |
202 if (!masm_->ImmediateFitsAddrMode1Instruction(sp_delta)) { | 204 if (!masm_->ImmediateFitsAddrMode1Instruction(sp_delta)) { |
203 // Additional mov instruction generated. | 205 // Additional mov instruction generated. |
204 return_sequence_length++; | 206 return_sequence_length++; |
205 } | 207 } |
206 masm_->BlockConstPoolFor(return_sequence_length); | 208 masm_->BlockConstPoolFor(return_sequence_length); |
207 | 209 |
208 CodeGenerator::RecordPositions(masm_, position); | 210 CodeGenerator::RecordPositions(masm_, position); |
209 __ RecordJSReturn(); | 211 __ RecordJSReturn(); |
(...skipping 295 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
505 } | 507 } |
506 | 508 |
507 | 509 |
508 MemOperand FullCodeGenerator::EmitSlotSearch(Slot* slot, Register scratch) { | 510 MemOperand FullCodeGenerator::EmitSlotSearch(Slot* slot, Register scratch) { |
509 switch (slot->type()) { | 511 switch (slot->type()) { |
510 case Slot::PARAMETER: | 512 case Slot::PARAMETER: |
511 case Slot::LOCAL: | 513 case Slot::LOCAL: |
512 return MemOperand(fp, SlotOffset(slot)); | 514 return MemOperand(fp, SlotOffset(slot)); |
513 case Slot::CONTEXT: { | 515 case Slot::CONTEXT: { |
514 int context_chain_length = | 516 int context_chain_length = |
515 function_->scope()->ContextChainLength(slot->var()->scope()); | 517 scope()->ContextChainLength(slot->var()->scope()); |
516 __ LoadContext(scratch, context_chain_length); | 518 __ LoadContext(scratch, context_chain_length); |
517 return CodeGenerator::ContextOperand(scratch, slot->index()); | 519 return CodeGenerator::ContextOperand(scratch, slot->index()); |
518 } | 520 } |
519 case Slot::LOOKUP: | 521 case Slot::LOOKUP: |
520 UNREACHABLE(); | 522 UNREACHABLE(); |
521 } | 523 } |
522 UNREACHABLE(); | 524 UNREACHABLE(); |
523 return MemOperand(r0, 0); | 525 return MemOperand(r0, 0); |
524 } | 526 } |
525 | 527 |
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
565 VisitForValue(decl->fun(), kAccumulator); | 567 VisitForValue(decl->fun(), kAccumulator); |
566 __ str(result_register(), MemOperand(fp, SlotOffset(slot))); | 568 __ str(result_register(), MemOperand(fp, SlotOffset(slot))); |
567 } | 569 } |
568 break; | 570 break; |
569 | 571 |
570 case Slot::CONTEXT: | 572 case Slot::CONTEXT: |
571 // We bypass the general EmitSlotSearch because we know more about | 573 // We bypass the general EmitSlotSearch because we know more about |
572 // this specific context. | 574 // this specific context. |
573 | 575 |
574 // The variable in the decl always resides in the current context. | 576 // The variable in the decl always resides in the current context. |
575 ASSERT_EQ(0, function_->scope()->ContextChainLength(var->scope())); | 577 ASSERT_EQ(0, scope()->ContextChainLength(var->scope())); |
576 if (FLAG_debug_code) { | 578 if (FLAG_debug_code) { |
577 // Check if we have the correct context pointer. | 579 // Check if we have the correct context pointer. |
578 __ ldr(r1, | 580 __ ldr(r1, |
579 CodeGenerator::ContextOperand(cp, Context::FCONTEXT_INDEX)); | 581 CodeGenerator::ContextOperand(cp, Context::FCONTEXT_INDEX)); |
580 __ cmp(r1, cp); | 582 __ cmp(r1, cp); |
581 __ Check(eq, "Unexpected declaration in current context."); | 583 __ Check(eq, "Unexpected declaration in current context."); |
582 } | 584 } |
583 if (decl->mode() == Variable::CONST) { | 585 if (decl->mode() == Variable::CONST) { |
584 __ LoadRoot(ip, Heap::kTheHoleValueRootIndex); | 586 __ LoadRoot(ip, Heap::kTheHoleValueRootIndex); |
585 __ str(ip, CodeGenerator::ContextOperand(cp, slot->index())); | 587 __ str(ip, CodeGenerator::ContextOperand(cp, slot->index())); |
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
645 __ Drop(2); | 647 __ Drop(2); |
646 } | 648 } |
647 } | 649 } |
648 } | 650 } |
649 | 651 |
650 | 652 |
651 void FullCodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) { | 653 void FullCodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) { |
652 // Call the runtime to declare the globals. | 654 // Call the runtime to declare the globals. |
653 // The context is the first argument. | 655 // The context is the first argument. |
654 __ mov(r1, Operand(pairs)); | 656 __ mov(r1, Operand(pairs)); |
655 __ mov(r0, Operand(Smi::FromInt(is_eval_ ? 1 : 0))); | 657 __ mov(r0, Operand(Smi::FromInt(is_eval() ? 1 : 0))); |
656 __ stm(db_w, sp, cp.bit() | r1.bit() | r0.bit()); | 658 __ stm(db_w, sp, cp.bit() | r1.bit() | r0.bit()); |
657 __ CallRuntime(Runtime::kDeclareGlobals, 3); | 659 __ CallRuntime(Runtime::kDeclareGlobals, 3); |
658 // Return value is ignored. | 660 // Return value is ignored. |
659 } | 661 } |
660 | 662 |
661 | 663 |
662 void FullCodeGenerator::VisitFunctionLiteral(FunctionLiteral* expr) { | 664 void FullCodeGenerator::VisitFunctionLiteral(FunctionLiteral* expr) { |
663 Comment cmnt(masm_, "[ FunctionLiteral"); | 665 Comment cmnt(masm_, "[ FunctionLiteral"); |
664 | 666 |
665 // Build the function boilerplate and instantiate it. | 667 // Build the function boilerplate and instantiate it. |
666 Handle<JSFunction> boilerplate = | 668 Handle<JSFunction> boilerplate = |
667 Compiler::BuildBoilerplate(expr, script_, this); | 669 Compiler::BuildBoilerplate(expr, script(), this); |
668 if (HasStackOverflow()) return; | 670 if (HasStackOverflow()) return; |
669 | 671 |
670 ASSERT(boilerplate->IsBoilerplate()); | 672 ASSERT(boilerplate->IsBoilerplate()); |
671 | 673 |
672 // Create a new closure. | 674 // Create a new closure. |
673 __ mov(r0, Operand(boilerplate)); | 675 __ mov(r0, Operand(boilerplate)); |
674 __ stm(db_w, sp, cp.bit() | r0.bit()); | 676 __ stm(db_w, sp, cp.bit() | r0.bit()); |
675 __ CallRuntime(Runtime::kNewClosure, 2); | 677 __ CallRuntime(Runtime::kNewClosure, 2); |
676 Apply(context_, r0); | 678 Apply(context_, r0); |
677 } | 679 } |
(...skipping 1094 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1772 __ pop(result_register()); | 1774 __ pop(result_register()); |
1773 ASSERT_EQ(1, kSmiTagSize + kSmiShiftSize); | 1775 ASSERT_EQ(1, kSmiTagSize + kSmiShiftSize); |
1774 __ mov(r1, Operand(r1, ASR, 1)); // Un-smi-tag value. | 1776 __ mov(r1, Operand(r1, ASR, 1)); // Un-smi-tag value. |
1775 __ add(pc, r1, Operand(masm_->CodeObject())); | 1777 __ add(pc, r1, Operand(masm_->CodeObject())); |
1776 } | 1778 } |
1777 | 1779 |
1778 | 1780 |
1779 #undef __ | 1781 #undef __ |
1780 | 1782 |
1781 } } // namespace v8::internal | 1783 } } // namespace v8::internal |
OLD | NEW |