OLD | NEW |
1 // Copyright 2006-2008 the V8 project authors. All rights reserved. | 1 // Copyright 2006-2008 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 157 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
168 bool is_eval) | 168 bool is_eval) |
169 : is_eval_(is_eval), | 169 : is_eval_(is_eval), |
170 script_(script), | 170 script_(script), |
171 deferred_(8), | 171 deferred_(8), |
172 masm_(new MacroAssembler(NULL, buffer_size)), | 172 masm_(new MacroAssembler(NULL, buffer_size)), |
173 scope_(NULL), | 173 scope_(NULL), |
174 frame_(NULL), | 174 frame_(NULL), |
175 cc_reg_(no_condition), | 175 cc_reg_(no_condition), |
176 state_(NULL), | 176 state_(NULL), |
177 is_inside_try_(false), | 177 is_inside_try_(false), |
178 break_stack_height_(0) { | 178 break_stack_height_(0), |
| 179 loop_nesting_(0) { |
179 } | 180 } |
180 | 181 |
181 | 182 |
182 // Calling conventions: | 183 // Calling conventions: |
183 // ebp: frame pointer | 184 // ebp: frame pointer |
184 // esp: stack pointer | 185 // esp: stack pointer |
185 // edi: caller's parameter pointer | 186 // edi: caller's parameter pointer |
186 // esi: callee's context | 187 // esi: callee's context |
187 | 188 |
188 void CodeGenerator::GenCode(FunctionLiteral* fun) { | 189 void CodeGenerator::GenCode(FunctionLiteral* fun) { |
(...skipping 590 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
779 // deferred->exit() is bound. | 780 // deferred->exit() is bound. |
780 __ push(eax); | 781 __ push(eax); |
781 } | 782 } |
782 | 783 |
783 private: | 784 private: |
784 GenericBinaryOpStub stub_; | 785 GenericBinaryOpStub stub_; |
785 }; | 786 }; |
786 | 787 |
787 | 788 |
788 void CodeGenerator::GenericBinaryOperation(Token::Value op, | 789 void CodeGenerator::GenericBinaryOperation(Token::Value op, |
| 790 StaticType* type, |
789 OverwriteMode overwrite_mode) { | 791 OverwriteMode overwrite_mode) { |
790 Comment cmnt(masm_, "[ BinaryOperation"); | 792 Comment cmnt(masm_, "[ BinaryOperation"); |
791 Comment cmnt_token(masm_, Token::String(op)); | 793 Comment cmnt_token(masm_, Token::String(op)); |
792 | 794 |
793 if (op == Token::COMMA) { | 795 if (op == Token::COMMA) { |
794 // Simply discard left value. | 796 // Simply discard left value. |
795 frame_->Pop(eax); | 797 frame_->Pop(eax); |
796 frame_->Pop(); | 798 frame_->Pop(); |
797 frame_->Push(eax); | 799 frame_->Push(eax); |
798 return; | 800 return; |
799 } | 801 } |
800 | 802 |
801 // For now, we keep the old behavior and only inline the smi code | 803 // For now, we keep the old behavior and only inline the smi code |
802 // for the bitwise operations. | 804 // for the bitwise operations. |
803 GenericBinaryFlags flags; | 805 GenericBinaryFlags flags; |
804 switch (op) { | 806 switch (op) { |
805 case Token::BIT_OR: | 807 case Token::BIT_OR: |
806 case Token::BIT_AND: | 808 case Token::BIT_AND: |
807 case Token::BIT_XOR: | 809 case Token::BIT_XOR: |
808 case Token::SHL: | 810 case Token::SHL: |
809 case Token::SHR: | 811 case Token::SHR: |
810 case Token::SAR: | 812 case Token::SAR: |
811 flags = SMI_CODE_INLINED; | 813 // Bit operations always assume they likely operate on Smis. Still only |
| 814 // generate the inline Smi check code if this operation is part of a loop. |
| 815 flags = (loop_nesting() > 0) |
| 816 ? SMI_CODE_INLINED |
| 817 : SMI_CODE_IN_STUB; |
812 break; | 818 break; |
813 | 819 |
814 default: | 820 default: |
815 flags = SMI_CODE_IN_STUB; | 821 // By default only inline the Smi check code for likely smis if this |
| 822 // operation is part of a loop. |
| 823 flags = ((loop_nesting() > 0) && type->IsLikelySmi()) |
| 824 ? SMI_CODE_INLINED |
| 825 : SMI_CODE_IN_STUB; |
816 break; | 826 break; |
817 } | 827 } |
818 | 828 |
819 if (flags == SMI_CODE_INLINED) { | 829 if (flags == SMI_CODE_INLINED) { |
820 // Create a new deferred code for the slow-case part. | 830 // Create a new deferred code for the slow-case part. |
821 DeferredInlineBinaryOperation* deferred = | 831 DeferredInlineBinaryOperation* deferred = |
822 new DeferredInlineBinaryOperation(this, op, overwrite_mode, flags); | 832 new DeferredInlineBinaryOperation(this, op, overwrite_mode, flags); |
823 // Fetch the operands from the stack. | 833 // Fetch the operands from the stack. |
824 frame_->Pop(ebx); // get y | 834 frame_->Pop(ebx); // get y |
825 __ mov(eax, frame_->Top()); // get x | 835 __ mov(eax, frame_->Top()); // get x |
(...skipping 152 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
978 __ CallStub(&igostub); | 988 __ CallStub(&igostub); |
979 } | 989 } |
980 | 990 |
981 private: | 991 private: |
982 Register tos_reg_; | 992 Register tos_reg_; |
983 OverwriteMode overwrite_mode_; | 993 OverwriteMode overwrite_mode_; |
984 }; | 994 }; |
985 | 995 |
986 | 996 |
987 void CodeGenerator::SmiOperation(Token::Value op, | 997 void CodeGenerator::SmiOperation(Token::Value op, |
| 998 StaticType* type, |
988 Handle<Object> value, | 999 Handle<Object> value, |
989 bool reversed, | 1000 bool reversed, |
990 OverwriteMode overwrite_mode) { | 1001 OverwriteMode overwrite_mode) { |
991 // NOTE: This is an attempt to inline (a bit) more of the code for | 1002 // NOTE: This is an attempt to inline (a bit) more of the code for |
992 // some possible smi operations (like + and -) when (at least) one | 1003 // some possible smi operations (like + and -) when (at least) one |
993 // of the operands is a literal smi. With this optimization, the | 1004 // of the operands is a literal smi. With this optimization, the |
994 // performance of the system is increased by ~15%, and the generated | 1005 // performance of the system is increased by ~15%, and the generated |
995 // code size is increased by ~1% (measured on a combination of | 1006 // code size is increased by ~1% (measured on a combination of |
996 // different benchmarks). | 1007 // different benchmarks). |
997 | 1008 |
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1039 __ bind(deferred->exit()); | 1050 __ bind(deferred->exit()); |
1040 frame_->Push(eax); | 1051 frame_->Push(eax); |
1041 break; | 1052 break; |
1042 } | 1053 } |
1043 | 1054 |
1044 case Token::SAR: { | 1055 case Token::SAR: { |
1045 if (reversed) { | 1056 if (reversed) { |
1046 frame_->Pop(eax); | 1057 frame_->Pop(eax); |
1047 frame_->Push(Immediate(value)); | 1058 frame_->Push(Immediate(value)); |
1048 frame_->Push(eax); | 1059 frame_->Push(eax); |
1049 GenericBinaryOperation(op, overwrite_mode); | 1060 GenericBinaryOperation(op, type, overwrite_mode); |
1050 } else { | 1061 } else { |
1051 int shift_value = int_value & 0x1f; // only least significant 5 bits | 1062 int shift_value = int_value & 0x1f; // only least significant 5 bits |
1052 DeferredCode* deferred = | 1063 DeferredCode* deferred = |
1053 new DeferredInlinedSmiOperation(this, Token::SAR, shift_value, | 1064 new DeferredInlinedSmiOperation(this, Token::SAR, shift_value, |
1054 overwrite_mode); | 1065 overwrite_mode); |
1055 frame_->Pop(eax); | 1066 frame_->Pop(eax); |
1056 __ test(eax, Immediate(kSmiTagMask)); | 1067 __ test(eax, Immediate(kSmiTagMask)); |
1057 __ j(not_zero, deferred->enter(), not_taken); | 1068 __ j(not_zero, deferred->enter(), not_taken); |
1058 __ sar(eax, shift_value); | 1069 __ sar(eax, shift_value); |
1059 __ and_(eax, ~kSmiTagMask); | 1070 __ and_(eax, ~kSmiTagMask); |
1060 __ bind(deferred->exit()); | 1071 __ bind(deferred->exit()); |
1061 frame_->Push(eax); | 1072 frame_->Push(eax); |
1062 } | 1073 } |
1063 break; | 1074 break; |
1064 } | 1075 } |
1065 | 1076 |
1066 case Token::SHR: { | 1077 case Token::SHR: { |
1067 if (reversed) { | 1078 if (reversed) { |
1068 frame_->Pop(eax); | 1079 frame_->Pop(eax); |
1069 frame_->Push(Immediate(value)); | 1080 frame_->Push(Immediate(value)); |
1070 frame_->Push(eax); | 1081 frame_->Push(eax); |
1071 GenericBinaryOperation(op, overwrite_mode); | 1082 GenericBinaryOperation(op, type, overwrite_mode); |
1072 } else { | 1083 } else { |
1073 int shift_value = int_value & 0x1f; // only least significant 5 bits | 1084 int shift_value = int_value & 0x1f; // only least significant 5 bits |
1074 DeferredCode* deferred = | 1085 DeferredCode* deferred = |
1075 new DeferredInlinedSmiOperation(this, Token::SHR, shift_value, | 1086 new DeferredInlinedSmiOperation(this, Token::SHR, shift_value, |
1076 overwrite_mode); | 1087 overwrite_mode); |
1077 frame_->Pop(eax); | 1088 frame_->Pop(eax); |
1078 __ test(eax, Immediate(kSmiTagMask)); | 1089 __ test(eax, Immediate(kSmiTagMask)); |
1079 __ mov(ebx, Operand(eax)); | 1090 __ mov(ebx, Operand(eax)); |
1080 __ j(not_zero, deferred->enter(), not_taken); | 1091 __ j(not_zero, deferred->enter(), not_taken); |
1081 __ sar(ebx, kSmiTagSize); | 1092 __ sar(ebx, kSmiTagSize); |
1082 __ shr(ebx, shift_value); | 1093 __ shr(ebx, shift_value); |
1083 __ test(ebx, Immediate(0xc0000000)); | 1094 __ test(ebx, Immediate(0xc0000000)); |
1084 __ j(not_zero, deferred->enter(), not_taken); | 1095 __ j(not_zero, deferred->enter(), not_taken); |
1085 // tag result and store it in TOS (eax) | 1096 // tag result and store it in TOS (eax) |
1086 ASSERT(kSmiTagSize == times_2); // adjust code if not the case | 1097 ASSERT(kSmiTagSize == times_2); // adjust code if not the case |
1087 __ lea(eax, Operand(ebx, times_2, kSmiTag)); | 1098 __ lea(eax, Operand(ebx, times_2, kSmiTag)); |
1088 __ bind(deferred->exit()); | 1099 __ bind(deferred->exit()); |
1089 frame_->Push(eax); | 1100 frame_->Push(eax); |
1090 } | 1101 } |
1091 break; | 1102 break; |
1092 } | 1103 } |
1093 | 1104 |
1094 case Token::SHL: { | 1105 case Token::SHL: { |
1095 if (reversed) { | 1106 if (reversed) { |
1096 frame_->Pop(eax); | 1107 frame_->Pop(eax); |
1097 frame_->Push(Immediate(value)); | 1108 frame_->Push(Immediate(value)); |
1098 frame_->Push(eax); | 1109 frame_->Push(eax); |
1099 GenericBinaryOperation(op, overwrite_mode); | 1110 GenericBinaryOperation(op, type, overwrite_mode); |
1100 } else { | 1111 } else { |
1101 int shift_value = int_value & 0x1f; // only least significant 5 bits | 1112 int shift_value = int_value & 0x1f; // only least significant 5 bits |
1102 DeferredCode* deferred = | 1113 DeferredCode* deferred = |
1103 new DeferredInlinedSmiOperation(this, Token::SHL, shift_value, | 1114 new DeferredInlinedSmiOperation(this, Token::SHL, shift_value, |
1104 overwrite_mode); | 1115 overwrite_mode); |
1105 frame_->Pop(eax); | 1116 frame_->Pop(eax); |
1106 __ test(eax, Immediate(kSmiTagMask)); | 1117 __ test(eax, Immediate(kSmiTagMask)); |
1107 __ mov(ebx, Operand(eax)); | 1118 __ mov(ebx, Operand(eax)); |
1108 __ j(not_zero, deferred->enter(), not_taken); | 1119 __ j(not_zero, deferred->enter(), not_taken); |
1109 __ sar(ebx, kSmiTagSize); | 1120 __ sar(ebx, kSmiTagSize); |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1148 } | 1159 } |
1149 | 1160 |
1150 default: { | 1161 default: { |
1151 if (!reversed) { | 1162 if (!reversed) { |
1152 frame_->Push(Immediate(value)); | 1163 frame_->Push(Immediate(value)); |
1153 } else { | 1164 } else { |
1154 frame_->Pop(eax); | 1165 frame_->Pop(eax); |
1155 frame_->Push(Immediate(value)); | 1166 frame_->Push(Immediate(value)); |
1156 frame_->Push(eax); | 1167 frame_->Push(eax); |
1157 } | 1168 } |
1158 GenericBinaryOperation(op, overwrite_mode); | 1169 GenericBinaryOperation(op, type, overwrite_mode); |
1159 break; | 1170 break; |
1160 } | 1171 } |
1161 } | 1172 } |
1162 } | 1173 } |
1163 | 1174 |
1164 | 1175 |
1165 class CompareStub: public CodeStub { | 1176 class CompareStub: public CodeStub { |
1166 public: | 1177 public: |
1167 CompareStub(Condition cc, bool strict) : cc_(cc), strict_(strict) { } | 1178 CompareStub(Condition cc, bool strict) : cc_(cc), strict_(strict) { } |
1168 | 1179 |
(...skipping 571 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1740 | 1751 |
1741 // init | 1752 // init |
1742 if (node->init() != NULL) { | 1753 if (node->init() != NULL) { |
1743 ASSERT(node->type() == LoopStatement::FOR_LOOP); | 1754 ASSERT(node->type() == LoopStatement::FOR_LOOP); |
1744 Visit(node->init()); | 1755 Visit(node->init()); |
1745 } | 1756 } |
1746 if (node->type() != LoopStatement::DO_LOOP && info != ALWAYS_TRUE) { | 1757 if (node->type() != LoopStatement::DO_LOOP && info != ALWAYS_TRUE) { |
1747 __ jmp(&entry); | 1758 __ jmp(&entry); |
1748 } | 1759 } |
1749 | 1760 |
| 1761 IncrementLoopNesting(); |
| 1762 |
1750 // body | 1763 // body |
1751 __ bind(&loop); | 1764 __ bind(&loop); |
1752 CheckStack(); // TODO(1222600): ignore if body contains calls. | 1765 CheckStack(); // TODO(1222600): ignore if body contains calls. |
1753 Visit(node->body()); | 1766 Visit(node->body()); |
1754 | 1767 |
1755 // next | 1768 // next |
1756 __ bind(node->continue_target()); | 1769 __ bind(node->continue_target()); |
1757 if (node->next() != NULL) { | 1770 if (node->next() != NULL) { |
1758 // Record source position of the statement as this code which is after the | 1771 // Record source position of the statement as this code which is after the |
1759 // code for the body actually belongs to the loop statement and not the | 1772 // code for the body actually belongs to the loop statement and not the |
(...skipping 12 matching lines...) Expand all Loading... |
1772 break; | 1785 break; |
1773 case ALWAYS_FALSE: | 1786 case ALWAYS_FALSE: |
1774 break; | 1787 break; |
1775 case DONT_KNOW: | 1788 case DONT_KNOW: |
1776 LoadCondition(node->cond(), NOT_INSIDE_TYPEOF, &loop, | 1789 LoadCondition(node->cond(), NOT_INSIDE_TYPEOF, &loop, |
1777 node->break_target(), true); | 1790 node->break_target(), true); |
1778 Branch(true, &loop); | 1791 Branch(true, &loop); |
1779 break; | 1792 break; |
1780 } | 1793 } |
1781 | 1794 |
| 1795 DecrementLoopNesting(); |
| 1796 |
1782 // exit | 1797 // exit |
1783 __ bind(node->break_target()); | 1798 __ bind(node->break_target()); |
1784 } | 1799 } |
1785 | 1800 |
1786 | 1801 |
1787 void CodeGenerator::VisitForInStatement(ForInStatement* node) { | 1802 void CodeGenerator::VisitForInStatement(ForInStatement* node) { |
1788 Comment cmnt(masm_, "[ ForInStatement"); | 1803 Comment cmnt(masm_, "[ ForInStatement"); |
1789 RecordStatementPosition(node); | 1804 RecordStatementPosition(node); |
1790 | 1805 |
1791 // We keep stuff on the stack while the body is executing. | 1806 // We keep stuff on the stack while the body is executing. |
(...skipping 788 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2580 | 2595 |
2581 if (node->op() == Token::ASSIGN || | 2596 if (node->op() == Token::ASSIGN || |
2582 node->op() == Token::INIT_VAR || | 2597 node->op() == Token::INIT_VAR || |
2583 node->op() == Token::INIT_CONST) { | 2598 node->op() == Token::INIT_CONST) { |
2584 Load(node->value()); | 2599 Load(node->value()); |
2585 | 2600 |
2586 } else { | 2601 } else { |
2587 target.GetValue(NOT_INSIDE_TYPEOF); | 2602 target.GetValue(NOT_INSIDE_TYPEOF); |
2588 Literal* literal = node->value()->AsLiteral(); | 2603 Literal* literal = node->value()->AsLiteral(); |
2589 if (IsInlineSmi(literal)) { | 2604 if (IsInlineSmi(literal)) { |
2590 SmiOperation(node->binary_op(), literal->handle(), false, NO_OVERWRITE); | 2605 SmiOperation(node->binary_op(), node->type(), literal->handle(), false, |
| 2606 NO_OVERWRITE); |
2591 } else { | 2607 } else { |
2592 Load(node->value()); | 2608 Load(node->value()); |
2593 GenericBinaryOperation(node->binary_op()); | 2609 GenericBinaryOperation(node->binary_op(), node->type()); |
2594 } | 2610 } |
2595 } | 2611 } |
2596 | 2612 |
2597 Variable* var = node->target()->AsVariableProxy()->AsVariable(); | 2613 Variable* var = node->target()->AsVariableProxy()->AsVariable(); |
2598 if (var != NULL && | 2614 if (var != NULL && |
2599 var->mode() == Variable::CONST && | 2615 var->mode() == Variable::CONST && |
2600 node->op() != Token::INIT_VAR && node->op() != Token::INIT_CONST) { | 2616 node->op() != Token::INIT_VAR && node->op() != Token::INIT_CONST) { |
2601 // Assignment ignored - leave the value on the stack. | 2617 // Assignment ignored - leave the value on the stack. |
2602 } else { | 2618 } else { |
2603 __ RecordPosition(node->position()); | 2619 __ RecordPosition(node->position()); |
(...skipping 841 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3445 overwrite_mode = OVERWRITE_RIGHT; | 3461 overwrite_mode = OVERWRITE_RIGHT; |
3446 } | 3462 } |
3447 | 3463 |
3448 // Optimize for the case where (at least) one of the expressions | 3464 // Optimize for the case where (at least) one of the expressions |
3449 // is a literal small integer. | 3465 // is a literal small integer. |
3450 Literal* lliteral = node->left()->AsLiteral(); | 3466 Literal* lliteral = node->left()->AsLiteral(); |
3451 Literal* rliteral = node->right()->AsLiteral(); | 3467 Literal* rliteral = node->right()->AsLiteral(); |
3452 | 3468 |
3453 if (IsInlineSmi(rliteral)) { | 3469 if (IsInlineSmi(rliteral)) { |
3454 Load(node->left()); | 3470 Load(node->left()); |
3455 SmiOperation(node->op(), rliteral->handle(), false, overwrite_mode); | 3471 SmiOperation(node->op(), node->type(), rliteral->handle(), false, |
3456 | 3472 overwrite_mode); |
3457 } else if (IsInlineSmi(lliteral)) { | 3473 } else if (IsInlineSmi(lliteral)) { |
3458 Load(node->right()); | 3474 Load(node->right()); |
3459 SmiOperation(node->op(), lliteral->handle(), true, overwrite_mode); | 3475 SmiOperation(node->op(), node->type(), lliteral->handle(), true, |
3460 | 3476 overwrite_mode); |
3461 } else { | 3477 } else { |
3462 Load(node->left()); | 3478 Load(node->left()); |
3463 Load(node->right()); | 3479 Load(node->right()); |
3464 GenericBinaryOperation(node->op(), overwrite_mode); | 3480 GenericBinaryOperation(node->op(), node->type(), overwrite_mode); |
3465 } | 3481 } |
3466 } | 3482 } |
3467 } | 3483 } |
3468 | 3484 |
3469 | 3485 |
3470 void CodeGenerator::VisitThisFunction(ThisFunction* node) { | 3486 void CodeGenerator::VisitThisFunction(ThisFunction* node) { |
3471 frame_->Push(frame_->Function()); | 3487 frame_->Push(frame_->Function()); |
3472 } | 3488 } |
3473 | 3489 |
3474 | 3490 |
(...skipping 1626 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5101 | 5117 |
5102 // Slow-case: Go through the JavaScript implementation. | 5118 // Slow-case: Go through the JavaScript implementation. |
5103 __ bind(&slow); | 5119 __ bind(&slow); |
5104 __ InvokeBuiltin(Builtins::INSTANCE_OF, JUMP_FUNCTION); | 5120 __ InvokeBuiltin(Builtins::INSTANCE_OF, JUMP_FUNCTION); |
5105 } | 5121 } |
5106 | 5122 |
5107 | 5123 |
5108 #undef __ | 5124 #undef __ |
5109 | 5125 |
5110 } } // namespace v8::internal | 5126 } } // namespace v8::internal |
OLD | NEW |