| OLD | NEW |
| 1 // Copyright 2011 the V8 project authors. All rights reserved. | 1 // Copyright 2011 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 728 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 739 kDontSaveFPRegs, | 739 kDontSaveFPRegs, |
| 740 EMIT_REMEMBERED_SET, | 740 EMIT_REMEMBERED_SET, |
| 741 OMIT_SMI_CHECK); | 741 OMIT_SMI_CHECK); |
| 742 } | 742 } |
| 743 break; | 743 break; |
| 744 | 744 |
| 745 case Slot::LOOKUP: { | 745 case Slot::LOOKUP: { |
| 746 __ push(esi); | 746 __ push(esi); |
| 747 __ push(Immediate(variable->name())); | 747 __ push(Immediate(variable->name())); |
| 748 // Declaration nodes are always introduced in one of two modes. | 748 // Declaration nodes are always introduced in one of two modes. |
| 749 ASSERT(mode == Variable::VAR || mode == Variable::CONST); | 749 ASSERT(mode == Variable::VAR || |
| 750 PropertyAttributes attr = (mode == Variable::VAR) ? NONE : READ_ONLY; | 750 mode == Variable::CONST || |
| 751 mode == Variable::LET); |
| 752 PropertyAttributes attr = (mode == Variable::CONST) ? READ_ONLY : NONE; |
| 751 __ push(Immediate(Smi::FromInt(attr))); | 753 __ push(Immediate(Smi::FromInt(attr))); |
| 752 // Push initial value, if any. | 754 // Push initial value, if any. |
| 753 // Note: For variables we must not push an initial value (such as | 755 // Note: For variables we must not push an initial value (such as |
| 754 // 'undefined') because we may have a (legal) redeclaration and we | 756 // 'undefined') because we may have a (legal) redeclaration and we |
| 755 // must not destroy the current value. | 757 // must not destroy the current value. |
| 756 increment_stack_height(3); | 758 increment_stack_height(3); |
| 757 if (mode == Variable::CONST) { | 759 if (mode == Variable::CONST) { |
| 758 __ push(Immediate(isolate()->factory()->the_hole_value())); | 760 __ push(Immediate(isolate()->factory()->the_hole_value())); |
| 759 increment_stack_height(); | 761 increment_stack_height(); |
| 760 } else if (function != NULL) { | 762 } else if (function != NULL) { |
| (...skipping 114 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 875 __ j(not_equal, &next_test); | 877 __ j(not_equal, &next_test); |
| 876 __ Drop(1); // Switch value is no longer needed. | 878 __ Drop(1); // Switch value is no longer needed. |
| 877 __ jmp(clause->body_target()); | 879 __ jmp(clause->body_target()); |
| 878 } | 880 } |
| 879 | 881 |
| 880 // Discard the test value and jump to the default if present, otherwise to | 882 // Discard the test value and jump to the default if present, otherwise to |
| 881 // the end of the statement. | 883 // the end of the statement. |
| 882 __ bind(&next_test); | 884 __ bind(&next_test); |
| 883 __ Drop(1); // Switch value is no longer needed. | 885 __ Drop(1); // Switch value is no longer needed. |
| 884 if (default_clause == NULL) { | 886 if (default_clause == NULL) { |
| 885 __ jmp(nested_statement.break_target()); | 887 __ jmp(nested_statement.break_label()); |
| 886 } else { | 888 } else { |
| 887 __ jmp(default_clause->body_target()); | 889 __ jmp(default_clause->body_target()); |
| 888 } | 890 } |
| 889 | 891 |
| 890 set_stack_height(switch_clause_stack_height); | 892 set_stack_height(switch_clause_stack_height); |
| 891 // Compile all the case bodies. | 893 // Compile all the case bodies. |
| 892 for (int i = 0; i < clauses->length(); i++) { | 894 for (int i = 0; i < clauses->length(); i++) { |
| 893 Comment cmnt(masm_, "[ Case body"); | 895 Comment cmnt(masm_, "[ Case body"); |
| 894 CaseClause* clause = clauses->at(i); | 896 CaseClause* clause = clauses->at(i); |
| 895 __ bind(clause->body_target()); | 897 __ bind(clause->body_target()); |
| 896 PrepareForBailoutForId(clause->EntryId(), NO_REGISTERS); | 898 PrepareForBailoutForId(clause->EntryId(), NO_REGISTERS); |
| 897 VisitStatements(clause->statements()); | 899 VisitStatements(clause->statements()); |
| 898 } | 900 } |
| 899 | 901 |
| 900 __ bind(nested_statement.break_target()); | 902 __ bind(nested_statement.break_label()); |
| 901 PrepareForBailoutForId(stmt->ExitId(), NO_REGISTERS); | 903 PrepareForBailoutForId(stmt->ExitId(), NO_REGISTERS); |
| 902 } | 904 } |
| 903 | 905 |
| 904 | 906 |
| 905 void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) { | 907 void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) { |
| 906 Comment cmnt(masm_, "[ ForInStatement"); | 908 Comment cmnt(masm_, "[ ForInStatement"); |
| 907 SetStatementPosition(stmt); | 909 SetStatementPosition(stmt); |
| 908 | 910 |
| 909 Label loop, exit; | 911 Label loop, exit; |
| 910 ForIn loop_statement(this, stmt); | 912 ForIn loop_statement(this, stmt); |
| (...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1006 __ jmp(&loop); | 1008 __ jmp(&loop); |
| 1007 | 1009 |
| 1008 // We got a fixed array in register eax. Iterate through that. | 1010 // We got a fixed array in register eax. Iterate through that. |
| 1009 __ bind(&fixed_array); | 1011 __ bind(&fixed_array); |
| 1010 __ push(Immediate(Smi::FromInt(0))); // Map (0) - force slow check. | 1012 __ push(Immediate(Smi::FromInt(0))); // Map (0) - force slow check. |
| 1011 __ push(eax); | 1013 __ push(eax); |
| 1012 __ mov(eax, FieldOperand(eax, FixedArray::kLengthOffset)); | 1014 __ mov(eax, FieldOperand(eax, FixedArray::kLengthOffset)); |
| 1013 __ push(eax); // Fixed array length (as smi). | 1015 __ push(eax); // Fixed array length (as smi). |
| 1014 __ push(Immediate(Smi::FromInt(0))); // Initial index. | 1016 __ push(Immediate(Smi::FromInt(0))); // Initial index. |
| 1015 | 1017 |
| 1016 increment_stack_height(4); | 1018 // 1 ~ The object has already been pushed. |
| 1019 increment_stack_height(ForIn::kElementCount - 1); |
| 1017 // Generate code for doing the condition check. | 1020 // Generate code for doing the condition check. |
| 1018 __ bind(&loop); | 1021 __ bind(&loop); |
| 1019 __ mov(eax, Operand(esp, 0 * kPointerSize)); // Get the current index. | 1022 __ mov(eax, Operand(esp, 0 * kPointerSize)); // Get the current index. |
| 1020 __ cmp(eax, Operand(esp, 1 * kPointerSize)); // Compare to the array length. | 1023 __ cmp(eax, Operand(esp, 1 * kPointerSize)); // Compare to the array length. |
| 1021 __ j(above_equal, loop_statement.break_target()); | 1024 __ j(above_equal, loop_statement.break_label()); |
| 1022 | 1025 |
| 1023 // Get the current entry of the array into register ebx. | 1026 // Get the current entry of the array into register ebx. |
| 1024 __ mov(ebx, Operand(esp, 2 * kPointerSize)); | 1027 __ mov(ebx, Operand(esp, 2 * kPointerSize)); |
| 1025 __ mov(ebx, FieldOperand(ebx, eax, times_2, FixedArray::kHeaderSize)); | 1028 __ mov(ebx, FieldOperand(ebx, eax, times_2, FixedArray::kHeaderSize)); |
| 1026 | 1029 |
| 1027 // Get the expected map from the stack or a zero map in the | 1030 // Get the expected map from the stack or a zero map in the |
| 1028 // permanent slow case into register edx. | 1031 // permanent slow case into register edx. |
| 1029 __ mov(edx, Operand(esp, 3 * kPointerSize)); | 1032 __ mov(edx, Operand(esp, 3 * kPointerSize)); |
| 1030 | 1033 |
| 1031 // Check if the expected map still matches that of the enumerable. | 1034 // Check if the expected map still matches that of the enumerable. |
| 1032 // If not, we have to filter the key. | 1035 // If not, we have to filter the key. |
| 1033 Label update_each; | 1036 Label update_each; |
| 1034 __ mov(ecx, Operand(esp, 4 * kPointerSize)); | 1037 __ mov(ecx, Operand(esp, 4 * kPointerSize)); |
| 1035 __ cmp(edx, FieldOperand(ecx, HeapObject::kMapOffset)); | 1038 __ cmp(edx, FieldOperand(ecx, HeapObject::kMapOffset)); |
| 1036 __ j(equal, &update_each, Label::kNear); | 1039 __ j(equal, &update_each, Label::kNear); |
| 1037 | 1040 |
| 1038 // Convert the entry to a string or null if it isn't a property | 1041 // Convert the entry to a string or null if it isn't a property |
| 1039 // anymore. If the property has been removed while iterating, we | 1042 // anymore. If the property has been removed while iterating, we |
| 1040 // just skip it. | 1043 // just skip it. |
| 1041 __ push(ecx); // Enumerable. | 1044 __ push(ecx); // Enumerable. |
| 1042 __ push(ebx); // Current entry. | 1045 __ push(ebx); // Current entry. |
| 1043 __ InvokeBuiltin(Builtins::FILTER_KEY, CALL_FUNCTION); | 1046 __ InvokeBuiltin(Builtins::FILTER_KEY, CALL_FUNCTION); |
| 1044 __ test(eax, Operand(eax)); | 1047 __ test(eax, Operand(eax)); |
| 1045 __ j(equal, loop_statement.continue_target()); | 1048 __ j(equal, loop_statement.continue_label()); |
| 1046 __ mov(ebx, Operand(eax)); | 1049 __ mov(ebx, Operand(eax)); |
| 1047 | 1050 |
| 1048 // Update the 'each' property or variable from the possibly filtered | 1051 // Update the 'each' property or variable from the possibly filtered |
| 1049 // entry in register ebx. | 1052 // entry in register ebx. |
| 1050 __ bind(&update_each); | 1053 __ bind(&update_each); |
| 1051 __ mov(result_register(), ebx); | 1054 __ mov(result_register(), ebx); |
| 1052 // Perform the assignment as if via '='. | 1055 // Perform the assignment as if via '='. |
| 1053 { EffectContext context(this); | 1056 { EffectContext context(this); |
| 1054 EmitAssignment(stmt->each(), stmt->AssignmentId()); | 1057 EmitAssignment(stmt->each(), stmt->AssignmentId()); |
| 1055 } | 1058 } |
| 1056 | 1059 |
| 1057 // Generate code for the body of the loop. | 1060 // Generate code for the body of the loop. |
| 1058 Visit(stmt->body()); | 1061 Visit(stmt->body()); |
| 1059 | 1062 |
| 1060 // Generate code for going to the next element by incrementing the | 1063 // Generate code for going to the next element by incrementing the |
| 1061 // index (smi) stored on top of the stack. | 1064 // index (smi) stored on top of the stack. |
| 1062 __ bind(loop_statement.continue_target()); | 1065 __ bind(loop_statement.continue_label()); |
| 1063 __ add(Operand(esp, 0 * kPointerSize), Immediate(Smi::FromInt(1))); | 1066 __ add(Operand(esp, 0 * kPointerSize), Immediate(Smi::FromInt(1))); |
| 1064 | 1067 |
| 1065 EmitStackCheck(stmt); | 1068 EmitStackCheck(stmt); |
| 1066 __ jmp(&loop); | 1069 __ jmp(&loop); |
| 1067 | 1070 |
| 1068 // Remove the pointers stored on the stack. | 1071 // Remove the pointers stored on the stack. |
| 1069 __ bind(loop_statement.break_target()); | 1072 __ bind(loop_statement.break_label()); |
| 1070 __ add(Operand(esp), Immediate(5 * kPointerSize)); | 1073 __ add(Operand(esp), Immediate(5 * kPointerSize)); |
| 1071 | 1074 |
| 1072 decrement_stack_height(5); | 1075 decrement_stack_height(ForIn::kElementCount); |
| 1073 // Exit and decrement the loop depth. | 1076 // Exit and decrement the loop depth. |
| 1074 __ bind(&exit); | 1077 __ bind(&exit); |
| 1075 decrement_loop_depth(); | 1078 decrement_loop_depth(); |
| 1076 } | 1079 } |
| 1077 | 1080 |
| 1078 | 1081 |
| 1079 void FullCodeGenerator::EmitNewClosure(Handle<SharedFunctionInfo> info, | 1082 void FullCodeGenerator::EmitNewClosure(Handle<SharedFunctionInfo> info, |
| 1080 bool pretenure) { | 1083 bool pretenure) { |
| 1081 // Use the fast case closure allocation code that allocates in new | 1084 // Use the fast case closure allocation code that allocates in new |
| 1082 // space for nested functions that don't need literals cloning. If | 1085 // space for nested functions that don't need literals cloning. If |
| (...skipping 2764 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3847 break; | 3850 break; |
| 3848 | 3851 |
| 3849 default: | 3852 default: |
| 3850 UNREACHABLE(); | 3853 UNREACHABLE(); |
| 3851 } | 3854 } |
| 3852 } | 3855 } |
| 3853 | 3856 |
| 3854 | 3857 |
| 3855 void FullCodeGenerator::EmitUnaryOperation(UnaryOperation* expr, | 3858 void FullCodeGenerator::EmitUnaryOperation(UnaryOperation* expr, |
| 3856 const char* comment) { | 3859 const char* comment) { |
| 3857 // TODO(svenpanne): Allowing format strings in Comment would be nice here... | |
| 3858 Comment cmt(masm_, comment); | 3860 Comment cmt(masm_, comment); |
| 3859 bool can_overwrite = expr->expression()->ResultOverwriteAllowed(); | 3861 bool can_overwrite = expr->expression()->ResultOverwriteAllowed(); |
| 3860 UnaryOverwriteMode overwrite = | 3862 UnaryOverwriteMode overwrite = |
| 3861 can_overwrite ? UNARY_OVERWRITE : UNARY_NO_OVERWRITE; | 3863 can_overwrite ? UNARY_OVERWRITE : UNARY_NO_OVERWRITE; |
| 3862 UnaryOpStub stub(expr->op(), overwrite); | 3864 UnaryOpStub stub(expr->op(), overwrite); |
| 3863 // UnaryOpStub expects the argument to be in the | 3865 // UnaryOpStub expects the argument to be in the |
| 3864 // accumulator register eax. | 3866 // accumulator register eax. |
| 3865 VisitForAccumulatorValue(expr->expression()); | 3867 VisitForAccumulatorValue(expr->expression()); |
| 3866 SetSourcePosition(expr->position()); | 3868 SetSourcePosition(expr->position()); |
| 3867 __ call(stub.GetCode(), RelocInfo::CODE_TARGET, expr->id()); | 3869 __ call(stub.GetCode(), RelocInfo::CODE_TARGET, expr->id()); |
| (...skipping 254 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4122 __ j(above_equal, if_false); | 4124 __ j(above_equal, if_false); |
| 4123 // Check for undetectable objects => false. | 4125 // Check for undetectable objects => false. |
| 4124 __ test_b(FieldOperand(edx, Map::kBitFieldOffset), | 4126 __ test_b(FieldOperand(edx, Map::kBitFieldOffset), |
| 4125 1 << Map::kIsUndetectable); | 4127 1 << Map::kIsUndetectable); |
| 4126 Split(zero, if_true, if_false, fall_through); | 4128 Split(zero, if_true, if_false, fall_through); |
| 4127 } else if (check->Equals(isolate()->heap()->boolean_symbol())) { | 4129 } else if (check->Equals(isolate()->heap()->boolean_symbol())) { |
| 4128 __ cmp(eax, isolate()->factory()->true_value()); | 4130 __ cmp(eax, isolate()->factory()->true_value()); |
| 4129 __ j(equal, if_true); | 4131 __ j(equal, if_true); |
| 4130 __ cmp(eax, isolate()->factory()->false_value()); | 4132 __ cmp(eax, isolate()->factory()->false_value()); |
| 4131 Split(equal, if_true, if_false, fall_through); | 4133 Split(equal, if_true, if_false, fall_through); |
| 4134 } else if (FLAG_harmony_typeof && |
| 4135 check->Equals(isolate()->heap()->null_symbol())) { |
| 4136 __ cmp(eax, isolate()->factory()->null_value()); |
| 4137 Split(equal, if_true, if_false, fall_through); |
| 4132 } else if (check->Equals(isolate()->heap()->undefined_symbol())) { | 4138 } else if (check->Equals(isolate()->heap()->undefined_symbol())) { |
| 4133 __ cmp(eax, isolate()->factory()->undefined_value()); | 4139 __ cmp(eax, isolate()->factory()->undefined_value()); |
| 4134 __ j(equal, if_true); | 4140 __ j(equal, if_true); |
| 4135 __ JumpIfSmi(eax, if_false); | 4141 __ JumpIfSmi(eax, if_false); |
| 4136 // Check for undetectable objects => true. | 4142 // Check for undetectable objects => true. |
| 4137 __ mov(edx, FieldOperand(eax, HeapObject::kMapOffset)); | 4143 __ mov(edx, FieldOperand(eax, HeapObject::kMapOffset)); |
| 4138 __ movzx_b(ecx, FieldOperand(edx, Map::kBitFieldOffset)); | 4144 __ movzx_b(ecx, FieldOperand(edx, Map::kBitFieldOffset)); |
| 4139 __ test(ecx, Immediate(1 << Map::kIsUndetectable)); | 4145 __ test(ecx, Immediate(1 << Map::kIsUndetectable)); |
| 4140 Split(not_zero, if_true, if_false, fall_through); | 4146 Split(not_zero, if_true, if_false, fall_through); |
| 4141 } else if (check->Equals(isolate()->heap()->function_symbol())) { | 4147 } else if (check->Equals(isolate()->heap()->function_symbol())) { |
| 4142 __ JumpIfSmi(eax, if_false); | 4148 __ JumpIfSmi(eax, if_false); |
| 4143 __ CmpObjectType(eax, FIRST_CALLABLE_SPEC_OBJECT_TYPE, edx); | 4149 __ CmpObjectType(eax, FIRST_CALLABLE_SPEC_OBJECT_TYPE, edx); |
| 4144 Split(above_equal, if_true, if_false, fall_through); | 4150 Split(above_equal, if_true, if_false, fall_through); |
| 4145 } else if (check->Equals(isolate()->heap()->object_symbol())) { | 4151 } else if (check->Equals(isolate()->heap()->object_symbol())) { |
| 4146 __ JumpIfSmi(eax, if_false); | 4152 __ JumpIfSmi(eax, if_false); |
| 4147 __ cmp(eax, isolate()->factory()->null_value()); | 4153 if (!FLAG_harmony_typeof) { |
| 4148 __ j(equal, if_true); | 4154 __ cmp(eax, isolate()->factory()->null_value()); |
| 4155 __ j(equal, if_true); |
| 4156 } |
| 4149 __ CmpObjectType(eax, FIRST_NONCALLABLE_SPEC_OBJECT_TYPE, edx); | 4157 __ CmpObjectType(eax, FIRST_NONCALLABLE_SPEC_OBJECT_TYPE, edx); |
| 4150 __ j(below, if_false); | 4158 __ j(below, if_false); |
| 4151 __ CmpInstanceType(edx, LAST_NONCALLABLE_SPEC_OBJECT_TYPE); | 4159 __ CmpInstanceType(edx, LAST_NONCALLABLE_SPEC_OBJECT_TYPE); |
| 4152 __ j(above, if_false); | 4160 __ j(above, if_false); |
| 4153 // Check for undetectable objects => false. | 4161 // Check for undetectable objects => false. |
| 4154 __ test_b(FieldOperand(edx, Map::kBitFieldOffset), | 4162 __ test_b(FieldOperand(edx, Map::kBitFieldOffset), |
| 4155 1 << Map::kIsUndetectable); | 4163 1 << Map::kIsUndetectable); |
| 4156 Split(zero, if_true, if_false, fall_through); | 4164 Split(zero, if_true, if_false, fall_through); |
| 4157 } else { | 4165 } else { |
| 4158 if (if_false != fall_through) __ jmp(if_false); | 4166 if (if_false != fall_through) __ jmp(if_false); |
| (...skipping 229 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4388 __ add(Operand(edx), Immediate(masm_->CodeObject())); | 4396 __ add(Operand(edx), Immediate(masm_->CodeObject())); |
| 4389 __ jmp(Operand(edx)); | 4397 __ jmp(Operand(edx)); |
| 4390 } | 4398 } |
| 4391 | 4399 |
| 4392 | 4400 |
| 4393 #undef __ | 4401 #undef __ |
| 4394 | 4402 |
| 4395 } } // namespace v8::internal | 4403 } } // namespace v8::internal |
| 4396 | 4404 |
| 4397 #endif // V8_TARGET_ARCH_IA32 | 4405 #endif // V8_TARGET_ARCH_IA32 |
| OLD | NEW |