| 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 // Set the flags based on the operation, type and loop nesting level. |
| 802 // for the bitwise operations. | |
| 803 GenericBinaryFlags flags; | 804 GenericBinaryFlags flags; |
| 804 switch (op) { | 805 switch (op) { |
| 805 case Token::BIT_OR: | 806 case Token::BIT_OR: |
| 806 case Token::BIT_AND: | 807 case Token::BIT_AND: |
| 807 case Token::BIT_XOR: | 808 case Token::BIT_XOR: |
| 808 case Token::SHL: | 809 case Token::SHL: |
| 809 case Token::SHR: | 810 case Token::SHR: |
| 810 case Token::SAR: | 811 case Token::SAR: |
| 811 flags = SMI_CODE_INLINED; | 812 // Bit operations always assume they likely operate on Smis. Still only |
| 813 // generate the inline Smi check code if this operation is part of a loop. |
| 814 flags = (loop_nesting() > 0) |
| 815 ? SMI_CODE_INLINED |
| 816 : SMI_CODE_IN_STUB; |
| 812 break; | 817 break; |
| 813 | 818 |
| 814 default: | 819 default: |
| 815 flags = SMI_CODE_IN_STUB; | 820 // By default only inline the Smi check code for likely smis if this |
| 821 // operation is part of a loop. |
| 822 flags = ((loop_nesting() > 0) && type->IsLikelySmi()) |
| 823 ? SMI_CODE_INLINED |
| 824 : SMI_CODE_IN_STUB; |
| 816 break; | 825 break; |
| 817 } | 826 } |
| 818 | 827 |
| 819 if (flags == SMI_CODE_INLINED) { | 828 if (flags == SMI_CODE_INLINED) { |
| 820 // Create a new deferred code for the slow-case part. | 829 // Create a new deferred code for the slow-case part. |
| 821 DeferredInlineBinaryOperation* deferred = | 830 DeferredInlineBinaryOperation* deferred = |
| 822 new DeferredInlineBinaryOperation(this, op, overwrite_mode, flags); | 831 new DeferredInlineBinaryOperation(this, op, overwrite_mode, flags); |
| 823 // Fetch the operands from the stack. | 832 // Fetch the operands from the stack. |
| 824 frame_->Pop(ebx); // get y | 833 frame_->Pop(ebx); // get y |
| 825 __ mov(eax, frame_->Top()); // get x | 834 __ mov(eax, frame_->Top()); // get x |
| (...skipping 152 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 978 __ CallStub(&igostub); | 987 __ CallStub(&igostub); |
| 979 } | 988 } |
| 980 | 989 |
| 981 private: | 990 private: |
| 982 Register tos_reg_; | 991 Register tos_reg_; |
| 983 OverwriteMode overwrite_mode_; | 992 OverwriteMode overwrite_mode_; |
| 984 }; | 993 }; |
| 985 | 994 |
| 986 | 995 |
| 987 void CodeGenerator::SmiOperation(Token::Value op, | 996 void CodeGenerator::SmiOperation(Token::Value op, |
| 997 StaticType* type, |
| 988 Handle<Object> value, | 998 Handle<Object> value, |
| 989 bool reversed, | 999 bool reversed, |
| 990 OverwriteMode overwrite_mode) { | 1000 OverwriteMode overwrite_mode) { |
| 991 // NOTE: This is an attempt to inline (a bit) more of the code for | 1001 // 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 | 1002 // some possible smi operations (like + and -) when (at least) one |
| 993 // of the operands is a literal smi. With this optimization, the | 1003 // of the operands is a literal smi. With this optimization, the |
| 994 // performance of the system is increased by ~15%, and the generated | 1004 // performance of the system is increased by ~15%, and the generated |
| 995 // code size is increased by ~1% (measured on a combination of | 1005 // code size is increased by ~1% (measured on a combination of |
| 996 // different benchmarks). | 1006 // different benchmarks). |
| 997 | 1007 |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1039 __ bind(deferred->exit()); | 1049 __ bind(deferred->exit()); |
| 1040 frame_->Push(eax); | 1050 frame_->Push(eax); |
| 1041 break; | 1051 break; |
| 1042 } | 1052 } |
| 1043 | 1053 |
| 1044 case Token::SAR: { | 1054 case Token::SAR: { |
| 1045 if (reversed) { | 1055 if (reversed) { |
| 1046 frame_->Pop(eax); | 1056 frame_->Pop(eax); |
| 1047 frame_->Push(Immediate(value)); | 1057 frame_->Push(Immediate(value)); |
| 1048 frame_->Push(eax); | 1058 frame_->Push(eax); |
| 1049 GenericBinaryOperation(op, overwrite_mode); | 1059 GenericBinaryOperation(op, type, overwrite_mode); |
| 1050 } else { | 1060 } else { |
| 1051 int shift_value = int_value & 0x1f; // only least significant 5 bits | 1061 int shift_value = int_value & 0x1f; // only least significant 5 bits |
| 1052 DeferredCode* deferred = | 1062 DeferredCode* deferred = |
| 1053 new DeferredInlinedSmiOperation(this, Token::SAR, shift_value, | 1063 new DeferredInlinedSmiOperation(this, Token::SAR, shift_value, |
| 1054 overwrite_mode); | 1064 overwrite_mode); |
| 1055 frame_->Pop(eax); | 1065 frame_->Pop(eax); |
| 1056 __ test(eax, Immediate(kSmiTagMask)); | 1066 __ test(eax, Immediate(kSmiTagMask)); |
| 1057 __ j(not_zero, deferred->enter(), not_taken); | 1067 __ j(not_zero, deferred->enter(), not_taken); |
| 1058 __ sar(eax, shift_value); | 1068 __ sar(eax, shift_value); |
| 1059 __ and_(eax, ~kSmiTagMask); | 1069 __ and_(eax, ~kSmiTagMask); |
| 1060 __ bind(deferred->exit()); | 1070 __ bind(deferred->exit()); |
| 1061 frame_->Push(eax); | 1071 frame_->Push(eax); |
| 1062 } | 1072 } |
| 1063 break; | 1073 break; |
| 1064 } | 1074 } |
| 1065 | 1075 |
| 1066 case Token::SHR: { | 1076 case Token::SHR: { |
| 1067 if (reversed) { | 1077 if (reversed) { |
| 1068 frame_->Pop(eax); | 1078 frame_->Pop(eax); |
| 1069 frame_->Push(Immediate(value)); | 1079 frame_->Push(Immediate(value)); |
| 1070 frame_->Push(eax); | 1080 frame_->Push(eax); |
| 1071 GenericBinaryOperation(op, overwrite_mode); | 1081 GenericBinaryOperation(op, type, overwrite_mode); |
| 1072 } else { | 1082 } else { |
| 1073 int shift_value = int_value & 0x1f; // only least significant 5 bits | 1083 int shift_value = int_value & 0x1f; // only least significant 5 bits |
| 1074 DeferredCode* deferred = | 1084 DeferredCode* deferred = |
| 1075 new DeferredInlinedSmiOperation(this, Token::SHR, shift_value, | 1085 new DeferredInlinedSmiOperation(this, Token::SHR, shift_value, |
| 1076 overwrite_mode); | 1086 overwrite_mode); |
| 1077 frame_->Pop(eax); | 1087 frame_->Pop(eax); |
| 1078 __ test(eax, Immediate(kSmiTagMask)); | 1088 __ test(eax, Immediate(kSmiTagMask)); |
| 1079 __ mov(ebx, Operand(eax)); | 1089 __ mov(ebx, Operand(eax)); |
| 1080 __ j(not_zero, deferred->enter(), not_taken); | 1090 __ j(not_zero, deferred->enter(), not_taken); |
| 1081 __ sar(ebx, kSmiTagSize); | 1091 __ sar(ebx, kSmiTagSize); |
| 1082 __ shr(ebx, shift_value); | 1092 __ shr(ebx, shift_value); |
| 1083 __ test(ebx, Immediate(0xc0000000)); | 1093 __ test(ebx, Immediate(0xc0000000)); |
| 1084 __ j(not_zero, deferred->enter(), not_taken); | 1094 __ j(not_zero, deferred->enter(), not_taken); |
| 1085 // tag result and store it in TOS (eax) | 1095 // tag result and store it in TOS (eax) |
| 1086 ASSERT(kSmiTagSize == times_2); // adjust code if not the case | 1096 ASSERT(kSmiTagSize == times_2); // adjust code if not the case |
| 1087 __ lea(eax, Operand(ebx, times_2, kSmiTag)); | 1097 __ lea(eax, Operand(ebx, times_2, kSmiTag)); |
| 1088 __ bind(deferred->exit()); | 1098 __ bind(deferred->exit()); |
| 1089 frame_->Push(eax); | 1099 frame_->Push(eax); |
| 1090 } | 1100 } |
| 1091 break; | 1101 break; |
| 1092 } | 1102 } |
| 1093 | 1103 |
| 1094 case Token::SHL: { | 1104 case Token::SHL: { |
| 1095 if (reversed) { | 1105 if (reversed) { |
| 1096 frame_->Pop(eax); | 1106 frame_->Pop(eax); |
| 1097 frame_->Push(Immediate(value)); | 1107 frame_->Push(Immediate(value)); |
| 1098 frame_->Push(eax); | 1108 frame_->Push(eax); |
| 1099 GenericBinaryOperation(op, overwrite_mode); | 1109 GenericBinaryOperation(op, type, overwrite_mode); |
| 1100 } else { | 1110 } else { |
| 1101 int shift_value = int_value & 0x1f; // only least significant 5 bits | 1111 int shift_value = int_value & 0x1f; // only least significant 5 bits |
| 1102 DeferredCode* deferred = | 1112 DeferredCode* deferred = |
| 1103 new DeferredInlinedSmiOperation(this, Token::SHL, shift_value, | 1113 new DeferredInlinedSmiOperation(this, Token::SHL, shift_value, |
| 1104 overwrite_mode); | 1114 overwrite_mode); |
| 1105 frame_->Pop(eax); | 1115 frame_->Pop(eax); |
| 1106 __ test(eax, Immediate(kSmiTagMask)); | 1116 __ test(eax, Immediate(kSmiTagMask)); |
| 1107 __ mov(ebx, Operand(eax)); | 1117 __ mov(ebx, Operand(eax)); |
| 1108 __ j(not_zero, deferred->enter(), not_taken); | 1118 __ j(not_zero, deferred->enter(), not_taken); |
| 1109 __ sar(ebx, kSmiTagSize); | 1119 __ sar(ebx, kSmiTagSize); |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1148 } | 1158 } |
| 1149 | 1159 |
| 1150 default: { | 1160 default: { |
| 1151 if (!reversed) { | 1161 if (!reversed) { |
| 1152 frame_->Push(Immediate(value)); | 1162 frame_->Push(Immediate(value)); |
| 1153 } else { | 1163 } else { |
| 1154 frame_->Pop(eax); | 1164 frame_->Pop(eax); |
| 1155 frame_->Push(Immediate(value)); | 1165 frame_->Push(Immediate(value)); |
| 1156 frame_->Push(eax); | 1166 frame_->Push(eax); |
| 1157 } | 1167 } |
| 1158 GenericBinaryOperation(op, overwrite_mode); | 1168 GenericBinaryOperation(op, type, overwrite_mode); |
| 1159 break; | 1169 break; |
| 1160 } | 1170 } |
| 1161 } | 1171 } |
| 1162 } | 1172 } |
| 1163 | 1173 |
| 1164 | 1174 |
| 1165 class CompareStub: public CodeStub { | 1175 class CompareStub: public CodeStub { |
| 1166 public: | 1176 public: |
| 1167 CompareStub(Condition cc, bool strict) : cc_(cc), strict_(strict) { } | 1177 CompareStub(Condition cc, bool strict) : cc_(cc), strict_(strict) { } |
| 1168 | 1178 |
| (...skipping 571 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1740 | 1750 |
| 1741 // init | 1751 // init |
| 1742 if (node->init() != NULL) { | 1752 if (node->init() != NULL) { |
| 1743 ASSERT(node->type() == LoopStatement::FOR_LOOP); | 1753 ASSERT(node->type() == LoopStatement::FOR_LOOP); |
| 1744 Visit(node->init()); | 1754 Visit(node->init()); |
| 1745 } | 1755 } |
| 1746 if (node->type() != LoopStatement::DO_LOOP && info != ALWAYS_TRUE) { | 1756 if (node->type() != LoopStatement::DO_LOOP && info != ALWAYS_TRUE) { |
| 1747 __ jmp(&entry); | 1757 __ jmp(&entry); |
| 1748 } | 1758 } |
| 1749 | 1759 |
| 1760 IncrementLoopNesting(); |
| 1761 |
| 1750 // body | 1762 // body |
| 1751 __ bind(&loop); | 1763 __ bind(&loop); |
| 1752 CheckStack(); // TODO(1222600): ignore if body contains calls. | 1764 CheckStack(); // TODO(1222600): ignore if body contains calls. |
| 1753 Visit(node->body()); | 1765 Visit(node->body()); |
| 1754 | 1766 |
| 1755 // next | 1767 // next |
| 1756 __ bind(node->continue_target()); | 1768 __ bind(node->continue_target()); |
| 1757 if (node->next() != NULL) { | 1769 if (node->next() != NULL) { |
| 1758 // Record source position of the statement as this code which is after the | 1770 // 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 | 1771 // code for the body actually belongs to the loop statement and not the |
| (...skipping 12 matching lines...) Expand all Loading... |
| 1772 break; | 1784 break; |
| 1773 case ALWAYS_FALSE: | 1785 case ALWAYS_FALSE: |
| 1774 break; | 1786 break; |
| 1775 case DONT_KNOW: | 1787 case DONT_KNOW: |
| 1776 LoadCondition(node->cond(), NOT_INSIDE_TYPEOF, &loop, | 1788 LoadCondition(node->cond(), NOT_INSIDE_TYPEOF, &loop, |
| 1777 node->break_target(), true); | 1789 node->break_target(), true); |
| 1778 Branch(true, &loop); | 1790 Branch(true, &loop); |
| 1779 break; | 1791 break; |
| 1780 } | 1792 } |
| 1781 | 1793 |
| 1794 DecrementLoopNesting(); |
| 1795 |
| 1782 // exit | 1796 // exit |
| 1783 __ bind(node->break_target()); | 1797 __ bind(node->break_target()); |
| 1784 } | 1798 } |
| 1785 | 1799 |
| 1786 | 1800 |
| 1787 void CodeGenerator::VisitForInStatement(ForInStatement* node) { | 1801 void CodeGenerator::VisitForInStatement(ForInStatement* node) { |
| 1788 Comment cmnt(masm_, "[ ForInStatement"); | 1802 Comment cmnt(masm_, "[ ForInStatement"); |
| 1789 RecordStatementPosition(node); | 1803 RecordStatementPosition(node); |
| 1790 | 1804 |
| 1791 // We keep stuff on the stack while the body is executing. | 1805 // 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 | 2594 |
| 2581 if (node->op() == Token::ASSIGN || | 2595 if (node->op() == Token::ASSIGN || |
| 2582 node->op() == Token::INIT_VAR || | 2596 node->op() == Token::INIT_VAR || |
| 2583 node->op() == Token::INIT_CONST) { | 2597 node->op() == Token::INIT_CONST) { |
| 2584 Load(node->value()); | 2598 Load(node->value()); |
| 2585 | 2599 |
| 2586 } else { | 2600 } else { |
| 2587 target.GetValue(NOT_INSIDE_TYPEOF); | 2601 target.GetValue(NOT_INSIDE_TYPEOF); |
| 2588 Literal* literal = node->value()->AsLiteral(); | 2602 Literal* literal = node->value()->AsLiteral(); |
| 2589 if (IsInlineSmi(literal)) { | 2603 if (IsInlineSmi(literal)) { |
| 2590 SmiOperation(node->binary_op(), literal->handle(), false, NO_OVERWRITE); | 2604 SmiOperation(node->binary_op(), node->type(), literal->handle(), false, |
| 2605 NO_OVERWRITE); |
| 2591 } else { | 2606 } else { |
| 2592 Load(node->value()); | 2607 Load(node->value()); |
| 2593 GenericBinaryOperation(node->binary_op()); | 2608 GenericBinaryOperation(node->binary_op(), node->type()); |
| 2594 } | 2609 } |
| 2595 } | 2610 } |
| 2596 | 2611 |
| 2597 Variable* var = node->target()->AsVariableProxy()->AsVariable(); | 2612 Variable* var = node->target()->AsVariableProxy()->AsVariable(); |
| 2598 if (var != NULL && | 2613 if (var != NULL && |
| 2599 var->mode() == Variable::CONST && | 2614 var->mode() == Variable::CONST && |
| 2600 node->op() != Token::INIT_VAR && node->op() != Token::INIT_CONST) { | 2615 node->op() != Token::INIT_VAR && node->op() != Token::INIT_CONST) { |
| 2601 // Assignment ignored - leave the value on the stack. | 2616 // Assignment ignored - leave the value on the stack. |
| 2602 } else { | 2617 } else { |
| 2603 __ RecordPosition(node->position()); | 2618 __ RecordPosition(node->position()); |
| (...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2653 // ------------------------------------------------------------------------ | 2668 // ------------------------------------------------------------------------ |
| 2654 | 2669 |
| 2655 if (var != NULL && !var->is_this() && var->is_global()) { | 2670 if (var != NULL && !var->is_this() && var->is_global()) { |
| 2656 // ---------------------------------- | 2671 // ---------------------------------- |
| 2657 // JavaScript example: 'foo(1, 2, 3)' // foo is global | 2672 // JavaScript example: 'foo(1, 2, 3)' // foo is global |
| 2658 // ---------------------------------- | 2673 // ---------------------------------- |
| 2659 | 2674 |
| 2660 // Push the name of the function and the receiver onto the stack. | 2675 // Push the name of the function and the receiver onto the stack. |
| 2661 frame_->Push(Immediate(var->name())); | 2676 frame_->Push(Immediate(var->name())); |
| 2662 | 2677 |
| 2663 // TODO(120): Use global object for function lookup and inline | 2678 // Pass the global object as the receiver and let the IC stub |
| 2664 // cache, and use global proxy as 'this' for invocation. | 2679 // patch the stack to use the global proxy as 'this' in the |
| 2665 LoadGlobalReceiver(eax); | 2680 // invoked function. |
| 2681 LoadGlobal(); |
| 2666 | 2682 |
| 2667 // Load the arguments. | 2683 // Load the arguments. |
| 2668 for (int i = 0; i < args->length(); i++) { | 2684 for (int i = 0; i < args->length(); i++) { |
| 2669 Load(args->at(i)); | 2685 Load(args->at(i)); |
| 2670 } | 2686 } |
| 2671 | 2687 |
| 2672 // Setup the receiver register and call the IC initialization code. | 2688 // Setup the receiver register and call the IC initialization code. |
| 2673 Handle<Code> stub = ComputeCallInitialize(args->length()); | 2689 Handle<Code> stub = ComputeCallInitialize(args->length()); |
| 2674 __ RecordPosition(node->position()); | 2690 __ RecordPosition(node->position()); |
| 2675 __ call(stub, RelocInfo::CODE_TARGET_CONTEXT); | 2691 __ call(stub, RelocInfo::CODE_TARGET_CONTEXT); |
| (...skipping 166 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2842 frame_->Pop(ebx); | 2858 frame_->Pop(ebx); |
| 2843 | 2859 |
| 2844 // Check for negative or non-smi index. | 2860 // Check for negative or non-smi index. |
| 2845 ASSERT(kSmiTag == 0); | 2861 ASSERT(kSmiTag == 0); |
| 2846 __ test(ebx, Immediate(kSmiTagMask | 0x80000000)); | 2862 __ test(ebx, Immediate(kSmiTagMask | 0x80000000)); |
| 2847 __ j(not_zero, &slow_case, not_taken); | 2863 __ j(not_zero, &slow_case, not_taken); |
| 2848 // Get rid of the smi tag on the index. | 2864 // Get rid of the smi tag on the index. |
| 2849 __ sar(ebx, kSmiTagSize); | 2865 __ sar(ebx, kSmiTagSize); |
| 2850 | 2866 |
| 2851 __ bind(&try_again_with_new_string); | 2867 __ bind(&try_again_with_new_string); |
| 2852 // Get the type of the heap object into ecx. | 2868 // Get the type of the heap object into edi. |
| 2853 __ mov(edx, FieldOperand(eax, HeapObject::kMapOffset)); | 2869 __ mov(edx, FieldOperand(eax, HeapObject::kMapOffset)); |
| 2854 __ movzx_b(ecx, FieldOperand(edx, Map::kInstanceTypeOffset)); | 2870 __ movzx_b(edi, FieldOperand(edx, Map::kInstanceTypeOffset)); |
| 2855 // We don't handle non-strings. | 2871 // We don't handle non-strings. |
| 2856 __ test(ecx, Immediate(kIsNotStringMask)); | 2872 __ test(edi, Immediate(kIsNotStringMask)); |
| 2857 __ j(not_zero, &slow_case, not_taken); | 2873 __ j(not_zero, &slow_case, not_taken); |
| 2858 | 2874 |
| 2875 // Here we make assumptions about the tag values and the shifts needed. |
| 2876 // See the comment in objects.h. |
| 2877 ASSERT(kLongStringTag == 0); |
| 2878 ASSERT(kMediumStringTag + String::kLongLengthShift == |
| 2879 String::kMediumLengthShift); |
| 2880 ASSERT(kShortStringTag + String::kLongLengthShift == |
| 2881 String::kShortLengthShift); |
| 2882 __ mov(ecx, Operand(edi)); |
| 2883 __ and_(ecx, kStringSizeMask); |
| 2884 __ add(Operand(ecx), Immediate(String::kLongLengthShift)); |
| 2859 // Get the length field. | 2885 // Get the length field. |
| 2860 __ mov(edx, FieldOperand(eax, String::kLengthOffset)); | 2886 __ mov(edx, FieldOperand(eax, String::kLengthOffset)); |
| 2861 Label long_string; | 2887 __ shr(edx); // ecx is implicit operand. |
| 2862 Label medium_string; | |
| 2863 Label string_length_shifted; | |
| 2864 // The code assumes the tags are disjoint. | |
| 2865 ASSERT((kLongStringTag & kMediumStringTag) == 0); | |
| 2866 ASSERT(kShortStringTag == 0); | |
| 2867 __ test(ecx, Immediate(kLongStringTag)); | |
| 2868 __ j(not_zero, &long_string, not_taken); | |
| 2869 __ test(ecx, Immediate(kMediumStringTag)); | |
| 2870 __ j(not_zero, &medium_string, taken); | |
| 2871 // Short string. | |
| 2872 __ shr(edx, String::kShortLengthShift); | |
| 2873 __ jmp(&string_length_shifted); | |
| 2874 | |
| 2875 // Medium string. | |
| 2876 __ bind(&medium_string); | |
| 2877 __ shr(edx, String::kMediumLengthShift - String::kLongLengthShift); | |
| 2878 // Fall through to long string. | |
| 2879 __ bind(&long_string); | |
| 2880 __ shr(edx, String::kLongLengthShift); | |
| 2881 | |
| 2882 __ bind(&string_length_shifted); | |
| 2883 ASSERT(kSmiTag == 0); | |
| 2884 // edx is now the length of the string. | 2888 // edx is now the length of the string. |
| 2885 | 2889 |
| 2886 // Check for index out of range. | 2890 // Check for index out of range. |
| 2887 __ cmp(ebx, Operand(edx)); | 2891 __ cmp(ebx, Operand(edx)); |
| 2888 __ j(greater_equal, &slow_case, not_taken); | 2892 __ j(greater_equal, &slow_case, not_taken); |
| 2889 | 2893 |
| 2890 // We need special handling for non-flat strings. | 2894 // We need special handling for non-flat strings. |
| 2891 ASSERT(kSeqStringTag == 0); | 2895 ASSERT(kSeqStringTag == 0); |
| 2892 __ test(ecx, Immediate(kStringRepresentationMask)); | 2896 __ test(edi, Immediate(kStringRepresentationMask)); |
| 2893 __ j(not_zero, ¬_a_flat_string, not_taken); | 2897 __ j(not_zero, ¬_a_flat_string, not_taken); |
| 2894 | 2898 |
| 2895 // Check for 1-byte or 2-byte string. | 2899 // Check for 1-byte or 2-byte string. |
| 2896 __ test(ecx, Immediate(kStringEncodingMask)); | 2900 __ test(edi, Immediate(kStringEncodingMask)); |
| 2897 __ j(not_zero, &ascii_string, taken); | 2901 __ j(not_zero, &ascii_string, taken); |
| 2898 | 2902 |
| 2899 // 2-byte string. | 2903 // 2-byte string. |
| 2900 // Load the 2-byte character code. | 2904 // Load the 2-byte character code. |
| 2901 __ movzx_w(eax, | 2905 __ movzx_w(eax, |
| 2902 FieldOperand(eax, ebx, times_2, SeqTwoByteString::kHeaderSize)); | 2906 FieldOperand(eax, ebx, times_2, SeqTwoByteString::kHeaderSize)); |
| 2903 __ jmp(&got_char_code); | 2907 __ jmp(&got_char_code); |
| 2904 | 2908 |
| 2905 // ASCII string. | 2909 // ASCII string. |
| 2906 __ bind(&ascii_string); | 2910 __ bind(&ascii_string); |
| 2907 // Load the byte. | 2911 // Load the byte. |
| 2908 __ movzx_b(eax, FieldOperand(eax, ebx, times_1, SeqAsciiString::kHeaderSize)); | 2912 __ movzx_b(eax, FieldOperand(eax, ebx, times_1, SeqAsciiString::kHeaderSize)); |
| 2909 | 2913 |
| 2910 __ bind(&got_char_code); | 2914 __ bind(&got_char_code); |
| 2911 ASSERT(kSmiTag == 0); | 2915 ASSERT(kSmiTag == 0); |
| 2912 __ shl(eax, kSmiTagSize); | 2916 __ shl(eax, kSmiTagSize); |
| 2913 frame_->Push(eax); | 2917 frame_->Push(eax); |
| 2914 __ jmp(&end); | 2918 __ jmp(&end); |
| 2915 | 2919 |
| 2916 | |
| 2917 // Handle non-flat strings. | 2920 // Handle non-flat strings. |
| 2918 __ bind(¬_a_flat_string); | 2921 __ bind(¬_a_flat_string); |
| 2919 __ and_(ecx, kStringRepresentationMask); | 2922 __ and_(edi, kStringRepresentationMask); |
| 2920 __ cmp(ecx, kConsStringTag); | 2923 __ cmp(edi, kConsStringTag); |
| 2921 __ j(not_equal, ¬_a_cons_string_either, not_taken); | 2924 __ j(not_equal, ¬_a_cons_string_either, not_taken); |
| 2922 | 2925 |
| 2923 // ConsString. | 2926 // ConsString. |
| 2924 // Get the first of the two strings. | 2927 // Get the first of the two strings. |
| 2925 __ mov(eax, FieldOperand(eax, ConsString::kFirstOffset)); | 2928 __ mov(eax, FieldOperand(eax, ConsString::kFirstOffset)); |
| 2926 __ jmp(&try_again_with_new_string); | 2929 __ jmp(&try_again_with_new_string); |
| 2927 | 2930 |
| 2928 __ bind(¬_a_cons_string_either); | 2931 __ bind(¬_a_cons_string_either); |
| 2929 __ cmp(ecx, kSlicedStringTag); | 2932 __ cmp(edi, kSlicedStringTag); |
| 2930 __ j(not_equal, &slow_case, not_taken); | 2933 __ j(not_equal, &slow_case, not_taken); |
| 2931 | 2934 |
| 2932 // SlicedString. | 2935 // SlicedString. |
| 2933 // Add the offset to the index. | 2936 // Add the offset to the index. |
| 2934 __ add(ebx, FieldOperand(eax, SlicedString::kStartOffset)); | 2937 __ add(ebx, FieldOperand(eax, SlicedString::kStartOffset)); |
| 2935 __ j(overflow, &slow_case); | 2938 __ j(overflow, &slow_case); |
| 2936 // Get the underlying string. | 2939 // Get the underlying string. |
| 2937 __ mov(eax, FieldOperand(eax, SlicedString::kBufferOffset)); | 2940 __ mov(eax, FieldOperand(eax, SlicedString::kBufferOffset)); |
| 2938 __ jmp(&try_again_with_new_string); | 2941 __ jmp(&try_again_with_new_string); |
| 2939 | 2942 |
| (...skipping 517 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3457 overwrite_mode = OVERWRITE_RIGHT; | 3460 overwrite_mode = OVERWRITE_RIGHT; |
| 3458 } | 3461 } |
| 3459 | 3462 |
| 3460 // Optimize for the case where (at least) one of the expressions | 3463 // Optimize for the case where (at least) one of the expressions |
| 3461 // is a literal small integer. | 3464 // is a literal small integer. |
| 3462 Literal* lliteral = node->left()->AsLiteral(); | 3465 Literal* lliteral = node->left()->AsLiteral(); |
| 3463 Literal* rliteral = node->right()->AsLiteral(); | 3466 Literal* rliteral = node->right()->AsLiteral(); |
| 3464 | 3467 |
| 3465 if (IsInlineSmi(rliteral)) { | 3468 if (IsInlineSmi(rliteral)) { |
| 3466 Load(node->left()); | 3469 Load(node->left()); |
| 3467 SmiOperation(node->op(), rliteral->handle(), false, overwrite_mode); | 3470 SmiOperation(node->op(), node->type(), rliteral->handle(), false, |
| 3468 | 3471 overwrite_mode); |
| 3469 } else if (IsInlineSmi(lliteral)) { | 3472 } else if (IsInlineSmi(lliteral)) { |
| 3470 Load(node->right()); | 3473 Load(node->right()); |
| 3471 SmiOperation(node->op(), lliteral->handle(), true, overwrite_mode); | 3474 SmiOperation(node->op(), node->type(), lliteral->handle(), true, |
| 3472 | 3475 overwrite_mode); |
| 3473 } else { | 3476 } else { |
| 3474 Load(node->left()); | 3477 Load(node->left()); |
| 3475 Load(node->right()); | 3478 Load(node->right()); |
| 3476 GenericBinaryOperation(node->op(), overwrite_mode); | 3479 GenericBinaryOperation(node->op(), node->type(), overwrite_mode); |
| 3477 } | 3480 } |
| 3478 } | 3481 } |
| 3479 } | 3482 } |
| 3480 | 3483 |
| 3481 | 3484 |
| 3482 void CodeGenerator::VisitThisFunction(ThisFunction* node) { | 3485 void CodeGenerator::VisitThisFunction(ThisFunction* node) { |
| 3483 frame_->Push(frame_->Function()); | 3486 frame_->Push(frame_->Function()); |
| 3484 } | 3487 } |
| 3485 | 3488 |
| 3486 | 3489 |
| (...skipping 1457 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4944 // eax: result parameter for PerformGC, if any (setup below) | 4947 // eax: result parameter for PerformGC, if any (setup below) |
| 4945 // ebx: pointer to builtin function (C callee-saved) | 4948 // ebx: pointer to builtin function (C callee-saved) |
| 4946 // ebp: frame pointer (restored after C call) | 4949 // ebp: frame pointer (restored after C call) |
| 4947 // esp: stack pointer (restored after C call) | 4950 // esp: stack pointer (restored after C call) |
| 4948 // edi: number of arguments including receiver (C callee-saved) | 4951 // edi: number of arguments including receiver (C callee-saved) |
| 4949 // esi: argv pointer (C callee-saved) | 4952 // esi: argv pointer (C callee-saved) |
| 4950 | 4953 |
| 4951 Label throw_out_of_memory_exception; | 4954 Label throw_out_of_memory_exception; |
| 4952 Label throw_normal_exception; | 4955 Label throw_normal_exception; |
| 4953 | 4956 |
| 4954 #ifdef DEBUG | 4957 // Call into the runtime system. Collect garbage before the call if |
| 4958 // running with --gc-greedy set. |
| 4955 if (FLAG_gc_greedy) { | 4959 if (FLAG_gc_greedy) { |
| 4956 Failure* failure = Failure::RetryAfterGC(0); | 4960 Failure* failure = Failure::RetryAfterGC(0); |
| 4957 __ mov(Operand(eax), Immediate(reinterpret_cast<int32_t>(failure))); | 4961 __ mov(Operand(eax), Immediate(reinterpret_cast<int32_t>(failure))); |
| 4958 } | 4962 } |
| 4959 GenerateCore(masm, &throw_normal_exception, | 4963 GenerateCore(masm, &throw_normal_exception, |
| 4960 &throw_out_of_memory_exception, | 4964 &throw_out_of_memory_exception, |
| 4961 frame_type, | 4965 frame_type, |
| 4962 FLAG_gc_greedy); | 4966 FLAG_gc_greedy); |
| 4963 #else | 4967 |
| 4968 // Do space-specific GC and retry runtime call. |
| 4964 GenerateCore(masm, | 4969 GenerateCore(masm, |
| 4965 &throw_normal_exception, | 4970 &throw_normal_exception, |
| 4966 &throw_out_of_memory_exception, | 4971 &throw_out_of_memory_exception, |
| 4967 frame_type, | 4972 frame_type, |
| 4968 false); | 4973 true); |
| 4969 #endif | |
| 4970 | 4974 |
| 4975 // Do full GC and retry runtime call one final time. |
| 4976 Failure* failure = Failure::InternalError(); |
| 4977 __ mov(Operand(eax), Immediate(reinterpret_cast<int32_t>(failure))); |
| 4971 GenerateCore(masm, | 4978 GenerateCore(masm, |
| 4972 &throw_normal_exception, | 4979 &throw_normal_exception, |
| 4973 &throw_out_of_memory_exception, | 4980 &throw_out_of_memory_exception, |
| 4974 frame_type, | 4981 frame_type, |
| 4975 true); | 4982 true); |
| 4976 | 4983 |
| 4977 __ bind(&throw_out_of_memory_exception); | 4984 __ bind(&throw_out_of_memory_exception); |
| 4978 GenerateThrowOutOfMemory(masm); | 4985 GenerateThrowOutOfMemory(masm); |
| 4979 // control flow for generated will not return. | 4986 // control flow for generated will not return. |
| 4980 | 4987 |
| (...skipping 132 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5113 | 5120 |
| 5114 // Slow-case: Go through the JavaScript implementation. | 5121 // Slow-case: Go through the JavaScript implementation. |
| 5115 __ bind(&slow); | 5122 __ bind(&slow); |
| 5116 __ InvokeBuiltin(Builtins::INSTANCE_OF, JUMP_FUNCTION); | 5123 __ InvokeBuiltin(Builtins::INSTANCE_OF, JUMP_FUNCTION); |
| 5117 } | 5124 } |
| 5118 | 5125 |
| 5119 | 5126 |
| 5120 #undef __ | 5127 #undef __ |
| 5121 | 5128 |
| 5122 } } // namespace v8::internal | 5129 } } // namespace v8::internal |
| OLD | NEW |