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 |