Chromium Code Reviews| 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 90 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 101 __ RecordJSReturn(); | 101 __ RecordJSReturn(); |
| 102 // Do not use the leave instruction here because it is too short to | 102 // Do not use the leave instruction here because it is too short to |
| 103 // patch with the code required by the debugger. | 103 // patch with the code required by the debugger. |
| 104 __ mov(esp, ebp); | 104 __ mov(esp, ebp); |
| 105 __ pop(ebp); | 105 __ pop(ebp); |
| 106 __ ret((fun->scope()->num_parameters() + 1) * kPointerSize); | 106 __ ret((fun->scope()->num_parameters() + 1) * kPointerSize); |
| 107 } | 107 } |
| 108 } | 108 } |
| 109 | 109 |
| 110 | 110 |
| 111 void FastCodeGenerator::Move(Expression::Context context, Register source) { | |
| 112 switch (context) { | |
| 113 case Expression::kUninitialized: | |
| 114 UNREACHABLE(); | |
| 115 case Expression::kEffect: | |
| 116 break; | |
| 117 case Expression::kValue: | |
| 118 __ push(source); | |
| 119 break; | |
| 120 case Expression::kTest: | |
| 121 TestAndBranch(source, true_label_, false_label_); | |
| 122 break; | |
| 123 case Expression::kValueTest: { | |
| 124 Label discard; | |
| 125 __ push(source); | |
| 126 TestAndBranch(source, true_label_, &discard); | |
|
William Hesse
2009/10/30 12:09:39
Why not
Label save;
TestAndBranch(source, &save, f
Kevin Millikin (Chromium)
2009/10/30 13:45:53
TestAndBranch destroys source.
| |
| 127 __ bind(&discard); | |
| 128 __ add(Operand(esp), Immediate(kPointerSize)); | |
| 129 __ jmp(false_label_); | |
| 130 break; | |
| 131 } | |
| 132 case Expression::kTestValue: { | |
| 133 Label discard; | |
| 134 __ push(source); | |
| 135 TestAndBranch(source, &discard, false_label_); | |
| 136 __ bind(&discard); | |
| 137 __ add(Operand(esp), Immediate(kPointerSize)); | |
| 138 __ jmp(true_label_); | |
| 139 } | |
| 140 } | |
| 141 } | |
| 142 | |
| 143 | |
| 111 void FastCodeGenerator::Move(Expression::Context context, Slot* source) { | 144 void FastCodeGenerator::Move(Expression::Context context, Slot* source) { |
| 112 switch (context) { | 145 switch (context) { |
| 113 case Expression::kUninitialized: | 146 case Expression::kUninitialized: |
| 114 UNREACHABLE(); | 147 UNREACHABLE(); |
| 115 case Expression::kEffect: | 148 case Expression::kEffect: |
| 116 break; | 149 break; |
| 117 case Expression::kValue: | 150 case Expression::kValue: |
| 118 __ push(Operand(ebp, SlotOffset(source))); | 151 __ push(Operand(ebp, SlotOffset(source))); |
| 119 break; | 152 break; |
| 153 case Expression::kTest: // Fall through. | |
| 154 case Expression::kValueTest: // Fall through. | |
| 155 case Expression::kTestValue: | |
| 156 __ mov(eax, Operand(ebp, SlotOffset(source))); | |
|
William Hesse
2009/10/30 12:09:39
This could be optimized if TestAndBranch took an o
Kevin Millikin (Chromium)
2009/10/30 13:45:53
TestAndBranch needs the value in a register to com
| |
| 157 Move(context, eax); | |
| 158 break; | |
| 120 } | 159 } |
| 121 } | 160 } |
| 122 | 161 |
| 123 | 162 |
| 124 void FastCodeGenerator::Move(Expression::Context context, Literal* expr) { | 163 void FastCodeGenerator::Move(Expression::Context context, Literal* expr) { |
| 125 switch (context) { | 164 switch (context) { |
| 126 case Expression::kUninitialized: | 165 case Expression::kUninitialized: |
| 127 UNREACHABLE(); | 166 UNREACHABLE(); |
| 128 case Expression::kEffect: | 167 case Expression::kEffect: |
| 129 break; | 168 break; |
| 130 case Expression::kValue: | 169 case Expression::kValue: |
| 131 __ push(Immediate(expr->handle())); | 170 __ push(Immediate(expr->handle())); |
| 132 break; | 171 break; |
| 172 case Expression::kTest: // Fall through. | |
| 173 case Expression::kValueTest: // Fall through. | |
| 174 case Expression::kTestValue: | |
| 175 __ mov(eax, expr->handle()); | |
| 176 Move(context, eax); | |
| 177 break; | |
| 133 } | 178 } |
| 134 } | 179 } |
| 135 | 180 |
| 136 | 181 |
| 137 void FastCodeGenerator::DropAndMove(Expression::Context context, | 182 void FastCodeGenerator::DropAndMove(Expression::Context context, |
| 138 Register source) { | 183 Register source) { |
| 139 switch (context) { | 184 switch (context) { |
| 140 case Expression::kUninitialized: | 185 case Expression::kUninitialized: |
| 141 UNREACHABLE(); | 186 UNREACHABLE(); |
| 142 case Expression::kEffect: | 187 case Expression::kEffect: |
| 143 __ add(Operand(esp), Immediate(kPointerSize)); | 188 __ add(Operand(esp), Immediate(kPointerSize)); |
| 144 break; | 189 break; |
| 145 case Expression::kValue: | 190 case Expression::kValue: |
| 146 __ mov(Operand(esp, 0), source); | 191 __ mov(Operand(esp, 0), source); |
| 147 break; | 192 break; |
| 193 case Expression::kTest: | |
| 194 ASSERT(!source.is(esp)); | |
| 195 __ add(Operand(esp), Immediate(kPointerSize)); | |
| 196 TestAndBranch(source, true_label_, false_label_); | |
| 197 break; | |
| 198 case Expression::kValueTest: { | |
| 199 Label discard; | |
| 200 __ mov(Operand(esp, 0), source); | |
| 201 TestAndBranch(source, true_label_, &discard); | |
| 202 __ bind(&discard); | |
| 203 __ add(Operand(esp), Immediate(kPointerSize)); | |
| 204 __ jmp(false_label_); | |
| 205 break; | |
| 206 } | |
| 207 case Expression::kTestValue: { | |
| 208 Label discard; | |
| 209 __ mov(Operand(esp, 0), source); | |
| 210 TestAndBranch(source, &discard, false_label_); | |
| 211 __ bind(&discard); | |
| 212 __ add(Operand(esp), Immediate(kPointerSize)); | |
| 213 __ jmp(true_label_); | |
| 214 break; | |
| 215 } | |
| 148 } | 216 } |
| 149 } | 217 } |
| 150 | 218 |
| 151 | 219 |
| 220 void FastCodeGenerator::TestAndBranch(Register source, | |
| 221 Label* true_label, | |
| 222 Label* false_label) { | |
| 223 ASSERT_NE(NULL, true_label); | |
| 224 ASSERT_NE(NULL, false_label); | |
| 225 // Use the shared ToBoolean stub to compile the value in the register into | |
| 226 // control flow to the code generator's true and false labels. Perform | |
| 227 // the fast checks assumed by the stub. | |
| 228 __ cmp(source, Factory::undefined_value()); // The undefined value is false. | |
| 229 __ j(equal, false_label); | |
| 230 __ cmp(source, Factory::true_value()); // True is true. | |
| 231 __ j(equal, true_label); | |
| 232 __ cmp(source, Factory::false_value()); // False is false. | |
| 233 __ j(equal, false_label); | |
| 234 ASSERT_EQ(0, kSmiTag); | |
| 235 __ test(source, Operand(source)); // The smi zero is false. | |
| 236 __ j(zero, false_label); | |
| 237 __ test(source, Immediate(kSmiTagMask)); // All other smis are true. | |
| 238 __ j(zero, true_label); | |
| 239 | |
| 240 // Call the stub for all other cases. | |
| 241 __ push(source); | |
| 242 ToBooleanStub stub; | |
| 243 __ CallStub(&stub); | |
| 244 __ test(eax, Operand(eax)); // The stub returns nonzero for true. | |
| 245 __ j(not_zero, true_label); | |
| 246 __ jmp(false_label); | |
| 247 } | |
| 248 | |
| 249 | |
| 152 void FastCodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) { | 250 void FastCodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) { |
| 153 // Call the runtime to declare the globals. | 251 // Call the runtime to declare the globals. |
| 154 __ push(esi); // The context is the first argument. | 252 __ push(esi); // The context is the first argument. |
| 155 __ push(Immediate(pairs)); | 253 __ push(Immediate(pairs)); |
| 156 __ push(Immediate(Smi::FromInt(is_eval_ ? 1 : 0))); | 254 __ push(Immediate(Smi::FromInt(is_eval_ ? 1 : 0))); |
| 157 __ CallRuntime(Runtime::kDeclareGlobals, 3); | 255 __ CallRuntime(Runtime::kDeclareGlobals, 3); |
| 158 // Return value is ignored. | 256 // Return value is ignored. |
| 159 } | 257 } |
| 160 | 258 |
| 161 | 259 |
| (...skipping 181 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 343 } | 441 } |
| 344 switch (expr->context()) { | 442 switch (expr->context()) { |
| 345 case Expression::kUninitialized: | 443 case Expression::kUninitialized: |
| 346 UNREACHABLE(); | 444 UNREACHABLE(); |
| 347 case Expression::kEffect: | 445 case Expression::kEffect: |
| 348 if (result_saved) __ add(Operand(esp), Immediate(kPointerSize)); | 446 if (result_saved) __ add(Operand(esp), Immediate(kPointerSize)); |
| 349 break; | 447 break; |
| 350 case Expression::kValue: | 448 case Expression::kValue: |
| 351 if (!result_saved) __ push(eax); | 449 if (!result_saved) __ push(eax); |
| 352 break; | 450 break; |
| 451 case Expression::kTest: | |
| 452 if (result_saved) __ pop(eax); | |
| 453 TestAndBranch(eax, true_label_, false_label_); | |
| 454 break; | |
| 455 case Expression::kValueTest: { | |
| 456 Label discard; | |
| 457 if (!result_saved) __ push(eax); | |
| 458 TestAndBranch(eax, true_label_, &discard); | |
| 459 __ bind(&discard); | |
| 460 __ add(Operand(esp), Immediate(kPointerSize)); | |
| 461 __ jmp(false_label_); | |
| 462 break; | |
| 463 } | |
| 464 case Expression::kTestValue: { | |
| 465 Label discard; | |
| 466 if (!result_saved) __ push(eax); | |
| 467 TestAndBranch(eax, &discard, false_label_); | |
| 468 __ bind(&discard); | |
| 469 __ add(Operand(esp), Immediate(kPointerSize)); | |
| 470 __ jmp(true_label_); | |
| 471 break; | |
| 472 } | |
| 353 } | 473 } |
| 354 } | 474 } |
| 355 | 475 |
| 356 | 476 |
| 357 void FastCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) { | 477 void FastCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) { |
| 358 Comment cmnt(masm_, "[ ArrayLiteral"); | 478 Comment cmnt(masm_, "[ ArrayLiteral"); |
| 359 Label make_clone; | 479 Label make_clone; |
| 360 | 480 |
| 361 // Fetch the function's literals array. | 481 // Fetch the function's literals array. |
| 362 __ mov(ebx, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset)); | 482 __ mov(ebx, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset)); |
| (...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 417 | 537 |
| 418 switch (expr->context()) { | 538 switch (expr->context()) { |
| 419 case Expression::kUninitialized: | 539 case Expression::kUninitialized: |
| 420 UNREACHABLE(); | 540 UNREACHABLE(); |
| 421 case Expression::kEffect: | 541 case Expression::kEffect: |
| 422 if (result_saved) __ add(Operand(esp), Immediate(kPointerSize)); | 542 if (result_saved) __ add(Operand(esp), Immediate(kPointerSize)); |
| 423 break; | 543 break; |
| 424 case Expression::kValue: | 544 case Expression::kValue: |
| 425 if (!result_saved) __ push(eax); | 545 if (!result_saved) __ push(eax); |
| 426 break; | 546 break; |
| 547 case Expression::kTest: | |
| 548 if (result_saved) __ pop(eax); | |
| 549 TestAndBranch(eax, true_label_, false_label_); | |
| 550 break; | |
| 551 case Expression::kValueTest: { | |
| 552 Label discard; | |
| 553 if (!result_saved) __ push(eax); | |
| 554 TestAndBranch(eax, true_label_, &discard); | |
| 555 __ bind(&discard); | |
| 556 __ add(Operand(esp), Immediate(kPointerSize)); | |
| 557 __ jmp(false_label_); | |
| 558 break; | |
| 559 } | |
| 560 case Expression::kTestValue: { | |
| 561 Label discard; | |
| 562 if (!result_saved) __ push(eax); | |
| 563 TestAndBranch(eax, &discard, false_label_); | |
| 564 __ bind(&discard); | |
| 565 __ add(Operand(esp), Immediate(kPointerSize)); | |
| 566 __ jmp(true_label_); | |
| 567 break; | |
| 568 } | |
| 427 } | 569 } |
| 428 } | 570 } |
| 429 | 571 |
| 430 | 572 |
| 431 void FastCodeGenerator::VisitAssignment(Assignment* expr) { | 573 void FastCodeGenerator::VisitAssignment(Assignment* expr) { |
| 432 Comment cmnt(masm_, "[ Assignment"); | 574 Comment cmnt(masm_, "[ Assignment"); |
| 433 ASSERT(expr->op() == Token::ASSIGN || expr->op() == Token::INIT_VAR); | 575 ASSERT(expr->op() == Token::ASSIGN || expr->op() == Token::INIT_VAR); |
| 434 | 576 |
| 435 // Record the source position for the assignment. | 577 // Record the source position for the assignment. |
| 436 SetSourcePosition(expr->position()); | 578 SetSourcePosition(expr->position()); |
| (...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 510 case Expression::kEffect: | 652 case Expression::kEffect: |
| 511 // Case 'var = temp'. Discard right-hand-side temporary. | 653 // Case 'var = temp'. Discard right-hand-side temporary. |
| 512 __ pop(Operand(ebp, SlotOffset(var->slot()))); | 654 __ pop(Operand(ebp, SlotOffset(var->slot()))); |
| 513 break; | 655 break; |
| 514 case Expression::kValue: | 656 case Expression::kValue: |
| 515 // Case 'temp1 <- (var = temp0)'. Preserve right-hand-side | 657 // Case 'temp1 <- (var = temp0)'. Preserve right-hand-side |
| 516 // temporary on the stack. | 658 // temporary on the stack. |
| 517 __ mov(eax, Operand(esp, 0)); | 659 __ mov(eax, Operand(esp, 0)); |
| 518 __ mov(Operand(ebp, SlotOffset(var->slot())), eax); | 660 __ mov(Operand(ebp, SlotOffset(var->slot())), eax); |
| 519 break; | 661 break; |
| 662 case Expression::kTest: | |
| 663 // Case 'if (var = temp) ...'. | |
| 664 __ pop(eax); | |
| 665 __ mov(Operand(ebp, SlotOffset(var->slot())), eax); | |
| 666 TestAndBranch(eax, true_label_, false_label_); | |
| 667 break; | |
| 668 case Expression::kValueTest: { | |
| 669 // Case '(var = temp) || ...' in value context. | |
| 670 Label discard; | |
|
William Hesse
2009/10/30 12:09:39
Same comment as above, on optimization.
| |
| 671 __ mov(eax, Operand(esp, 0)); | |
| 672 __ mov(Operand(ebp, SlotOffset(var->slot())), eax); | |
| 673 TestAndBranch(eax, true_label_, &discard); | |
|
William Hesse
2009/10/30 12:09:39
Can we give TestAndBranch a fallthrough label, so
Kevin Millikin (Chromium)
2009/10/30 13:45:53
We'd need a global fallthrough to get the whole be
| |
| 674 __ bind(&discard); | |
| 675 __ add(Operand(esp), Immediate(kPointerSize)); | |
| 676 __ jmp(false_label_); | |
| 677 break; | |
| 678 } | |
| 679 case Expression::kTestValue: { | |
| 680 // Case '(var = temp) && ...' in value context. | |
| 681 Label discard; | |
| 682 __ mov(eax, Operand(esp, 0)); | |
| 683 __ mov(Operand(ebp, SlotOffset(var->slot())), eax); | |
| 684 TestAndBranch(eax, &discard, false_label_); | |
| 685 __ bind(&discard); | |
| 686 __ add(Operand(esp), Immediate(kPointerSize)); | |
| 687 __ jmp(true_label_); | |
| 688 break; | |
| 689 } | |
| 520 } | 690 } |
| 521 } | 691 } |
| 522 } | 692 } |
| 523 } | 693 } |
| 524 | 694 |
| 525 | 695 |
| 526 void FastCodeGenerator::VisitProperty(Property* expr) { | 696 void FastCodeGenerator::VisitProperty(Property* expr) { |
| 527 Comment cmnt(masm_, "[ Property"); | 697 Comment cmnt(masm_, "[ Property"); |
| 528 Expression* key = expr->key(); | 698 Expression* key = expr->key(); |
| 529 uint32_t dummy; | 699 uint32_t dummy; |
| (...skipping 151 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 681 Move(expr->context(), eax); | 851 Move(expr->context(), eax); |
| 682 | 852 |
| 683 break; | 853 break; |
| 684 } | 854 } |
| 685 default: | 855 default: |
| 686 UNREACHABLE(); | 856 UNREACHABLE(); |
| 687 } | 857 } |
| 688 } | 858 } |
| 689 | 859 |
| 690 | 860 |
| 691 void FastCodeGenerator::EmitLogicalOperation(BinaryOperation* expr) { | 861 #undef __ |
| 692 // Compile a short-circuited boolean operation in a non-test context. | |
| 693 | |
| 694 // Compile (e0 || e1) or (e0 && e1) as if it were | |
| 695 // (let (temp = e0) temp [or !temp, for &&] ? temp : e1). | |
| 696 | |
| 697 Label eval_right, done; | |
| 698 Label *left_true, *left_false; // Where to branch to if lhs has that value. | |
| 699 if (expr->op() == Token::OR) { | |
| 700 left_true = &done; | |
| 701 left_false = &eval_right; | |
| 702 } else { | |
| 703 left_true = &eval_right; | |
| 704 left_false = &done; | |
| 705 } | |
| 706 Expression::Context context = expr->context(); | |
| 707 Expression* left = expr->left(); | |
| 708 Expression* right = expr->right(); | |
| 709 | |
| 710 // Use the shared ToBoolean stub to find the boolean value of the | |
| 711 // left-hand subexpression. Load the value into eax to perform some | |
| 712 // inlined checks assumed by the stub. | |
| 713 | |
| 714 // Compile the left-hand value into eax. Put it on the stack if we may | |
| 715 // need it as the value of the whole expression. | |
| 716 if (left->AsLiteral() != NULL) { | |
| 717 __ mov(eax, left->AsLiteral()->handle()); | |
| 718 if (context == Expression::kValue) __ push(eax); | |
| 719 } else { | |
| 720 Visit(left); | |
| 721 ASSERT_EQ(Expression::kValue, left->context()); | |
| 722 switch (context) { | |
| 723 case Expression::kUninitialized: | |
| 724 UNREACHABLE(); | |
| 725 case Expression::kEffect: | |
| 726 // Pop the left-hand value into eax because we will not need it as the | |
| 727 // final result. | |
| 728 __ pop(eax); | |
| 729 break; | |
| 730 case Expression::kValue: | |
| 731 // Copy the left-hand value into eax because we may need it as the | |
| 732 // final result. | |
| 733 __ mov(eax, Operand(esp, 0)); | |
| 734 break; | |
| 735 } | |
| 736 } | |
| 737 // The left-hand value is in eax. It is also on the stack iff the | |
| 738 // destination location is value. | |
| 739 | |
| 740 // Perform fast checks assumed by the stub. | |
| 741 __ cmp(eax, Factory::undefined_value()); // The undefined value is false. | |
| 742 __ j(equal, left_false); | |
| 743 __ cmp(eax, Factory::true_value()); // True is true. | |
| 744 __ j(equal, left_true); | |
| 745 __ cmp(eax, Factory::false_value()); // False is false. | |
| 746 __ j(equal, left_false); | |
| 747 ASSERT_EQ(0, kSmiTag); | |
| 748 __ test(eax, Operand(eax)); // The smi zero is false. | |
| 749 __ j(zero, left_false); | |
| 750 __ test(eax, Immediate(kSmiTagMask)); // All other smis are true. | |
| 751 __ j(zero, left_true); | |
| 752 | |
| 753 // Call the stub for all other cases. | |
| 754 __ push(eax); | |
| 755 ToBooleanStub stub; | |
| 756 __ CallStub(&stub); | |
| 757 __ test(eax, Operand(eax)); // The stub returns nonzero for true. | |
| 758 if (expr->op() == Token::OR) { | |
| 759 __ j(not_zero, &done); | |
| 760 } else { | |
| 761 __ j(zero, &done); | |
| 762 } | |
| 763 | |
| 764 __ bind(&eval_right); | |
| 765 // Discard the left-hand value if present on the stack. | |
| 766 if (context == Expression::kValue) { | |
| 767 __ add(Operand(esp), Immediate(kPointerSize)); | |
| 768 } | |
| 769 // Save or discard the right-hand value as needed. | |
| 770 Visit(right); | |
| 771 ASSERT_EQ(context, right->context()); | |
| 772 | |
| 773 __ bind(&done); | |
| 774 } | |
| 775 | 862 |
| 776 | 863 |
| 777 } } // namespace v8::internal | 864 } } // namespace v8::internal |
| OLD | NEW |