| OLD | NEW |
| 1 // Copyright 2010 the V8 project authors. All rights reserved. | 1 // Copyright 2010 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 144 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 155 // Visit all the explicit declarations unless there is an illegal | 155 // Visit all the explicit declarations unless there is an illegal |
| 156 // redeclaration. | 156 // redeclaration. |
| 157 if (scope()->HasIllegalRedeclaration()) { | 157 if (scope()->HasIllegalRedeclaration()) { |
| 158 scope()->VisitIllegalRedeclaration(this); | 158 scope()->VisitIllegalRedeclaration(this); |
| 159 } else { | 159 } else { |
| 160 VisitDeclarations(scope()->declarations()); | 160 VisitDeclarations(scope()->declarations()); |
| 161 } | 161 } |
| 162 } | 162 } |
| 163 | 163 |
| 164 { Comment cmnt(masm_, "[ Stack check"); | 164 { Comment cmnt(masm_, "[ Stack check"); |
| 165 Label ok; | 165 NearLabel ok; |
| 166 ExternalReference stack_limit = | 166 ExternalReference stack_limit = |
| 167 ExternalReference::address_of_stack_limit(); | 167 ExternalReference::address_of_stack_limit(); |
| 168 __ cmp(esp, Operand::StaticVariable(stack_limit)); | 168 __ cmp(esp, Operand::StaticVariable(stack_limit)); |
| 169 __ j(above_equal, &ok, taken); | 169 __ j(above_equal, &ok, taken); |
| 170 StackCheckStub stub; | 170 StackCheckStub stub; |
| 171 __ CallStub(&stub); | 171 __ CallStub(&stub); |
| 172 __ bind(&ok); | 172 __ bind(&ok); |
| 173 } | 173 } |
| 174 | 174 |
| 175 if (FLAG_trace) { | 175 if (FLAG_trace) { |
| (...skipping 220 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 396 Label* materialize_false) { | 396 Label* materialize_false) { |
| 397 switch (context) { | 397 switch (context) { |
| 398 case Expression::kUninitialized: | 398 case Expression::kUninitialized: |
| 399 | 399 |
| 400 case Expression::kEffect: | 400 case Expression::kEffect: |
| 401 ASSERT_EQ(materialize_true, materialize_false); | 401 ASSERT_EQ(materialize_true, materialize_false); |
| 402 __ bind(materialize_true); | 402 __ bind(materialize_true); |
| 403 break; | 403 break; |
| 404 | 404 |
| 405 case Expression::kValue: { | 405 case Expression::kValue: { |
| 406 Label done; | 406 NearLabel done; |
| 407 switch (location_) { | 407 switch (location_) { |
| 408 case kAccumulator: | 408 case kAccumulator: |
| 409 __ bind(materialize_true); | 409 __ bind(materialize_true); |
| 410 __ mov(result_register(), Factory::true_value()); | 410 __ mov(result_register(), Factory::true_value()); |
| 411 __ jmp(&done); | 411 __ jmp(&done); |
| 412 __ bind(materialize_false); | 412 __ bind(materialize_false); |
| 413 __ mov(result_register(), Factory::false_value()); | 413 __ mov(result_register(), Factory::false_value()); |
| 414 break; | 414 break; |
| 415 case kStack: | 415 case kStack: |
| 416 __ bind(materialize_true); | 416 __ bind(materialize_true); |
| (...skipping 261 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 678 Comment cmnt(masm_, "[ Case comparison"); | 678 Comment cmnt(masm_, "[ Case comparison"); |
| 679 __ bind(&next_test); | 679 __ bind(&next_test); |
| 680 next_test.Unuse(); | 680 next_test.Unuse(); |
| 681 | 681 |
| 682 // Compile the label expression. | 682 // Compile the label expression. |
| 683 VisitForValue(clause->label(), kAccumulator); | 683 VisitForValue(clause->label(), kAccumulator); |
| 684 | 684 |
| 685 // Perform the comparison as if via '==='. | 685 // Perform the comparison as if via '==='. |
| 686 __ mov(edx, Operand(esp, 0)); // Switch value. | 686 __ mov(edx, Operand(esp, 0)); // Switch value. |
| 687 if (ShouldInlineSmiCase(Token::EQ_STRICT)) { | 687 if (ShouldInlineSmiCase(Token::EQ_STRICT)) { |
| 688 Label slow_case; | 688 NearLabel slow_case; |
| 689 __ mov(ecx, edx); | 689 __ mov(ecx, edx); |
| 690 __ or_(ecx, Operand(eax)); | 690 __ or_(ecx, Operand(eax)); |
| 691 __ test(ecx, Immediate(kSmiTagMask)); | 691 __ test(ecx, Immediate(kSmiTagMask)); |
| 692 __ j(not_zero, &slow_case, not_taken); | 692 __ j(not_zero, &slow_case, not_taken); |
| 693 __ cmp(edx, Operand(eax)); | 693 __ cmp(edx, Operand(eax)); |
| 694 __ j(not_equal, &next_test); | 694 __ j(not_equal, &next_test); |
| 695 __ Drop(1); // Switch value is no longer needed. | 695 __ Drop(1); // Switch value is no longer needed. |
| 696 __ jmp(clause->body_target()->entry_label()); | 696 __ jmp(clause->body_target()->entry_label()); |
| 697 __ bind(&slow_case); | 697 __ bind(&slow_case); |
| 698 } | 698 } |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 738 // Get the object to enumerate over. Both SpiderMonkey and JSC | 738 // Get the object to enumerate over. Both SpiderMonkey and JSC |
| 739 // ignore null and undefined in contrast to the specification; see | 739 // ignore null and undefined in contrast to the specification; see |
| 740 // ECMA-262 section 12.6.4. | 740 // ECMA-262 section 12.6.4. |
| 741 VisitForValue(stmt->enumerable(), kAccumulator); | 741 VisitForValue(stmt->enumerable(), kAccumulator); |
| 742 __ cmp(eax, Factory::undefined_value()); | 742 __ cmp(eax, Factory::undefined_value()); |
| 743 __ j(equal, &exit); | 743 __ j(equal, &exit); |
| 744 __ cmp(eax, Factory::null_value()); | 744 __ cmp(eax, Factory::null_value()); |
| 745 __ j(equal, &exit); | 745 __ j(equal, &exit); |
| 746 | 746 |
| 747 // Convert the object to a JS object. | 747 // Convert the object to a JS object. |
| 748 Label convert, done_convert; | 748 NearLabel convert, done_convert; |
| 749 __ test(eax, Immediate(kSmiTagMask)); | 749 __ test(eax, Immediate(kSmiTagMask)); |
| 750 __ j(zero, &convert); | 750 __ j(zero, &convert); |
| 751 __ CmpObjectType(eax, FIRST_JS_OBJECT_TYPE, ecx); | 751 __ CmpObjectType(eax, FIRST_JS_OBJECT_TYPE, ecx); |
| 752 __ j(above_equal, &done_convert); | 752 __ j(above_equal, &done_convert); |
| 753 __ bind(&convert); | 753 __ bind(&convert); |
| 754 __ push(eax); | 754 __ push(eax); |
| 755 __ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION); | 755 __ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION); |
| 756 __ bind(&done_convert); | 756 __ bind(&done_convert); |
| 757 __ push(eax); | 757 __ push(eax); |
| 758 | 758 |
| (...skipping 20 matching lines...) Expand all Loading... |
| 779 __ j(equal, &call_runtime); | 779 __ j(equal, &call_runtime); |
| 780 | 780 |
| 781 // Check that there in an enum cache in the non-empty instance | 781 // Check that there in an enum cache in the non-empty instance |
| 782 // descriptors (edx). This is the case if the next enumeration | 782 // descriptors (edx). This is the case if the next enumeration |
| 783 // index field does not contain a smi. | 783 // index field does not contain a smi. |
| 784 __ mov(edx, FieldOperand(edx, DescriptorArray::kEnumerationIndexOffset)); | 784 __ mov(edx, FieldOperand(edx, DescriptorArray::kEnumerationIndexOffset)); |
| 785 __ test(edx, Immediate(kSmiTagMask)); | 785 __ test(edx, Immediate(kSmiTagMask)); |
| 786 __ j(zero, &call_runtime); | 786 __ j(zero, &call_runtime); |
| 787 | 787 |
| 788 // For all objects but the receiver, check that the cache is empty. | 788 // For all objects but the receiver, check that the cache is empty. |
| 789 Label check_prototype; | 789 NearLabel check_prototype; |
| 790 __ cmp(ecx, Operand(eax)); | 790 __ cmp(ecx, Operand(eax)); |
| 791 __ j(equal, &check_prototype); | 791 __ j(equal, &check_prototype); |
| 792 __ mov(edx, FieldOperand(edx, DescriptorArray::kEnumCacheBridgeCacheOffset)); | 792 __ mov(edx, FieldOperand(edx, DescriptorArray::kEnumCacheBridgeCacheOffset)); |
| 793 __ cmp(edx, Factory::empty_fixed_array()); | 793 __ cmp(edx, Factory::empty_fixed_array()); |
| 794 __ j(not_equal, &call_runtime); | 794 __ j(not_equal, &call_runtime); |
| 795 | 795 |
| 796 // Load the prototype from the map and loop if non-null. | 796 // Load the prototype from the map and loop if non-null. |
| 797 __ bind(&check_prototype); | 797 __ bind(&check_prototype); |
| 798 __ mov(ecx, FieldOperand(ebx, Map::kPrototypeOffset)); | 798 __ mov(ecx, FieldOperand(ebx, Map::kPrototypeOffset)); |
| 799 __ cmp(ecx, Factory::null_value()); | 799 __ cmp(ecx, Factory::null_value()); |
| 800 __ j(not_equal, &next); | 800 __ j(not_equal, &next); |
| 801 | 801 |
| 802 // The enum cache is valid. Load the map of the object being | 802 // The enum cache is valid. Load the map of the object being |
| 803 // iterated over and use the cache for the iteration. | 803 // iterated over and use the cache for the iteration. |
| 804 Label use_cache; | 804 NearLabel use_cache; |
| 805 __ mov(eax, FieldOperand(eax, HeapObject::kMapOffset)); | 805 __ mov(eax, FieldOperand(eax, HeapObject::kMapOffset)); |
| 806 __ jmp(&use_cache); | 806 __ jmp(&use_cache); |
| 807 | 807 |
| 808 // Get the set of properties to enumerate. | 808 // Get the set of properties to enumerate. |
| 809 __ bind(&call_runtime); | 809 __ bind(&call_runtime); |
| 810 __ push(eax); // Duplicate the enumerable object on the stack. | 810 __ push(eax); // Duplicate the enumerable object on the stack. |
| 811 __ CallRuntime(Runtime::kGetPropertyNamesFast, 1); | 811 __ CallRuntime(Runtime::kGetPropertyNamesFast, 1); |
| 812 | 812 |
| 813 // If we got a map from the runtime call, we can do a fast | 813 // If we got a map from the runtime call, we can do a fast |
| 814 // modification check. Otherwise, we got a fixed array, and we have | 814 // modification check. Otherwise, we got a fixed array, and we have |
| 815 // to do a slow check. | 815 // to do a slow check. |
| 816 Label fixed_array; | 816 NearLabel fixed_array; |
| 817 __ cmp(FieldOperand(eax, HeapObject::kMapOffset), Factory::meta_map()); | 817 __ cmp(FieldOperand(eax, HeapObject::kMapOffset), Factory::meta_map()); |
| 818 __ j(not_equal, &fixed_array); | 818 __ j(not_equal, &fixed_array); |
| 819 | 819 |
| 820 // We got a map in register eax. Get the enumeration cache from it. | 820 // We got a map in register eax. Get the enumeration cache from it. |
| 821 __ bind(&use_cache); | 821 __ bind(&use_cache); |
| 822 __ mov(ecx, FieldOperand(eax, Map::kInstanceDescriptorsOffset)); | 822 __ mov(ecx, FieldOperand(eax, Map::kInstanceDescriptorsOffset)); |
| 823 __ mov(ecx, FieldOperand(ecx, DescriptorArray::kEnumerationIndexOffset)); | 823 __ mov(ecx, FieldOperand(ecx, DescriptorArray::kEnumerationIndexOffset)); |
| 824 __ mov(edx, FieldOperand(ecx, DescriptorArray::kEnumCacheBridgeCacheOffset)); | 824 __ mov(edx, FieldOperand(ecx, DescriptorArray::kEnumCacheBridgeCacheOffset)); |
| 825 | 825 |
| 826 // Setup the four remaining stack slots. | 826 // Setup the four remaining stack slots. |
| (...skipping 21 matching lines...) Expand all Loading... |
| 848 // Get the current entry of the array into register ebx. | 848 // Get the current entry of the array into register ebx. |
| 849 __ mov(ebx, Operand(esp, 2 * kPointerSize)); | 849 __ mov(ebx, Operand(esp, 2 * kPointerSize)); |
| 850 __ mov(ebx, FieldOperand(ebx, eax, times_2, FixedArray::kHeaderSize)); | 850 __ mov(ebx, FieldOperand(ebx, eax, times_2, FixedArray::kHeaderSize)); |
| 851 | 851 |
| 852 // Get the expected map from the stack or a zero map in the | 852 // Get the expected map from the stack or a zero map in the |
| 853 // permanent slow case into register edx. | 853 // permanent slow case into register edx. |
| 854 __ mov(edx, Operand(esp, 3 * kPointerSize)); | 854 __ mov(edx, Operand(esp, 3 * kPointerSize)); |
| 855 | 855 |
| 856 // Check if the expected map still matches that of the enumerable. | 856 // Check if the expected map still matches that of the enumerable. |
| 857 // If not, we have to filter the key. | 857 // If not, we have to filter the key. |
| 858 Label update_each; | 858 NearLabel update_each; |
| 859 __ mov(ecx, Operand(esp, 4 * kPointerSize)); | 859 __ mov(ecx, Operand(esp, 4 * kPointerSize)); |
| 860 __ cmp(edx, FieldOperand(ecx, HeapObject::kMapOffset)); | 860 __ cmp(edx, FieldOperand(ecx, HeapObject::kMapOffset)); |
| 861 __ j(equal, &update_each); | 861 __ j(equal, &update_each); |
| 862 | 862 |
| 863 // Convert the entry to a string or null if it isn't a property | 863 // Convert the entry to a string or null if it isn't a property |
| 864 // anymore. If the property has been removed while iterating, we | 864 // anymore. If the property has been removed while iterating, we |
| 865 // just skip it. | 865 // just skip it. |
| 866 __ push(ecx); // Enumerable. | 866 __ push(ecx); // Enumerable. |
| 867 __ push(ebx); // Current entry. | 867 __ push(ebx); // Current entry. |
| 868 __ InvokeBuiltin(Builtins::FILTER_KEY, CALL_FUNCTION); | 868 __ InvokeBuiltin(Builtins::FILTER_KEY, CALL_FUNCTION); |
| 869 __ test(eax, Operand(eax)); | 869 __ test(eax, Operand(eax)); |
| 870 __ j(equal, loop_statement.continue_target()); | 870 __ j(equal, loop_statement.continue_target()); |
| 871 __ mov(ebx, Operand(eax)); | 871 __ mov(ebx, Operand(eax)); |
| 872 | 872 |
| 873 // Update the 'each' property or variable from the possibly filtered | 873 // Update the 'each' property or variable from the possibly filtered |
| 874 // entry in register ebx. | 874 // entry in register ebx. |
| 875 __ bind(&update_each); | 875 __ bind(&update_each); |
| 876 __ mov(result_register(), ebx); | 876 __ mov(result_register(), ebx); |
| 877 // Perform the assignment as if via '='. | 877 // Perform the assignment as if via '='. |
| 878 EmitAssignment(stmt->each()); | 878 EmitAssignment(stmt->each()); |
| 879 | 879 |
| 880 // Generate code for the body of the loop. | 880 // Generate code for the body of the loop. |
| 881 Label stack_limit_hit, stack_check_done; | 881 Label stack_limit_hit; |
| 882 NearLabel stack_check_done; |
| 882 Visit(stmt->body()); | 883 Visit(stmt->body()); |
| 883 | 884 |
| 884 __ StackLimitCheck(&stack_limit_hit); | 885 __ StackLimitCheck(&stack_limit_hit); |
| 885 __ bind(&stack_check_done); | 886 __ bind(&stack_check_done); |
| 886 | 887 |
| 887 // Generate code for going to the next element by incrementing the | 888 // Generate code for going to the next element by incrementing the |
| 888 // index (smi) stored on top of the stack. | 889 // index (smi) stored on top of the stack. |
| 889 __ bind(loop_statement.continue_target()); | 890 __ bind(loop_statement.continue_target()); |
| 890 __ add(Operand(esp, 0 * kPointerSize), Immediate(Smi::FromInt(1))); | 891 __ add(Operand(esp, 0 * kPointerSize), Immediate(Smi::FromInt(1))); |
| 891 __ jmp(&loop); | 892 __ jmp(&loop); |
| (...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 953 // If no outer scope calls eval, we do not need to check more | 954 // If no outer scope calls eval, we do not need to check more |
| 954 // context extensions. If we have reached an eval scope, we check | 955 // context extensions. If we have reached an eval scope, we check |
| 955 // all extensions from this point. | 956 // all extensions from this point. |
| 956 if (!s->outer_scope_calls_eval() || s->is_eval_scope()) break; | 957 if (!s->outer_scope_calls_eval() || s->is_eval_scope()) break; |
| 957 s = s->outer_scope(); | 958 s = s->outer_scope(); |
| 958 } | 959 } |
| 959 | 960 |
| 960 if (s != NULL && s->is_eval_scope()) { | 961 if (s != NULL && s->is_eval_scope()) { |
| 961 // Loop up the context chain. There is no frame effect so it is | 962 // Loop up the context chain. There is no frame effect so it is |
| 962 // safe to use raw labels here. | 963 // safe to use raw labels here. |
| 963 Label next, fast; | 964 NearLabel next, fast; |
| 964 if (!context.is(temp)) { | 965 if (!context.is(temp)) { |
| 965 __ mov(temp, context); | 966 __ mov(temp, context); |
| 966 } | 967 } |
| 967 __ bind(&next); | 968 __ bind(&next); |
| 968 // Terminate at global context. | 969 // Terminate at global context. |
| 969 __ cmp(FieldOperand(temp, HeapObject::kMapOffset), | 970 __ cmp(FieldOperand(temp, HeapObject::kMapOffset), |
| 970 Immediate(Factory::global_context_map())); | 971 Immediate(Factory::global_context_map())); |
| 971 __ j(equal, &fast); | 972 __ j(equal, &fast); |
| 972 // Check that extension is NULL. | 973 // Check that extension is NULL. |
| 973 __ cmp(ContextOperand(temp, Context::EXTENSION_INDEX), Immediate(0)); | 974 __ cmp(ContextOperand(temp, Context::EXTENSION_INDEX), Immediate(0)); |
| (...skipping 138 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1112 | 1113 |
| 1113 Apply(context, eax); | 1114 Apply(context, eax); |
| 1114 | 1115 |
| 1115 } else if (slot != NULL) { | 1116 } else if (slot != NULL) { |
| 1116 Comment cmnt(masm_, (slot->type() == Slot::CONTEXT) | 1117 Comment cmnt(masm_, (slot->type() == Slot::CONTEXT) |
| 1117 ? "Context slot" | 1118 ? "Context slot" |
| 1118 : "Stack slot"); | 1119 : "Stack slot"); |
| 1119 if (var->mode() == Variable::CONST) { | 1120 if (var->mode() == Variable::CONST) { |
| 1120 // Constants may be the hole value if they have not been initialized. | 1121 // Constants may be the hole value if they have not been initialized. |
| 1121 // Unhole them. | 1122 // Unhole them. |
| 1122 Label done; | 1123 NearLabel done; |
| 1123 MemOperand slot_operand = EmitSlotSearch(slot, eax); | 1124 MemOperand slot_operand = EmitSlotSearch(slot, eax); |
| 1124 __ mov(eax, slot_operand); | 1125 __ mov(eax, slot_operand); |
| 1125 __ cmp(eax, Factory::the_hole_value()); | 1126 __ cmp(eax, Factory::the_hole_value()); |
| 1126 __ j(not_equal, &done); | 1127 __ j(not_equal, &done); |
| 1127 __ mov(eax, Factory::undefined_value()); | 1128 __ mov(eax, Factory::undefined_value()); |
| 1128 __ bind(&done); | 1129 __ bind(&done); |
| 1129 Apply(context, eax); | 1130 Apply(context, eax); |
| 1130 } else { | 1131 } else { |
| 1131 Apply(context, slot); | 1132 Apply(context, slot); |
| 1132 } | 1133 } |
| (...skipping 28 matching lines...) Expand all Loading... |
| 1161 // call. It is treated specially by the LoadIC code. | 1162 // call. It is treated specially by the LoadIC code. |
| 1162 __ nop(); | 1163 __ nop(); |
| 1163 // Drop key and object left on the stack by IC. | 1164 // Drop key and object left on the stack by IC. |
| 1164 Apply(context, eax); | 1165 Apply(context, eax); |
| 1165 } | 1166 } |
| 1166 } | 1167 } |
| 1167 | 1168 |
| 1168 | 1169 |
| 1169 void FullCodeGenerator::VisitRegExpLiteral(RegExpLiteral* expr) { | 1170 void FullCodeGenerator::VisitRegExpLiteral(RegExpLiteral* expr) { |
| 1170 Comment cmnt(masm_, "[ RegExpLiteral"); | 1171 Comment cmnt(masm_, "[ RegExpLiteral"); |
| 1171 Label materialized; | 1172 NearLabel materialized; |
| 1172 // Registers will be used as follows: | 1173 // Registers will be used as follows: |
| 1173 // edi = JS function. | 1174 // edi = JS function. |
| 1174 // ecx = literals array. | 1175 // ecx = literals array. |
| 1175 // ebx = regexp literal. | 1176 // ebx = regexp literal. |
| 1176 // eax = regexp literal clone. | 1177 // eax = regexp literal clone. |
| 1177 __ mov(edi, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset)); | 1178 __ mov(edi, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset)); |
| 1178 __ mov(ecx, FieldOperand(edi, JSFunction::kLiteralsOffset)); | 1179 __ mov(ecx, FieldOperand(edi, JSFunction::kLiteralsOffset)); |
| 1179 int literal_offset = | 1180 int literal_offset = |
| 1180 FixedArray::kHeaderSize + expr->literal_index() * kPointerSize; | 1181 FixedArray::kHeaderSize + expr->literal_index() * kPointerSize; |
| 1181 __ mov(ebx, FieldOperand(ecx, literal_offset)); | 1182 __ mov(ebx, FieldOperand(ecx, literal_offset)); |
| (...skipping 300 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1482 __ call(ic, RelocInfo::CODE_TARGET); | 1483 __ call(ic, RelocInfo::CODE_TARGET); |
| 1483 __ nop(); | 1484 __ nop(); |
| 1484 } | 1485 } |
| 1485 | 1486 |
| 1486 | 1487 |
| 1487 void FullCodeGenerator::EmitConstantSmiAdd(Expression* expr, | 1488 void FullCodeGenerator::EmitConstantSmiAdd(Expression* expr, |
| 1488 Expression::Context context, | 1489 Expression::Context context, |
| 1489 OverwriteMode mode, | 1490 OverwriteMode mode, |
| 1490 bool left_is_constant_smi, | 1491 bool left_is_constant_smi, |
| 1491 Smi* value) { | 1492 Smi* value) { |
| 1492 Label call_stub, done; | 1493 NearLabel call_stub; |
| 1494 Label done; |
| 1493 __ add(Operand(eax), Immediate(value)); | 1495 __ add(Operand(eax), Immediate(value)); |
| 1494 __ j(overflow, &call_stub); | 1496 __ j(overflow, &call_stub); |
| 1495 __ test(eax, Immediate(kSmiTagMask)); | 1497 __ test(eax, Immediate(kSmiTagMask)); |
| 1496 __ j(zero, &done); | 1498 __ j(zero, &done); |
| 1497 | 1499 |
| 1498 // Undo the optimistic add operation and call the shared stub. | 1500 // Undo the optimistic add operation and call the shared stub. |
| 1499 __ bind(&call_stub); | 1501 __ bind(&call_stub); |
| 1500 __ sub(Operand(eax), Immediate(value)); | 1502 __ sub(Operand(eax), Immediate(value)); |
| 1501 Token::Value op = Token::ADD; | 1503 Token::Value op = Token::ADD; |
| 1502 GenericBinaryOpStub stub(op, mode, NO_SMI_CODE_IN_STUB, TypeInfo::Unknown()); | 1504 GenericBinaryOpStub stub(op, mode, NO_SMI_CODE_IN_STUB, TypeInfo::Unknown()); |
| (...skipping 1204 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2707 __ CallStub(&stub); | 2709 __ CallStub(&stub); |
| 2708 Apply(context_, eax); | 2710 Apply(context_, eax); |
| 2709 } | 2711 } |
| 2710 | 2712 |
| 2711 | 2713 |
| 2712 void FullCodeGenerator::EmitValueOf(ZoneList<Expression*>* args) { | 2714 void FullCodeGenerator::EmitValueOf(ZoneList<Expression*>* args) { |
| 2713 ASSERT(args->length() == 1); | 2715 ASSERT(args->length() == 1); |
| 2714 | 2716 |
| 2715 VisitForValue(args->at(0), kAccumulator); // Load the object. | 2717 VisitForValue(args->at(0), kAccumulator); // Load the object. |
| 2716 | 2718 |
| 2717 Label done; | 2719 NearLabel done; |
| 2718 // If the object is a smi return the object. | 2720 // If the object is a smi return the object. |
| 2719 __ test(eax, Immediate(kSmiTagMask)); | 2721 __ test(eax, Immediate(kSmiTagMask)); |
| 2720 __ j(zero, &done); | 2722 __ j(zero, &done); |
| 2721 // If the object is not a value type, return the object. | 2723 // If the object is not a value type, return the object. |
| 2722 __ CmpObjectType(eax, JS_VALUE_TYPE, ebx); | 2724 __ CmpObjectType(eax, JS_VALUE_TYPE, ebx); |
| 2723 __ j(not_equal, &done); | 2725 __ j(not_equal, &done); |
| 2724 __ mov(eax, FieldOperand(eax, JSValue::kValueOffset)); | 2726 __ mov(eax, FieldOperand(eax, JSValue::kValueOffset)); |
| 2725 | 2727 |
| 2726 __ bind(&done); | 2728 __ bind(&done); |
| 2727 Apply(context_, eax); | 2729 Apply(context_, eax); |
| (...skipping 10 matching lines...) Expand all Loading... |
| 2738 } | 2740 } |
| 2739 | 2741 |
| 2740 | 2742 |
| 2741 void FullCodeGenerator::EmitSetValueOf(ZoneList<Expression*>* args) { | 2743 void FullCodeGenerator::EmitSetValueOf(ZoneList<Expression*>* args) { |
| 2742 ASSERT(args->length() == 2); | 2744 ASSERT(args->length() == 2); |
| 2743 | 2745 |
| 2744 VisitForValue(args->at(0), kStack); // Load the object. | 2746 VisitForValue(args->at(0), kStack); // Load the object. |
| 2745 VisitForValue(args->at(1), kAccumulator); // Load the value. | 2747 VisitForValue(args->at(1), kAccumulator); // Load the value. |
| 2746 __ pop(ebx); // eax = value. ebx = object. | 2748 __ pop(ebx); // eax = value. ebx = object. |
| 2747 | 2749 |
| 2748 Label done; | 2750 NearLabel done; |
| 2749 // If the object is a smi, return the value. | 2751 // If the object is a smi, return the value. |
| 2750 __ test(ebx, Immediate(kSmiTagMask)); | 2752 __ test(ebx, Immediate(kSmiTagMask)); |
| 2751 __ j(zero, &done); | 2753 __ j(zero, &done); |
| 2752 | 2754 |
| 2753 // If the object is not a value type, return the value. | 2755 // If the object is not a value type, return the value. |
| 2754 __ CmpObjectType(ebx, JS_VALUE_TYPE, ecx); | 2756 __ CmpObjectType(ebx, JS_VALUE_TYPE, ecx); |
| 2755 __ j(not_equal, &done); | 2757 __ j(not_equal, &done); |
| 2756 | 2758 |
| 2757 // Store the value. | 2759 // Store the value. |
| 2758 __ mov(FieldOperand(ebx, JSValue::kValueOffset), eax); | 2760 __ mov(FieldOperand(ebx, JSValue::kValueOffset), eax); |
| (...skipping 507 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3266 break; | 3268 break; |
| 3267 } | 3269 } |
| 3268 | 3270 |
| 3269 case Token::BIT_NOT: { | 3271 case Token::BIT_NOT: { |
| 3270 Comment cmt(masm_, "[ UnaryOperation (BIT_NOT)"); | 3272 Comment cmt(masm_, "[ UnaryOperation (BIT_NOT)"); |
| 3271 // The generic unary operation stub expects the argument to be | 3273 // The generic unary operation stub expects the argument to be |
| 3272 // in the accumulator register eax. | 3274 // in the accumulator register eax. |
| 3273 VisitForValue(expr->expression(), kAccumulator); | 3275 VisitForValue(expr->expression(), kAccumulator); |
| 3274 Label done; | 3276 Label done; |
| 3275 if (ShouldInlineSmiCase(expr->op())) { | 3277 if (ShouldInlineSmiCase(expr->op())) { |
| 3276 Label call_stub; | 3278 NearLabel call_stub; |
| 3277 __ test(eax, Immediate(kSmiTagMask)); | 3279 __ test(eax, Immediate(kSmiTagMask)); |
| 3278 __ j(not_zero, &call_stub); | 3280 __ j(not_zero, &call_stub); |
| 3279 __ lea(eax, Operand(eax, kSmiTagMask)); | 3281 __ lea(eax, Operand(eax, kSmiTagMask)); |
| 3280 __ not_(eax); | 3282 __ not_(eax); |
| 3281 __ jmp(&done); | 3283 __ jmp(&done); |
| 3282 __ bind(&call_stub); | 3284 __ bind(&call_stub); |
| 3283 } | 3285 } |
| 3284 bool overwrite = expr->expression()->ResultOverwriteAllowed(); | 3286 bool overwrite = expr->expression()->ResultOverwriteAllowed(); |
| 3285 UnaryOverwriteMode mode = | 3287 UnaryOverwriteMode mode = |
| 3286 overwrite ? UNARY_OVERWRITE : UNARY_NO_OVERWRITE; | 3288 overwrite ? UNARY_OVERWRITE : UNARY_NO_OVERWRITE; |
| (...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3341 } else { | 3343 } else { |
| 3342 VisitForValue(prop->obj(), kStack); | 3344 VisitForValue(prop->obj(), kStack); |
| 3343 VisitForValue(prop->key(), kAccumulator); | 3345 VisitForValue(prop->key(), kAccumulator); |
| 3344 __ mov(edx, Operand(esp, 0)); | 3346 __ mov(edx, Operand(esp, 0)); |
| 3345 __ push(eax); | 3347 __ push(eax); |
| 3346 EmitKeyedPropertyLoad(prop); | 3348 EmitKeyedPropertyLoad(prop); |
| 3347 } | 3349 } |
| 3348 } | 3350 } |
| 3349 | 3351 |
| 3350 // Call ToNumber only if operand is not a smi. | 3352 // Call ToNumber only if operand is not a smi. |
| 3351 Label no_conversion; | 3353 NearLabel no_conversion; |
| 3352 if (ShouldInlineSmiCase(expr->op())) { | 3354 if (ShouldInlineSmiCase(expr->op())) { |
| 3353 __ test(eax, Immediate(kSmiTagMask)); | 3355 __ test(eax, Immediate(kSmiTagMask)); |
| 3354 __ j(zero, &no_conversion); | 3356 __ j(zero, &no_conversion); |
| 3355 } | 3357 } |
| 3356 __ push(eax); | 3358 __ push(eax); |
| 3357 __ InvokeBuiltin(Builtins::TO_NUMBER, CALL_FUNCTION); | 3359 __ InvokeBuiltin(Builtins::TO_NUMBER, CALL_FUNCTION); |
| 3358 __ bind(&no_conversion); | 3360 __ bind(&no_conversion); |
| 3359 | 3361 |
| 3360 // Save result for postfix expressions. | 3362 // Save result for postfix expressions. |
| 3361 if (expr->is_postfix()) { | 3363 if (expr->is_postfix()) { |
| (...skipping 17 matching lines...) Expand all Loading... |
| 3379 break; | 3381 break; |
| 3380 case KEYED_PROPERTY: | 3382 case KEYED_PROPERTY: |
| 3381 __ mov(Operand(esp, 2 * kPointerSize), eax); | 3383 __ mov(Operand(esp, 2 * kPointerSize), eax); |
| 3382 break; | 3384 break; |
| 3383 } | 3385 } |
| 3384 break; | 3386 break; |
| 3385 } | 3387 } |
| 3386 } | 3388 } |
| 3387 | 3389 |
| 3388 // Inline smi case if we are in a loop. | 3390 // Inline smi case if we are in a loop. |
| 3389 Label stub_call, done; | 3391 NearLabel stub_call; |
| 3392 Label done; |
| 3390 if (ShouldInlineSmiCase(expr->op())) { | 3393 if (ShouldInlineSmiCase(expr->op())) { |
| 3391 if (expr->op() == Token::INC) { | 3394 if (expr->op() == Token::INC) { |
| 3392 __ add(Operand(eax), Immediate(Smi::FromInt(1))); | 3395 __ add(Operand(eax), Immediate(Smi::FromInt(1))); |
| 3393 } else { | 3396 } else { |
| 3394 __ sub(Operand(eax), Immediate(Smi::FromInt(1))); | 3397 __ sub(Operand(eax), Immediate(Smi::FromInt(1))); |
| 3395 } | 3398 } |
| 3396 __ j(overflow, &stub_call); | 3399 __ j(overflow, &stub_call); |
| 3397 // We could eliminate this smi check if we split the code at | 3400 // We could eliminate this smi check if we split the code at |
| 3398 // the first smi check before calling ToNumber. | 3401 // the first smi check before calling ToNumber. |
| 3399 __ test(eax, Immediate(kSmiTagMask)); | 3402 __ test(eax, Immediate(kSmiTagMask)); |
| (...skipping 266 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3666 cc = greater_equal; | 3669 cc = greater_equal; |
| 3667 __ pop(edx); | 3670 __ pop(edx); |
| 3668 break; | 3671 break; |
| 3669 case Token::IN: | 3672 case Token::IN: |
| 3670 case Token::INSTANCEOF: | 3673 case Token::INSTANCEOF: |
| 3671 default: | 3674 default: |
| 3672 UNREACHABLE(); | 3675 UNREACHABLE(); |
| 3673 } | 3676 } |
| 3674 | 3677 |
| 3675 if (ShouldInlineSmiCase(op)) { | 3678 if (ShouldInlineSmiCase(op)) { |
| 3676 Label slow_case; | 3679 NearLabel slow_case; |
| 3677 __ mov(ecx, Operand(edx)); | 3680 __ mov(ecx, Operand(edx)); |
| 3678 __ or_(ecx, Operand(eax)); | 3681 __ or_(ecx, Operand(eax)); |
| 3679 __ test(ecx, Immediate(kSmiTagMask)); | 3682 __ test(ecx, Immediate(kSmiTagMask)); |
| 3680 __ j(not_zero, &slow_case, not_taken); | 3683 __ j(not_zero, &slow_case, not_taken); |
| 3681 __ cmp(edx, Operand(eax)); | 3684 __ cmp(edx, Operand(eax)); |
| 3682 Split(cc, if_true, if_false, NULL); | 3685 Split(cc, if_true, if_false, NULL); |
| 3683 __ bind(&slow_case); | 3686 __ bind(&slow_case); |
| 3684 } | 3687 } |
| 3685 | 3688 |
| 3686 CompareStub stub(cc, strict); | 3689 CompareStub stub(cc, strict); |
| (...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3776 // And return. | 3779 // And return. |
| 3777 __ ret(0); | 3780 __ ret(0); |
| 3778 } | 3781 } |
| 3779 | 3782 |
| 3780 | 3783 |
| 3781 #undef __ | 3784 #undef __ |
| 3782 | 3785 |
| 3783 } } // namespace v8::internal | 3786 } } // namespace v8::internal |
| 3784 | 3787 |
| 3785 #endif // V8_TARGET_ARCH_IA32 | 3788 #endif // V8_TARGET_ARCH_IA32 |
| OLD | NEW |