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 |