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 11 matching lines...) Expand all Loading... |
22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | 22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | 23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
27 | 27 |
28 #include "v8.h" | 28 #include "v8.h" |
29 | 29 |
30 #include "codegen-inl.h" | 30 #include "codegen-inl.h" |
31 #include "fast-codegen.h" | 31 #include "fast-codegen.h" |
| 32 #include "parser.h" |
32 | 33 |
33 namespace v8 { | 34 namespace v8 { |
34 namespace internal { | 35 namespace internal { |
35 | 36 |
36 #define __ ACCESS_MASM(masm_) | 37 #define __ ACCESS_MASM(masm_) |
37 | 38 |
38 // Generate code for a JS function. On entry to the function the receiver | 39 // Generate code for a JS function. On entry to the function the receiver |
39 // and arguments have been pushed on the stack left to right, with the | 40 // and arguments have been pushed on the stack left to right, with the |
40 // return address on top of them. The actual argument count matches the | 41 // return address on top of them. The actual argument count matches the |
41 // formal parameter count expected by the function. | 42 // formal parameter count expected by the function. |
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
93 // patch with the code required by the debugger. | 94 // patch with the code required by the debugger. |
94 __ mov(esp, ebp); | 95 __ mov(esp, ebp); |
95 __ pop(ebp); | 96 __ pop(ebp); |
96 __ ret((fun->scope()->num_parameters() + 1) * kPointerSize); | 97 __ ret((fun->scope()->num_parameters() + 1) * kPointerSize); |
97 } | 98 } |
98 } | 99 } |
99 | 100 |
100 | 101 |
101 void FastCodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) { | 102 void FastCodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) { |
102 // Call the runtime to declare the globals. | 103 // Call the runtime to declare the globals. |
| 104 __ push(esi); // The context is the first argument. |
103 __ push(Immediate(pairs)); | 105 __ push(Immediate(pairs)); |
104 __ push(esi); // The context is the second argument. | |
105 __ push(Immediate(Smi::FromInt(is_eval_ ? 1 : 0))); | 106 __ push(Immediate(Smi::FromInt(is_eval_ ? 1 : 0))); |
106 __ CallRuntime(Runtime::kDeclareGlobals, 3); | 107 __ CallRuntime(Runtime::kDeclareGlobals, 3); |
107 // Return value is ignored. | 108 // Return value is ignored. |
108 } | 109 } |
109 | 110 |
110 | 111 |
111 void FastCodeGenerator::VisitBlock(Block* stmt) { | 112 void FastCodeGenerator::VisitBlock(Block* stmt) { |
112 Comment cmnt(masm_, "[ Block"); | 113 Comment cmnt(masm_, "[ Block"); |
113 SetStatementPosition(stmt); | 114 SetStatementPosition(stmt); |
114 VisitStatements(stmt->statements()); | 115 VisitStatements(stmt->statements()); |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
150 void FastCodeGenerator::VisitFunctionLiteral(FunctionLiteral* expr) { | 151 void FastCodeGenerator::VisitFunctionLiteral(FunctionLiteral* expr) { |
151 Comment cmnt(masm_, "[ FunctionLiteral"); | 152 Comment cmnt(masm_, "[ FunctionLiteral"); |
152 | 153 |
153 // Build the function boilerplate and instantiate it. | 154 // Build the function boilerplate and instantiate it. |
154 Handle<JSFunction> boilerplate = BuildBoilerplate(expr); | 155 Handle<JSFunction> boilerplate = BuildBoilerplate(expr); |
155 if (HasStackOverflow()) return; | 156 if (HasStackOverflow()) return; |
156 | 157 |
157 ASSERT(boilerplate->IsBoilerplate()); | 158 ASSERT(boilerplate->IsBoilerplate()); |
158 | 159 |
159 // Create a new closure. | 160 // Create a new closure. |
| 161 __ push(esi); |
160 __ push(Immediate(boilerplate)); | 162 __ push(Immediate(boilerplate)); |
161 __ push(esi); | |
162 __ CallRuntime(Runtime::kNewClosure, 2); | 163 __ CallRuntime(Runtime::kNewClosure, 2); |
163 | 164 |
164 if (expr->location().is_temporary()) { | 165 if (expr->location().is_temporary()) { |
165 __ push(eax); | 166 __ push(eax); |
166 } else { | 167 } else { |
167 ASSERT(expr->location().is_nowhere()); | 168 ASSERT(expr->location().is_nowhere()); |
168 } | 169 } |
169 } | 170 } |
170 | 171 |
171 | 172 |
(...skipping 11 matching lines...) Expand all Loading... |
183 | 184 |
184 // A test eax instruction following the call is used by the IC to | 185 // A test eax instruction following the call is used by the IC to |
185 // indicate that the inobject property case was inlined. Ensure there | 186 // indicate that the inobject property case was inlined. Ensure there |
186 // is no test eax instruction here. Remember that the assembler may | 187 // is no test eax instruction here. Remember that the assembler may |
187 // choose to do peephole optimization (eg, push/pop elimination). | 188 // choose to do peephole optimization (eg, push/pop elimination). |
188 if (expr->location().is_temporary()) { | 189 if (expr->location().is_temporary()) { |
189 // Replace the global object with the result. | 190 // Replace the global object with the result. |
190 __ mov(Operand(esp, 0), eax); | 191 __ mov(Operand(esp, 0), eax); |
191 } else { | 192 } else { |
192 ASSERT(expr->location().is_nowhere()); | 193 ASSERT(expr->location().is_nowhere()); |
193 __ pop(eax); | 194 __ add(Operand(esp), Immediate(kPointerSize)); |
194 } | 195 } |
195 | 196 |
196 } else { | 197 } else { |
197 Comment cmnt(masm_, "Stack slot"); | 198 Comment cmnt(masm_, "Stack slot"); |
198 Slot* slot = rewrite->AsSlot(); | 199 Slot* slot = rewrite->AsSlot(); |
199 ASSERT(slot != NULL); | 200 ASSERT(slot != NULL); |
200 if (expr->location().is_temporary()) { | 201 if (expr->location().is_temporary()) { |
201 __ push(Operand(ebp, SlotOffset(slot))); | 202 __ push(Operand(ebp, SlotOffset(slot))); |
202 } else { | 203 } else { |
203 ASSERT(expr->location().is_nowhere()); | 204 ASSERT(expr->location().is_nowhere()); |
204 } | 205 } |
205 } | 206 } |
206 } | 207 } |
207 | 208 |
208 | 209 |
| 210 void FastCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) { |
| 211 Comment cmnt(masm_, "[ ArrayLiteral"); |
| 212 Label make_clone; |
| 213 |
| 214 // Fetch the function's literals array. |
| 215 __ mov(ebx, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset)); |
| 216 __ mov(ebx, FieldOperand(ebx, JSFunction::kLiteralsOffset)); |
| 217 // Check if the literal's boilerplate has been instantiated. |
| 218 int offset = |
| 219 FixedArray::kHeaderSize + (expr->literal_index() * kPointerSize); |
| 220 __ mov(eax, FieldOperand(ebx, offset)); |
| 221 __ cmp(eax, Factory::undefined_value()); |
| 222 __ j(not_equal, &make_clone); |
| 223 |
| 224 // Instantiate the boilerplate. |
| 225 __ push(ebx); |
| 226 __ push(Immediate(Smi::FromInt(expr->literal_index()))); |
| 227 __ push(Immediate(expr->literals())); |
| 228 __ CallRuntime(Runtime::kCreateArrayLiteralBoilerplate, 3); |
| 229 |
| 230 __ bind(&make_clone); |
| 231 // Clone the boilerplate. |
| 232 __ push(eax); |
| 233 if (expr->depth() > 1) { |
| 234 __ CallRuntime(Runtime::kCloneLiteralBoilerplate, 1); |
| 235 } else { |
| 236 __ CallRuntime(Runtime::kCloneShallowLiteralBoilerplate, 1); |
| 237 } |
| 238 |
| 239 bool result_saved = false; // Is the result saved to the stack? |
| 240 |
| 241 // Emit code to evaluate all the non-constant subexpressions and to store |
| 242 // them into the newly cloned array. |
| 243 ZoneList<Expression*>* subexprs = expr->values(); |
| 244 for (int i = 0, len = subexprs->length(); i < len; i++) { |
| 245 Expression* subexpr = subexprs->at(i); |
| 246 // If the subexpression is a literal or a simple materialized literal it |
| 247 // is already set in the cloned array. |
| 248 if (subexpr->AsLiteral() != NULL || |
| 249 CompileTimeValue::IsCompileTimeValue(subexpr)) { |
| 250 continue; |
| 251 } |
| 252 |
| 253 if (!result_saved) { |
| 254 __ push(eax); |
| 255 result_saved = true; |
| 256 } |
| 257 Visit(subexpr); |
| 258 ASSERT(subexpr->location().is_temporary()); |
| 259 |
| 260 // Store the subexpression value in the array's elements. |
| 261 __ pop(eax); // Subexpression value. |
| 262 __ mov(ebx, Operand(esp, 0)); // Copy of array literal. |
| 263 __ mov(ebx, FieldOperand(ebx, JSObject::kElementsOffset)); |
| 264 int offset = FixedArray::kHeaderSize + (i * kPointerSize); |
| 265 __ mov(FieldOperand(ebx, offset), eax); |
| 266 |
| 267 // Update the write barrier for the array store. |
| 268 __ RecordWrite(ebx, offset, eax, ecx); |
| 269 } |
| 270 |
| 271 Location destination = expr->location(); |
| 272 if (destination.is_nowhere() && result_saved) { |
| 273 __ add(Operand(esp), Immediate(kPointerSize)); |
| 274 } else if (destination.is_temporary() && !result_saved) { |
| 275 __ push(eax); |
| 276 } |
| 277 } |
| 278 |
| 279 |
209 void FastCodeGenerator::VisitAssignment(Assignment* expr) { | 280 void FastCodeGenerator::VisitAssignment(Assignment* expr) { |
210 Comment cmnt(masm_, "[ Assignment"); | 281 Comment cmnt(masm_, "[ Assignment"); |
211 ASSERT(expr->op() == Token::ASSIGN || expr->op() == Token::INIT_VAR); | 282 ASSERT(expr->op() == Token::ASSIGN || expr->op() == Token::INIT_VAR); |
212 Expression* rhs = expr->value(); | 283 Expression* rhs = expr->value(); |
213 Visit(rhs); | 284 Visit(rhs); |
214 | 285 |
215 // Left-hand side can only be a global or a (parameter or local) slot. | 286 // Left-hand side can only be a global or a (parameter or local) slot. |
216 Variable* var = expr->target()->AsVariableProxy()->AsVariable(); | 287 Variable* var = expr->target()->AsVariableProxy()->AsVariable(); |
217 ASSERT(var != NULL); | 288 ASSERT(var != NULL); |
218 ASSERT(var->is_global() || var->slot() != NULL); | 289 ASSERT(var->is_global() || var->slot() != NULL); |
(...skipping 18 matching lines...) Expand all Loading... |
237 } | 308 } |
238 __ mov(ecx, var->name()); | 309 __ mov(ecx, var->name()); |
239 __ push(CodeGenerator::GlobalObject()); | 310 __ push(CodeGenerator::GlobalObject()); |
240 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize)); | 311 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize)); |
241 __ call(ic, RelocInfo::CODE_TARGET); | 312 __ call(ic, RelocInfo::CODE_TARGET); |
242 // Overwrite the global object on the stack with the result if needed. | 313 // Overwrite the global object on the stack with the result if needed. |
243 if (destination.is_temporary()) { | 314 if (destination.is_temporary()) { |
244 __ mov(Operand(esp, 0), eax); | 315 __ mov(Operand(esp, 0), eax); |
245 } else { | 316 } else { |
246 ASSERT(destination.is_nowhere()); | 317 ASSERT(destination.is_nowhere()); |
247 __ pop(eax); | 318 __ add(Operand(esp), Immediate(kPointerSize)); |
248 } | 319 } |
249 | 320 |
250 } else { | 321 } else { |
251 // Local or parameter assignment. | 322 // Local or parameter assignment. |
252 if (source.is_temporary()) { | 323 if (source.is_temporary()) { |
253 if (destination.is_temporary()) { | 324 if (destination.is_temporary()) { |
254 // Case 'temp1 <- (var = temp0)'. Preserve right-hand-side | 325 // Case 'temp1 <- (var = temp0)'. Preserve right-hand-side |
255 // temporary on the stack. | 326 // temporary on the stack. |
256 __ mov(eax, Operand(esp, 0)); | 327 __ mov(eax, Operand(esp, 0)); |
257 __ mov(Operand(ebp, SlotOffset(var->slot())), eax); | 328 __ mov(Operand(ebp, SlotOffset(var->slot())), eax); |
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
301 Handle<Code> ic = CodeGenerator::ComputeCallInitialize(arg_count, | 372 Handle<Code> ic = CodeGenerator::ComputeCallInitialize(arg_count, |
302 NOT_IN_LOOP); | 373 NOT_IN_LOOP); |
303 __ call(ic, RelocInfo::CODE_TARGET_CONTEXT); | 374 __ call(ic, RelocInfo::CODE_TARGET_CONTEXT); |
304 // Restore context register. | 375 // Restore context register. |
305 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); | 376 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); |
306 // Discard the function left on TOS. | 377 // Discard the function left on TOS. |
307 if (expr->location().is_temporary()) { | 378 if (expr->location().is_temporary()) { |
308 __ mov(Operand(esp, 0), eax); | 379 __ mov(Operand(esp, 0), eax); |
309 } else { | 380 } else { |
310 ASSERT(expr->location().is_nowhere()); | 381 ASSERT(expr->location().is_nowhere()); |
311 __ pop(eax); | 382 __ add(Operand(esp), Immediate(kPointerSize)); |
312 } | 383 } |
313 } | 384 } |
314 | 385 |
315 | 386 |
316 void FastCodeGenerator::VisitCallRuntime(CallRuntime* expr) { | 387 void FastCodeGenerator::VisitCallRuntime(CallRuntime* expr) { |
317 Comment cmnt(masm_, "[ CallRuntime"); | 388 Comment cmnt(masm_, "[ CallRuntime"); |
318 ZoneList<Expression*>* args = expr->arguments(); | 389 ZoneList<Expression*>* args = expr->arguments(); |
319 Runtime::Function* function = expr->function(); | 390 Runtime::Function* function = expr->function(); |
320 | 391 |
321 ASSERT(function != NULL); | 392 ASSERT(function != NULL); |
(...skipping 12 matching lines...) Expand all Loading... |
334 __ CallRuntime(function, arg_count); | 405 __ CallRuntime(function, arg_count); |
335 if (expr->location().is_temporary()) { | 406 if (expr->location().is_temporary()) { |
336 __ push(eax); | 407 __ push(eax); |
337 } else { | 408 } else { |
338 ASSERT(expr->location().is_nowhere()); | 409 ASSERT(expr->location().is_nowhere()); |
339 } | 410 } |
340 } | 411 } |
341 | 412 |
342 | 413 |
343 } } // namespace v8::internal | 414 } } // namespace v8::internal |
OLD | NEW |