OLD | NEW |
1 // Copyright 2010 the V8 project authors. All rights reserved. | 1 // Copyright 2010 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 125 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
136 function_return_is_shadowed_(false) { | 136 function_return_is_shadowed_(false) { |
137 } | 137 } |
138 | 138 |
139 | 139 |
140 // Calling conventions: | 140 // Calling conventions: |
141 // fp: caller's frame pointer | 141 // fp: caller's frame pointer |
142 // sp: stack pointer | 142 // sp: stack pointer |
143 // r1: called JS function | 143 // r1: called JS function |
144 // cp: callee's context | 144 // cp: callee's context |
145 | 145 |
146 void CodeGenerator::GenCode(FunctionLiteral* fun, CompilationInfo* info) { | 146 void CodeGenerator::Generate(FunctionLiteral* fun, |
| 147 Mode mode, |
| 148 CompilationInfo* info) { |
147 // Record the position for debugging purposes. | 149 // Record the position for debugging purposes. |
148 CodeForFunctionPosition(fun); | 150 CodeForFunctionPosition(fun); |
149 | 151 |
150 ZoneList<Statement*>* body = fun->body(); | 152 ZoneList<Statement*>* body = fun->body(); |
151 | 153 |
152 // Initialize state. | 154 // Initialize state. |
153 ASSERT(scope_ == NULL); | 155 ASSERT(scope_ == NULL); |
154 scope_ = fun->scope(); | 156 scope_ = fun->scope(); |
155 ASSERT(allocator_ == NULL); | 157 ASSERT(allocator_ == NULL); |
156 RegisterAllocator register_allocator(this); | 158 RegisterAllocator register_allocator(this); |
157 allocator_ = ®ister_allocator; | 159 allocator_ = ®ister_allocator; |
158 ASSERT(frame_ == NULL); | 160 ASSERT(frame_ == NULL); |
159 frame_ = new VirtualFrame(); | 161 frame_ = new VirtualFrame(); |
160 cc_reg_ = al; | 162 cc_reg_ = al; |
161 { | 163 { |
162 CodeGenState state(this); | 164 CodeGenState state(this); |
163 | 165 |
164 // Entry: | 166 // Entry: |
165 // Stack: receiver, arguments | 167 // Stack: receiver, arguments |
166 // lr: return address | 168 // lr: return address |
167 // fp: caller's frame pointer | 169 // fp: caller's frame pointer |
168 // sp: stack pointer | 170 // sp: stack pointer |
169 // r1: called JS function | 171 // r1: called JS function |
170 // cp: callee's context | 172 // cp: callee's context |
171 allocator_->Initialize(); | 173 allocator_->Initialize(); |
172 frame_->Enter(); | 174 |
173 // tos: code slot | |
174 #ifdef DEBUG | 175 #ifdef DEBUG |
175 if (strlen(FLAG_stop_at) > 0 && | 176 if (strlen(FLAG_stop_at) > 0 && |
176 fun->name()->IsEqualTo(CStrVector(FLAG_stop_at))) { | 177 fun->name()->IsEqualTo(CStrVector(FLAG_stop_at))) { |
177 frame_->SpillAll(); | 178 frame_->SpillAll(); |
178 __ stop("stop-at"); | 179 __ stop("stop-at"); |
179 } | 180 } |
180 #endif | 181 #endif |
181 | 182 |
182 // Allocate space for locals and initialize them. This also checks | 183 if (mode == PRIMARY) { |
183 // for stack overflow. | 184 frame_->Enter(); |
184 frame_->AllocateStackSlots(); | 185 // tos: code slot |
| 186 |
| 187 // Allocate space for locals and initialize them. This also checks |
| 188 // for stack overflow. |
| 189 frame_->AllocateStackSlots(); |
| 190 |
| 191 VirtualFrame::SpilledScope spilled_scope; |
| 192 int heap_slots = scope_->num_heap_slots(); |
| 193 if (heap_slots > 0) { |
| 194 // Allocate local context. |
| 195 // Get outer context and create a new context based on it. |
| 196 __ ldr(r0, frame_->Function()); |
| 197 frame_->EmitPush(r0); |
| 198 if (heap_slots <= FastNewContextStub::kMaximumSlots) { |
| 199 FastNewContextStub stub(heap_slots); |
| 200 frame_->CallStub(&stub, 1); |
| 201 } else { |
| 202 frame_->CallRuntime(Runtime::kNewContext, 1); |
| 203 } |
| 204 |
| 205 #ifdef DEBUG |
| 206 JumpTarget verified_true; |
| 207 __ cmp(r0, Operand(cp)); |
| 208 verified_true.Branch(eq); |
| 209 __ stop("NewContext: r0 is expected to be the same as cp"); |
| 210 verified_true.Bind(); |
| 211 #endif |
| 212 // Update context local. |
| 213 __ str(cp, frame_->Context()); |
| 214 } |
| 215 |
| 216 // TODO(1241774): Improve this code: |
| 217 // 1) only needed if we have a context |
| 218 // 2) no need to recompute context ptr every single time |
| 219 // 3) don't copy parameter operand code from SlotOperand! |
| 220 { |
| 221 Comment cmnt2(masm_, "[ copy context parameters into .context"); |
| 222 |
| 223 // Note that iteration order is relevant here! If we have the same |
| 224 // parameter twice (e.g., function (x, y, x)), and that parameter |
| 225 // needs to be copied into the context, it must be the last argument |
| 226 // passed to the parameter that needs to be copied. This is a rare |
| 227 // case so we don't check for it, instead we rely on the copying |
| 228 // order: such a parameter is copied repeatedly into the same |
| 229 // context location and thus the last value is what is seen inside |
| 230 // the function. |
| 231 for (int i = 0; i < scope_->num_parameters(); i++) { |
| 232 Variable* par = scope_->parameter(i); |
| 233 Slot* slot = par->slot(); |
| 234 if (slot != NULL && slot->type() == Slot::CONTEXT) { |
| 235 // No parameters in global scope. |
| 236 ASSERT(!scope_->is_global_scope()); |
| 237 __ ldr(r1, frame_->ParameterAt(i)); |
| 238 // Loads r2 with context; used below in RecordWrite. |
| 239 __ str(r1, SlotOperand(slot, r2)); |
| 240 // Load the offset into r3. |
| 241 int slot_offset = |
| 242 FixedArray::kHeaderSize + slot->index() * kPointerSize; |
| 243 __ mov(r3, Operand(slot_offset)); |
| 244 __ RecordWrite(r2, r3, r1); |
| 245 } |
| 246 } |
| 247 } |
| 248 |
| 249 // Store the arguments object. This must happen after context |
| 250 // initialization because the arguments object may be stored in the |
| 251 // context. |
| 252 if (scope_->arguments() != NULL) { |
| 253 Comment cmnt(masm_, "[ allocate arguments object"); |
| 254 ASSERT(scope_->arguments_shadow() != NULL); |
| 255 Variable* arguments = scope_->arguments()->var(); |
| 256 Variable* shadow = scope_->arguments_shadow()->var(); |
| 257 ASSERT(arguments != NULL && arguments->slot() != NULL); |
| 258 ASSERT(shadow != NULL && shadow->slot() != NULL); |
| 259 ArgumentsAccessStub stub(ArgumentsAccessStub::NEW_OBJECT); |
| 260 __ ldr(r2, frame_->Function()); |
| 261 // The receiver is below the arguments, the return address, and the |
| 262 // frame pointer on the stack. |
| 263 const int kReceiverDisplacement = 2 + scope_->num_parameters(); |
| 264 __ add(r1, fp, Operand(kReceiverDisplacement * kPointerSize)); |
| 265 __ mov(r0, Operand(Smi::FromInt(scope_->num_parameters()))); |
| 266 frame_->Adjust(3); |
| 267 __ stm(db_w, sp, r0.bit() | r1.bit() | r2.bit()); |
| 268 frame_->CallStub(&stub, 3); |
| 269 frame_->EmitPush(r0); |
| 270 StoreToSlot(arguments->slot(), NOT_CONST_INIT); |
| 271 StoreToSlot(shadow->slot(), NOT_CONST_INIT); |
| 272 frame_->Drop(); // Value is no longer needed. |
| 273 } |
| 274 |
| 275 // Initialize ThisFunction reference if present. |
| 276 if (scope_->is_function_scope() && scope_->function() != NULL) { |
| 277 __ mov(ip, Operand(Factory::the_hole_value())); |
| 278 frame_->EmitPush(ip); |
| 279 StoreToSlot(scope_->function()->slot(), NOT_CONST_INIT); |
| 280 } |
| 281 } else { |
| 282 // When used as the secondary compiler for splitting, r1, cp, |
| 283 // fp, and lr have been pushed on the stack. Adjust the virtual |
| 284 // frame to match this state. |
| 285 frame_->Adjust(4); |
| 286 allocator_->Unuse(r1); |
| 287 allocator_->Unuse(lr); |
| 288 } |
| 289 |
185 // Initialize the function return target after the locals are set | 290 // Initialize the function return target after the locals are set |
186 // up, because it needs the expected frame height from the frame. | 291 // up, because it needs the expected frame height from the frame. |
187 function_return_.set_direction(JumpTarget::BIDIRECTIONAL); | 292 function_return_.set_direction(JumpTarget::BIDIRECTIONAL); |
188 function_return_is_shadowed_ = false; | 293 function_return_is_shadowed_ = false; |
189 | 294 |
190 VirtualFrame::SpilledScope spilled_scope; | |
191 int heap_slots = scope_->num_heap_slots(); | |
192 if (heap_slots > 0) { | |
193 // Allocate local context. | |
194 // Get outer context and create a new context based on it. | |
195 __ ldr(r0, frame_->Function()); | |
196 frame_->EmitPush(r0); | |
197 if (heap_slots <= FastNewContextStub::kMaximumSlots) { | |
198 FastNewContextStub stub(heap_slots); | |
199 frame_->CallStub(&stub, 1); | |
200 } else { | |
201 frame_->CallRuntime(Runtime::kNewContext, 1); | |
202 } | |
203 | |
204 #ifdef DEBUG | |
205 JumpTarget verified_true; | |
206 __ cmp(r0, Operand(cp)); | |
207 verified_true.Branch(eq); | |
208 __ stop("NewContext: r0 is expected to be the same as cp"); | |
209 verified_true.Bind(); | |
210 #endif | |
211 // Update context local. | |
212 __ str(cp, frame_->Context()); | |
213 } | |
214 | |
215 // TODO(1241774): Improve this code: | |
216 // 1) only needed if we have a context | |
217 // 2) no need to recompute context ptr every single time | |
218 // 3) don't copy parameter operand code from SlotOperand! | |
219 { | |
220 Comment cmnt2(masm_, "[ copy context parameters into .context"); | |
221 | |
222 // Note that iteration order is relevant here! If we have the same | |
223 // parameter twice (e.g., function (x, y, x)), and that parameter | |
224 // needs to be copied into the context, it must be the last argument | |
225 // passed to the parameter that needs to be copied. This is a rare | |
226 // case so we don't check for it, instead we rely on the copying | |
227 // order: such a parameter is copied repeatedly into the same | |
228 // context location and thus the last value is what is seen inside | |
229 // the function. | |
230 for (int i = 0; i < scope_->num_parameters(); i++) { | |
231 Variable* par = scope_->parameter(i); | |
232 Slot* slot = par->slot(); | |
233 if (slot != NULL && slot->type() == Slot::CONTEXT) { | |
234 ASSERT(!scope_->is_global_scope()); // no parameters in global scope | |
235 __ ldr(r1, frame_->ParameterAt(i)); | |
236 // Loads r2 with context; used below in RecordWrite. | |
237 __ str(r1, SlotOperand(slot, r2)); | |
238 // Load the offset into r3. | |
239 int slot_offset = | |
240 FixedArray::kHeaderSize + slot->index() * kPointerSize; | |
241 __ mov(r3, Operand(slot_offset)); | |
242 __ RecordWrite(r2, r3, r1); | |
243 } | |
244 } | |
245 } | |
246 | |
247 // Store the arguments object. This must happen after context | |
248 // initialization because the arguments object may be stored in the | |
249 // context. | |
250 if (scope_->arguments() != NULL) { | |
251 Comment cmnt(masm_, "[ allocate arguments object"); | |
252 ASSERT(scope_->arguments_shadow() != NULL); | |
253 Variable* arguments = scope_->arguments()->var(); | |
254 Variable* shadow = scope_->arguments_shadow()->var(); | |
255 ASSERT(arguments != NULL && arguments->slot() != NULL); | |
256 ASSERT(shadow != NULL && shadow->slot() != NULL); | |
257 ArgumentsAccessStub stub(ArgumentsAccessStub::NEW_OBJECT); | |
258 __ ldr(r2, frame_->Function()); | |
259 // The receiver is below the arguments, the return address, and the | |
260 // frame pointer on the stack. | |
261 const int kReceiverDisplacement = 2 + scope_->num_parameters(); | |
262 __ add(r1, fp, Operand(kReceiverDisplacement * kPointerSize)); | |
263 __ mov(r0, Operand(Smi::FromInt(scope_->num_parameters()))); | |
264 frame_->Adjust(3); | |
265 __ stm(db_w, sp, r0.bit() | r1.bit() | r2.bit()); | |
266 frame_->CallStub(&stub, 3); | |
267 frame_->EmitPush(r0); | |
268 StoreToSlot(arguments->slot(), NOT_CONST_INIT); | |
269 StoreToSlot(shadow->slot(), NOT_CONST_INIT); | |
270 frame_->Drop(); // Value is no longer needed. | |
271 } | |
272 | |
273 // Initialize ThisFunction reference if present. | |
274 if (scope_->is_function_scope() && scope_->function() != NULL) { | |
275 __ mov(ip, Operand(Factory::the_hole_value())); | |
276 frame_->EmitPush(ip); | |
277 StoreToSlot(scope_->function()->slot(), NOT_CONST_INIT); | |
278 } | |
279 | |
280 // Generate code to 'execute' declarations and initialize functions | 295 // Generate code to 'execute' declarations and initialize functions |
281 // (source elements). In case of an illegal redeclaration we need to | 296 // (source elements). In case of an illegal redeclaration we need to |
282 // handle that instead of processing the declarations. | 297 // handle that instead of processing the declarations. |
283 if (scope_->HasIllegalRedeclaration()) { | 298 if (scope_->HasIllegalRedeclaration()) { |
284 Comment cmnt(masm_, "[ illegal redeclarations"); | 299 Comment cmnt(masm_, "[ illegal redeclarations"); |
285 scope_->VisitIllegalRedeclaration(this); | 300 scope_->VisitIllegalRedeclaration(this); |
286 } else { | 301 } else { |
287 Comment cmnt(masm_, "[ declarations"); | 302 Comment cmnt(masm_, "[ declarations"); |
288 ProcessDeclarations(scope_->declarations()); | 303 ProcessDeclarations(scope_->declarations()); |
289 // Bail out if a stack-overflow exception occurred when processing | 304 // Bail out if a stack-overflow exception occurred when processing |
(...skipping 6623 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
6913 // Call the runtime; it returns -1 (less), 0 (equal), or 1 (greater) | 6928 // Call the runtime; it returns -1 (less), 0 (equal), or 1 (greater) |
6914 // tagged as a small integer. | 6929 // tagged as a small integer. |
6915 __ bind(&runtime); | 6930 __ bind(&runtime); |
6916 __ TailCallRuntime(ExternalReference(Runtime::kStringCompare), 2, 1); | 6931 __ TailCallRuntime(ExternalReference(Runtime::kStringCompare), 2, 1); |
6917 } | 6932 } |
6918 | 6933 |
6919 | 6934 |
6920 #undef __ | 6935 #undef __ |
6921 | 6936 |
6922 } } // namespace v8::internal | 6937 } } // namespace v8::internal |
OLD | NEW |