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 "compiler.h" | 31 #include "compiler.h" |
| 32 #include "debug.h" |
32 #include "fast-codegen.h" | 33 #include "fast-codegen.h" |
33 #include "parser.h" | 34 #include "parser.h" |
34 #include "debug.h" | |
35 | 35 |
36 namespace v8 { | 36 namespace v8 { |
37 namespace internal { | 37 namespace internal { |
38 | 38 |
39 #define __ ACCESS_MASM(masm_) | 39 #define __ ACCESS_MASM(masm_) |
40 | 40 |
41 // Generate code for a JS function. On entry to the function the receiver | 41 // Generate code for a JS function. On entry to the function the receiver |
42 // and arguments have been pushed on the stack left to right, with the | 42 // and arguments have been pushed on the stack left to right, with the |
43 // return address on top of them. The actual argument count matches the | 43 // return address on top of them. The actual argument count matches the |
44 // formal parameter count expected by the function. | 44 // formal parameter count expected by the function. |
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
109 } else { | 109 } else { |
110 __ push(Operand(ebp, JavaScriptFrameConstants::kFunctionOffset)); | 110 __ push(Operand(ebp, JavaScriptFrameConstants::kFunctionOffset)); |
111 } | 111 } |
112 // Receiver is just before the parameters on the caller's stack. | 112 // Receiver is just before the parameters on the caller's stack. |
113 __ lea(edx, Operand(ebp, StandardFrameConstants::kCallerSPOffset + | 113 __ lea(edx, Operand(ebp, StandardFrameConstants::kCallerSPOffset + |
114 fun->num_parameters() * kPointerSize)); | 114 fun->num_parameters() * kPointerSize)); |
115 __ push(edx); | 115 __ push(edx); |
116 __ push(Immediate(Smi::FromInt(fun->num_parameters()))); | 116 __ push(Immediate(Smi::FromInt(fun->num_parameters()))); |
117 // Arguments to ArgumentsAccessStub: | 117 // Arguments to ArgumentsAccessStub: |
118 // function, receiver address, parameter count. | 118 // function, receiver address, parameter count. |
119 // The stub will rewrite receiever and parameter count if the previous | 119 // The stub will rewrite receiver and parameter count if the previous |
120 // stack frame was an arguments adapter frame. | 120 // stack frame was an arguments adapter frame. |
121 ArgumentsAccessStub stub(ArgumentsAccessStub::NEW_OBJECT); | 121 ArgumentsAccessStub stub(ArgumentsAccessStub::NEW_OBJECT); |
122 __ CallStub(&stub); | 122 __ CallStub(&stub); |
123 __ mov(ecx, eax); // Duplicate result. | 123 __ mov(ecx, eax); // Duplicate result. |
124 Move(arguments->slot(), eax, ebx, edx); | 124 Move(arguments->slot(), eax, ebx, edx); |
125 Slot* dot_arguments_slot = | 125 Slot* dot_arguments_slot = |
126 fun->scope()->arguments_shadow()->AsVariable()->slot(); | 126 fun->scope()->arguments_shadow()->AsVariable()->slot(); |
127 Move(dot_arguments_slot, ecx, ebx, edx); | 127 Move(dot_arguments_slot, ecx, ebx, edx); |
128 } | 128 } |
129 | 129 |
130 | |
131 { Comment cmnt(masm_, "[ Declarations"); | 130 { Comment cmnt(masm_, "[ Declarations"); |
132 VisitDeclarations(fun->scope()->declarations()); | 131 VisitDeclarations(fun->scope()->declarations()); |
133 } | 132 } |
134 | 133 |
135 { Comment cmnt(masm_, "[ Stack check"); | 134 { Comment cmnt(masm_, "[ Stack check"); |
136 Label ok; | 135 Label ok; |
137 ExternalReference stack_limit = | 136 ExternalReference stack_limit = |
138 ExternalReference::address_of_stack_limit(); | 137 ExternalReference::address_of_stack_limit(); |
139 __ cmp(esp, Operand::StaticVariable(stack_limit)); | 138 __ cmp(esp, Operand::StaticVariable(stack_limit)); |
140 __ j(above_equal, &ok, taken); | 139 __ j(above_equal, &ok, taken); |
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
187 #ifdef ENABLE_DEBUGGER_SUPPORT | 186 #ifdef ENABLE_DEBUGGER_SUPPORT |
188 // Check that the size of the code used for returning matches what is | 187 // Check that the size of the code used for returning matches what is |
189 // expected by the debugger. | 188 // expected by the debugger. |
190 ASSERT_EQ(Assembler::kJSReturnSequenceLength, | 189 ASSERT_EQ(Assembler::kJSReturnSequenceLength, |
191 masm_->SizeOfCodeGeneratedSince(&check_exit_codesize)); | 190 masm_->SizeOfCodeGeneratedSince(&check_exit_codesize)); |
192 #endif | 191 #endif |
193 } | 192 } |
194 } | 193 } |
195 | 194 |
196 | 195 |
197 void FastCodeGenerator::Apply(Expression::Context context, | 196 void FastCodeGenerator::Apply(Expression::Context context, Register reg) { |
198 Slot* slot, | 197 switch (context) { |
199 Register scratch) { | 198 case Expression::kUninitialized: |
| 199 UNREACHABLE(); |
| 200 |
| 201 case Expression::kEffect: |
| 202 // Nothing to do. |
| 203 break; |
| 204 |
| 205 case Expression::kValue: |
| 206 // Move value into place. |
| 207 switch (location_) { |
| 208 case kAccumulator: |
| 209 if (!reg.is(result_register())) __ mov(result_register(), reg); |
| 210 break; |
| 211 case kStack: |
| 212 __ push(reg); |
| 213 break; |
| 214 } |
| 215 break; |
| 216 |
| 217 case Expression::kTest: |
| 218 // For simplicity we always test the accumulator register. |
| 219 if (!reg.is(result_register())) __ mov(result_register(), reg); |
| 220 DoTest(context); |
| 221 break; |
| 222 |
| 223 case Expression::kValueTest: |
| 224 case Expression::kTestValue: |
| 225 if (!reg.is(result_register())) __ mov(result_register(), reg); |
| 226 switch (location_) { |
| 227 case kAccumulator: |
| 228 break; |
| 229 case kStack: |
| 230 __ push(result_register()); |
| 231 break; |
| 232 } |
| 233 DoTest(context); |
| 234 break; |
| 235 } |
| 236 } |
| 237 |
| 238 |
| 239 void FastCodeGenerator::Apply(Expression::Context context, Slot* slot) { |
200 switch (context) { | 240 switch (context) { |
201 case Expression::kUninitialized: | 241 case Expression::kUninitialized: |
202 UNREACHABLE(); | 242 UNREACHABLE(); |
203 case Expression::kEffect: | 243 case Expression::kEffect: |
| 244 // Nothing to do. |
204 break; | 245 break; |
205 case Expression::kValue: { | 246 case Expression::kValue: { |
206 MemOperand location = EmitSlotSearch(slot, scratch); | 247 MemOperand slot_operand = EmitSlotSearch(slot, result_register()); |
207 __ push(location); | 248 switch (location_) { |
| 249 case kAccumulator: |
| 250 __ mov(result_register(), slot_operand); |
| 251 break; |
| 252 case kStack: |
| 253 // Memory operands can be pushed directly. |
| 254 __ push(slot_operand); |
| 255 break; |
| 256 } |
208 break; | 257 break; |
209 } | 258 } |
| 259 |
210 case Expression::kTest: | 260 case Expression::kTest: |
| 261 // For simplicity we always test the accumulator register. |
| 262 Move(result_register(), slot); |
| 263 DoTest(context); |
| 264 break; |
| 265 |
211 case Expression::kValueTest: | 266 case Expression::kValueTest: |
212 case Expression::kTestValue: | 267 case Expression::kTestValue: |
213 Move(scratch, slot); | 268 Move(result_register(), slot); |
214 Apply(context, scratch); | 269 switch (location_) { |
| 270 case kAccumulator: |
| 271 break; |
| 272 case kStack: |
| 273 __ push(result_register()); |
| 274 break; |
| 275 } |
| 276 DoTest(context); |
215 break; | 277 break; |
216 } | 278 } |
217 } | 279 } |
218 | 280 |
219 | 281 |
220 void FastCodeGenerator::Apply(Expression::Context context, Literal* lit) { | 282 void FastCodeGenerator::Apply(Expression::Context context, Literal* lit) { |
221 switch (context) { | 283 switch (context) { |
222 case Expression::kUninitialized: | 284 case Expression::kUninitialized: |
223 UNREACHABLE(); | 285 UNREACHABLE(); |
224 case Expression::kEffect: | 286 case Expression::kEffect: |
| 287 // Nothing to do. |
225 break; | 288 break; |
226 case Expression::kValue: | 289 case Expression::kValue: |
227 __ push(Immediate(lit->handle())); | 290 switch (location_) { |
| 291 case kAccumulator: |
| 292 __ mov(result_register(), lit->handle()); |
| 293 break; |
| 294 case kStack: |
| 295 // Immediates can be pushed directly. |
| 296 __ push(Immediate(lit->handle())); |
| 297 break; |
| 298 } |
228 break; | 299 break; |
| 300 |
229 case Expression::kTest: | 301 case Expression::kTest: |
| 302 // For simplicity we always test the accumulator register. |
| 303 __ mov(result_register(), lit->handle()); |
| 304 DoTest(context); |
| 305 break; |
| 306 |
230 case Expression::kValueTest: | 307 case Expression::kValueTest: |
231 case Expression::kTestValue: | 308 case Expression::kTestValue: |
232 __ mov(eax, lit->handle()); | 309 __ mov(result_register(), lit->handle()); |
233 Apply(context, eax); | 310 switch (location_) { |
| 311 case kAccumulator: |
| 312 break; |
| 313 case kStack: |
| 314 __ push(result_register()); |
| 315 break; |
| 316 } |
| 317 DoTest(context); |
234 break; | 318 break; |
235 } | 319 } |
236 } | 320 } |
237 | 321 |
238 | 322 |
239 void FastCodeGenerator::ApplyTOS(Expression::Context context) { | 323 void FastCodeGenerator::ApplyTOS(Expression::Context context) { |
240 switch (context) { | 324 switch (context) { |
241 case Expression::kUninitialized: | 325 case Expression::kUninitialized: |
242 UNREACHABLE(); | 326 UNREACHABLE(); |
| 327 |
243 case Expression::kEffect: | 328 case Expression::kEffect: |
244 __ Drop(1); | 329 __ Drop(1); |
245 break; | 330 break; |
| 331 |
246 case Expression::kValue: | 332 case Expression::kValue: |
| 333 switch (location_) { |
| 334 case kAccumulator: |
| 335 __ pop(result_register()); |
| 336 break; |
| 337 case kStack: |
| 338 break; |
| 339 } |
247 break; | 340 break; |
| 341 |
248 case Expression::kTest: | 342 case Expression::kTest: |
249 __ pop(eax); | 343 // For simplicity we always test the accumulator register. |
250 TestAndBranch(eax, true_label_, false_label_); | 344 __ pop(result_register()); |
| 345 DoTest(context); |
251 break; | 346 break; |
252 case Expression::kValueTest: { | 347 |
253 Label discard; | 348 case Expression::kValueTest: |
254 __ mov(eax, Operand(esp, 0)); | 349 case Expression::kTestValue: |
255 TestAndBranch(eax, true_label_, &discard); | 350 switch (location_) { |
256 __ bind(&discard); | 351 case kAccumulator: |
257 __ Drop(1); | 352 __ pop(result_register()); |
258 __ jmp(false_label_); | 353 break; |
| 354 case kStack: |
| 355 __ mov(result_register(), Operand(esp, 0)); |
| 356 break; |
| 357 } |
| 358 DoTest(context); |
259 break; | 359 break; |
260 } | |
261 case Expression::kTestValue: { | |
262 Label discard; | |
263 __ mov(eax, Operand(esp, 0)); | |
264 TestAndBranch(eax, &discard, false_label_); | |
265 __ bind(&discard); | |
266 __ Drop(1); | |
267 __ jmp(true_label_); | |
268 } | |
269 } | 360 } |
270 } | 361 } |
271 | 362 |
272 | 363 |
273 void FastCodeGenerator::DropAndApply(int count, | 364 void FastCodeGenerator::DropAndApply(int count, |
274 Expression::Context context, | 365 Expression::Context context, |
275 Register reg) { | 366 Register reg) { |
276 ASSERT(count > 0); | 367 ASSERT(count > 0); |
277 ASSERT(!reg.is(esp)); | 368 ASSERT(!reg.is(esp)); |
278 switch (context) { | 369 switch (context) { |
279 case Expression::kUninitialized: | 370 case Expression::kUninitialized: |
280 UNREACHABLE(); | 371 UNREACHABLE(); |
| 372 |
281 case Expression::kEffect: | 373 case Expression::kEffect: |
282 __ Drop(count); | 374 __ Drop(count); |
283 break; | 375 break; |
284 case Expression::kValue: | 376 |
285 if (count > 1) __ Drop(count - 1); | 377 case Expression::kValue: |
286 __ mov(Operand(esp, 0), reg); | 378 switch (location_) { |
287 break; | 379 case kAccumulator: |
288 case Expression::kTest: | 380 __ Drop(count); |
| 381 if (!reg.is(result_register())) __ mov(result_register(), reg); |
| 382 break; |
| 383 case kStack: |
| 384 if (count > 1) __ Drop(count - 1); |
| 385 __ mov(Operand(esp, 0), reg); |
| 386 break; |
| 387 } |
| 388 break; |
| 389 |
| 390 case Expression::kTest: |
| 391 // For simplicity we always test the accumulator register. |
289 __ Drop(count); | 392 __ Drop(count); |
290 TestAndBranch(reg, true_label_, false_label_); | 393 if (!reg.is(result_register())) __ mov(result_register(), reg); |
291 break; | 394 DoTest(context); |
292 case Expression::kValueTest: { | 395 break; |
293 Label discard; | 396 |
294 if (count > 1) __ Drop(count - 1); | 397 case Expression::kValueTest: |
295 __ mov(Operand(esp, 0), reg); | 398 case Expression::kTestValue: |
296 TestAndBranch(reg, true_label_, &discard); | 399 switch (location_) { |
| 400 case kAccumulator: |
| 401 __ Drop(count); |
| 402 if (!reg.is(result_register())) __ mov(result_register(), reg); |
| 403 break; |
| 404 case kStack: |
| 405 if (count > 1) __ Drop(count - 1); |
| 406 __ mov(result_register(), reg); |
| 407 __ mov(Operand(esp, 0), result_register()); |
| 408 break; |
| 409 } |
| 410 DoTest(context); |
| 411 break; |
| 412 } |
| 413 } |
| 414 |
| 415 |
| 416 void FastCodeGenerator::Apply(Expression::Context context, |
| 417 Label* materialize_true, |
| 418 Label* materialize_false) { |
| 419 switch (context) { |
| 420 case Expression::kUninitialized: |
| 421 |
| 422 case Expression::kEffect: |
| 423 ASSERT_EQ(materialize_true, materialize_false); |
| 424 __ bind(materialize_true); |
| 425 break; |
| 426 |
| 427 case Expression::kValue: { |
| 428 Label done; |
| 429 switch (location_) { |
| 430 case kAccumulator: |
| 431 __ bind(materialize_true); |
| 432 __ mov(result_register(), Factory::true_value()); |
| 433 __ jmp(&done); |
| 434 __ bind(materialize_false); |
| 435 __ mov(result_register(), Factory::false_value()); |
| 436 break; |
| 437 case kStack: |
| 438 __ bind(materialize_true); |
| 439 __ push(Immediate(Factory::true_value())); |
| 440 __ jmp(&done); |
| 441 __ bind(materialize_false); |
| 442 __ push(Immediate(Factory::false_value())); |
| 443 break; |
| 444 } |
| 445 __ bind(&done); |
| 446 break; |
| 447 } |
| 448 |
| 449 case Expression::kTest: |
| 450 break; |
| 451 |
| 452 case Expression::kValueTest: |
| 453 __ bind(materialize_true); |
| 454 switch (location_) { |
| 455 case kAccumulator: |
| 456 __ mov(result_register(), Factory::true_value()); |
| 457 break; |
| 458 case kStack: |
| 459 __ push(Immediate(Factory::true_value())); |
| 460 break; |
| 461 } |
| 462 __ jmp(true_label_); |
| 463 break; |
| 464 |
| 465 case Expression::kTestValue: |
| 466 __ bind(materialize_false); |
| 467 switch (location_) { |
| 468 case kAccumulator: |
| 469 __ mov(result_register(), Factory::false_value()); |
| 470 break; |
| 471 case kStack: |
| 472 __ push(Immediate(Factory::false_value())); |
| 473 break; |
| 474 } |
| 475 __ jmp(false_label_); |
| 476 break; |
| 477 } |
| 478 } |
| 479 |
| 480 |
| 481 void FastCodeGenerator::DoTest(Expression::Context context) { |
| 482 // The value to test is in the accumulator. If the value might be needed |
| 483 // on the stack (value/test and test/value contexts with a stack location |
| 484 // desired), then the value is already duplicated on the stack. |
| 485 ASSERT_NE(NULL, true_label_); |
| 486 ASSERT_NE(NULL, false_label_); |
| 487 |
| 488 // In value/test and test/value expression contexts with stack as the |
| 489 // desired location, there is already an extra value on the stack. Use a |
| 490 // label to discard it if unneeded. |
| 491 Label discard; |
| 492 Label* if_true = true_label_; |
| 493 Label* if_false = false_label_; |
| 494 switch (context) { |
| 495 case Expression::kUninitialized: |
| 496 case Expression::kEffect: |
| 497 case Expression::kValue: |
| 498 UNREACHABLE(); |
| 499 case Expression::kTest: |
| 500 break; |
| 501 case Expression::kValueTest: |
| 502 switch (location_) { |
| 503 case kAccumulator: |
| 504 break; |
| 505 case kStack: |
| 506 if_false = &discard; |
| 507 break; |
| 508 } |
| 509 break; |
| 510 case Expression::kTestValue: |
| 511 switch (location_) { |
| 512 case kAccumulator: |
| 513 break; |
| 514 case kStack: |
| 515 if_true = &discard; |
| 516 break; |
| 517 } |
| 518 break; |
| 519 } |
| 520 |
| 521 // Emit the inlined tests assumed by the stub. |
| 522 __ cmp(result_register(), Factory::undefined_value()); |
| 523 __ j(equal, if_false); |
| 524 __ cmp(result_register(), Factory::true_value()); |
| 525 __ j(equal, if_true); |
| 526 __ cmp(result_register(), Factory::false_value()); |
| 527 __ j(equal, if_false); |
| 528 ASSERT_EQ(0, kSmiTag); |
| 529 __ test(result_register(), Operand(result_register())); |
| 530 __ j(zero, if_false); |
| 531 __ test(result_register(), Immediate(kSmiTagMask)); |
| 532 __ j(zero, if_true); |
| 533 |
| 534 // Save a copy of the value if it may be needed and isn't already saved. |
| 535 switch (context) { |
| 536 case Expression::kUninitialized: |
| 537 case Expression::kEffect: |
| 538 case Expression::kValue: |
| 539 UNREACHABLE(); |
| 540 case Expression::kTest: |
| 541 break; |
| 542 case Expression::kValueTest: |
| 543 switch (location_) { |
| 544 case kAccumulator: |
| 545 __ push(result_register()); |
| 546 break; |
| 547 case kStack: |
| 548 break; |
| 549 } |
| 550 break; |
| 551 case Expression::kTestValue: |
| 552 switch (location_) { |
| 553 case kAccumulator: |
| 554 __ push(result_register()); |
| 555 break; |
| 556 case kStack: |
| 557 break; |
| 558 } |
| 559 break; |
| 560 } |
| 561 |
| 562 // Call the ToBoolean stub for all other cases. |
| 563 ToBooleanStub stub; |
| 564 __ push(result_register()); |
| 565 __ CallStub(&stub); |
| 566 __ test(eax, Operand(eax)); |
| 567 |
| 568 // The stub returns nonzero for true. Complete based on the context. |
| 569 switch (context) { |
| 570 case Expression::kUninitialized: |
| 571 case Expression::kEffect: |
| 572 case Expression::kValue: |
| 573 UNREACHABLE(); |
| 574 |
| 575 case Expression::kTest: |
| 576 __ j(not_zero, true_label_); |
| 577 __ jmp(false_label_); |
| 578 break; |
| 579 |
| 580 case Expression::kValueTest: |
| 581 switch (location_) { |
| 582 case kAccumulator: |
| 583 __ j(zero, &discard); |
| 584 __ pop(result_register()); |
| 585 __ jmp(true_label_); |
| 586 break; |
| 587 case kStack: |
| 588 __ j(not_zero, true_label_); |
| 589 break; |
| 590 } |
297 __ bind(&discard); | 591 __ bind(&discard); |
298 __ Drop(1); | 592 __ Drop(1); |
299 __ jmp(false_label_); | 593 __ jmp(false_label_); |
300 break; | 594 break; |
301 } | 595 |
302 case Expression::kTestValue: { | 596 case Expression::kTestValue: |
303 Label discard; | 597 switch (location_) { |
304 if (count > 1) __ Drop(count - 1); | 598 case kAccumulator: |
305 __ mov(Operand(esp, 0), reg); | 599 __ j(not_zero, &discard); |
306 TestAndBranch(reg, &discard, false_label_); | 600 __ pop(result_register()); |
| 601 __ jmp(false_label_); |
| 602 break; |
| 603 case kStack: |
| 604 __ j(zero, false_label_); |
| 605 break; |
| 606 } |
307 __ bind(&discard); | 607 __ bind(&discard); |
308 __ Drop(1); | 608 __ Drop(1); |
309 __ jmp(true_label_); | 609 __ jmp(true_label_); |
310 break; | 610 break; |
311 } | |
312 } | 611 } |
313 } | 612 } |
314 | 613 |
315 | 614 |
316 MemOperand FastCodeGenerator::EmitSlotSearch(Slot* slot, Register scratch) { | 615 MemOperand FastCodeGenerator::EmitSlotSearch(Slot* slot, Register scratch) { |
317 switch (slot->type()) { | 616 switch (slot->type()) { |
318 case Slot::PARAMETER: | 617 case Slot::PARAMETER: |
319 case Slot::LOCAL: | 618 case Slot::LOCAL: |
320 return Operand(ebp, SlotOffset(slot)); | 619 return Operand(ebp, SlotOffset(slot)); |
321 case Slot::CONTEXT: { | 620 case Slot::CONTEXT: { |
(...skipping 25 matching lines...) Expand all Loading... |
347 MemOperand location = EmitSlotSearch(dst, scratch1); | 646 MemOperand location = EmitSlotSearch(dst, scratch1); |
348 __ mov(location, src); | 647 __ mov(location, src); |
349 // Emit the write barrier code if the location is in the heap. | 648 // Emit the write barrier code if the location is in the heap. |
350 if (dst->type() == Slot::CONTEXT) { | 649 if (dst->type() == Slot::CONTEXT) { |
351 int offset = FixedArray::kHeaderSize + dst->index() * kPointerSize; | 650 int offset = FixedArray::kHeaderSize + dst->index() * kPointerSize; |
352 __ RecordWrite(scratch1, offset, src, scratch2); | 651 __ RecordWrite(scratch1, offset, src, scratch2); |
353 } | 652 } |
354 } | 653 } |
355 | 654 |
356 | 655 |
357 void FastCodeGenerator::TestAndBranch(Register source, | |
358 Label* true_label, | |
359 Label* false_label) { | |
360 ASSERT_NE(NULL, true_label); | |
361 ASSERT_NE(NULL, false_label); | |
362 // Use the shared ToBoolean stub to compile the value in the register into | |
363 // control flow to the code generator's true and false labels. Perform | |
364 // the fast checks assumed by the stub. | |
365 __ cmp(source, Factory::undefined_value()); // The undefined value is false. | |
366 __ j(equal, false_label); | |
367 __ cmp(source, Factory::true_value()); // True is true. | |
368 __ j(equal, true_label); | |
369 __ cmp(source, Factory::false_value()); // False is false. | |
370 __ j(equal, false_label); | |
371 ASSERT_EQ(0, kSmiTag); | |
372 __ test(source, Operand(source)); // The smi zero is false. | |
373 __ j(zero, false_label); | |
374 __ test(source, Immediate(kSmiTagMask)); // All other smis are true. | |
375 __ j(zero, true_label); | |
376 | |
377 // Call the stub for all other cases. | |
378 __ push(source); | |
379 ToBooleanStub stub; | |
380 __ CallStub(&stub); | |
381 __ test(eax, Operand(eax)); // The stub returns nonzero for true. | |
382 __ j(not_zero, true_label); | |
383 __ jmp(false_label); | |
384 } | |
385 | |
386 | |
387 void FastCodeGenerator::VisitDeclaration(Declaration* decl) { | 656 void FastCodeGenerator::VisitDeclaration(Declaration* decl) { |
388 Comment cmnt(masm_, "[ Declaration"); | 657 Comment cmnt(masm_, "[ Declaration"); |
389 Variable* var = decl->proxy()->var(); | 658 Variable* var = decl->proxy()->var(); |
390 ASSERT(var != NULL); // Must have been resolved. | 659 ASSERT(var != NULL); // Must have been resolved. |
391 Slot* slot = var->slot(); | 660 Slot* slot = var->slot(); |
392 Property* prop = var->AsProperty(); | 661 Property* prop = var->AsProperty(); |
393 | 662 |
394 if (slot != NULL) { | 663 if (slot != NULL) { |
395 switch (slot->type()) { | 664 switch (slot->type()) { |
396 case Slot::PARAMETER: | 665 case Slot::PARAMETER: |
397 case Slot::LOCAL: | 666 case Slot::LOCAL: |
398 if (decl->mode() == Variable::CONST) { | 667 if (decl->mode() == Variable::CONST) { |
399 __ mov(Operand(ebp, SlotOffset(slot)), | 668 __ mov(Operand(ebp, SlotOffset(slot)), |
400 Immediate(Factory::the_hole_value())); | 669 Immediate(Factory::the_hole_value())); |
401 } else if (decl->fun() != NULL) { | 670 } else if (decl->fun() != NULL) { |
402 Visit(decl->fun()); | 671 VisitForValue(decl->fun(), kAccumulator); |
403 __ pop(Operand(ebp, SlotOffset(slot))); | 672 __ mov(Operand(ebp, SlotOffset(slot)), result_register()); |
404 } | 673 } |
405 break; | 674 break; |
406 | 675 |
407 case Slot::CONTEXT: | 676 case Slot::CONTEXT: |
408 // We bypass the general EmitSlotSearch because we know more about | 677 // We bypass the general EmitSlotSearch because we know more about |
409 // this specific context. | 678 // this specific context. |
410 | 679 |
411 // The variable in the decl always resides in the current context. | 680 // The variable in the decl always resides in the current context. |
412 ASSERT_EQ(0, function_->scope()->ContextChainLength(var->scope())); | 681 ASSERT_EQ(0, function_->scope()->ContextChainLength(var->scope())); |
413 if (FLAG_debug_code) { | 682 if (FLAG_debug_code) { |
414 // Check if we have the correct context pointer. | 683 // Check if we have the correct context pointer. |
415 __ mov(ebx, | 684 __ mov(ebx, |
416 CodeGenerator::ContextOperand(esi, Context::FCONTEXT_INDEX)); | 685 CodeGenerator::ContextOperand(esi, Context::FCONTEXT_INDEX)); |
417 __ cmp(ebx, Operand(esi)); | 686 __ cmp(ebx, Operand(esi)); |
418 __ Check(equal, "Unexpected declaration in current context."); | 687 __ Check(equal, "Unexpected declaration in current context."); |
419 } | 688 } |
420 if (decl->mode() == Variable::CONST) { | 689 if (decl->mode() == Variable::CONST) { |
421 __ mov(eax, Immediate(Factory::the_hole_value())); | 690 __ mov(eax, Immediate(Factory::the_hole_value())); |
422 __ mov(CodeGenerator::ContextOperand(esi, slot->index()), eax); | 691 __ mov(CodeGenerator::ContextOperand(esi, slot->index()), eax); |
423 // No write barrier since the hole value is in old space. | 692 // No write barrier since the hole value is in old space. |
424 } else if (decl->fun() != NULL) { | 693 } else if (decl->fun() != NULL) { |
425 Visit(decl->fun()); | 694 VisitForValue(decl->fun(), kAccumulator); |
426 __ pop(eax); | 695 __ mov(CodeGenerator::ContextOperand(esi, slot->index()), |
427 __ mov(CodeGenerator::ContextOperand(esi, slot->index()), eax); | 696 result_register()); |
428 int offset = Context::SlotOffset(slot->index()); | 697 int offset = Context::SlotOffset(slot->index()); |
429 __ RecordWrite(esi, offset, eax, ecx); | 698 __ RecordWrite(esi, offset, result_register(), ecx); |
430 } | 699 } |
431 break; | 700 break; |
432 | 701 |
433 case Slot::LOOKUP: { | 702 case Slot::LOOKUP: { |
434 __ push(esi); | 703 __ push(esi); |
435 __ push(Immediate(var->name())); | 704 __ push(Immediate(var->name())); |
436 // Declaration nodes are always introduced in one of two modes. | 705 // Declaration nodes are always introduced in one of two modes. |
437 ASSERT(decl->mode() == Variable::VAR || | 706 ASSERT(decl->mode() == Variable::VAR || |
438 decl->mode() == Variable::CONST); | 707 decl->mode() == Variable::CONST); |
439 PropertyAttributes attr = | 708 PropertyAttributes attr = |
440 (decl->mode() == Variable::VAR) ? NONE : READ_ONLY; | 709 (decl->mode() == Variable::VAR) ? NONE : READ_ONLY; |
441 __ push(Immediate(Smi::FromInt(attr))); | 710 __ push(Immediate(Smi::FromInt(attr))); |
442 // Push initial value, if any. | 711 // Push initial value, if any. |
443 // Note: For variables we must not push an initial value (such as | 712 // Note: For variables we must not push an initial value (such as |
444 // 'undefined') because we may have a (legal) redeclaration and we | 713 // 'undefined') because we may have a (legal) redeclaration and we |
445 // must not destroy the current value. | 714 // must not destroy the current value. |
446 if (decl->mode() == Variable::CONST) { | 715 if (decl->mode() == Variable::CONST) { |
447 __ push(Immediate(Factory::the_hole_value())); | 716 __ push(Immediate(Factory::the_hole_value())); |
448 } else if (decl->fun() != NULL) { | 717 } else if (decl->fun() != NULL) { |
449 Visit(decl->fun()); | 718 VisitForValue(decl->fun(), kStack); |
450 } else { | 719 } else { |
451 __ push(Immediate(Smi::FromInt(0))); // No initial value! | 720 __ push(Immediate(Smi::FromInt(0))); // No initial value! |
452 } | 721 } |
453 __ CallRuntime(Runtime::kDeclareContextSlot, 4); | 722 __ CallRuntime(Runtime::kDeclareContextSlot, 4); |
454 break; | 723 break; |
455 } | 724 } |
456 } | 725 } |
457 | 726 |
458 } else if (prop != NULL) { | 727 } else if (prop != NULL) { |
459 if (decl->fun() != NULL || decl->mode() == Variable::CONST) { | 728 if (decl->fun() != NULL || decl->mode() == Variable::CONST) { |
460 // We are declaring a function or constant that rewrites to a | 729 // We are declaring a function or constant that rewrites to a |
461 // property. Use (keyed) IC to set the initial value. | 730 // property. Use (keyed) IC to set the initial value. |
462 ASSERT_EQ(Expression::kValue, prop->obj()->context()); | 731 VisitForValue(prop->obj(), kStack); |
463 Visit(prop->obj()); | 732 VisitForValue(prop->key(), kStack); |
464 ASSERT_EQ(Expression::kValue, prop->key()->context()); | |
465 Visit(prop->key()); | |
466 | 733 |
467 if (decl->fun() != NULL) { | 734 if (decl->fun() != NULL) { |
468 ASSERT_EQ(Expression::kValue, decl->fun()->context()); | 735 VisitForValue(decl->fun(), kAccumulator); |
469 Visit(decl->fun()); | |
470 __ pop(eax); | |
471 } else { | 736 } else { |
472 __ Set(eax, Immediate(Factory::the_hole_value())); | 737 __ mov(result_register(), Factory::the_hole_value()); |
473 } | 738 } |
474 | 739 |
475 Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize)); | 740 Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize)); |
476 __ call(ic, RelocInfo::CODE_TARGET); | 741 __ call(ic, RelocInfo::CODE_TARGET); |
477 // Absence of a test eax instruction following the call | 742 // Absence of a test eax instruction following the call |
478 // indicates that none of the load was inlined. | 743 // indicates that none of the load was inlined. |
| 744 __ nop(); |
479 | 745 |
480 // Value in eax is ignored (declarations are statements). Receiver | 746 // Value in eax is ignored (declarations are statements). Receiver |
481 // and key on stack are discarded. | 747 // and key on stack are discarded. |
482 __ Drop(2); | 748 __ Drop(2); |
483 } | 749 } |
484 } | 750 } |
485 } | 751 } |
486 | 752 |
487 | 753 |
488 void FastCodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) { | 754 void FastCodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) { |
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
548 } | 814 } |
549 case Slot::CONTEXT: { | 815 case Slot::CONTEXT: { |
550 Comment cmnt(masm_, "Context slot"); | 816 Comment cmnt(masm_, "Context slot"); |
551 break; | 817 break; |
552 } | 818 } |
553 case Slot::LOOKUP: | 819 case Slot::LOOKUP: |
554 UNIMPLEMENTED(); | 820 UNIMPLEMENTED(); |
555 break; | 821 break; |
556 } | 822 } |
557 } | 823 } |
558 Apply(context, slot, eax); | 824 Apply(context, slot); |
559 } else { | 825 } else { |
560 Comment cmnt(masm_, "Variable rewritten to property"); | 826 Comment cmnt(masm_, "Variable rewritten to property"); |
561 // A variable has been rewritten into an explicit access to an object | 827 // A variable has been rewritten into an explicit access to an object |
562 // property. | 828 // property. |
563 Property* property = rewrite->AsProperty(); | 829 Property* property = rewrite->AsProperty(); |
564 ASSERT_NOT_NULL(property); | 830 ASSERT_NOT_NULL(property); |
565 | 831 |
566 // The only property expressions that can occur are of the form | 832 // The only property expressions that can occur are of the form |
567 // "slot[literal]". | 833 // "slot[literal]". |
568 | 834 |
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
628 __ mov(edi, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset)); | 894 __ mov(edi, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset)); |
629 __ push(FieldOperand(edi, JSFunction::kLiteralsOffset)); | 895 __ push(FieldOperand(edi, JSFunction::kLiteralsOffset)); |
630 __ push(Immediate(Smi::FromInt(expr->literal_index()))); | 896 __ push(Immediate(Smi::FromInt(expr->literal_index()))); |
631 __ push(Immediate(expr->constant_properties())); | 897 __ push(Immediate(expr->constant_properties())); |
632 if (expr->depth() > 1) { | 898 if (expr->depth() > 1) { |
633 __ CallRuntime(Runtime::kCreateObjectLiteral, 3); | 899 __ CallRuntime(Runtime::kCreateObjectLiteral, 3); |
634 } else { | 900 } else { |
635 __ CallRuntime(Runtime::kCreateObjectLiteralShallow, 3); | 901 __ CallRuntime(Runtime::kCreateObjectLiteralShallow, 3); |
636 } | 902 } |
637 | 903 |
638 // If result_saved == true: The result is saved on top of the | 904 // If result_saved is true the result is on top of the stack. If |
639 // stack and in eax. | 905 // result_saved is false the result is in eax. |
640 // If result_saved == false: The result not on the stack, just in eax. | |
641 bool result_saved = false; | 906 bool result_saved = false; |
642 | 907 |
643 for (int i = 0; i < expr->properties()->length(); i++) { | 908 for (int i = 0; i < expr->properties()->length(); i++) { |
644 ObjectLiteral::Property* property = expr->properties()->at(i); | 909 ObjectLiteral::Property* property = expr->properties()->at(i); |
645 if (property->IsCompileTimeValue()) continue; | 910 if (property->IsCompileTimeValue()) continue; |
646 | 911 |
647 Literal* key = property->key(); | 912 Literal* key = property->key(); |
648 Expression* value = property->value(); | 913 Expression* value = property->value(); |
649 if (!result_saved) { | 914 if (!result_saved) { |
650 __ push(eax); // Save result on the stack | 915 __ push(eax); // Save result on the stack |
651 result_saved = true; | 916 result_saved = true; |
652 } | 917 } |
653 switch (property->kind()) { | 918 switch (property->kind()) { |
654 case ObjectLiteral::Property::MATERIALIZED_LITERAL: // Fall through. | 919 case ObjectLiteral::Property::MATERIALIZED_LITERAL: |
655 ASSERT(!CompileTimeValue::IsCompileTimeValue(value)); | 920 ASSERT(!CompileTimeValue::IsCompileTimeValue(value)); |
| 921 // Fall through. |
656 case ObjectLiteral::Property::COMPUTED: | 922 case ObjectLiteral::Property::COMPUTED: |
657 if (key->handle()->IsSymbol()) { | 923 if (key->handle()->IsSymbol()) { |
658 Visit(value); | 924 VisitForValue(value, kAccumulator); |
659 ASSERT_EQ(Expression::kValue, value->context()); | |
660 __ pop(eax); | |
661 __ mov(ecx, Immediate(key->handle())); | 925 __ mov(ecx, Immediate(key->handle())); |
662 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize)); | 926 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize)); |
663 __ call(ic, RelocInfo::CODE_TARGET); | 927 __ call(ic, RelocInfo::CODE_TARGET); |
| 928 __ nop(); |
664 // StoreIC leaves the receiver on the stack. | 929 // StoreIC leaves the receiver on the stack. |
665 __ mov(eax, Operand(esp, 0)); // Restore result into eax. | |
666 break; | 930 break; |
667 } | 931 } |
668 // Fall through. | 932 // Fall through. |
669 case ObjectLiteral::Property::PROTOTYPE: | 933 case ObjectLiteral::Property::PROTOTYPE: |
670 __ push(eax); | 934 __ push(Operand(esp, 0)); // Duplicate receiver. |
671 Visit(key); | 935 VisitForValue(key, kStack); |
672 ASSERT_EQ(Expression::kValue, key->context()); | 936 VisitForValue(value, kStack); |
673 Visit(value); | |
674 ASSERT_EQ(Expression::kValue, value->context()); | |
675 __ CallRuntime(Runtime::kSetProperty, 3); | 937 __ CallRuntime(Runtime::kSetProperty, 3); |
676 __ mov(eax, Operand(esp, 0)); // Restore result into eax. | |
677 break; | 938 break; |
678 case ObjectLiteral::Property::SETTER: | 939 case ObjectLiteral::Property::SETTER: |
679 case ObjectLiteral::Property::GETTER: | 940 case ObjectLiteral::Property::GETTER: |
680 __ push(eax); | 941 __ push(Operand(esp, 0)); // Duplicate receiver. |
681 Visit(key); | 942 VisitForValue(key, kStack); |
682 ASSERT_EQ(Expression::kValue, key->context()); | |
683 __ push(Immediate(property->kind() == ObjectLiteral::Property::SETTER ? | 943 __ push(Immediate(property->kind() == ObjectLiteral::Property::SETTER ? |
684 Smi::FromInt(1) : | 944 Smi::FromInt(1) : |
685 Smi::FromInt(0))); | 945 Smi::FromInt(0))); |
686 Visit(value); | 946 VisitForValue(value, kStack); |
687 ASSERT_EQ(Expression::kValue, value->context()); | |
688 __ CallRuntime(Runtime::kDefineAccessor, 4); | 947 __ CallRuntime(Runtime::kDefineAccessor, 4); |
689 __ mov(eax, Operand(esp, 0)); // Restore result into eax. | |
690 break; | 948 break; |
691 default: UNREACHABLE(); | 949 default: UNREACHABLE(); |
692 } | 950 } |
693 } | 951 } |
694 switch (expr->context()) { | 952 |
695 case Expression::kUninitialized: | 953 if (result_saved) { |
696 UNREACHABLE(); | 954 ApplyTOS(expr->context()); |
697 case Expression::kEffect: | 955 } else { |
698 if (result_saved) __ Drop(1); | 956 Apply(expr->context(), eax); |
699 break; | |
700 case Expression::kValue: | |
701 if (!result_saved) __ push(eax); | |
702 break; | |
703 case Expression::kTest: | |
704 if (result_saved) __ pop(eax); | |
705 TestAndBranch(eax, true_label_, false_label_); | |
706 break; | |
707 case Expression::kValueTest: { | |
708 Label discard; | |
709 if (!result_saved) __ push(eax); | |
710 TestAndBranch(eax, true_label_, &discard); | |
711 __ bind(&discard); | |
712 __ Drop(1); | |
713 __ jmp(false_label_); | |
714 break; | |
715 } | |
716 case Expression::kTestValue: { | |
717 Label discard; | |
718 if (!result_saved) __ push(eax); | |
719 TestAndBranch(eax, &discard, false_label_); | |
720 __ bind(&discard); | |
721 __ Drop(1); | |
722 __ jmp(true_label_); | |
723 break; | |
724 } | |
725 } | 957 } |
726 } | 958 } |
727 | 959 |
728 | 960 |
729 void FastCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) { | 961 void FastCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) { |
730 Comment cmnt(masm_, "[ ArrayLiteral"); | 962 Comment cmnt(masm_, "[ ArrayLiteral"); |
731 __ mov(ebx, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset)); | 963 __ mov(ebx, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset)); |
732 __ push(FieldOperand(ebx, JSFunction::kLiteralsOffset)); | 964 __ push(FieldOperand(ebx, JSFunction::kLiteralsOffset)); |
733 __ push(Immediate(Smi::FromInt(expr->literal_index()))); | 965 __ push(Immediate(Smi::FromInt(expr->literal_index()))); |
734 __ push(Immediate(expr->constant_elements())); | 966 __ push(Immediate(expr->constant_elements())); |
(...skipping 14 matching lines...) Expand all Loading... |
749 // is already set in the cloned array. | 981 // is already set in the cloned array. |
750 if (subexpr->AsLiteral() != NULL || | 982 if (subexpr->AsLiteral() != NULL || |
751 CompileTimeValue::IsCompileTimeValue(subexpr)) { | 983 CompileTimeValue::IsCompileTimeValue(subexpr)) { |
752 continue; | 984 continue; |
753 } | 985 } |
754 | 986 |
755 if (!result_saved) { | 987 if (!result_saved) { |
756 __ push(eax); | 988 __ push(eax); |
757 result_saved = true; | 989 result_saved = true; |
758 } | 990 } |
759 Visit(subexpr); | 991 VisitForValue(subexpr, kAccumulator); |
760 ASSERT_EQ(Expression::kValue, subexpr->context()); | |
761 | 992 |
762 // Store the subexpression value in the array's elements. | 993 // Store the subexpression value in the array's elements. |
763 __ pop(eax); // Subexpression value. | |
764 __ mov(ebx, Operand(esp, 0)); // Copy of array literal. | 994 __ mov(ebx, Operand(esp, 0)); // Copy of array literal. |
765 __ mov(ebx, FieldOperand(ebx, JSObject::kElementsOffset)); | 995 __ mov(ebx, FieldOperand(ebx, JSObject::kElementsOffset)); |
766 int offset = FixedArray::kHeaderSize + (i * kPointerSize); | 996 int offset = FixedArray::kHeaderSize + (i * kPointerSize); |
767 __ mov(FieldOperand(ebx, offset), eax); | 997 __ mov(FieldOperand(ebx, offset), result_register()); |
768 | 998 |
769 // Update the write barrier for the array store. | 999 // Update the write barrier for the array store. |
770 __ RecordWrite(ebx, offset, eax, ecx); | 1000 __ RecordWrite(ebx, offset, result_register(), ecx); |
771 } | 1001 } |
772 | 1002 |
773 switch (expr->context()) { | 1003 if (result_saved) { |
774 case Expression::kUninitialized: | 1004 ApplyTOS(expr->context()); |
775 UNREACHABLE(); | 1005 } else { |
776 case Expression::kEffect: | 1006 Apply(expr->context(), eax); |
777 if (result_saved) __ Drop(1); | |
778 break; | |
779 case Expression::kValue: | |
780 if (!result_saved) __ push(eax); | |
781 break; | |
782 case Expression::kTest: | |
783 if (result_saved) __ pop(eax); | |
784 TestAndBranch(eax, true_label_, false_label_); | |
785 break; | |
786 case Expression::kValueTest: { | |
787 Label discard; | |
788 if (!result_saved) __ push(eax); | |
789 TestAndBranch(eax, true_label_, &discard); | |
790 __ bind(&discard); | |
791 __ Drop(1); | |
792 __ jmp(false_label_); | |
793 break; | |
794 } | |
795 case Expression::kTestValue: { | |
796 Label discard; | |
797 if (!result_saved) __ push(eax); | |
798 TestAndBranch(eax, &discard, false_label_); | |
799 __ bind(&discard); | |
800 __ Drop(1); | |
801 __ jmp(true_label_); | |
802 break; | |
803 } | |
804 } | 1007 } |
805 } | 1008 } |
806 | 1009 |
807 | 1010 |
808 void FastCodeGenerator::EmitNamedPropertyLoad(Property* prop, | 1011 void FastCodeGenerator::EmitNamedPropertyLoad(Property* prop) { |
809 Expression::Context context) { | |
810 SetSourcePosition(prop->position()); | 1012 SetSourcePosition(prop->position()); |
811 Literal* key = prop->key()->AsLiteral(); | 1013 Literal* key = prop->key()->AsLiteral(); |
812 __ mov(ecx, Immediate(key->handle())); | 1014 __ mov(ecx, Immediate(key->handle())); |
813 Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize)); | 1015 Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize)); |
814 __ call(ic, RelocInfo::CODE_TARGET); | 1016 __ call(ic, RelocInfo::CODE_TARGET); |
815 Apply(context, eax); | 1017 __ nop(); |
816 } | 1018 } |
817 | 1019 |
818 | 1020 |
819 void FastCodeGenerator::EmitKeyedPropertyLoad(Property* prop, | 1021 void FastCodeGenerator::EmitKeyedPropertyLoad(Property* prop) { |
820 Expression::Context context) { | |
821 SetSourcePosition(prop->position()); | 1022 SetSourcePosition(prop->position()); |
822 Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize)); | 1023 Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize)); |
823 __ call(ic, RelocInfo::CODE_TARGET); | 1024 __ call(ic, RelocInfo::CODE_TARGET); |
824 Apply(context, eax); | 1025 __ nop(); |
825 } | 1026 } |
826 | 1027 |
827 | 1028 |
828 void FastCodeGenerator::EmitCompoundAssignmentOp(Token::Value op, | 1029 void FastCodeGenerator::EmitBinaryOp(Token::Value op, |
829 Expression::Context context) { | 1030 Expression::Context context) { |
| 1031 __ push(result_register()); |
830 GenericBinaryOpStub stub(op, | 1032 GenericBinaryOpStub stub(op, |
831 NO_OVERWRITE, | 1033 NO_OVERWRITE, |
832 NO_GENERIC_BINARY_FLAGS); | 1034 NO_GENERIC_BINARY_FLAGS); |
833 __ CallStub(&stub); | 1035 __ CallStub(&stub); |
834 Apply(context, eax); | 1036 Apply(context, eax); |
835 } | 1037 } |
836 | 1038 |
837 | 1039 |
838 void FastCodeGenerator::EmitVariableAssignment(Variable* var, | 1040 void FastCodeGenerator::EmitVariableAssignment(Variable* var, |
839 Expression::Context context) { | 1041 Expression::Context context) { |
840 ASSERT(var != NULL); | 1042 ASSERT(var != NULL); |
841 ASSERT(var->is_global() || var->slot() != NULL); | 1043 ASSERT(var->is_global() || var->slot() != NULL); |
842 if (var->is_global()) { | 1044 if (var->is_global()) { |
843 // Assignment to a global variable. Use inline caching for the | 1045 // Assignment to a global variable. Use inline caching for the |
844 // assignment. Right-hand-side value is passed in eax, variable name in | 1046 // assignment. Right-hand-side value is passed in eax, variable name in |
845 // ecx, and the global object on the stack. | 1047 // ecx, and the global object on the stack. |
846 __ pop(eax); | |
847 __ mov(ecx, var->name()); | 1048 __ mov(ecx, var->name()); |
848 __ push(CodeGenerator::GlobalObject()); | 1049 __ push(CodeGenerator::GlobalObject()); |
849 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize)); | 1050 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize)); |
850 __ call(ic, RelocInfo::CODE_TARGET); | 1051 __ call(ic, RelocInfo::CODE_TARGET); |
| 1052 __ nop(); |
851 // Overwrite the receiver on the stack with the result if needed. | 1053 // Overwrite the receiver on the stack with the result if needed. |
852 DropAndApply(1, context, eax); | 1054 DropAndApply(1, context, eax); |
853 | 1055 |
854 } else if (var->slot() != NULL) { | 1056 } else if (var->slot() != NULL) { |
855 Slot* slot = var->slot(); | 1057 Slot* slot = var->slot(); |
856 switch (slot->type()) { | 1058 switch (slot->type()) { |
857 case Slot::LOCAL: | 1059 case Slot::LOCAL: |
858 case Slot::PARAMETER: { | 1060 case Slot::PARAMETER: |
859 Operand target = Operand(ebp, SlotOffset(slot)); | 1061 __ mov(Operand(ebp, SlotOffset(slot)), result_register()); |
860 switch (context) { | 1062 break; |
861 case Expression::kUninitialized: | 1063 |
862 UNREACHABLE(); | 1064 case Slot::CONTEXT: { |
863 case Expression::kEffect: | 1065 MemOperand target = EmitSlotSearch(slot, ecx); |
864 // Perform assignment and discard value. | 1066 __ mov(target, result_register()); |
865 __ pop(target); | 1067 |
866 break; | 1068 // RecordWrite may destroy all its register arguments. |
867 case Expression::kValue: | 1069 __ mov(edx, result_register()); |
868 // Perform assignment and preserve value. | 1070 int offset = FixedArray::kHeaderSize + slot->index() * kPointerSize; |
869 __ mov(eax, Operand(esp, 0)); | 1071 __ RecordWrite(ecx, offset, edx, ebx); |
870 __ mov(target, eax); | |
871 break; | |
872 case Expression::kTest: | |
873 // Perform assignment and test (and discard) value. | |
874 __ pop(eax); | |
875 __ mov(target, eax); | |
876 TestAndBranch(eax, true_label_, false_label_); | |
877 break; | |
878 case Expression::kValueTest: { | |
879 Label discard; | |
880 __ mov(eax, Operand(esp, 0)); | |
881 __ mov(target, eax); | |
882 TestAndBranch(eax, true_label_, &discard); | |
883 __ bind(&discard); | |
884 __ Drop(1); | |
885 __ jmp(false_label_); | |
886 break; | |
887 } | |
888 case Expression::kTestValue: { | |
889 Label discard; | |
890 __ mov(eax, Operand(esp, 0)); | |
891 __ mov(target, eax); | |
892 TestAndBranch(eax, &discard, false_label_); | |
893 __ bind(&discard); | |
894 __ Drop(1); | |
895 __ jmp(true_label_); | |
896 break; | |
897 } | |
898 } | |
899 break; | 1072 break; |
900 } | 1073 } |
901 | 1074 |
902 case Slot::CONTEXT: { | |
903 MemOperand target = EmitSlotSearch(slot, ecx); | |
904 __ pop(eax); | |
905 __ mov(target, eax); | |
906 | |
907 // RecordWrite may destroy all its register arguments. | |
908 if (context == Expression::kValue) { | |
909 __ push(eax); | |
910 } else if (context != Expression::kEffect) { | |
911 __ mov(edx, eax); | |
912 } | |
913 int offset = FixedArray::kHeaderSize + slot->index() * kPointerSize; | |
914 __ RecordWrite(ecx, offset, eax, ebx); | |
915 if (context != Expression::kEffect && context != Expression::kValue) { | |
916 Apply(context, edx); | |
917 } | |
918 break; | |
919 } | |
920 | |
921 case Slot::LOOKUP: | 1075 case Slot::LOOKUP: |
922 UNREACHABLE(); | 1076 UNREACHABLE(); |
923 break; | 1077 break; |
924 } | 1078 } |
| 1079 Apply(context, result_register()); |
| 1080 |
925 } else { | 1081 } else { |
926 // Variables rewritten as properties are not treated as variables in | 1082 // Variables rewritten as properties are not treated as variables in |
927 // assignments. | 1083 // assignments. |
928 UNREACHABLE(); | 1084 UNREACHABLE(); |
929 } | 1085 } |
930 } | 1086 } |
931 | 1087 |
932 | 1088 |
933 void FastCodeGenerator::EmitNamedPropertyAssignment(Assignment* expr) { | 1089 void FastCodeGenerator::EmitNamedPropertyAssignment(Assignment* expr) { |
934 // Assignment to a property, using a named store IC. | 1090 // Assignment to a property, using a named store IC. |
935 Property* prop = expr->target()->AsProperty(); | 1091 Property* prop = expr->target()->AsProperty(); |
936 ASSERT(prop != NULL); | 1092 ASSERT(prop != NULL); |
937 ASSERT(prop->key()->AsLiteral() != NULL); | 1093 ASSERT(prop->key()->AsLiteral() != NULL); |
938 | 1094 |
939 // If the assignment starts a block of assignments to the same object, | 1095 // If the assignment starts a block of assignments to the same object, |
940 // change to slow case to avoid the quadratic behavior of repeatedly | 1096 // change to slow case to avoid the quadratic behavior of repeatedly |
941 // adding fast properties. | 1097 // adding fast properties. |
942 if (expr->starts_initialization_block()) { | 1098 if (expr->starts_initialization_block()) { |
943 __ push(Operand(esp, kPointerSize)); // Receiver is under value. | 1099 __ push(result_register()); |
| 1100 __ push(Operand(esp, kPointerSize)); // Receiver is now under value. |
944 __ CallRuntime(Runtime::kToSlowProperties, 1); | 1101 __ CallRuntime(Runtime::kToSlowProperties, 1); |
| 1102 __ pop(result_register()); |
945 } | 1103 } |
946 | 1104 |
947 __ pop(eax); | 1105 // Record source code position before IC call. |
| 1106 SetSourcePosition(expr->position()); |
948 __ mov(ecx, prop->key()->AsLiteral()->handle()); | 1107 __ mov(ecx, prop->key()->AsLiteral()->handle()); |
949 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize)); | 1108 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize)); |
950 __ call(ic, RelocInfo::CODE_TARGET); | 1109 __ call(ic, RelocInfo::CODE_TARGET); |
| 1110 __ nop(); |
951 | 1111 |
952 // If the assignment ends an initialization block, revert to fast case. | 1112 // If the assignment ends an initialization block, revert to fast case. |
953 if (expr->ends_initialization_block()) { | 1113 if (expr->ends_initialization_block()) { |
954 __ push(eax); // Result of assignment, saved even if not needed. | 1114 __ push(eax); // Result of assignment, saved even if not needed. |
955 __ push(Operand(esp, kPointerSize)); // Receiver is under value. | 1115 __ push(Operand(esp, kPointerSize)); // Receiver is under value. |
956 __ CallRuntime(Runtime::kToFastProperties, 1); | 1116 __ CallRuntime(Runtime::kToFastProperties, 1); |
957 __ pop(eax); | 1117 __ pop(eax); |
958 } | 1118 } |
959 | 1119 |
960 DropAndApply(1, expr->context(), eax); | 1120 DropAndApply(1, expr->context(), eax); |
961 } | 1121 } |
962 | 1122 |
963 | 1123 |
964 void FastCodeGenerator::EmitKeyedPropertyAssignment(Assignment* expr) { | 1124 void FastCodeGenerator::EmitKeyedPropertyAssignment(Assignment* expr) { |
965 // Assignment to a property, using a keyed store IC. | 1125 // Assignment to a property, using a keyed store IC. |
966 | 1126 |
967 // If the assignment starts a block of assignments to the same object, | 1127 // If the assignment starts a block of assignments to the same object, |
968 // change to slow case to avoid the quadratic behavior of repeatedly | 1128 // change to slow case to avoid the quadratic behavior of repeatedly |
969 // adding fast properties. | 1129 // adding fast properties. |
970 if (expr->starts_initialization_block()) { | 1130 if (expr->starts_initialization_block()) { |
971 // Reciever is under the key and value. | 1131 __ push(result_register()); |
| 1132 // Receiver is now under the key and value. |
972 __ push(Operand(esp, 2 * kPointerSize)); | 1133 __ push(Operand(esp, 2 * kPointerSize)); |
973 __ CallRuntime(Runtime::kToSlowProperties, 1); | 1134 __ CallRuntime(Runtime::kToSlowProperties, 1); |
| 1135 __ pop(result_register()); |
974 } | 1136 } |
975 | 1137 |
976 __ pop(eax); | 1138 // Record source code position before IC call. |
| 1139 SetSourcePosition(expr->position()); |
977 Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize)); | 1140 Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize)); |
978 __ call(ic, RelocInfo::CODE_TARGET); | 1141 __ call(ic, RelocInfo::CODE_TARGET); |
979 // This nop signals to the IC that there is no inlined code at the call | 1142 // This nop signals to the IC that there is no inlined code at the call |
980 // site for it to patch. | 1143 // site for it to patch. |
981 __ nop(); | 1144 __ nop(); |
982 | 1145 |
983 // If the assignment ends an initialization block, revert to fast case. | 1146 // If the assignment ends an initialization block, revert to fast case. |
984 if (expr->ends_initialization_block()) { | 1147 if (expr->ends_initialization_block()) { |
985 __ push(eax); // Result of assignment, saved even if not needed. | 1148 __ push(eax); // Result of assignment, saved even if not needed. |
986 // Reciever is under the key and value. | 1149 // Receiver is under the key and value. |
987 __ push(Operand(esp, 2 * kPointerSize)); | 1150 __ push(Operand(esp, 2 * kPointerSize)); |
988 __ CallRuntime(Runtime::kToFastProperties, 1); | 1151 __ CallRuntime(Runtime::kToFastProperties, 1); |
989 __ pop(eax); | 1152 __ pop(eax); |
990 } | 1153 } |
991 | 1154 |
992 // Receiver and key are still on stack. | 1155 // Receiver and key are still on stack. |
993 DropAndApply(2, expr->context(), eax); | 1156 DropAndApply(2, expr->context(), eax); |
994 } | 1157 } |
995 | 1158 |
996 | 1159 |
997 void FastCodeGenerator::VisitProperty(Property* expr) { | 1160 void FastCodeGenerator::VisitProperty(Property* expr) { |
998 Comment cmnt(masm_, "[ Property"); | 1161 Comment cmnt(masm_, "[ Property"); |
999 Expression* key = expr->key(); | 1162 Expression* key = expr->key(); |
1000 | 1163 |
1001 // Record the source position for the property load. | |
1002 SetSourcePosition(expr->position()); | |
1003 | |
1004 // Evaluate the receiver. | 1164 // Evaluate the receiver. |
1005 Visit(expr->obj()); | 1165 VisitForValue(expr->obj(), kStack); |
1006 | 1166 |
1007 if (key->IsPropertyName()) { | 1167 if (key->IsPropertyName()) { |
1008 // Do a named property load. The IC expects the property name in ecx | 1168 EmitNamedPropertyLoad(expr); |
1009 // and the receiver on the stack. | 1169 // Drop receiver left on the stack by IC. |
1010 __ mov(ecx, Immediate(key->AsLiteral()->handle())); | |
1011 Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize)); | |
1012 __ call(ic, RelocInfo::CODE_TARGET); | |
1013 // By emitting a nop we make sure that we do not have a test eax | |
1014 // instruction after the call it is treated specially by the LoadIC code. | |
1015 __ nop(); | |
1016 DropAndApply(1, expr->context(), eax); | 1170 DropAndApply(1, expr->context(), eax); |
1017 } else { | 1171 } else { |
1018 // Do a keyed property load. | 1172 VisitForValue(expr->key(), kStack); |
1019 Visit(expr->key()); | 1173 EmitKeyedPropertyLoad(expr); |
1020 Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize)); | 1174 // Drop key and receiver left on the stack by IC. |
1021 __ call(ic, RelocInfo::CODE_TARGET); | |
1022 // By emitting a nop we make sure that we do not have a "test eax,..." | |
1023 // instruction after the call it is treated specially by the LoadIC code. | |
1024 __ nop(); | |
1025 // Drop key left on the stack by IC. | |
1026 DropAndApply(2, expr->context(), eax); | 1175 DropAndApply(2, expr->context(), eax); |
1027 } | 1176 } |
1028 } | 1177 } |
1029 | 1178 |
1030 | 1179 |
1031 void FastCodeGenerator::EmitCallWithIC(Call* expr, | 1180 void FastCodeGenerator::EmitCallWithIC(Call* expr, |
1032 Handle<Object> name, | 1181 Handle<Object> name, |
1033 RelocInfo::Mode mode) { | 1182 RelocInfo::Mode mode) { |
1034 // Code common for calls using the IC. | 1183 // Code common for calls using the IC. |
1035 ZoneList<Expression*>* args = expr->arguments(); | 1184 ZoneList<Expression*>* args = expr->arguments(); |
1036 int arg_count = args->length(); | 1185 int arg_count = args->length(); |
1037 for (int i = 0; i < arg_count; i++) { | 1186 for (int i = 0; i < arg_count; i++) { |
1038 Visit(args->at(i)); | 1187 VisitForValue(args->at(i), kStack); |
1039 ASSERT_EQ(Expression::kValue, args->at(i)->context()); | |
1040 } | 1188 } |
1041 __ Set(ecx, Immediate(name)); | 1189 __ Set(ecx, Immediate(name)); |
1042 // Record source position of the IC call. | 1190 // Record source position of the IC call. |
1043 SetSourcePosition(expr->position()); | 1191 SetSourcePosition(expr->position()); |
1044 InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP; | 1192 InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP; |
1045 Handle<Code> ic = CodeGenerator::ComputeCallInitialize(arg_count, in_loop); | 1193 Handle<Code> ic = CodeGenerator::ComputeCallInitialize(arg_count, in_loop); |
1046 __ call(ic, mode); | 1194 __ call(ic, mode); |
1047 // Restore context register. | 1195 // Restore context register. |
1048 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); | 1196 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); |
1049 Apply(expr->context(), eax); | 1197 Apply(expr->context(), eax); |
1050 } | 1198 } |
1051 | 1199 |
1052 | 1200 |
1053 void FastCodeGenerator::EmitCallWithStub(Call* expr) { | 1201 void FastCodeGenerator::EmitCallWithStub(Call* expr) { |
1054 // Code common for calls using the call stub. | 1202 // Code common for calls using the call stub. |
1055 ZoneList<Expression*>* args = expr->arguments(); | 1203 ZoneList<Expression*>* args = expr->arguments(); |
1056 int arg_count = args->length(); | 1204 int arg_count = args->length(); |
1057 for (int i = 0; i < arg_count; i++) { | 1205 for (int i = 0; i < arg_count; i++) { |
1058 Visit(args->at(i)); | 1206 VisitForValue(args->at(i), kStack); |
1059 } | 1207 } |
1060 // Record source position for debugger. | 1208 // Record source position for debugger. |
1061 SetSourcePosition(expr->position()); | 1209 SetSourcePosition(expr->position()); |
1062 CallFunctionStub stub(arg_count, NOT_IN_LOOP); | 1210 CallFunctionStub stub(arg_count, NOT_IN_LOOP); |
1063 __ CallStub(&stub); | 1211 __ CallStub(&stub); |
1064 // Restore context register. | 1212 // Restore context register. |
1065 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); | 1213 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); |
1066 DropAndApply(1, expr->context(), eax); | 1214 DropAndApply(1, expr->context(), eax); |
1067 } | 1215 } |
1068 | 1216 |
(...skipping 13 matching lines...) Expand all Loading... |
1082 } else if (var != NULL && var->slot() != NULL && | 1230 } else if (var != NULL && var->slot() != NULL && |
1083 var->slot()->type() == Slot::LOOKUP) { | 1231 var->slot()->type() == Slot::LOOKUP) { |
1084 // Call to a lookup slot. | 1232 // Call to a lookup slot. |
1085 UNREACHABLE(); | 1233 UNREACHABLE(); |
1086 } else if (fun->AsProperty() != NULL) { | 1234 } else if (fun->AsProperty() != NULL) { |
1087 // Call to an object property. | 1235 // Call to an object property. |
1088 Property* prop = fun->AsProperty(); | 1236 Property* prop = fun->AsProperty(); |
1089 Literal* key = prop->key()->AsLiteral(); | 1237 Literal* key = prop->key()->AsLiteral(); |
1090 if (key != NULL && key->handle()->IsSymbol()) { | 1238 if (key != NULL && key->handle()->IsSymbol()) { |
1091 // Call to a named property, use call IC. | 1239 // Call to a named property, use call IC. |
1092 Visit(prop->obj()); | 1240 VisitForValue(prop->obj(), kStack); |
1093 EmitCallWithIC(expr, key->handle(), RelocInfo::CODE_TARGET); | 1241 EmitCallWithIC(expr, key->handle(), RelocInfo::CODE_TARGET); |
1094 } else { | 1242 } else { |
1095 // Call to a keyed property, use keyed load IC followed by function | 1243 // Call to a keyed property, use keyed load IC followed by function |
1096 // call. | 1244 // call. |
1097 Visit(prop->obj()); | 1245 VisitForValue(prop->obj(), kStack); |
1098 Visit(prop->key()); | 1246 VisitForValue(prop->key(), kStack); |
1099 // Record source code position for IC call. | 1247 // Record source code position for IC call. |
1100 SetSourcePosition(prop->position()); | 1248 SetSourcePosition(prop->position()); |
1101 Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize)); | 1249 Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize)); |
1102 __ call(ic, RelocInfo::CODE_TARGET); | 1250 __ call(ic, RelocInfo::CODE_TARGET); |
1103 // By emitting a nop we make sure that we do not have a "test eax,..." | 1251 // By emitting a nop we make sure that we do not have a "test eax,..." |
1104 // instruction after the call it is treated specially by the LoadIC code. | 1252 // instruction after the call it is treated specially by the LoadIC code. |
1105 __ nop(); | 1253 __ nop(); |
1106 // Drop key left on the stack by IC. | 1254 // Drop key left on the stack by IC. |
1107 __ Drop(1); | 1255 __ Drop(1); |
1108 // Pop receiver. | 1256 // Pop receiver. |
(...skipping 12 matching lines...) Expand all Loading... |
1121 } else { | 1269 } else { |
1122 // Call to some other expression. If the expression is an anonymous | 1270 // Call to some other expression. If the expression is an anonymous |
1123 // function literal not called in a loop, mark it as one that should | 1271 // function literal not called in a loop, mark it as one that should |
1124 // also use the fast code generator. | 1272 // also use the fast code generator. |
1125 FunctionLiteral* lit = fun->AsFunctionLiteral(); | 1273 FunctionLiteral* lit = fun->AsFunctionLiteral(); |
1126 if (lit != NULL && | 1274 if (lit != NULL && |
1127 lit->name()->Equals(Heap::empty_string()) && | 1275 lit->name()->Equals(Heap::empty_string()) && |
1128 loop_depth() == 0) { | 1276 loop_depth() == 0) { |
1129 lit->set_try_fast_codegen(true); | 1277 lit->set_try_fast_codegen(true); |
1130 } | 1278 } |
1131 Visit(fun); | 1279 VisitForValue(fun, kStack); |
1132 // Load global receiver object. | 1280 // Load global receiver object. |
1133 __ mov(ebx, CodeGenerator::GlobalObject()); | 1281 __ mov(ebx, CodeGenerator::GlobalObject()); |
1134 __ push(FieldOperand(ebx, GlobalObject::kGlobalReceiverOffset)); | 1282 __ push(FieldOperand(ebx, GlobalObject::kGlobalReceiverOffset)); |
1135 // Emit function call. | 1283 // Emit function call. |
1136 EmitCallWithStub(expr); | 1284 EmitCallWithStub(expr); |
1137 } | 1285 } |
1138 } | 1286 } |
1139 | 1287 |
1140 | 1288 |
1141 void FastCodeGenerator::VisitCallNew(CallNew* expr) { | 1289 void FastCodeGenerator::VisitCallNew(CallNew* expr) { |
1142 Comment cmnt(masm_, "[ CallNew"); | 1290 Comment cmnt(masm_, "[ CallNew"); |
1143 // According to ECMA-262, section 11.2.2, page 44, the function | 1291 // According to ECMA-262, section 11.2.2, page 44, the function |
1144 // expression in new calls must be evaluated before the | 1292 // expression in new calls must be evaluated before the |
1145 // arguments. | 1293 // arguments. |
1146 // Push function on the stack. | 1294 // Push function on the stack. |
1147 Visit(expr->expression()); | 1295 VisitForValue(expr->expression(), kStack); |
1148 ASSERT_EQ(Expression::kValue, expr->expression()->context()); | |
1149 | 1296 |
1150 // Push global object (receiver). | 1297 // Push global object (receiver). |
1151 __ push(CodeGenerator::GlobalObject()); | 1298 __ push(CodeGenerator::GlobalObject()); |
1152 | 1299 |
1153 // Push the arguments ("left-to-right") on the stack. | 1300 // Push the arguments ("left-to-right") on the stack. |
1154 ZoneList<Expression*>* args = expr->arguments(); | 1301 ZoneList<Expression*>* args = expr->arguments(); |
1155 int arg_count = args->length(); | 1302 int arg_count = args->length(); |
1156 for (int i = 0; i < arg_count; i++) { | 1303 for (int i = 0; i < arg_count; i++) { |
1157 Visit(args->at(i)); | 1304 VisitForValue(args->at(i), kStack); |
1158 ASSERT_EQ(Expression::kValue, args->at(i)->context()); | |
1159 // If location is value, it is already on the stack, | |
1160 // so nothing to do here. | |
1161 } | 1305 } |
1162 | 1306 |
1163 // Call the construct call builtin that handles allocation and | 1307 // Call the construct call builtin that handles allocation and |
1164 // constructor invocation. | 1308 // constructor invocation. |
1165 SetSourcePosition(expr->position()); | 1309 SetSourcePosition(expr->position()); |
1166 | 1310 |
1167 // Load function, arg_count into edi and eax. | 1311 // Load function, arg_count into edi and eax. |
1168 __ Set(eax, Immediate(arg_count)); | 1312 __ Set(eax, Immediate(arg_count)); |
1169 // Function is in esp[arg_count + 1]. | 1313 // Function is in esp[arg_count + 1]. |
1170 __ mov(edi, Operand(esp, eax, times_pointer_size, kPointerSize)); | 1314 __ mov(edi, Operand(esp, eax, times_pointer_size, kPointerSize)); |
(...skipping 12 matching lines...) Expand all Loading... |
1183 | 1327 |
1184 if (expr->is_jsruntime()) { | 1328 if (expr->is_jsruntime()) { |
1185 // Prepare for calling JS runtime function. | 1329 // Prepare for calling JS runtime function. |
1186 __ mov(eax, CodeGenerator::GlobalObject()); | 1330 __ mov(eax, CodeGenerator::GlobalObject()); |
1187 __ push(FieldOperand(eax, GlobalObject::kBuiltinsOffset)); | 1331 __ push(FieldOperand(eax, GlobalObject::kBuiltinsOffset)); |
1188 } | 1332 } |
1189 | 1333 |
1190 // Push the arguments ("left-to-right"). | 1334 // Push the arguments ("left-to-right"). |
1191 int arg_count = args->length(); | 1335 int arg_count = args->length(); |
1192 for (int i = 0; i < arg_count; i++) { | 1336 for (int i = 0; i < arg_count; i++) { |
1193 Visit(args->at(i)); | 1337 VisitForValue(args->at(i), kStack); |
1194 ASSERT_EQ(Expression::kValue, args->at(i)->context()); | |
1195 } | 1338 } |
1196 | 1339 |
1197 if (expr->is_jsruntime()) { | 1340 if (expr->is_jsruntime()) { |
1198 // Call the JS runtime function via a call IC. | 1341 // Call the JS runtime function via a call IC. |
1199 __ Set(ecx, Immediate(expr->name())); | 1342 __ Set(ecx, Immediate(expr->name())); |
1200 InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP; | 1343 InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP; |
1201 Handle<Code> ic = CodeGenerator::ComputeCallInitialize(arg_count, in_loop); | 1344 Handle<Code> ic = CodeGenerator::ComputeCallInitialize(arg_count, in_loop); |
1202 __ call(ic, RelocInfo::CODE_TARGET); | 1345 __ call(ic, RelocInfo::CODE_TARGET); |
1203 // Restore context register. | 1346 // Restore context register. |
1204 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); | 1347 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); |
1205 } else { | 1348 } else { |
1206 // Call the C runtime function. | 1349 // Call the C runtime function. |
1207 __ CallRuntime(expr->function(), arg_count); | 1350 __ CallRuntime(expr->function(), arg_count); |
1208 } | 1351 } |
1209 Apply(expr->context(), eax); | 1352 Apply(expr->context(), eax); |
1210 } | 1353 } |
1211 | 1354 |
1212 | 1355 |
1213 void FastCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) { | 1356 void FastCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) { |
1214 switch (expr->op()) { | 1357 switch (expr->op()) { |
1215 case Token::VOID: { | 1358 case Token::VOID: { |
1216 Comment cmnt(masm_, "[ UnaryOperation (VOID)"); | 1359 Comment cmnt(masm_, "[ UnaryOperation (VOID)"); |
| 1360 ASSERT_EQ(Expression::kEffect, expr->expression()->context()); |
1217 Visit(expr->expression()); | 1361 Visit(expr->expression()); |
1218 ASSERT_EQ(Expression::kEffect, expr->expression()->context()); | |
1219 switch (expr->context()) { | 1362 switch (expr->context()) { |
1220 case Expression::kUninitialized: | 1363 case Expression::kUninitialized: |
1221 UNREACHABLE(); | 1364 UNREACHABLE(); |
1222 break; | 1365 break; |
1223 case Expression::kEffect: | 1366 case Expression::kEffect: |
1224 break; | 1367 break; |
1225 case Expression::kValue: | 1368 case Expression::kValue: |
1226 __ push(Immediate(Factory::undefined_value())); | 1369 switch (location_) { |
| 1370 case kAccumulator: |
| 1371 __ mov(result_register(), Factory::undefined_value()); |
| 1372 break; |
| 1373 case kStack: |
| 1374 __ push(Immediate(Factory::undefined_value())); |
| 1375 break; |
| 1376 } |
1227 break; | 1377 break; |
1228 case Expression::kTestValue: | 1378 case Expression::kTestValue: |
1229 // Value is false so it's needed. | 1379 // Value is false so it's needed. |
1230 __ push(Immediate(Factory::undefined_value())); | 1380 switch (location_) { |
| 1381 case kAccumulator: |
| 1382 __ mov(result_register(), Factory::undefined_value()); |
| 1383 break; |
| 1384 case kStack: |
| 1385 __ push(Immediate(Factory::undefined_value())); |
| 1386 break; |
| 1387 } |
1231 // Fall through. | 1388 // Fall through. |
1232 case Expression::kTest: | 1389 case Expression::kTest: |
1233 case Expression::kValueTest: | 1390 case Expression::kValueTest: |
1234 __ jmp(false_label_); | 1391 __ jmp(false_label_); |
1235 break; | 1392 break; |
1236 } | 1393 } |
1237 break; | 1394 break; |
1238 } | 1395 } |
1239 | 1396 |
1240 case Token::NOT: { | 1397 case Token::NOT: { |
1241 Comment cmnt(masm_, "[ UnaryOperation (NOT)"); | 1398 Comment cmnt(masm_, "[ UnaryOperation (NOT)"); |
1242 ASSERT_EQ(Expression::kTest, expr->expression()->context()); | 1399 ASSERT_EQ(Expression::kTest, expr->expression()->context()); |
1243 | 1400 |
1244 Label push_true, push_false, done; | 1401 Label materialize_true, materialize_false, done; |
| 1402 // Initially assume a pure test context. Notice that the labels are |
| 1403 // swapped. |
| 1404 Label* if_true = false_label_; |
| 1405 Label* if_false = true_label_; |
1245 switch (expr->context()) { | 1406 switch (expr->context()) { |
1246 case Expression::kUninitialized: | 1407 case Expression::kUninitialized: |
1247 UNREACHABLE(); | 1408 UNREACHABLE(); |
1248 break; | 1409 break; |
1249 | |
1250 case Expression::kEffect: | 1410 case Expression::kEffect: |
1251 VisitForControl(expr->expression(), &done, &done); | 1411 if_true = &done; |
1252 __ bind(&done); | 1412 if_false = &done; |
1253 break; | 1413 break; |
1254 | |
1255 case Expression::kValue: | 1414 case Expression::kValue: |
1256 VisitForControl(expr->expression(), &push_false, &push_true); | 1415 if_true = &materialize_false; |
1257 __ bind(&push_true); | 1416 if_false = &materialize_true; |
1258 __ push(Immediate(Factory::true_value())); | |
1259 __ jmp(&done); | |
1260 __ bind(&push_false); | |
1261 __ push(Immediate(Factory::false_value())); | |
1262 __ bind(&done); | |
1263 break; | 1417 break; |
1264 | |
1265 case Expression::kTest: | 1418 case Expression::kTest: |
1266 VisitForControl(expr->expression(), false_label_, true_label_); | |
1267 break; | 1419 break; |
1268 | |
1269 case Expression::kValueTest: | 1420 case Expression::kValueTest: |
1270 VisitForControl(expr->expression(), false_label_, &push_true); | 1421 if_false = &materialize_true; |
1271 __ bind(&push_true); | |
1272 __ push(Immediate(Factory::true_value())); | |
1273 __ jmp(true_label_); | |
1274 break; | 1422 break; |
1275 | |
1276 case Expression::kTestValue: | 1423 case Expression::kTestValue: |
1277 VisitForControl(expr->expression(), &push_false, true_label_); | 1424 if_true = &materialize_false; |
1278 __ bind(&push_false); | |
1279 __ push(Immediate(Factory::false_value())); | |
1280 __ jmp(false_label_); | |
1281 break; | 1425 break; |
1282 } | 1426 } |
| 1427 VisitForControl(expr->expression(), if_true, if_false); |
| 1428 Apply(expr->context(), if_false, if_true); // Labels swapped. |
1283 break; | 1429 break; |
1284 } | 1430 } |
1285 | 1431 |
1286 case Token::TYPEOF: { | 1432 case Token::TYPEOF: { |
1287 Comment cmnt(masm_, "[ UnaryOperation (TYPEOF)"); | 1433 Comment cmnt(masm_, "[ UnaryOperation (TYPEOF)"); |
1288 ASSERT_EQ(Expression::kValue, expr->expression()->context()); | 1434 ASSERT_EQ(Expression::kValue, expr->expression()->context()); |
1289 | 1435 |
1290 VariableProxy* proxy = expr->expression()->AsVariableProxy(); | 1436 VariableProxy* proxy = expr->expression()->AsVariableProxy(); |
1291 if (proxy != NULL && | 1437 if (proxy != NULL && |
1292 !proxy->var()->is_this() && | 1438 !proxy->var()->is_this() && |
1293 proxy->var()->is_global()) { | 1439 proxy->var()->is_global()) { |
1294 Comment cmnt(masm_, "Global variable"); | 1440 Comment cmnt(masm_, "Global variable"); |
1295 __ push(CodeGenerator::GlobalObject()); | 1441 __ push(CodeGenerator::GlobalObject()); |
1296 __ mov(ecx, Immediate(proxy->name())); | 1442 __ mov(ecx, Immediate(proxy->name())); |
1297 Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize)); | 1443 Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize)); |
1298 // Use a regular load, not a contextual load, to avoid a reference | 1444 // Use a regular load, not a contextual load, to avoid a reference |
1299 // error. | 1445 // error. |
1300 __ call(ic, RelocInfo::CODE_TARGET); | 1446 __ call(ic, RelocInfo::CODE_TARGET); |
1301 __ mov(Operand(esp, 0), eax); | 1447 __ mov(Operand(esp, 0), eax); |
1302 } else if (proxy != NULL && | 1448 } else if (proxy != NULL && |
1303 proxy->var()->slot() != NULL && | 1449 proxy->var()->slot() != NULL && |
1304 proxy->var()->slot()->type() == Slot::LOOKUP) { | 1450 proxy->var()->slot()->type() == Slot::LOOKUP) { |
1305 __ push(esi); | 1451 __ push(esi); |
1306 __ push(Immediate(proxy->name())); | 1452 __ push(Immediate(proxy->name())); |
1307 __ CallRuntime(Runtime::kLoadContextSlotNoReferenceError, 2); | 1453 __ CallRuntime(Runtime::kLoadContextSlotNoReferenceError, 2); |
1308 __ push(eax); | 1454 __ push(eax); |
1309 } else { | 1455 } else { |
1310 // This expression cannot throw a reference error at the top level. | 1456 // This expression cannot throw a reference error at the top level. |
1311 Visit(expr->expression()); | 1457 VisitForValue(expr->expression(), kStack); |
1312 } | 1458 } |
1313 | 1459 |
1314 __ CallRuntime(Runtime::kTypeof, 1); | 1460 __ CallRuntime(Runtime::kTypeof, 1); |
1315 Apply(expr->context(), eax); | 1461 Apply(expr->context(), eax); |
1316 break; | 1462 break; |
1317 } | 1463 } |
1318 | 1464 |
1319 default: | 1465 default: |
1320 UNREACHABLE(); | 1466 UNREACHABLE(); |
1321 } | 1467 } |
(...skipping 12 matching lines...) Expand all Loading... |
1334 // of the key to detect a named property. | 1480 // of the key to detect a named property. |
1335 if (prop != NULL) { | 1481 if (prop != NULL) { |
1336 assign_type = (prop->key()->context() == Expression::kUninitialized) | 1482 assign_type = (prop->key()->context() == Expression::kUninitialized) |
1337 ? NAMED_PROPERTY | 1483 ? NAMED_PROPERTY |
1338 : KEYED_PROPERTY; | 1484 : KEYED_PROPERTY; |
1339 } | 1485 } |
1340 | 1486 |
1341 // Evaluate expression and get value. | 1487 // Evaluate expression and get value. |
1342 if (assign_type == VARIABLE) { | 1488 if (assign_type == VARIABLE) { |
1343 ASSERT(expr->expression()->AsVariableProxy()->var() != NULL); | 1489 ASSERT(expr->expression()->AsVariableProxy()->var() != NULL); |
| 1490 Location saved_location = location_; |
| 1491 location_ = kStack; |
1344 EmitVariableLoad(expr->expression()->AsVariableProxy()->var(), | 1492 EmitVariableLoad(expr->expression()->AsVariableProxy()->var(), |
1345 Expression::kValue); | 1493 Expression::kValue); |
| 1494 location_ = saved_location; |
1346 } else { | 1495 } else { |
1347 // Reserve space for result of postfix operation. | 1496 // Reserve space for result of postfix operation. |
1348 if (expr->is_postfix() && expr->context() != Expression::kEffect) { | 1497 if (expr->is_postfix() && expr->context() != Expression::kEffect) { |
1349 ASSERT(expr->context() != Expression::kUninitialized); | 1498 ASSERT(expr->context() != Expression::kUninitialized); |
1350 __ push(Immediate(Smi::FromInt(0))); | 1499 __ push(Immediate(Smi::FromInt(0))); |
1351 } | 1500 } |
1352 Visit(prop->obj()); | 1501 VisitForValue(prop->obj(), kStack); |
1353 ASSERT_EQ(Expression::kValue, prop->obj()->context()); | |
1354 if (assign_type == NAMED_PROPERTY) { | 1502 if (assign_type == NAMED_PROPERTY) { |
1355 EmitNamedPropertyLoad(prop, Expression::kValue); | 1503 EmitNamedPropertyLoad(prop); |
1356 } else { | 1504 } else { |
1357 Visit(prop->key()); | 1505 VisitForValue(prop->key(), kStack); |
1358 ASSERT_EQ(Expression::kValue, prop->key()->context()); | 1506 EmitKeyedPropertyLoad(prop); |
1359 EmitKeyedPropertyLoad(prop, Expression::kValue); | |
1360 } | 1507 } |
| 1508 __ push(eax); |
1361 } | 1509 } |
1362 | 1510 |
1363 // Convert to number. | 1511 // Convert to number. |
1364 __ InvokeBuiltin(Builtins::TO_NUMBER, CALL_FUNCTION); | 1512 __ InvokeBuiltin(Builtins::TO_NUMBER, CALL_FUNCTION); |
1365 | 1513 |
1366 // Save result for postfix expressions. | 1514 // Save result for postfix expressions. |
1367 if (expr->is_postfix()) { | 1515 if (expr->is_postfix()) { |
1368 switch (expr->context()) { | 1516 switch (expr->context()) { |
1369 case Expression::kUninitialized: | 1517 case Expression::kUninitialized: |
1370 UNREACHABLE(); | 1518 UNREACHABLE(); |
1371 case Expression::kEffect: | 1519 case Expression::kEffect: |
1372 // Do not save result. | 1520 // Do not save result. |
1373 break; | 1521 break; |
1374 case Expression::kValue: | 1522 case Expression::kValue: |
1375 case Expression::kTest: | 1523 case Expression::kTest: |
| 1524 case Expression::kValueTest: |
1376 case Expression::kTestValue: | 1525 case Expression::kTestValue: |
1377 case Expression::kValueTest: | |
1378 // Save the result on the stack. If we have a named or keyed property | 1526 // Save the result on the stack. If we have a named or keyed property |
1379 // we store the result under the receiver that is currently on top | 1527 // we store the result under the receiver that is currently on top |
1380 // of the stack. | 1528 // of the stack. |
1381 switch (assign_type) { | 1529 switch (assign_type) { |
1382 case VARIABLE: | 1530 case VARIABLE: |
1383 __ push(eax); | 1531 __ push(eax); |
1384 break; | 1532 break; |
1385 case NAMED_PROPERTY: | 1533 case NAMED_PROPERTY: |
1386 __ mov(Operand(esp, kPointerSize), eax); | 1534 __ mov(Operand(esp, kPointerSize), eax); |
1387 break; | 1535 break; |
1388 case KEYED_PROPERTY: | 1536 case KEYED_PROPERTY: |
1389 __ mov(Operand(esp, 2 * kPointerSize), eax); | 1537 __ mov(Operand(esp, 2 * kPointerSize), eax); |
1390 break; | 1538 break; |
1391 } | 1539 } |
1392 break; | 1540 break; |
1393 } | 1541 } |
1394 } | 1542 } |
1395 | 1543 |
1396 // Call runtime for +1/-1. | 1544 // Call stub for +1/-1. |
1397 __ push(eax); | 1545 __ push(eax); |
1398 __ push(Immediate(Smi::FromInt(1))); | 1546 __ push(Immediate(Smi::FromInt(1))); |
1399 if (expr->op() == Token::INC) { | 1547 GenericBinaryOpStub stub(expr->binary_op(), |
1400 __ CallRuntime(Runtime::kNumberAdd, 2); | 1548 NO_OVERWRITE, |
1401 } else { | 1549 NO_GENERIC_BINARY_FLAGS); |
1402 __ CallRuntime(Runtime::kNumberSub, 2); | 1550 __ CallStub(&stub); |
1403 } | |
1404 | 1551 |
1405 // Store the value returned in eax. | 1552 // Store the value returned in eax. |
1406 switch (assign_type) { | 1553 switch (assign_type) { |
1407 case VARIABLE: | 1554 case VARIABLE: |
1408 __ push(eax); | |
1409 if (expr->is_postfix()) { | 1555 if (expr->is_postfix()) { |
1410 EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(), | 1556 EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(), |
1411 Expression::kEffect); | 1557 Expression::kEffect); |
1412 // For all contexts except kEffect: We have the result on | 1558 // For all contexts except kEffect: We have the result on |
1413 // top of the stack. | 1559 // top of the stack. |
1414 if (expr->context() != Expression::kEffect) { | 1560 if (expr->context() != Expression::kEffect) { |
1415 ApplyTOS(expr->context()); | 1561 ApplyTOS(expr->context()); |
1416 } | 1562 } |
1417 } else { | 1563 } else { |
1418 EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(), | 1564 EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(), |
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1474 case Token::ADD: | 1620 case Token::ADD: |
1475 case Token::SUB: | 1621 case Token::SUB: |
1476 case Token::DIV: | 1622 case Token::DIV: |
1477 case Token::MOD: | 1623 case Token::MOD: |
1478 case Token::MUL: | 1624 case Token::MUL: |
1479 case Token::BIT_OR: | 1625 case Token::BIT_OR: |
1480 case Token::BIT_AND: | 1626 case Token::BIT_AND: |
1481 case Token::BIT_XOR: | 1627 case Token::BIT_XOR: |
1482 case Token::SHL: | 1628 case Token::SHL: |
1483 case Token::SHR: | 1629 case Token::SHR: |
1484 case Token::SAR: { | 1630 case Token::SAR: |
1485 ASSERT_EQ(Expression::kValue, expr->left()->context()); | 1631 VisitForValue(expr->left(), kStack); |
1486 ASSERT_EQ(Expression::kValue, expr->right()->context()); | 1632 VisitForValue(expr->right(), kAccumulator); |
| 1633 EmitBinaryOp(expr->op(), expr->context()); |
| 1634 break; |
1487 | 1635 |
1488 Visit(expr->left()); | |
1489 Visit(expr->right()); | |
1490 GenericBinaryOpStub stub(expr->op(), | |
1491 NO_OVERWRITE, | |
1492 NO_GENERIC_BINARY_FLAGS); | |
1493 __ CallStub(&stub); | |
1494 Apply(expr->context(), eax); | |
1495 | |
1496 break; | |
1497 } | |
1498 default: | 1636 default: |
1499 UNREACHABLE(); | 1637 UNREACHABLE(); |
1500 } | 1638 } |
1501 } | 1639 } |
1502 | 1640 |
1503 | 1641 |
1504 void FastCodeGenerator::VisitCompareOperation(CompareOperation* expr) { | 1642 void FastCodeGenerator::VisitCompareOperation(CompareOperation* expr) { |
1505 Comment cmnt(masm_, "[ CompareOperation"); | 1643 Comment cmnt(masm_, "[ CompareOperation"); |
1506 ASSERT_EQ(Expression::kValue, expr->left()->context()); | |
1507 ASSERT_EQ(Expression::kValue, expr->right()->context()); | |
1508 Visit(expr->left()); | |
1509 Visit(expr->right()); | |
1510 | 1644 |
1511 // Always perform the comparison for its control flow. Pack the result | 1645 // Always perform the comparison for its control flow. Pack the result |
1512 // into the expression's context after the comparison is performed. | 1646 // into the expression's context after the comparison is performed. |
1513 Label push_true, push_false, done; | 1647 Label materialize_true, materialize_false, done; |
1514 // Initially assume we are in a test context. | 1648 // Initially assume we are in a test context. |
1515 Label* if_true = true_label_; | 1649 Label* if_true = true_label_; |
1516 Label* if_false = false_label_; | 1650 Label* if_false = false_label_; |
1517 switch (expr->context()) { | 1651 switch (expr->context()) { |
1518 case Expression::kUninitialized: | 1652 case Expression::kUninitialized: |
1519 UNREACHABLE(); | 1653 UNREACHABLE(); |
1520 break; | 1654 break; |
1521 case Expression::kEffect: | 1655 case Expression::kEffect: |
1522 if_true = &done; | 1656 if_true = &done; |
1523 if_false = &done; | 1657 if_false = &done; |
1524 break; | 1658 break; |
1525 case Expression::kValue: | 1659 case Expression::kValue: |
1526 if_true = &push_true; | 1660 if_true = &materialize_true; |
1527 if_false = &push_false; | 1661 if_false = &materialize_false; |
1528 break; | 1662 break; |
1529 case Expression::kTest: | 1663 case Expression::kTest: |
1530 break; | 1664 break; |
1531 case Expression::kValueTest: | 1665 case Expression::kValueTest: |
1532 if_true = &push_true; | 1666 if_true = &materialize_true; |
1533 break; | 1667 break; |
1534 case Expression::kTestValue: | 1668 case Expression::kTestValue: |
1535 if_false = &push_false; | 1669 if_false = &materialize_false; |
1536 break; | 1670 break; |
1537 } | 1671 } |
1538 | 1672 |
| 1673 VisitForValue(expr->left(), kStack); |
1539 switch (expr->op()) { | 1674 switch (expr->op()) { |
1540 case Token::IN: { | 1675 case Token::IN: |
| 1676 VisitForValue(expr->right(), kStack); |
1541 __ InvokeBuiltin(Builtins::IN, CALL_FUNCTION); | 1677 __ InvokeBuiltin(Builtins::IN, CALL_FUNCTION); |
1542 __ cmp(eax, Factory::true_value()); | 1678 __ cmp(eax, Factory::true_value()); |
1543 __ j(equal, if_true); | 1679 __ j(equal, if_true); |
1544 __ jmp(if_false); | 1680 __ jmp(if_false); |
1545 break; | 1681 break; |
1546 } | |
1547 | 1682 |
1548 case Token::INSTANCEOF: { | 1683 case Token::INSTANCEOF: { |
| 1684 VisitForValue(expr->right(), kStack); |
1549 InstanceofStub stub; | 1685 InstanceofStub stub; |
1550 __ CallStub(&stub); | 1686 __ CallStub(&stub); |
1551 __ test(eax, Operand(eax)); | 1687 __ test(eax, Operand(eax)); |
1552 __ j(zero, if_true); // The stub returns 0 for true. | 1688 __ j(zero, if_true); // The stub returns 0 for true. |
1553 __ jmp(if_false); | 1689 __ jmp(if_false); |
1554 break; | 1690 break; |
1555 } | 1691 } |
1556 | 1692 |
1557 default: { | 1693 default: { |
| 1694 VisitForValue(expr->right(), kAccumulator); |
1558 Condition cc = no_condition; | 1695 Condition cc = no_condition; |
1559 bool strict = false; | 1696 bool strict = false; |
1560 switch (expr->op()) { | 1697 switch (expr->op()) { |
1561 case Token::EQ_STRICT: | 1698 case Token::EQ_STRICT: |
1562 strict = true; | 1699 strict = true; |
1563 // Fall through | 1700 // Fall through |
1564 case Token::EQ: | 1701 case Token::EQ: |
1565 cc = equal; | 1702 cc = equal; |
1566 __ pop(eax); | |
1567 __ pop(edx); | 1703 __ pop(edx); |
1568 break; | 1704 break; |
1569 case Token::LT: | 1705 case Token::LT: |
1570 cc = less; | 1706 cc = less; |
1571 __ pop(eax); | |
1572 __ pop(edx); | 1707 __ pop(edx); |
1573 break; | 1708 break; |
1574 case Token::GT: | 1709 case Token::GT: |
1575 // Reverse left and right sizes to obtain ECMA-262 conversion order. | 1710 // Reverse left and right sizes to obtain ECMA-262 conversion order. |
1576 cc = less; | 1711 cc = less; |
1577 __ pop(edx); | 1712 __ mov(edx, result_register()); |
1578 __ pop(eax); | 1713 __ pop(eax); |
1579 break; | 1714 break; |
1580 case Token::LTE: | 1715 case Token::LTE: |
1581 // Reverse left and right sizes to obtain ECMA-262 conversion order. | 1716 // Reverse left and right sizes to obtain ECMA-262 conversion order. |
1582 cc = greater_equal; | 1717 cc = greater_equal; |
1583 __ pop(edx); | 1718 __ mov(edx, result_register()); |
1584 __ pop(eax); | 1719 __ pop(eax); |
1585 break; | 1720 break; |
1586 case Token::GTE: | 1721 case Token::GTE: |
1587 cc = greater_equal; | 1722 cc = greater_equal; |
1588 __ pop(eax); | |
1589 __ pop(edx); | 1723 __ pop(edx); |
1590 break; | 1724 break; |
1591 case Token::IN: | 1725 case Token::IN: |
1592 case Token::INSTANCEOF: | 1726 case Token::INSTANCEOF: |
1593 default: | 1727 default: |
1594 UNREACHABLE(); | 1728 UNREACHABLE(); |
1595 } | 1729 } |
1596 | 1730 |
1597 // The comparison stub expects the smi vs. smi case to be handled | 1731 // The comparison stub expects the smi vs. smi case to be handled |
1598 // before it is called. | 1732 // before it is called. |
(...skipping 10 matching lines...) Expand all Loading... |
1609 CompareStub stub(cc, strict); | 1743 CompareStub stub(cc, strict); |
1610 __ CallStub(&stub); | 1744 __ CallStub(&stub); |
1611 __ test(eax, Operand(eax)); | 1745 __ test(eax, Operand(eax)); |
1612 __ j(cc, if_true); | 1746 __ j(cc, if_true); |
1613 __ jmp(if_false); | 1747 __ jmp(if_false); |
1614 } | 1748 } |
1615 } | 1749 } |
1616 | 1750 |
1617 // Convert the result of the comparison into one expected for this | 1751 // Convert the result of the comparison into one expected for this |
1618 // expression's context. | 1752 // expression's context. |
1619 switch (expr->context()) { | 1753 Apply(expr->context(), if_true, if_false); |
1620 case Expression::kUninitialized: | |
1621 UNREACHABLE(); | |
1622 break; | |
1623 | |
1624 case Expression::kEffect: | |
1625 __ bind(&done); | |
1626 break; | |
1627 | |
1628 case Expression::kValue: | |
1629 __ bind(&push_true); | |
1630 __ push(Immediate(Factory::true_value())); | |
1631 __ jmp(&done); | |
1632 __ bind(&push_false); | |
1633 __ push(Immediate(Factory::false_value())); | |
1634 __ bind(&done); | |
1635 break; | |
1636 | |
1637 case Expression::kTest: | |
1638 break; | |
1639 | |
1640 case Expression::kValueTest: | |
1641 __ bind(&push_true); | |
1642 __ push(Immediate(Factory::true_value())); | |
1643 __ jmp(true_label_); | |
1644 break; | |
1645 | |
1646 case Expression::kTestValue: | |
1647 __ bind(&push_false); | |
1648 __ push(Immediate(Factory::false_value())); | |
1649 __ jmp(false_label_); | |
1650 break; | |
1651 } | |
1652 } | 1754 } |
1653 | 1755 |
1654 | 1756 |
1655 void FastCodeGenerator::VisitThisFunction(ThisFunction* expr) { | 1757 void FastCodeGenerator::VisitThisFunction(ThisFunction* expr) { |
1656 __ mov(eax, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset)); | 1758 __ mov(eax, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset)); |
1657 Apply(expr->context(), eax); | 1759 Apply(expr->context(), eax); |
1658 } | 1760 } |
1659 | 1761 |
1660 | 1762 |
1661 Register FastCodeGenerator::result_register() { return eax; } | 1763 Register FastCodeGenerator::result_register() { return eax; } |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1702 __ add(Operand(edx), Immediate(masm_->CodeObject())); | 1804 __ add(Operand(edx), Immediate(masm_->CodeObject())); |
1703 __ mov(Operand(esp, 0), edx); | 1805 __ mov(Operand(esp, 0), edx); |
1704 // And return. | 1806 // And return. |
1705 __ ret(0); | 1807 __ ret(0); |
1706 } | 1808 } |
1707 | 1809 |
1708 | 1810 |
1709 #undef __ | 1811 #undef __ |
1710 | 1812 |
1711 } } // namespace v8::internal | 1813 } } // namespace v8::internal |
OLD | NEW |