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 98 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 109 // (3 + 1 + 3). | 109 // (3 + 1 + 3). |
| 110 const int kPadding = Debug::kX64JSReturnSequenceLength - 7; | 110 const int kPadding = Debug::kX64JSReturnSequenceLength - 7; |
| 111 for (int i = 0; i < kPadding; ++i) { | 111 for (int i = 0; i < kPadding; ++i) { |
| 112 masm_->int3(); | 112 masm_->int3(); |
| 113 } | 113 } |
| 114 #endif | 114 #endif |
| 115 } | 115 } |
| 116 } | 116 } |
| 117 | 117 |
| 118 | 118 |
| 119 | |
| 120 void FastCodeGenerator::Move(Expression::Context context, Register source) { | |
| 121 switch (context) { | |
| 122 case Expression::kUninitialized: | |
| 123 UNREACHABLE(); | |
| 124 case Expression::kEffect: | |
| 125 break; | |
| 126 case Expression::kValue: | |
| 127 __ push(source); | |
| 128 break; | |
| 129 case Expression::kTest: | |
| 130 TestAndBranch(source, true_label_, false_label_); | |
| 131 break; | |
| 132 case Expression::kValueTest: { | |
| 133 Label discard; | |
| 134 __ push(source); | |
| 135 TestAndBranch(source, true_label_, &discard); | |
| 136 __ bind(&discard); | |
| 137 __ addq(rsp, Immediate(kPointerSize)); | |
| 138 __ jmp(false_label_); | |
| 139 break; | |
| 140 } | |
| 141 case Expression::kTestValue: { | |
| 142 Label discard; | |
| 143 __ push(source); | |
| 144 TestAndBranch(source, &discard, false_label_); | |
| 145 __ bind(&discard); | |
| 146 __ addq(rsp, Immediate(kPointerSize)); | |
| 147 __ jmp(true_label_); | |
| 148 break; | |
| 149 } | |
| 150 } | |
| 151 } | |
| 152 | |
| 153 | |
| 119 void FastCodeGenerator::Move(Expression::Context context, Slot* source) { | 154 void FastCodeGenerator::Move(Expression::Context context, Slot* source) { |
| 120 switch (context) { | 155 switch (context) { |
| 121 case Expression::kUninitialized: | 156 case Expression::kUninitialized: |
| 122 UNREACHABLE(); | 157 UNREACHABLE(); |
| 123 case Expression::kEffect: | 158 case Expression::kEffect: |
| 124 break; | 159 break; |
| 125 case Expression::kValue: | 160 case Expression::kValue: |
| 126 __ push(Operand(rbp, SlotOffset(source))); | 161 __ push(Operand(rbp, SlotOffset(source))); |
| 127 break; | 162 break; |
| 163 case Expression::kTest: // Fall through. | |
| 164 case Expression::kValueTest: // Fall through. | |
| 165 case Expression::kTestValue: | |
| 166 __ movq(rax, Operand(rbp, SlotOffset(source))); | |
| 167 Move(context, rax); | |
| 168 break; | |
| 128 } | 169 } |
| 129 } | 170 } |
| 130 | 171 |
| 131 | 172 |
| 132 void FastCodeGenerator::Move(Expression::Context context, Literal* expr) { | 173 void FastCodeGenerator::Move(Expression::Context context, Literal* expr) { |
| 133 switch (context) { | 174 switch (context) { |
| 134 case Expression::kUninitialized: | 175 case Expression::kUninitialized: |
| 135 UNREACHABLE(); | 176 UNREACHABLE(); |
| 136 case Expression::kEffect: | 177 case Expression::kEffect: |
| 137 break; | 178 break; |
| 138 case Expression::kValue: | 179 case Expression::kValue: |
| 139 __ Push(expr->handle()); | 180 __ Push(expr->handle()); |
| 140 break; | 181 break; |
| 182 case Expression::kTest: // Fall through. | |
| 183 case Expression::kValueTest: // Fall through. | |
| 184 case Expression::kTestValue: | |
| 185 __ Move(rax, expr->handle()); | |
| 186 Move(context, rax); | |
| 187 break; | |
| 141 } | 188 } |
| 142 } | 189 } |
| 143 | 190 |
| 144 | 191 |
| 145 void FastCodeGenerator::DropAndMove(Expression::Context context, | 192 void FastCodeGenerator::DropAndMove(Expression::Context context, |
| 146 Register source) { | 193 Register source) { |
| 147 switch (context) { | 194 switch (context) { |
| 148 case Expression::kUninitialized: | 195 case Expression::kUninitialized: |
| 149 UNREACHABLE(); | 196 UNREACHABLE(); |
| 150 case Expression::kEffect: | 197 case Expression::kEffect: |
| 151 __ addq(rsp, Immediate(kPointerSize)); | 198 __ addq(rsp, Immediate(kPointerSize)); |
| 152 break; | 199 break; |
| 153 case Expression::kValue: | 200 case Expression::kValue: |
| 154 __ movq(Operand(rsp, 0), source); | 201 __ movq(Operand(rsp, 0), source); |
| 155 break; | 202 break; |
| 203 case Expression::kTest: | |
| 204 ASSERT(!source.is(rsp)); | |
| 205 __ addq(rsp, Immediate(kPointerSize)); | |
| 206 TestAndBranch(source, true_label_, false_label_); | |
| 207 break; | |
| 208 case Expression::kValueTest: { | |
| 209 Label discard; | |
| 210 __ movq(Operand(rsp, 0), source); | |
| 211 TestAndBranch(source, true_label_, &discard); | |
| 212 __ bind(&discard); | |
| 213 __ addq(rsp, Immediate(kPointerSize)); | |
| 214 __ jmp(false_label_); | |
| 215 break; | |
| 216 } | |
| 217 case Expression::kTestValue: { | |
| 218 Label discard; | |
| 219 __ movq(Operand(rsp, 0), source); | |
| 220 TestAndBranch(source, &discard, false_label_); | |
| 221 __ bind(&discard); | |
| 222 __ addq(rsp, Immediate(kPointerSize)); | |
| 223 __ jmp(true_label_); | |
| 224 break; | |
| 225 } | |
| 156 } | 226 } |
| 157 } | 227 } |
| 158 | 228 |
| 159 | 229 |
| 230 void FastCodeGenerator::TestAndBranch(Register source, | |
| 231 Label* true_label, | |
| 232 Label* false_label) { | |
| 233 ASSERT_NE(NULL, true_label); | |
| 234 ASSERT_NE(NULL, false_label); | |
| 235 // Use the shared ToBoolean stub to compile the value in the register into | |
| 236 // control flow to the code generator's true and false labels. Perform | |
| 237 // the fast checks assumed by the stub. | |
| 238 | |
| 239 // The undefined value is false. | |
| 240 __ CompareRoot(source, Heap::kUndefinedValueRootIndex); | |
| 241 __ j(equal, false_label); | |
| 242 __ CompareRoot(source, Heap::kTrueValueRootIndex); // True is true. | |
| 243 __ j(equal, true_label); | |
| 244 __ CompareRoot(source, Heap::kFalseValueRootIndex); // False is false. | |
| 245 __ j(equal, false_label); | |
| 246 ASSERT_EQ(0, kSmiTag); | |
| 247 __ SmiCompare(source, Smi::FromInt(0)); // The smi zero is false. | |
| 248 __ j(equal, false_label); | |
| 249 Condition is_smi = masm_->CheckSmi(source); // All other smis are true. | |
| 250 __ j(is_smi, true_label); | |
| 251 | |
| 252 // Call the stub for all other cases. | |
| 253 __ push(source); | |
| 254 ToBooleanStub stub; | |
| 255 __ CallStub(&stub); | |
| 256 __ testq(rax, rax); // The stub returns nonzero for true. | |
| 257 __ j(not_zero, true_label); | |
| 258 __ jmp(false_label); | |
| 259 } | |
| 260 | |
| 261 | |
| 160 void FastCodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) { | 262 void FastCodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) { |
| 161 // Call the runtime to declare the globals. | 263 // Call the runtime to declare the globals. |
| 162 __ push(rsi); // The context is the first argument. | 264 __ push(rsi); // The context is the first argument. |
| 163 __ Push(pairs); | 265 __ Push(pairs); |
| 164 __ Push(Smi::FromInt(is_eval_ ? 1 : 0)); | 266 __ Push(Smi::FromInt(is_eval_ ? 1 : 0)); |
| 165 __ CallRuntime(Runtime::kDeclareGlobals, 3); | 267 __ CallRuntime(Runtime::kDeclareGlobals, 3); |
| 166 // Return value is ignored. | 268 // Return value is ignored. |
| 167 } | 269 } |
| 168 | 270 |
| 169 | 271 |
| (...skipping 184 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 354 } | 456 } |
| 355 switch (expr->context()) { | 457 switch (expr->context()) { |
| 356 case Expression::kUninitialized: | 458 case Expression::kUninitialized: |
| 357 UNREACHABLE(); | 459 UNREACHABLE(); |
| 358 case Expression::kEffect: | 460 case Expression::kEffect: |
| 359 if (result_saved) __ addq(rsp, Immediate(kPointerSize)); | 461 if (result_saved) __ addq(rsp, Immediate(kPointerSize)); |
| 360 break; | 462 break; |
| 361 case Expression::kValue: | 463 case Expression::kValue: |
| 362 if (!result_saved) __ push(rax); | 464 if (!result_saved) __ push(rax); |
| 363 break; | 465 break; |
| 466 case Expression::kTest: | |
| 467 if (result_saved) __ pop(rax); | |
| 468 TestAndBranch(rax, true_label_, false_label_); | |
| 469 break; | |
| 470 case Expression::kValueTest: { | |
| 471 Label discard; | |
| 472 if (!result_saved) __ push(rax); | |
| 473 TestAndBranch(rax, true_label_, &discard); | |
| 474 __ bind(&discard); | |
| 475 __ addq(rsp, Immediate(kPointerSize)); | |
| 476 __ jmp(false_label_); | |
| 477 break; | |
| 478 } | |
| 479 case Expression::kTestValue: { | |
| 480 Label discard; | |
| 481 if (!result_saved) __ push(rax); | |
| 482 TestAndBranch(rax, &discard, false_label_); | |
| 483 __ bind(&discard); | |
| 484 __ addq(rsp, Immediate(kPointerSize)); | |
| 485 __ jmp(true_label_); | |
| 486 break; | |
| 487 } | |
| 364 } | 488 } |
| 365 } | 489 } |
| 366 | 490 |
| 367 | 491 |
| 368 void FastCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) { | 492 void FastCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) { |
| 369 Comment cmnt(masm_, "[ ArrayLiteral"); | 493 Comment cmnt(masm_, "[ ArrayLiteral"); |
| 370 Label make_clone; | 494 Label make_clone; |
| 371 | 495 |
| 372 // Fetch the function's literals array. | 496 // Fetch the function's literals array. |
| 373 __ movq(rbx, Operand(rbp, JavaScriptFrameConstants::kFunctionOffset)); | 497 __ movq(rbx, Operand(rbp, JavaScriptFrameConstants::kFunctionOffset)); |
| (...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 428 | 552 |
| 429 switch (expr->context()) { | 553 switch (expr->context()) { |
| 430 case Expression::kUninitialized: | 554 case Expression::kUninitialized: |
| 431 UNREACHABLE(); | 555 UNREACHABLE(); |
| 432 case Expression::kEffect: | 556 case Expression::kEffect: |
| 433 if (result_saved) __ addq(rsp, Immediate(kPointerSize)); | 557 if (result_saved) __ addq(rsp, Immediate(kPointerSize)); |
| 434 break; | 558 break; |
| 435 case Expression::kValue: | 559 case Expression::kValue: |
| 436 if (!result_saved) __ push(rax); | 560 if (!result_saved) __ push(rax); |
| 437 break; | 561 break; |
| 562 case Expression::kTest: | |
| 563 if (result_saved) __ pop(rax); | |
| 564 TestAndBranch(rax, true_label_, false_label_); | |
| 565 break; | |
| 566 case Expression::kValueTest: { | |
| 567 Label discard; | |
| 568 if (!result_saved) __ push(rax); | |
| 569 TestAndBranch(rax, true_label_, &discard); | |
| 570 __ bind(&discard); | |
| 571 __ addq(rsp, Immediate(kPointerSize)); | |
| 572 __ jmp(false_label_); | |
| 573 break; | |
| 574 } | |
| 575 case Expression::kTestValue: { | |
| 576 Label discard; | |
| 577 if (!result_saved) __ push(rax); | |
| 578 TestAndBranch(rax, &discard, false_label_); | |
| 579 __ bind(&discard); | |
| 580 __ addq(rsp, Immediate(kPointerSize)); | |
| 581 __ jmp(true_label_); | |
| 582 break; | |
| 583 } | |
| 438 } | 584 } |
| 439 } | 585 } |
| 440 | 586 |
| 441 | 587 |
| 442 void FastCodeGenerator::VisitAssignment(Assignment* expr) { | 588 void FastCodeGenerator::VisitAssignment(Assignment* expr) { |
| 443 Comment cmnt(masm_, "[ Assignment"); | 589 Comment cmnt(masm_, "[ Assignment"); |
| 444 ASSERT(expr->op() == Token::ASSIGN || expr->op() == Token::INIT_VAR); | 590 ASSERT(expr->op() == Token::ASSIGN || expr->op() == Token::INIT_VAR); |
| 445 | 591 |
| 446 // Record the source position for the assignment. | 592 // Record the source position for the assignment. |
| 447 SetSourcePosition(expr->position()); | 593 SetSourcePosition(expr->position()); |
| (...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 520 case Expression::kEffect: | 666 case Expression::kEffect: |
| 521 // Case 'var = temp'. Discard right-hand-side temporary. | 667 // Case 'var = temp'. Discard right-hand-side temporary. |
| 522 __ pop(Operand(rbp, SlotOffset(var->slot()))); | 668 __ pop(Operand(rbp, SlotOffset(var->slot()))); |
| 523 break; | 669 break; |
| 524 case Expression::kValue: | 670 case Expression::kValue: |
| 525 // Case 'temp1 <- (var = temp0)'. Preserve right-hand-side | 671 // Case 'temp1 <- (var = temp0)'. Preserve right-hand-side |
| 526 // temporary on the stack. | 672 // temporary on the stack. |
| 527 __ movq(kScratchRegister, Operand(rsp, 0)); | 673 __ movq(kScratchRegister, Operand(rsp, 0)); |
| 528 __ movq(Operand(rbp, SlotOffset(var->slot())), kScratchRegister); | 674 __ movq(Operand(rbp, SlotOffset(var->slot())), kScratchRegister); |
| 529 break; | 675 break; |
| 676 case Expression::kTest: | |
| 677 // Case 'if (var = temp) ...'. | |
| 678 __ pop(rax); | |
| 679 __ movq(Operand(rbp, SlotOffset(var->slot())), rax); | |
| 680 TestAndBranch(rax, true_label_, false_label_); | |
|
William Hesse
2009/10/30 12:09:39
Maybe we should have an operation "TestDropAndBran
Kevin Millikin (Chromium)
2009/10/30 13:45:53
Possibly. This whole chunk of platform-specific c
| |
| 681 break; | |
| 682 case Expression::kValueTest: { | |
| 683 // Case '(var = temp) || ...' in value context. | |
| 684 Label discard; | |
| 685 __ movq(rax, Operand(rsp, 0)); | |
| 686 __ movq(Operand(rbp, SlotOffset(var->slot())), rax); | |
| 687 TestAndBranch(rax, true_label_, &discard); | |
| 688 __ bind(&discard); | |
| 689 __ addq(rsp, Immediate(kPointerSize)); | |
| 690 __ jmp(false_label_); | |
| 691 break; | |
| 692 } | |
| 693 case Expression::kTestValue: { | |
| 694 // Case '(var = temp) && ...' in value context. | |
| 695 Label discard; | |
| 696 __ movq(rax, Operand(rsp, 0)); | |
| 697 __ movq(Operand(rbp, SlotOffset(var->slot())), rax); | |
| 698 TestAndBranch(rax, &discard, false_label_); | |
| 699 __ bind(&discard); | |
| 700 __ addq(rsp, Immediate(kPointerSize)); | |
| 701 __ jmp(true_label_); | |
| 702 break; | |
| 703 } | |
| 530 } | 704 } |
| 531 } | 705 } |
| 532 } | 706 } |
| 533 } | 707 } |
| 534 | 708 |
| 535 | 709 |
| 536 void FastCodeGenerator::VisitProperty(Property* expr) { | 710 void FastCodeGenerator::VisitProperty(Property* expr) { |
| 537 Comment cmnt(masm_, "[ Property"); | 711 Comment cmnt(masm_, "[ Property"); |
| 538 Expression* key = expr->key(); | 712 Expression* key = expr->key(); |
| 539 uint32_t dummy; | 713 uint32_t dummy; |
| (...skipping 153 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 693 Move(expr->context(), rax); | 867 Move(expr->context(), rax); |
| 694 | 868 |
| 695 break; | 869 break; |
| 696 } | 870 } |
| 697 default: | 871 default: |
| 698 UNREACHABLE(); | 872 UNREACHABLE(); |
| 699 } | 873 } |
| 700 } | 874 } |
| 701 | 875 |
| 702 | 876 |
| 703 void FastCodeGenerator::EmitLogicalOperation(BinaryOperation* expr) { | |
| 704 // Compile a short-circuited boolean operation in a non-test context. | |
| 705 | |
| 706 // Compile (e0 || e1) as if it were | |
| 707 // (let (temp = e0) temp ? temp : e1). | |
| 708 // Compile (e0 && e1) as if it were | |
| 709 // (let (temp = e0) !temp ? temp : e1). | |
| 710 | |
| 711 Label eval_right, done; | |
| 712 Label *left_true, *left_false; // Where to branch to if lhs has that value. | |
| 713 if (expr->op() == Token::OR) { | |
| 714 left_true = &done; | |
| 715 left_false = &eval_right; | |
| 716 } else { | |
| 717 left_true = &eval_right; | |
| 718 left_false = &done; | |
| 719 } | |
| 720 Expression::Context context = expr->context(); | |
| 721 Expression* left = expr->left(); | |
| 722 Expression* right = expr->right(); | |
| 723 | |
| 724 // Use the shared ToBoolean stub to find the boolean value of the | |
| 725 // left-hand subexpression. Load the value into rax to perform some | |
| 726 // inlined checks assumed by the stub. | |
| 727 | |
| 728 // Compile the left-hand value into rax. Put it on the stack if we may | |
| 729 // need it as the value of the whole expression. | |
| 730 if (left->AsLiteral() != NULL) { | |
| 731 __ Move(rax, left->AsLiteral()->handle()); | |
| 732 if (context == Expression::kValue) __ push(rax); | |
| 733 } else { | |
| 734 Visit(left); | |
| 735 ASSERT_EQ(Expression::kValue, left->context()); | |
| 736 switch (context) { | |
| 737 case Expression::kUninitialized: | |
| 738 UNREACHABLE(); | |
| 739 case Expression::kEffect: | |
| 740 // Pop the left-hand value into rax because we will not need it as the | |
| 741 // final result. | |
| 742 __ pop(rax); | |
| 743 break; | |
| 744 case Expression::kValue: | |
| 745 // Copy the left-hand value into rax because we may need it as the | |
| 746 // final result. | |
| 747 __ movq(rax, Operand(rsp, 0)); | |
| 748 break; | |
| 749 } | |
| 750 } | |
| 751 // The left-hand value is in rax. It is also on the stack iff the | |
| 752 // destination location is value. | |
| 753 | |
| 754 // Perform fast checks assumed by the stub. | |
| 755 // The undefined value is false. | |
| 756 __ CompareRoot(rax, Heap::kUndefinedValueRootIndex); | |
| 757 __ j(equal, left_false); | |
| 758 __ CompareRoot(rax, Heap::kTrueValueRootIndex); // True is true. | |
| 759 __ j(equal, left_true); | |
| 760 __ CompareRoot(rax, Heap::kFalseValueRootIndex); // False is false. | |
| 761 __ j(equal, left_false); | |
| 762 ASSERT(kSmiTag == 0); | |
| 763 __ SmiCompare(rax, Smi::FromInt(0)); // The smi zero is false. | |
| 764 __ j(equal, left_false); | |
| 765 Condition is_smi = masm_->CheckSmi(rax); // All other smis are true. | |
| 766 __ j(is_smi, left_true); | |
| 767 | |
| 768 // Call the stub for all other cases. | |
| 769 __ push(rax); | |
| 770 ToBooleanStub stub; | |
| 771 __ CallStub(&stub); | |
| 772 __ testq(rax, rax); // The stub returns nonzero for true. | |
| 773 if (expr->op() == Token::OR) { | |
| 774 __ j(not_zero, &done); | |
| 775 } else { | |
| 776 __ j(zero, &done); | |
| 777 } | |
| 778 | |
| 779 __ bind(&eval_right); | |
| 780 // Discard the left-hand value if present on the stack. | |
| 781 if (context == Expression::kValue) { | |
| 782 __ addq(rsp, Immediate(kPointerSize)); | |
| 783 } | |
| 784 // Save or discard the right-hand value as needed. | |
| 785 Visit(right); | |
| 786 ASSERT_EQ(context, right->context()); | |
| 787 | |
| 788 __ bind(&done); | |
| 789 } | |
| 790 | |
| 791 | |
| 792 } } // namespace v8::internal | 877 } } // namespace v8::internal |
| OLD | NEW |