| 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 |