| OLD | NEW |
| 1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 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 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 67 private: | 67 private: |
| 68 LCodeGen* codegen_; | 68 LCodeGen* codegen_; |
| 69 LPointerMap* pointers_; | 69 LPointerMap* pointers_; |
| 70 Safepoint::DeoptMode deopt_mode_; | 70 Safepoint::DeoptMode deopt_mode_; |
| 71 }; | 71 }; |
| 72 | 72 |
| 73 | 73 |
| 74 #define __ masm()-> | 74 #define __ masm()-> |
| 75 | 75 |
| 76 bool LCodeGen::GenerateCode() { | 76 bool LCodeGen::GenerateCode() { |
| 77 HPhase phase("Z_Code generation", chunk()); | 77 LPhase phase("Z_Code generation", chunk()); |
| 78 ASSERT(is_unused()); | 78 ASSERT(is_unused()); |
| 79 status_ = GENERATING; | 79 status_ = GENERATING; |
| 80 | 80 |
| 81 // Open a frame scope to indicate that there is a frame on the stack. The | 81 // Open a frame scope to indicate that there is a frame on the stack. The |
| 82 // MANUAL indicates that the scope shouldn't actually generate code to set up | 82 // MANUAL indicates that the scope shouldn't actually generate code to set up |
| 83 // the frame (that is done in GeneratePrologue). | 83 // the frame (that is done in GeneratePrologue). |
| 84 FrameScope frame_scope(masm_, StackFrame::MANUAL); | 84 FrameScope frame_scope(masm_, StackFrame::MANUAL); |
| 85 | 85 |
| 86 support_aligned_spilled_doubles_ = info()->IsOptimizing(); | 86 support_aligned_spilled_doubles_ = info()->IsOptimizing(); |
| 87 | 87 |
| (...skipping 14 matching lines...) Expand all Loading... |
| 102 ASSERT(is_done()); | 102 ASSERT(is_done()); |
| 103 code->set_stack_slots(GetStackSlotCount()); | 103 code->set_stack_slots(GetStackSlotCount()); |
| 104 code->set_safepoint_table_offset(safepoints_.GetCodeOffset()); | 104 code->set_safepoint_table_offset(safepoints_.GetCodeOffset()); |
| 105 if (FLAG_weak_embedded_maps_in_optimized_code) { | 105 if (FLAG_weak_embedded_maps_in_optimized_code) { |
| 106 RegisterDependentCodeForEmbeddedMaps(code); | 106 RegisterDependentCodeForEmbeddedMaps(code); |
| 107 } | 107 } |
| 108 PopulateDeoptimizationData(code); | 108 PopulateDeoptimizationData(code); |
| 109 if (!info()->IsStub()) { | 109 if (!info()->IsStub()) { |
| 110 Deoptimizer::EnsureRelocSpaceForLazyDeoptimization(code); | 110 Deoptimizer::EnsureRelocSpaceForLazyDeoptimization(code); |
| 111 } | 111 } |
| 112 info()->CommitDependentMaps(code); | 112 info()->CommitDependencies(code); |
| 113 } | 113 } |
| 114 | 114 |
| 115 | 115 |
| 116 void LCodeGen::Abort(const char* reason) { | 116 void LCodeGen::Abort(const char* reason) { |
| 117 info()->set_bailout_reason(reason); | 117 info()->set_bailout_reason(reason); |
| 118 status_ = ABORTED; | 118 status_ = ABORTED; |
| 119 } | 119 } |
| 120 | 120 |
| 121 | 121 |
| 122 void LCodeGen::Comment(const char* format, ...) { | 122 void LCodeGen::Comment(const char* format, ...) { |
| (...skipping 527 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 650 break; | 650 break; |
| 651 case STUB: | 651 case STUB: |
| 652 translation->BeginCompiledStubFrame(); | 652 translation->BeginCompiledStubFrame(); |
| 653 break; | 653 break; |
| 654 default: | 654 default: |
| 655 UNREACHABLE(); | 655 UNREACHABLE(); |
| 656 } | 656 } |
| 657 | 657 |
| 658 for (int i = 0; i < translation_size; ++i) { | 658 for (int i = 0; i < translation_size; ++i) { |
| 659 LOperand* value = environment->values()->at(i); | 659 LOperand* value = environment->values()->at(i); |
| 660 // spilled_registers_ and spilled_double_registers_ are either | |
| 661 // both NULL or both set. | |
| 662 if (environment->spilled_registers() != NULL && value != NULL) { | |
| 663 if (value->IsRegister() && | |
| 664 environment->spilled_registers()[value->index()] != NULL) { | |
| 665 translation->MarkDuplicate(); | |
| 666 AddToTranslation(translation, | |
| 667 environment->spilled_registers()[value->index()], | |
| 668 environment->HasTaggedValueAt(i), | |
| 669 environment->HasUint32ValueAt(i)); | |
| 670 } else if ( | |
| 671 value->IsDoubleRegister() && | |
| 672 environment->spilled_double_registers()[value->index()] != NULL) { | |
| 673 translation->MarkDuplicate(); | |
| 674 AddToTranslation( | |
| 675 translation, | |
| 676 environment->spilled_double_registers()[value->index()], | |
| 677 false, | |
| 678 false); | |
| 679 } | |
| 680 } | |
| 681 | 660 |
| 682 // TODO(mstarzinger): Introduce marker operands to indicate that this value | 661 // TODO(mstarzinger): Introduce marker operands to indicate that this value |
| 683 // is not present and must be reconstructed from the deoptimizer. Currently | 662 // is not present and must be reconstructed from the deoptimizer. Currently |
| 684 // this is only used for the arguments object. | 663 // this is only used for the arguments object. |
| 685 if (value == NULL) { | 664 if (value == NULL) { |
| 686 int arguments_count = environment->values()->length() - translation_size; | 665 int arguments_count = environment->values()->length() - translation_size; |
| 687 translation->BeginArgumentsObject(arguments_count); | 666 translation->BeginArgumentsObject(arguments_count); |
| 688 for (int i = 0; i < arguments_count; ++i) { | 667 for (int i = 0; i < arguments_count; ++i) { |
| 689 LOperand* value = environment->values()->at(translation_size + i); | 668 LOperand* value = environment->values()->at(translation_size + i); |
| 690 ASSERT(environment->spilled_registers() == NULL || | |
| 691 !value->IsRegister() || | |
| 692 environment->spilled_registers()[value->index()] == NULL); | |
| 693 ASSERT(environment->spilled_registers() == NULL || | |
| 694 !value->IsDoubleRegister() || | |
| 695 environment->spilled_double_registers()[value->index()] == NULL); | |
| 696 AddToTranslation(translation, | 669 AddToTranslation(translation, |
| 697 value, | 670 value, |
| 698 environment->HasTaggedValueAt(translation_size + i), | 671 environment->HasTaggedValueAt(translation_size + i), |
| 699 environment->HasUint32ValueAt(translation_size + i)); | 672 environment->HasUint32ValueAt(translation_size + i)); |
| 700 } | 673 } |
| 701 continue; | 674 continue; |
| 702 } | 675 } |
| 703 | 676 |
| 704 AddToTranslation(translation, | 677 AddToTranslation(translation, |
| 705 value, | 678 value, |
| (...skipping 476 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1182 CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr); | 1155 CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr); |
| 1183 break; | 1156 break; |
| 1184 } | 1157 } |
| 1185 default: | 1158 default: |
| 1186 UNREACHABLE(); | 1159 UNREACHABLE(); |
| 1187 } | 1160 } |
| 1188 } | 1161 } |
| 1189 | 1162 |
| 1190 | 1163 |
| 1191 void LCodeGen::DoUnknownOSRValue(LUnknownOSRValue* instr) { | 1164 void LCodeGen::DoUnknownOSRValue(LUnknownOSRValue* instr) { |
| 1192 // Nothing to do. | 1165 // Record the address of the first unknown OSR value as the place to enter. |
| 1166 if (osr_pc_offset_ == -1) osr_pc_offset_ = masm()->pc_offset(); |
| 1193 } | 1167 } |
| 1194 | 1168 |
| 1195 | 1169 |
| 1196 void LCodeGen::DoModI(LModI* instr) { | 1170 void LCodeGen::DoModI(LModI* instr) { |
| 1197 HMod* hmod = instr->hydrogen(); | 1171 HMod* hmod = instr->hydrogen(); |
| 1198 HValue* left = hmod->left(); | 1172 HValue* left = hmod->left(); |
| 1199 HValue* right = hmod->right(); | 1173 HValue* right = hmod->right(); |
| 1200 if (hmod->HasPowerOf2Divisor()) { | 1174 if (hmod->HasPowerOf2Divisor()) { |
| 1201 // TODO(svenpanne) We should really do the strength reduction on the | 1175 // TODO(svenpanne) We should really do the strength reduction on the |
| 1202 // Hydrogen level. | 1176 // Hydrogen level. |
| (...skipping 13 matching lines...) Expand all Loading... |
| 1216 if (hmod->CheckFlag(HValue::kBailoutOnMinusZero)) { | 1190 if (hmod->CheckFlag(HValue::kBailoutOnMinusZero)) { |
| 1217 DeoptimizeIf(zero, instr->environment()); | 1191 DeoptimizeIf(zero, instr->environment()); |
| 1218 } | 1192 } |
| 1219 __ jmp(&done, Label::kNear); | 1193 __ jmp(&done, Label::kNear); |
| 1220 } | 1194 } |
| 1221 | 1195 |
| 1222 __ bind(&left_is_not_negative); | 1196 __ bind(&left_is_not_negative); |
| 1223 __ and_(left_reg, divisor - 1); | 1197 __ and_(left_reg, divisor - 1); |
| 1224 __ bind(&done); | 1198 __ bind(&done); |
| 1225 | 1199 |
| 1226 } else if (hmod->has_fixed_right_arg()) { | 1200 } else if (hmod->fixed_right_arg().has_value) { |
| 1227 Register left_reg = ToRegister(instr->left()); | 1201 Register left_reg = ToRegister(instr->left()); |
| 1228 ASSERT(left_reg.is(ToRegister(instr->result()))); | 1202 ASSERT(left_reg.is(ToRegister(instr->result()))); |
| 1229 Register right_reg = ToRegister(instr->right()); | 1203 Register right_reg = ToRegister(instr->right()); |
| 1230 | 1204 |
| 1231 int32_t divisor = hmod->fixed_right_arg_value(); | 1205 int32_t divisor = hmod->fixed_right_arg().value; |
| 1232 ASSERT(IsPowerOf2(divisor)); | 1206 ASSERT(IsPowerOf2(divisor)); |
| 1233 | 1207 |
| 1234 // Check if our assumption of a fixed right operand still holds. | 1208 // Check if our assumption of a fixed right operand still holds. |
| 1235 __ cmp(right_reg, Immediate(divisor)); | 1209 __ cmp(right_reg, Immediate(divisor)); |
| 1236 DeoptimizeIf(not_equal, instr->environment()); | 1210 DeoptimizeIf(not_equal, instr->environment()); |
| 1237 | 1211 |
| 1238 Label left_is_not_negative, done; | 1212 Label left_is_not_negative, done; |
| 1239 if (left->CanBeNegative()) { | 1213 if (left->CanBeNegative()) { |
| 1240 __ test(left_reg, Operand(left_reg)); | 1214 __ test(left_reg, Operand(left_reg)); |
| 1241 __ j(not_sign, &left_is_not_negative, Label::kNear); | 1215 __ j(not_sign, &left_is_not_negative, Label::kNear); |
| (...skipping 587 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1829 } | 1803 } |
| 1830 | 1804 |
| 1831 | 1805 |
| 1832 void LCodeGen::DoValueOf(LValueOf* instr) { | 1806 void LCodeGen::DoValueOf(LValueOf* instr) { |
| 1833 Register input = ToRegister(instr->value()); | 1807 Register input = ToRegister(instr->value()); |
| 1834 Register result = ToRegister(instr->result()); | 1808 Register result = ToRegister(instr->result()); |
| 1835 Register map = ToRegister(instr->temp()); | 1809 Register map = ToRegister(instr->temp()); |
| 1836 ASSERT(input.is(result)); | 1810 ASSERT(input.is(result)); |
| 1837 | 1811 |
| 1838 Label done; | 1812 Label done; |
| 1839 // If the object is a smi return the object. | 1813 |
| 1840 __ JumpIfSmi(input, &done, Label::kNear); | 1814 if (!instr->hydrogen()->value()->IsHeapObject()) { |
| 1815 // If the object is a smi return the object. |
| 1816 __ JumpIfSmi(input, &done, Label::kNear); |
| 1817 } |
| 1841 | 1818 |
| 1842 // If the object is not a value type, return the object. | 1819 // If the object is not a value type, return the object. |
| 1843 __ CmpObjectType(input, JS_VALUE_TYPE, map); | 1820 __ CmpObjectType(input, JS_VALUE_TYPE, map); |
| 1844 __ j(not_equal, &done, Label::kNear); | 1821 __ j(not_equal, &done, Label::kNear); |
| 1845 __ mov(result, FieldOperand(input, JSValue::kValueOffset)); | 1822 __ mov(result, FieldOperand(input, JSValue::kValueOffset)); |
| 1846 | 1823 |
| 1847 __ bind(&done); | 1824 __ bind(&done); |
| 1848 } | 1825 } |
| 1849 | 1826 |
| 1850 | 1827 |
| (...skipping 229 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2080 | 2057 |
| 2081 | 2058 |
| 2082 int LCodeGen::GetNextEmittedBlock() const { | 2059 int LCodeGen::GetNextEmittedBlock() const { |
| 2083 for (int i = current_block_ + 1; i < graph()->blocks()->length(); ++i) { | 2060 for (int i = current_block_ + 1; i < graph()->blocks()->length(); ++i) { |
| 2084 if (!chunk_->GetLabel(i)->HasReplacement()) return i; | 2061 if (!chunk_->GetLabel(i)->HasReplacement()) return i; |
| 2085 } | 2062 } |
| 2086 return -1; | 2063 return -1; |
| 2087 } | 2064 } |
| 2088 | 2065 |
| 2089 | 2066 |
| 2090 void LCodeGen::EmitBranch(int left_block, int right_block, Condition cc) { | 2067 template<class InstrType> |
| 2068 void LCodeGen::EmitBranch(InstrType instr, Condition cc) { |
| 2069 int right_block = instr->FalseDestination(chunk_); |
| 2070 int left_block = instr->TrueDestination(chunk_); |
| 2071 |
| 2091 int next_block = GetNextEmittedBlock(); | 2072 int next_block = GetNextEmittedBlock(); |
| 2092 right_block = chunk_->LookupDestination(right_block); | |
| 2093 left_block = chunk_->LookupDestination(left_block); | |
| 2094 | 2073 |
| 2095 if (right_block == left_block) { | 2074 if (right_block == left_block) { |
| 2096 EmitGoto(left_block); | 2075 EmitGoto(left_block); |
| 2097 } else if (left_block == next_block) { | 2076 } else if (left_block == next_block) { |
| 2098 __ j(NegateCondition(cc), chunk_->GetAssemblyLabel(right_block)); | 2077 __ j(NegateCondition(cc), chunk_->GetAssemblyLabel(right_block)); |
| 2099 } else if (right_block == next_block) { | 2078 } else if (right_block == next_block) { |
| 2100 __ j(cc, chunk_->GetAssemblyLabel(left_block)); | 2079 __ j(cc, chunk_->GetAssemblyLabel(left_block)); |
| 2101 } else { | 2080 } else { |
| 2102 __ j(cc, chunk_->GetAssemblyLabel(left_block)); | 2081 __ j(cc, chunk_->GetAssemblyLabel(left_block)); |
| 2103 __ jmp(chunk_->GetAssemblyLabel(right_block)); | 2082 __ jmp(chunk_->GetAssemblyLabel(right_block)); |
| 2104 } | 2083 } |
| 2105 } | 2084 } |
| 2106 | 2085 |
| 2107 | 2086 |
| 2108 void LCodeGen::DoBranch(LBranch* instr) { | 2087 void LCodeGen::DoBranch(LBranch* instr) { |
| 2109 int true_block = chunk_->LookupDestination(instr->true_block_id()); | |
| 2110 int false_block = chunk_->LookupDestination(instr->false_block_id()); | |
| 2111 | |
| 2112 Representation r = instr->hydrogen()->value()->representation(); | 2088 Representation r = instr->hydrogen()->value()->representation(); |
| 2113 if (r.IsSmiOrInteger32()) { | 2089 if (r.IsSmiOrInteger32()) { |
| 2114 ASSERT(!info()->IsStub()); | 2090 ASSERT(!info()->IsStub()); |
| 2115 Register reg = ToRegister(instr->value()); | 2091 Register reg = ToRegister(instr->value()); |
| 2116 __ test(reg, Operand(reg)); | 2092 __ test(reg, Operand(reg)); |
| 2117 EmitBranch(true_block, false_block, not_zero); | 2093 EmitBranch(instr, not_zero); |
| 2118 } else if (r.IsDouble()) { | 2094 } else if (r.IsDouble()) { |
| 2119 ASSERT(!info()->IsStub()); | 2095 ASSERT(!info()->IsStub()); |
| 2120 CpuFeatureScope scope(masm(), SSE2); | 2096 CpuFeatureScope scope(masm(), SSE2); |
| 2121 XMMRegister reg = ToDoubleRegister(instr->value()); | 2097 XMMRegister reg = ToDoubleRegister(instr->value()); |
| 2122 __ xorps(xmm0, xmm0); | 2098 __ xorps(xmm0, xmm0); |
| 2123 __ ucomisd(reg, xmm0); | 2099 __ ucomisd(reg, xmm0); |
| 2124 EmitBranch(true_block, false_block, not_equal); | 2100 EmitBranch(instr, not_equal); |
| 2125 } else { | 2101 } else { |
| 2126 ASSERT(r.IsTagged()); | 2102 ASSERT(r.IsTagged()); |
| 2127 Register reg = ToRegister(instr->value()); | 2103 Register reg = ToRegister(instr->value()); |
| 2128 HType type = instr->hydrogen()->value()->type(); | 2104 HType type = instr->hydrogen()->value()->type(); |
| 2129 if (type.IsBoolean()) { | 2105 if (type.IsBoolean()) { |
| 2130 ASSERT(!info()->IsStub()); | 2106 ASSERT(!info()->IsStub()); |
| 2131 __ cmp(reg, factory()->true_value()); | 2107 __ cmp(reg, factory()->true_value()); |
| 2132 EmitBranch(true_block, false_block, equal); | 2108 EmitBranch(instr, equal); |
| 2133 } else if (type.IsSmi()) { | 2109 } else if (type.IsSmi()) { |
| 2134 ASSERT(!info()->IsStub()); | 2110 ASSERT(!info()->IsStub()); |
| 2135 __ test(reg, Operand(reg)); | 2111 __ test(reg, Operand(reg)); |
| 2136 EmitBranch(true_block, false_block, not_equal); | 2112 EmitBranch(instr, not_equal); |
| 2113 } else if (type.IsJSArray()) { |
| 2114 ASSERT(!info()->IsStub()); |
| 2115 EmitBranch(instr, no_condition); |
| 2116 } else if (type.IsHeapNumber()) { |
| 2117 ASSERT(!info()->IsStub()); |
| 2118 CpuFeatureScope scope(masm(), SSE2); |
| 2119 __ xorps(xmm0, xmm0); |
| 2120 __ ucomisd(xmm0, FieldOperand(reg, HeapNumber::kValueOffset)); |
| 2121 EmitBranch(instr, not_equal); |
| 2122 } else if (type.IsString()) { |
| 2123 ASSERT(!info()->IsStub()); |
| 2124 __ cmp(FieldOperand(reg, String::kLengthOffset), Immediate(0)); |
| 2125 EmitBranch(instr, not_equal); |
| 2137 } else { | 2126 } else { |
| 2138 Label* true_label = chunk_->GetAssemblyLabel(true_block); | |
| 2139 Label* false_label = chunk_->GetAssemblyLabel(false_block); | |
| 2140 | |
| 2141 ToBooleanStub::Types expected = instr->hydrogen()->expected_input_types(); | 2127 ToBooleanStub::Types expected = instr->hydrogen()->expected_input_types(); |
| 2142 // Avoid deopts in the case where we've never executed this path before. | 2128 if (expected.IsEmpty()) expected = ToBooleanStub::Types::Generic(); |
| 2143 if (expected.IsEmpty()) expected = ToBooleanStub::all_types(); | |
| 2144 | 2129 |
| 2145 if (expected.Contains(ToBooleanStub::UNDEFINED)) { | 2130 if (expected.Contains(ToBooleanStub::UNDEFINED)) { |
| 2146 // undefined -> false. | 2131 // undefined -> false. |
| 2147 __ cmp(reg, factory()->undefined_value()); | 2132 __ cmp(reg, factory()->undefined_value()); |
| 2148 __ j(equal, false_label); | 2133 __ j(equal, instr->FalseLabel(chunk_)); |
| 2149 } | 2134 } |
| 2150 if (expected.Contains(ToBooleanStub::BOOLEAN)) { | 2135 if (expected.Contains(ToBooleanStub::BOOLEAN)) { |
| 2151 // true -> true. | 2136 // true -> true. |
| 2152 __ cmp(reg, factory()->true_value()); | 2137 __ cmp(reg, factory()->true_value()); |
| 2153 __ j(equal, true_label); | 2138 __ j(equal, instr->TrueLabel(chunk_)); |
| 2154 // false -> false. | 2139 // false -> false. |
| 2155 __ cmp(reg, factory()->false_value()); | 2140 __ cmp(reg, factory()->false_value()); |
| 2156 __ j(equal, false_label); | 2141 __ j(equal, instr->FalseLabel(chunk_)); |
| 2157 } | 2142 } |
| 2158 if (expected.Contains(ToBooleanStub::NULL_TYPE)) { | 2143 if (expected.Contains(ToBooleanStub::NULL_TYPE)) { |
| 2159 // 'null' -> false. | 2144 // 'null' -> false. |
| 2160 __ cmp(reg, factory()->null_value()); | 2145 __ cmp(reg, factory()->null_value()); |
| 2161 __ j(equal, false_label); | 2146 __ j(equal, instr->FalseLabel(chunk_)); |
| 2162 } | 2147 } |
| 2163 | 2148 |
| 2164 if (expected.Contains(ToBooleanStub::SMI)) { | 2149 if (expected.Contains(ToBooleanStub::SMI)) { |
| 2165 // Smis: 0 -> false, all other -> true. | 2150 // Smis: 0 -> false, all other -> true. |
| 2166 __ test(reg, Operand(reg)); | 2151 __ test(reg, Operand(reg)); |
| 2167 __ j(equal, false_label); | 2152 __ j(equal, instr->FalseLabel(chunk_)); |
| 2168 __ JumpIfSmi(reg, true_label); | 2153 __ JumpIfSmi(reg, instr->TrueLabel(chunk_)); |
| 2169 } else if (expected.NeedsMap()) { | 2154 } else if (expected.NeedsMap()) { |
| 2170 // If we need a map later and have a Smi -> deopt. | 2155 // If we need a map later and have a Smi -> deopt. |
| 2171 __ test(reg, Immediate(kSmiTagMask)); | 2156 __ test(reg, Immediate(kSmiTagMask)); |
| 2172 DeoptimizeIf(zero, instr->environment()); | 2157 DeoptimizeIf(zero, instr->environment()); |
| 2173 } | 2158 } |
| 2174 | 2159 |
| 2175 Register map = no_reg; // Keep the compiler happy. | 2160 Register map = no_reg; // Keep the compiler happy. |
| 2176 if (expected.NeedsMap()) { | 2161 if (expected.NeedsMap()) { |
| 2177 map = ToRegister(instr->temp()); | 2162 map = ToRegister(instr->temp()); |
| 2178 ASSERT(!map.is(reg)); | 2163 ASSERT(!map.is(reg)); |
| 2179 __ mov(map, FieldOperand(reg, HeapObject::kMapOffset)); | 2164 __ mov(map, FieldOperand(reg, HeapObject::kMapOffset)); |
| 2180 | 2165 |
| 2181 if (expected.CanBeUndetectable()) { | 2166 if (expected.CanBeUndetectable()) { |
| 2182 // Undetectable -> false. | 2167 // Undetectable -> false. |
| 2183 __ test_b(FieldOperand(map, Map::kBitFieldOffset), | 2168 __ test_b(FieldOperand(map, Map::kBitFieldOffset), |
| 2184 1 << Map::kIsUndetectable); | 2169 1 << Map::kIsUndetectable); |
| 2185 __ j(not_zero, false_label); | 2170 __ j(not_zero, instr->FalseLabel(chunk_)); |
| 2186 } | 2171 } |
| 2187 } | 2172 } |
| 2188 | 2173 |
| 2189 if (expected.Contains(ToBooleanStub::SPEC_OBJECT)) { | 2174 if (expected.Contains(ToBooleanStub::SPEC_OBJECT)) { |
| 2190 // spec object -> true. | 2175 // spec object -> true. |
| 2191 __ CmpInstanceType(map, FIRST_SPEC_OBJECT_TYPE); | 2176 __ CmpInstanceType(map, FIRST_SPEC_OBJECT_TYPE); |
| 2192 __ j(above_equal, true_label); | 2177 __ j(above_equal, instr->TrueLabel(chunk_)); |
| 2193 } | 2178 } |
| 2194 | 2179 |
| 2195 if (expected.Contains(ToBooleanStub::STRING)) { | 2180 if (expected.Contains(ToBooleanStub::STRING)) { |
| 2196 // String value -> false iff empty. | 2181 // String value -> false iff empty. |
| 2197 Label not_string; | 2182 Label not_string; |
| 2198 __ CmpInstanceType(map, FIRST_NONSTRING_TYPE); | 2183 __ CmpInstanceType(map, FIRST_NONSTRING_TYPE); |
| 2199 __ j(above_equal, ¬_string, Label::kNear); | 2184 __ j(above_equal, ¬_string, Label::kNear); |
| 2200 __ cmp(FieldOperand(reg, String::kLengthOffset), Immediate(0)); | 2185 __ cmp(FieldOperand(reg, String::kLengthOffset), Immediate(0)); |
| 2201 __ j(not_zero, true_label); | 2186 __ j(not_zero, instr->TrueLabel(chunk_)); |
| 2202 __ jmp(false_label); | 2187 __ jmp(instr->FalseLabel(chunk_)); |
| 2203 __ bind(¬_string); | 2188 __ bind(¬_string); |
| 2204 } | 2189 } |
| 2205 | 2190 |
| 2206 if (expected.Contains(ToBooleanStub::SYMBOL)) { | 2191 if (expected.Contains(ToBooleanStub::SYMBOL)) { |
| 2207 // Symbol value -> true. | 2192 // Symbol value -> true. |
| 2208 __ CmpInstanceType(map, SYMBOL_TYPE); | 2193 __ CmpInstanceType(map, SYMBOL_TYPE); |
| 2209 __ j(equal, true_label); | 2194 __ j(equal, instr->TrueLabel(chunk_)); |
| 2210 } | 2195 } |
| 2211 | 2196 |
| 2212 if (expected.Contains(ToBooleanStub::HEAP_NUMBER)) { | 2197 if (expected.Contains(ToBooleanStub::HEAP_NUMBER)) { |
| 2213 // heap number -> false iff +0, -0, or NaN. | 2198 // heap number -> false iff +0, -0, or NaN. |
| 2214 Label not_heap_number; | 2199 Label not_heap_number; |
| 2215 __ cmp(FieldOperand(reg, HeapObject::kMapOffset), | 2200 __ cmp(FieldOperand(reg, HeapObject::kMapOffset), |
| 2216 factory()->heap_number_map()); | 2201 factory()->heap_number_map()); |
| 2217 __ j(not_equal, ¬_heap_number, Label::kNear); | 2202 __ j(not_equal, ¬_heap_number, Label::kNear); |
| 2218 if (CpuFeatures::IsSafeForSnapshot(SSE2)) { | 2203 if (CpuFeatures::IsSafeForSnapshot(SSE2)) { |
| 2219 CpuFeatureScope scope(masm(), SSE2); | 2204 CpuFeatureScope scope(masm(), SSE2); |
| 2220 __ xorps(xmm0, xmm0); | 2205 __ xorps(xmm0, xmm0); |
| 2221 __ ucomisd(xmm0, FieldOperand(reg, HeapNumber::kValueOffset)); | 2206 __ ucomisd(xmm0, FieldOperand(reg, HeapNumber::kValueOffset)); |
| 2222 } else { | 2207 } else { |
| 2223 __ fldz(); | 2208 __ fldz(); |
| 2224 __ fld_d(FieldOperand(reg, HeapNumber::kValueOffset)); | 2209 __ fld_d(FieldOperand(reg, HeapNumber::kValueOffset)); |
| 2225 __ FCmp(); | 2210 __ FCmp(); |
| 2226 } | 2211 } |
| 2227 __ j(zero, false_label); | 2212 __ j(zero, instr->FalseLabel(chunk_)); |
| 2228 __ jmp(true_label); | 2213 __ jmp(instr->TrueLabel(chunk_)); |
| 2229 __ bind(¬_heap_number); | 2214 __ bind(¬_heap_number); |
| 2230 } | 2215 } |
| 2231 | 2216 |
| 2232 // We've seen something for the first time -> deopt. | 2217 if (!expected.IsGeneric()) { |
| 2233 DeoptimizeIf(no_condition, instr->environment()); | 2218 // We've seen something for the first time -> deopt. |
| 2219 // This can only happen if we are not generic already. |
| 2220 DeoptimizeIf(no_condition, instr->environment()); |
| 2221 } |
| 2234 } | 2222 } |
| 2235 } | 2223 } |
| 2236 } | 2224 } |
| 2237 | 2225 |
| 2238 | 2226 |
| 2239 void LCodeGen::EmitGoto(int block) { | 2227 void LCodeGen::EmitGoto(int block) { |
| 2240 if (!IsNextEmittedBlock(block)) { | 2228 if (!IsNextEmittedBlock(block)) { |
| 2241 __ jmp(chunk_->GetAssemblyLabel(chunk_->LookupDestination(block))); | 2229 __ jmp(chunk_->GetAssemblyLabel(LookupDestination(block))); |
| 2242 } | 2230 } |
| 2243 } | 2231 } |
| 2244 | 2232 |
| 2245 | 2233 |
| 2246 void LCodeGen::DoGoto(LGoto* instr) { | 2234 void LCodeGen::DoGoto(LGoto* instr) { |
| 2247 EmitGoto(instr->block_id()); | 2235 EmitGoto(instr->block_id()); |
| 2248 } | 2236 } |
| 2249 | 2237 |
| 2250 | 2238 |
| 2251 Condition LCodeGen::TokenToCondition(Token::Value op, bool is_unsigned) { | 2239 Condition LCodeGen::TokenToCondition(Token::Value op, bool is_unsigned) { |
| (...skipping 20 matching lines...) Expand all Loading... |
| 2272 default: | 2260 default: |
| 2273 UNREACHABLE(); | 2261 UNREACHABLE(); |
| 2274 } | 2262 } |
| 2275 return cond; | 2263 return cond; |
| 2276 } | 2264 } |
| 2277 | 2265 |
| 2278 | 2266 |
| 2279 void LCodeGen::DoCmpIDAndBranch(LCmpIDAndBranch* instr) { | 2267 void LCodeGen::DoCmpIDAndBranch(LCmpIDAndBranch* instr) { |
| 2280 LOperand* left = instr->left(); | 2268 LOperand* left = instr->left(); |
| 2281 LOperand* right = instr->right(); | 2269 LOperand* right = instr->right(); |
| 2282 int false_block = chunk_->LookupDestination(instr->false_block_id()); | |
| 2283 int true_block = chunk_->LookupDestination(instr->true_block_id()); | |
| 2284 Condition cc = TokenToCondition(instr->op(), instr->is_double()); | 2270 Condition cc = TokenToCondition(instr->op(), instr->is_double()); |
| 2285 | 2271 |
| 2286 if (left->IsConstantOperand() && right->IsConstantOperand()) { | 2272 if (left->IsConstantOperand() && right->IsConstantOperand()) { |
| 2287 // We can statically evaluate the comparison. | 2273 // We can statically evaluate the comparison. |
| 2288 double left_val = ToDouble(LConstantOperand::cast(left)); | 2274 double left_val = ToDouble(LConstantOperand::cast(left)); |
| 2289 double right_val = ToDouble(LConstantOperand::cast(right)); | 2275 double right_val = ToDouble(LConstantOperand::cast(right)); |
| 2290 int next_block = | 2276 int next_block = EvalComparison(instr->op(), left_val, right_val) ? |
| 2291 EvalComparison(instr->op(), left_val, right_val) ? true_block | 2277 instr->TrueDestination(chunk_) : instr->FalseDestination(chunk_); |
| 2292 : false_block; | |
| 2293 EmitGoto(next_block); | 2278 EmitGoto(next_block); |
| 2294 } else { | 2279 } else { |
| 2295 if (instr->is_double()) { | 2280 if (instr->is_double()) { |
| 2296 CpuFeatureScope scope(masm(), SSE2); | 2281 CpuFeatureScope scope(masm(), SSE2); |
| 2297 // Don't base result on EFLAGS when a NaN is involved. Instead | 2282 // Don't base result on EFLAGS when a NaN is involved. Instead |
| 2298 // jump to the false block. | 2283 // jump to the false block. |
| 2299 __ ucomisd(ToDoubleRegister(left), ToDoubleRegister(right)); | 2284 __ ucomisd(ToDoubleRegister(left), ToDoubleRegister(right)); |
| 2300 __ j(parity_even, chunk_->GetAssemblyLabel(false_block)); | 2285 __ j(parity_even, instr->FalseLabel(chunk_)); |
| 2301 } else { | 2286 } else { |
| 2302 if (right->IsConstantOperand()) { | 2287 if (right->IsConstantOperand()) { |
| 2303 int32_t const_value = ToInteger32(LConstantOperand::cast(right)); | 2288 int32_t const_value = ToInteger32(LConstantOperand::cast(right)); |
| 2304 if (instr->hydrogen_value()->representation().IsSmi()) { | 2289 if (instr->hydrogen_value()->representation().IsSmi()) { |
| 2305 __ cmp(ToOperand(left), Immediate(Smi::FromInt(const_value))); | 2290 __ cmp(ToOperand(left), Immediate(Smi::FromInt(const_value))); |
| 2306 } else { | 2291 } else { |
| 2307 __ cmp(ToOperand(left), Immediate(const_value)); | 2292 __ cmp(ToOperand(left), Immediate(const_value)); |
| 2308 } | 2293 } |
| 2309 } else if (left->IsConstantOperand()) { | 2294 } else if (left->IsConstantOperand()) { |
| 2310 int32_t const_value = ToInteger32(LConstantOperand::cast(left)); | 2295 int32_t const_value = ToInteger32(LConstantOperand::cast(left)); |
| 2311 if (instr->hydrogen_value()->representation().IsSmi()) { | 2296 if (instr->hydrogen_value()->representation().IsSmi()) { |
| 2312 __ cmp(ToOperand(right), Immediate(Smi::FromInt(const_value))); | 2297 __ cmp(ToOperand(right), Immediate(Smi::FromInt(const_value))); |
| 2313 } else { | 2298 } else { |
| 2314 __ cmp(ToOperand(right), Immediate(const_value)); | 2299 __ cmp(ToOperand(right), Immediate(const_value)); |
| 2315 } | 2300 } |
| 2316 // We transposed the operands. Reverse the condition. | 2301 // We transposed the operands. Reverse the condition. |
| 2317 cc = ReverseCondition(cc); | 2302 cc = ReverseCondition(cc); |
| 2318 } else { | 2303 } else { |
| 2319 __ cmp(ToRegister(left), ToOperand(right)); | 2304 __ cmp(ToRegister(left), ToOperand(right)); |
| 2320 } | 2305 } |
| 2321 } | 2306 } |
| 2322 EmitBranch(true_block, false_block, cc); | 2307 EmitBranch(instr, cc); |
| 2323 } | 2308 } |
| 2324 } | 2309 } |
| 2325 | 2310 |
| 2326 | 2311 |
| 2327 void LCodeGen::DoCmpObjectEqAndBranch(LCmpObjectEqAndBranch* instr) { | 2312 void LCodeGen::DoCmpObjectEqAndBranch(LCmpObjectEqAndBranch* instr) { |
| 2328 Register left = ToRegister(instr->left()); | 2313 Register left = ToRegister(instr->left()); |
| 2329 int false_block = chunk_->LookupDestination(instr->false_block_id()); | |
| 2330 int true_block = chunk_->LookupDestination(instr->true_block_id()); | |
| 2331 | 2314 |
| 2332 if (instr->right()->IsConstantOperand()) { | 2315 if (instr->right()->IsConstantOperand()) { |
| 2333 Handle<Object> right = ToHandle(LConstantOperand::cast(instr->right())); | 2316 Handle<Object> right = ToHandle(LConstantOperand::cast(instr->right())); |
| 2334 __ CmpObject(left, right); | 2317 __ CmpObject(left, right); |
| 2335 } else { | 2318 } else { |
| 2336 Operand right = ToOperand(instr->right()); | 2319 Operand right = ToOperand(instr->right()); |
| 2337 __ cmp(left, right); | 2320 __ cmp(left, right); |
| 2338 } | 2321 } |
| 2339 EmitBranch(true_block, false_block, equal); | 2322 EmitBranch(instr, equal); |
| 2340 } | 2323 } |
| 2341 | 2324 |
| 2342 | 2325 |
| 2343 void LCodeGen::DoCmpConstantEqAndBranch(LCmpConstantEqAndBranch* instr) { | 2326 void LCodeGen::DoCmpConstantEqAndBranch(LCmpConstantEqAndBranch* instr) { |
| 2344 Register left = ToRegister(instr->left()); | 2327 Register left = ToRegister(instr->left()); |
| 2345 int true_block = chunk_->LookupDestination(instr->true_block_id()); | |
| 2346 int false_block = chunk_->LookupDestination(instr->false_block_id()); | |
| 2347 | 2328 |
| 2348 __ cmp(left, instr->hydrogen()->right()); | 2329 __ cmp(left, instr->hydrogen()->right()); |
| 2349 EmitBranch(true_block, false_block, equal); | 2330 EmitBranch(instr, equal); |
| 2350 } | 2331 } |
| 2351 | 2332 |
| 2352 | 2333 |
| 2353 Condition LCodeGen::EmitIsObject(Register input, | 2334 Condition LCodeGen::EmitIsObject(Register input, |
| 2354 Register temp1, | 2335 Register temp1, |
| 2355 Label* is_not_object, | 2336 Label* is_not_object, |
| 2356 Label* is_object) { | 2337 Label* is_object) { |
| 2357 __ JumpIfSmi(input, is_not_object); | 2338 __ JumpIfSmi(input, is_not_object); |
| 2358 | 2339 |
| 2359 __ cmp(input, isolate()->factory()->null_value()); | 2340 __ cmp(input, isolate()->factory()->null_value()); |
| (...skipping 10 matching lines...) Expand all Loading... |
| 2370 __ j(below, is_not_object); | 2351 __ j(below, is_not_object); |
| 2371 __ cmp(temp1, LAST_NONCALLABLE_SPEC_OBJECT_TYPE); | 2352 __ cmp(temp1, LAST_NONCALLABLE_SPEC_OBJECT_TYPE); |
| 2372 return below_equal; | 2353 return below_equal; |
| 2373 } | 2354 } |
| 2374 | 2355 |
| 2375 | 2356 |
| 2376 void LCodeGen::DoIsObjectAndBranch(LIsObjectAndBranch* instr) { | 2357 void LCodeGen::DoIsObjectAndBranch(LIsObjectAndBranch* instr) { |
| 2377 Register reg = ToRegister(instr->value()); | 2358 Register reg = ToRegister(instr->value()); |
| 2378 Register temp = ToRegister(instr->temp()); | 2359 Register temp = ToRegister(instr->temp()); |
| 2379 | 2360 |
| 2380 int true_block = chunk_->LookupDestination(instr->true_block_id()); | 2361 Condition true_cond = EmitIsObject( |
| 2381 int false_block = chunk_->LookupDestination(instr->false_block_id()); | 2362 reg, temp, instr->FalseLabel(chunk_), instr->TrueLabel(chunk_)); |
| 2382 Label* true_label = chunk_->GetAssemblyLabel(true_block); | |
| 2383 Label* false_label = chunk_->GetAssemblyLabel(false_block); | |
| 2384 | 2363 |
| 2385 Condition true_cond = EmitIsObject(reg, temp, false_label, true_label); | 2364 EmitBranch(instr, true_cond); |
| 2386 | |
| 2387 EmitBranch(true_block, false_block, true_cond); | |
| 2388 } | 2365 } |
| 2389 | 2366 |
| 2390 | 2367 |
| 2391 Condition LCodeGen::EmitIsString(Register input, | 2368 Condition LCodeGen::EmitIsString(Register input, |
| 2392 Register temp1, | 2369 Register temp1, |
| 2393 Label* is_not_string) { | 2370 Label* is_not_string, |
| 2394 __ JumpIfSmi(input, is_not_string); | 2371 SmiCheck check_needed = INLINE_SMI_CHECK) { |
| 2372 if (check_needed == INLINE_SMI_CHECK) { |
| 2373 __ JumpIfSmi(input, is_not_string); |
| 2374 } |
| 2395 | 2375 |
| 2396 Condition cond = masm_->IsObjectStringType(input, temp1, temp1); | 2376 Condition cond = masm_->IsObjectStringType(input, temp1, temp1); |
| 2397 | 2377 |
| 2398 return cond; | 2378 return cond; |
| 2399 } | 2379 } |
| 2400 | 2380 |
| 2401 | 2381 |
| 2402 void LCodeGen::DoIsStringAndBranch(LIsStringAndBranch* instr) { | 2382 void LCodeGen::DoIsStringAndBranch(LIsStringAndBranch* instr) { |
| 2403 Register reg = ToRegister(instr->value()); | 2383 Register reg = ToRegister(instr->value()); |
| 2404 Register temp = ToRegister(instr->temp()); | 2384 Register temp = ToRegister(instr->temp()); |
| 2405 | 2385 |
| 2406 int true_block = chunk_->LookupDestination(instr->true_block_id()); | 2386 SmiCheck check_needed = |
| 2407 int false_block = chunk_->LookupDestination(instr->false_block_id()); | 2387 instr->hydrogen()->value()->IsHeapObject() |
| 2408 Label* false_label = chunk_->GetAssemblyLabel(false_block); | 2388 ? OMIT_SMI_CHECK : INLINE_SMI_CHECK; |
| 2409 | 2389 |
| 2410 Condition true_cond = EmitIsString(reg, temp, false_label); | 2390 Condition true_cond = EmitIsString( |
| 2391 reg, temp, instr->FalseLabel(chunk_), check_needed); |
| 2411 | 2392 |
| 2412 EmitBranch(true_block, false_block, true_cond); | 2393 EmitBranch(instr, true_cond); |
| 2413 } | 2394 } |
| 2414 | 2395 |
| 2415 | 2396 |
| 2416 void LCodeGen::DoIsSmiAndBranch(LIsSmiAndBranch* instr) { | 2397 void LCodeGen::DoIsSmiAndBranch(LIsSmiAndBranch* instr) { |
| 2417 Operand input = ToOperand(instr->value()); | 2398 Operand input = ToOperand(instr->value()); |
| 2418 | 2399 |
| 2419 int true_block = chunk_->LookupDestination(instr->true_block_id()); | |
| 2420 int false_block = chunk_->LookupDestination(instr->false_block_id()); | |
| 2421 | |
| 2422 __ test(input, Immediate(kSmiTagMask)); | 2400 __ test(input, Immediate(kSmiTagMask)); |
| 2423 EmitBranch(true_block, false_block, zero); | 2401 EmitBranch(instr, zero); |
| 2424 } | 2402 } |
| 2425 | 2403 |
| 2426 | 2404 |
| 2427 void LCodeGen::DoIsUndetectableAndBranch(LIsUndetectableAndBranch* instr) { | 2405 void LCodeGen::DoIsUndetectableAndBranch(LIsUndetectableAndBranch* instr) { |
| 2428 Register input = ToRegister(instr->value()); | 2406 Register input = ToRegister(instr->value()); |
| 2429 Register temp = ToRegister(instr->temp()); | 2407 Register temp = ToRegister(instr->temp()); |
| 2430 | 2408 |
| 2431 int true_block = chunk_->LookupDestination(instr->true_block_id()); | 2409 if (!instr->hydrogen()->value()->IsHeapObject()) { |
| 2432 int false_block = chunk_->LookupDestination(instr->false_block_id()); | 2410 STATIC_ASSERT(kSmiTag == 0); |
| 2433 | 2411 __ JumpIfSmi(input, instr->FalseLabel(chunk_)); |
| 2434 STATIC_ASSERT(kSmiTag == 0); | 2412 } |
| 2435 __ JumpIfSmi(input, chunk_->GetAssemblyLabel(false_block)); | |
| 2436 __ mov(temp, FieldOperand(input, HeapObject::kMapOffset)); | 2413 __ mov(temp, FieldOperand(input, HeapObject::kMapOffset)); |
| 2437 __ test_b(FieldOperand(temp, Map::kBitFieldOffset), | 2414 __ test_b(FieldOperand(temp, Map::kBitFieldOffset), |
| 2438 1 << Map::kIsUndetectable); | 2415 1 << Map::kIsUndetectable); |
| 2439 EmitBranch(true_block, false_block, not_zero); | 2416 EmitBranch(instr, not_zero); |
| 2440 } | 2417 } |
| 2441 | 2418 |
| 2442 | 2419 |
| 2443 static Condition ComputeCompareCondition(Token::Value op) { | 2420 static Condition ComputeCompareCondition(Token::Value op) { |
| 2444 switch (op) { | 2421 switch (op) { |
| 2445 case Token::EQ_STRICT: | 2422 case Token::EQ_STRICT: |
| 2446 case Token::EQ: | 2423 case Token::EQ: |
| 2447 return equal; | 2424 return equal; |
| 2448 case Token::LT: | 2425 case Token::LT: |
| 2449 return less; | 2426 return less; |
| 2450 case Token::GT: | 2427 case Token::GT: |
| 2451 return greater; | 2428 return greater; |
| 2452 case Token::LTE: | 2429 case Token::LTE: |
| 2453 return less_equal; | 2430 return less_equal; |
| 2454 case Token::GTE: | 2431 case Token::GTE: |
| 2455 return greater_equal; | 2432 return greater_equal; |
| 2456 default: | 2433 default: |
| 2457 UNREACHABLE(); | 2434 UNREACHABLE(); |
| 2458 return no_condition; | 2435 return no_condition; |
| 2459 } | 2436 } |
| 2460 } | 2437 } |
| 2461 | 2438 |
| 2462 | 2439 |
| 2463 void LCodeGen::DoStringCompareAndBranch(LStringCompareAndBranch* instr) { | 2440 void LCodeGen::DoStringCompareAndBranch(LStringCompareAndBranch* instr) { |
| 2464 Token::Value op = instr->op(); | 2441 Token::Value op = instr->op(); |
| 2465 int true_block = chunk_->LookupDestination(instr->true_block_id()); | |
| 2466 int false_block = chunk_->LookupDestination(instr->false_block_id()); | |
| 2467 | 2442 |
| 2468 Handle<Code> ic = CompareIC::GetUninitialized(isolate(), op); | 2443 Handle<Code> ic = CompareIC::GetUninitialized(isolate(), op); |
| 2469 CallCode(ic, RelocInfo::CODE_TARGET, instr); | 2444 CallCode(ic, RelocInfo::CODE_TARGET, instr); |
| 2470 | 2445 |
| 2471 Condition condition = ComputeCompareCondition(op); | 2446 Condition condition = ComputeCompareCondition(op); |
| 2472 __ test(eax, Operand(eax)); | 2447 __ test(eax, Operand(eax)); |
| 2473 | 2448 |
| 2474 EmitBranch(true_block, false_block, condition); | 2449 EmitBranch(instr, condition); |
| 2475 } | 2450 } |
| 2476 | 2451 |
| 2477 | 2452 |
| 2478 static InstanceType TestType(HHasInstanceTypeAndBranch* instr) { | 2453 static InstanceType TestType(HHasInstanceTypeAndBranch* instr) { |
| 2479 InstanceType from = instr->from(); | 2454 InstanceType from = instr->from(); |
| 2480 InstanceType to = instr->to(); | 2455 InstanceType to = instr->to(); |
| 2481 if (from == FIRST_TYPE) return to; | 2456 if (from == FIRST_TYPE) return to; |
| 2482 ASSERT(from == to || to == LAST_TYPE); | 2457 ASSERT(from == to || to == LAST_TYPE); |
| 2483 return from; | 2458 return from; |
| 2484 } | 2459 } |
| 2485 | 2460 |
| 2486 | 2461 |
| 2487 static Condition BranchCondition(HHasInstanceTypeAndBranch* instr) { | 2462 static Condition BranchCondition(HHasInstanceTypeAndBranch* instr) { |
| 2488 InstanceType from = instr->from(); | 2463 InstanceType from = instr->from(); |
| 2489 InstanceType to = instr->to(); | 2464 InstanceType to = instr->to(); |
| 2490 if (from == to) return equal; | 2465 if (from == to) return equal; |
| 2491 if (to == LAST_TYPE) return above_equal; | 2466 if (to == LAST_TYPE) return above_equal; |
| 2492 if (from == FIRST_TYPE) return below_equal; | 2467 if (from == FIRST_TYPE) return below_equal; |
| 2493 UNREACHABLE(); | 2468 UNREACHABLE(); |
| 2494 return equal; | 2469 return equal; |
| 2495 } | 2470 } |
| 2496 | 2471 |
| 2497 | 2472 |
| 2498 void LCodeGen::DoHasInstanceTypeAndBranch(LHasInstanceTypeAndBranch* instr) { | 2473 void LCodeGen::DoHasInstanceTypeAndBranch(LHasInstanceTypeAndBranch* instr) { |
| 2499 Register input = ToRegister(instr->value()); | 2474 Register input = ToRegister(instr->value()); |
| 2500 Register temp = ToRegister(instr->temp()); | 2475 Register temp = ToRegister(instr->temp()); |
| 2501 | 2476 |
| 2502 int true_block = chunk_->LookupDestination(instr->true_block_id()); | 2477 if (!instr->hydrogen()->value()->IsHeapObject()) { |
| 2503 int false_block = chunk_->LookupDestination(instr->false_block_id()); | 2478 __ JumpIfSmi(input, instr->FalseLabel(chunk_)); |
| 2504 | 2479 } |
| 2505 Label* false_label = chunk_->GetAssemblyLabel(false_block); | |
| 2506 | |
| 2507 __ JumpIfSmi(input, false_label); | |
| 2508 | 2480 |
| 2509 __ CmpObjectType(input, TestType(instr->hydrogen()), temp); | 2481 __ CmpObjectType(input, TestType(instr->hydrogen()), temp); |
| 2510 EmitBranch(true_block, false_block, BranchCondition(instr->hydrogen())); | 2482 EmitBranch(instr, BranchCondition(instr->hydrogen())); |
| 2511 } | 2483 } |
| 2512 | 2484 |
| 2513 | 2485 |
| 2514 void LCodeGen::DoGetCachedArrayIndex(LGetCachedArrayIndex* instr) { | 2486 void LCodeGen::DoGetCachedArrayIndex(LGetCachedArrayIndex* instr) { |
| 2515 Register input = ToRegister(instr->value()); | 2487 Register input = ToRegister(instr->value()); |
| 2516 Register result = ToRegister(instr->result()); | 2488 Register result = ToRegister(instr->result()); |
| 2517 | 2489 |
| 2518 __ AssertString(input); | 2490 __ AssertString(input); |
| 2519 | 2491 |
| 2520 __ mov(result, FieldOperand(input, String::kHashFieldOffset)); | 2492 __ mov(result, FieldOperand(input, String::kHashFieldOffset)); |
| 2521 __ IndexFromHash(result, result); | 2493 __ IndexFromHash(result, result); |
| 2522 } | 2494 } |
| 2523 | 2495 |
| 2524 | 2496 |
| 2525 void LCodeGen::DoHasCachedArrayIndexAndBranch( | 2497 void LCodeGen::DoHasCachedArrayIndexAndBranch( |
| 2526 LHasCachedArrayIndexAndBranch* instr) { | 2498 LHasCachedArrayIndexAndBranch* instr) { |
| 2527 Register input = ToRegister(instr->value()); | 2499 Register input = ToRegister(instr->value()); |
| 2528 | 2500 |
| 2529 int true_block = chunk_->LookupDestination(instr->true_block_id()); | |
| 2530 int false_block = chunk_->LookupDestination(instr->false_block_id()); | |
| 2531 | |
| 2532 __ test(FieldOperand(input, String::kHashFieldOffset), | 2501 __ test(FieldOperand(input, String::kHashFieldOffset), |
| 2533 Immediate(String::kContainsCachedArrayIndexMask)); | 2502 Immediate(String::kContainsCachedArrayIndexMask)); |
| 2534 EmitBranch(true_block, false_block, equal); | 2503 EmitBranch(instr, equal); |
| 2535 } | 2504 } |
| 2536 | 2505 |
| 2537 | 2506 |
| 2538 // Branches to a label or falls through with the answer in the z flag. Trashes | 2507 // Branches to a label or falls through with the answer in the z flag. Trashes |
| 2539 // the temp registers, but not the input. | 2508 // the temp registers, but not the input. |
| 2540 void LCodeGen::EmitClassOfTest(Label* is_true, | 2509 void LCodeGen::EmitClassOfTest(Label* is_true, |
| 2541 Label* is_false, | 2510 Label* is_false, |
| 2542 Handle<String>class_name, | 2511 Handle<String>class_name, |
| 2543 Register input, | 2512 Register input, |
| 2544 Register temp, | 2513 Register temp, |
| (...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2600 } | 2569 } |
| 2601 | 2570 |
| 2602 | 2571 |
| 2603 void LCodeGen::DoClassOfTestAndBranch(LClassOfTestAndBranch* instr) { | 2572 void LCodeGen::DoClassOfTestAndBranch(LClassOfTestAndBranch* instr) { |
| 2604 Register input = ToRegister(instr->value()); | 2573 Register input = ToRegister(instr->value()); |
| 2605 Register temp = ToRegister(instr->temp()); | 2574 Register temp = ToRegister(instr->temp()); |
| 2606 Register temp2 = ToRegister(instr->temp2()); | 2575 Register temp2 = ToRegister(instr->temp2()); |
| 2607 | 2576 |
| 2608 Handle<String> class_name = instr->hydrogen()->class_name(); | 2577 Handle<String> class_name = instr->hydrogen()->class_name(); |
| 2609 | 2578 |
| 2610 int true_block = chunk_->LookupDestination(instr->true_block_id()); | 2579 EmitClassOfTest(instr->TrueLabel(chunk_), instr->FalseLabel(chunk_), |
| 2611 int false_block = chunk_->LookupDestination(instr->false_block_id()); | 2580 class_name, input, temp, temp2); |
| 2612 | 2581 |
| 2613 Label* true_label = chunk_->GetAssemblyLabel(true_block); | 2582 EmitBranch(instr, equal); |
| 2614 Label* false_label = chunk_->GetAssemblyLabel(false_block); | |
| 2615 | |
| 2616 EmitClassOfTest(true_label, false_label, class_name, input, temp, temp2); | |
| 2617 | |
| 2618 EmitBranch(true_block, false_block, equal); | |
| 2619 } | 2583 } |
| 2620 | 2584 |
| 2621 | 2585 |
| 2622 void LCodeGen::DoCmpMapAndBranch(LCmpMapAndBranch* instr) { | 2586 void LCodeGen::DoCmpMapAndBranch(LCmpMapAndBranch* instr) { |
| 2623 Register reg = ToRegister(instr->value()); | 2587 Register reg = ToRegister(instr->value()); |
| 2624 int true_block = instr->true_block_id(); | |
| 2625 int false_block = instr->false_block_id(); | |
| 2626 | |
| 2627 __ cmp(FieldOperand(reg, HeapObject::kMapOffset), instr->map()); | 2588 __ cmp(FieldOperand(reg, HeapObject::kMapOffset), instr->map()); |
| 2628 EmitBranch(true_block, false_block, equal); | 2589 EmitBranch(instr, equal); |
| 2629 } | 2590 } |
| 2630 | 2591 |
| 2631 | 2592 |
| 2632 void LCodeGen::DoInstanceOf(LInstanceOf* instr) { | 2593 void LCodeGen::DoInstanceOf(LInstanceOf* instr) { |
| 2633 // Object and function are in fixed registers defined by the stub. | 2594 // Object and function are in fixed registers defined by the stub. |
| 2634 ASSERT(ToRegister(instr->context()).is(esi)); | 2595 ASSERT(ToRegister(instr->context()).is(esi)); |
| 2635 InstanceofStub stub(InstanceofStub::kArgsInRegisters); | 2596 InstanceofStub stub(InstanceofStub::kArgsInRegisters); |
| 2636 CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr); | 2597 CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr); |
| 2637 | 2598 |
| 2638 Label true_value, done; | 2599 Label true_value, done; |
| (...skipping 306 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2945 __ cmp(target, factory()->the_hole_value()); | 2906 __ cmp(target, factory()->the_hole_value()); |
| 2946 if (instr->hydrogen()->DeoptimizesOnHole()) { | 2907 if (instr->hydrogen()->DeoptimizesOnHole()) { |
| 2947 DeoptimizeIf(equal, instr->environment()); | 2908 DeoptimizeIf(equal, instr->environment()); |
| 2948 } else { | 2909 } else { |
| 2949 __ j(not_equal, &skip_assignment, Label::kNear); | 2910 __ j(not_equal, &skip_assignment, Label::kNear); |
| 2950 } | 2911 } |
| 2951 } | 2912 } |
| 2952 | 2913 |
| 2953 __ mov(target, value); | 2914 __ mov(target, value); |
| 2954 if (instr->hydrogen()->NeedsWriteBarrier()) { | 2915 if (instr->hydrogen()->NeedsWriteBarrier()) { |
| 2955 HType type = instr->hydrogen()->value()->type(); | |
| 2956 SmiCheck check_needed = | 2916 SmiCheck check_needed = |
| 2957 type.IsHeapObject() ? OMIT_SMI_CHECK : INLINE_SMI_CHECK; | 2917 instr->hydrogen()->value()->IsHeapObject() |
| 2918 ? OMIT_SMI_CHECK : INLINE_SMI_CHECK; |
| 2958 Register temp = ToRegister(instr->temp()); | 2919 Register temp = ToRegister(instr->temp()); |
| 2959 int offset = Context::SlotOffset(instr->slot_index()); | 2920 int offset = Context::SlotOffset(instr->slot_index()); |
| 2960 __ RecordWriteContextSlot(context, | 2921 __ RecordWriteContextSlot(context, |
| 2961 offset, | 2922 offset, |
| 2962 value, | 2923 value, |
| 2963 temp, | 2924 temp, |
| 2964 GetSaveFPRegsMode(), | 2925 GetSaveFPRegsMode(), |
| 2965 EMIT_REMEMBERED_SET, | 2926 EMIT_REMEMBERED_SET, |
| 2966 check_needed); | 2927 check_needed); |
| 2967 } | 2928 } |
| (...skipping 1222 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4190 CALL_AS_FUNCTION, | 4151 CALL_AS_FUNCTION, |
| 4191 EDI_UNINITIALIZED); | 4152 EDI_UNINITIALIZED); |
| 4192 } | 4153 } |
| 4193 | 4154 |
| 4194 | 4155 |
| 4195 void LCodeGen::DoCallNew(LCallNew* instr) { | 4156 void LCodeGen::DoCallNew(LCallNew* instr) { |
| 4196 ASSERT(ToRegister(instr->context()).is(esi)); | 4157 ASSERT(ToRegister(instr->context()).is(esi)); |
| 4197 ASSERT(ToRegister(instr->constructor()).is(edi)); | 4158 ASSERT(ToRegister(instr->constructor()).is(edi)); |
| 4198 ASSERT(ToRegister(instr->result()).is(eax)); | 4159 ASSERT(ToRegister(instr->result()).is(eax)); |
| 4199 | 4160 |
| 4200 if (FLAG_optimize_constructed_arrays) { | 4161 // No cell in ebx for construct type feedback in optimized code |
| 4201 // No cell in ebx for construct type feedback in optimized code | 4162 Handle<Object> undefined_value(isolate()->factory()->undefined_value()); |
| 4202 Handle<Object> undefined_value(isolate()->heap()->undefined_value(), | 4163 __ mov(ebx, Immediate(undefined_value)); |
| 4203 isolate()); | |
| 4204 __ mov(ebx, Immediate(undefined_value)); | |
| 4205 } | |
| 4206 CallConstructStub stub(NO_CALL_FUNCTION_FLAGS); | 4164 CallConstructStub stub(NO_CALL_FUNCTION_FLAGS); |
| 4207 __ Set(eax, Immediate(instr->arity())); | 4165 __ Set(eax, Immediate(instr->arity())); |
| 4208 CallCode(stub.GetCode(isolate()), RelocInfo::CONSTRUCT_CALL, instr); | 4166 CallCode(stub.GetCode(isolate()), RelocInfo::CONSTRUCT_CALL, instr); |
| 4209 } | 4167 } |
| 4210 | 4168 |
| 4211 | 4169 |
| 4212 void LCodeGen::DoCallNewArray(LCallNewArray* instr) { | 4170 void LCodeGen::DoCallNewArray(LCallNewArray* instr) { |
| 4213 ASSERT(ToRegister(instr->context()).is(esi)); | 4171 ASSERT(ToRegister(instr->context()).is(esi)); |
| 4214 ASSERT(ToRegister(instr->constructor()).is(edi)); | 4172 ASSERT(ToRegister(instr->constructor()).is(edi)); |
| 4215 ASSERT(ToRegister(instr->result()).is(eax)); | 4173 ASSERT(ToRegister(instr->result()).is(eax)); |
| 4216 ASSERT(FLAG_optimize_constructed_arrays); | |
| 4217 | 4174 |
| 4218 __ Set(eax, Immediate(instr->arity())); | 4175 __ Set(eax, Immediate(instr->arity())); |
| 4219 __ mov(ebx, instr->hydrogen()->property_cell()); | 4176 __ mov(ebx, instr->hydrogen()->property_cell()); |
| 4220 ElementsKind kind = instr->hydrogen()->elements_kind(); | 4177 ElementsKind kind = instr->hydrogen()->elements_kind(); |
| 4221 bool disable_allocation_sites = | 4178 bool disable_allocation_sites = |
| 4222 (AllocationSiteInfo::GetMode(kind) == TRACK_ALLOCATION_SITE); | 4179 (AllocationSiteInfo::GetMode(kind) == TRACK_ALLOCATION_SITE); |
| 4223 | 4180 |
| 4224 if (instr->arity() == 0) { | 4181 if (instr->arity() == 0) { |
| 4225 ArrayNoArgumentConstructorStub stub(kind, disable_allocation_sites); | 4182 ArrayNoArgumentConstructorStub stub(kind, disable_allocation_sites); |
| 4226 CallCode(stub.GetCode(isolate()), RelocInfo::CONSTRUCT_CALL, instr); | 4183 CallCode(stub.GetCode(isolate()), RelocInfo::CONSTRUCT_CALL, instr); |
| (...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4320 HeapObject::kMapOffset, | 4277 HeapObject::kMapOffset, |
| 4321 temp_map, | 4278 temp_map, |
| 4322 temp, | 4279 temp, |
| 4323 GetSaveFPRegsMode(), | 4280 GetSaveFPRegsMode(), |
| 4324 OMIT_REMEMBERED_SET, | 4281 OMIT_REMEMBERED_SET, |
| 4325 OMIT_SMI_CHECK); | 4282 OMIT_SMI_CHECK); |
| 4326 } | 4283 } |
| 4327 } | 4284 } |
| 4328 | 4285 |
| 4329 // Do the store. | 4286 // Do the store. |
| 4330 HType type = instr->hydrogen()->value()->type(); | |
| 4331 SmiCheck check_needed = | 4287 SmiCheck check_needed = |
| 4332 type.IsHeapObject() ? OMIT_SMI_CHECK : INLINE_SMI_CHECK; | 4288 instr->hydrogen()->value()->IsHeapObject() |
| 4289 ? OMIT_SMI_CHECK : INLINE_SMI_CHECK; |
| 4333 | 4290 |
| 4334 Register write_register = object; | 4291 Register write_register = object; |
| 4335 if (!access.IsInobject()) { | 4292 if (!access.IsInobject()) { |
| 4336 write_register = ToRegister(instr->temp()); | 4293 write_register = ToRegister(instr->temp()); |
| 4337 __ mov(write_register, | 4294 __ mov(write_register, |
| 4338 FieldOperand(object, JSObject::kPropertiesOffset)); | 4295 FieldOperand(object, JSObject::kPropertiesOffset)); |
| 4339 } | 4296 } |
| 4340 | 4297 |
| 4341 if (instr->value()->IsConstantOperand()) { | 4298 if (instr->value()->IsConstantOperand()) { |
| 4342 LConstantOperand* operand_value = LConstantOperand::cast(instr->value()); | 4299 LConstantOperand* operand_value = LConstantOperand::cast(instr->value()); |
| (...skipping 216 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4559 } else { | 4516 } else { |
| 4560 Handle<Object> handle_value = ToHandle(operand_value); | 4517 Handle<Object> handle_value = ToHandle(operand_value); |
| 4561 __ mov(operand, handle_value); | 4518 __ mov(operand, handle_value); |
| 4562 } | 4519 } |
| 4563 } | 4520 } |
| 4564 | 4521 |
| 4565 if (instr->hydrogen()->NeedsWriteBarrier()) { | 4522 if (instr->hydrogen()->NeedsWriteBarrier()) { |
| 4566 ASSERT(instr->value()->IsRegister()); | 4523 ASSERT(instr->value()->IsRegister()); |
| 4567 Register value = ToRegister(instr->value()); | 4524 Register value = ToRegister(instr->value()); |
| 4568 ASSERT(!instr->key()->IsConstantOperand()); | 4525 ASSERT(!instr->key()->IsConstantOperand()); |
| 4569 HType type = instr->hydrogen()->value()->type(); | |
| 4570 SmiCheck check_needed = | 4526 SmiCheck check_needed = |
| 4571 type.IsHeapObject() ? OMIT_SMI_CHECK : INLINE_SMI_CHECK; | 4527 instr->hydrogen()->value()->IsHeapObject() |
| 4528 ? OMIT_SMI_CHECK : INLINE_SMI_CHECK; |
| 4572 // Compute address of modified element and store it into key register. | 4529 // Compute address of modified element and store it into key register. |
| 4573 __ lea(key, operand); | 4530 __ lea(key, operand); |
| 4574 __ RecordWrite(elements, | 4531 __ RecordWrite(elements, |
| 4575 key, | 4532 key, |
| 4576 value, | 4533 value, |
| 4577 GetSaveFPRegsMode(), | 4534 GetSaveFPRegsMode(), |
| 4578 EMIT_REMEMBERED_SET, | 4535 EMIT_REMEMBERED_SET, |
| 4579 check_needed); | 4536 check_needed); |
| 4580 } | 4537 } |
| 4581 } | 4538 } |
| (...skipping 322 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4904 CpuFeatureScope feature_scope(masm(), SSE2); | 4861 CpuFeatureScope feature_scope(masm(), SSE2); |
| 4905 __ cvtsi2sd(xmm0, Operand(reg)); | 4862 __ cvtsi2sd(xmm0, Operand(reg)); |
| 4906 } else { | 4863 } else { |
| 4907 __ push(reg); | 4864 __ push(reg); |
| 4908 __ fild_s(Operand(esp, 0)); | 4865 __ fild_s(Operand(esp, 0)); |
| 4909 __ pop(reg); | 4866 __ pop(reg); |
| 4910 } | 4867 } |
| 4911 } else { | 4868 } else { |
| 4912 if (CpuFeatures::IsSupported(SSE2)) { | 4869 if (CpuFeatures::IsSupported(SSE2)) { |
| 4913 CpuFeatureScope feature_scope(masm(), SSE2); | 4870 CpuFeatureScope feature_scope(masm(), SSE2); |
| 4914 __ LoadUint32(xmm0, reg, xmm1); | 4871 __ LoadUint32(xmm0, reg, |
| 4872 ToDoubleRegister(LNumberTagU::cast(instr)->temp())); |
| 4915 } else { | 4873 } else { |
| 4916 // There's no fild variant for unsigned values, so zero-extend to a 64-bit | 4874 // There's no fild variant for unsigned values, so zero-extend to a 64-bit |
| 4917 // int manually. | 4875 // int manually. |
| 4918 __ push(Immediate(0)); | 4876 __ push(Immediate(0)); |
| 4919 __ push(reg); | 4877 __ push(reg); |
| 4920 __ fild_d(Operand(esp, 0)); | 4878 __ fild_d(Operand(esp, 0)); |
| 4921 __ pop(reg); | 4879 __ pop(reg); |
| 4922 __ pop(reg); | 4880 __ pop(reg); |
| 4923 } | 4881 } |
| 4924 } | 4882 } |
| (...skipping 777 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5702 | 5660 |
| 5703 | 5661 |
| 5704 void LCodeGen::DoCheckSmi(LCheckSmi* instr) { | 5662 void LCodeGen::DoCheckSmi(LCheckSmi* instr) { |
| 5705 LOperand* input = instr->value(); | 5663 LOperand* input = instr->value(); |
| 5706 __ test(ToOperand(input), Immediate(kSmiTagMask)); | 5664 __ test(ToOperand(input), Immediate(kSmiTagMask)); |
| 5707 DeoptimizeIf(not_zero, instr->environment()); | 5665 DeoptimizeIf(not_zero, instr->environment()); |
| 5708 } | 5666 } |
| 5709 | 5667 |
| 5710 | 5668 |
| 5711 void LCodeGen::DoCheckNonSmi(LCheckNonSmi* instr) { | 5669 void LCodeGen::DoCheckNonSmi(LCheckNonSmi* instr) { |
| 5712 LOperand* input = instr->value(); | 5670 if (!instr->hydrogen()->value()->IsHeapObject()) { |
| 5713 __ test(ToOperand(input), Immediate(kSmiTagMask)); | 5671 LOperand* input = instr->value(); |
| 5714 DeoptimizeIf(zero, instr->environment()); | 5672 __ test(ToOperand(input), Immediate(kSmiTagMask)); |
| 5673 DeoptimizeIf(zero, instr->environment()); |
| 5674 } |
| 5715 } | 5675 } |
| 5716 | 5676 |
| 5717 | 5677 |
| 5718 void LCodeGen::DoCheckInstanceType(LCheckInstanceType* instr) { | 5678 void LCodeGen::DoCheckInstanceType(LCheckInstanceType* instr) { |
| 5719 Register input = ToRegister(instr->value()); | 5679 Register input = ToRegister(instr->value()); |
| 5720 Register temp = ToRegister(instr->temp()); | 5680 Register temp = ToRegister(instr->temp()); |
| 5721 | 5681 |
| 5722 __ mov(temp, FieldOperand(input, HeapObject::kMapOffset)); | 5682 __ mov(temp, FieldOperand(input, HeapObject::kMapOffset)); |
| 5723 | 5683 |
| 5724 if (instr->hydrogen()->is_interval_check()) { | 5684 if (instr->hydrogen()->is_interval_check()) { |
| (...skipping 259 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5984 | 5944 |
| 5985 if (!instr->hydrogen()->CanOmitPrototypeChecks()) { | 5945 if (!instr->hydrogen()->CanOmitPrototypeChecks()) { |
| 5986 for (int i = 0; i < prototypes->length(); i++) { | 5946 for (int i = 0; i < prototypes->length(); i++) { |
| 5987 __ LoadHeapObject(reg, prototypes->at(i)); | 5947 __ LoadHeapObject(reg, prototypes->at(i)); |
| 5988 DoCheckMapCommon(reg, maps->at(i), instr); | 5948 DoCheckMapCommon(reg, maps->at(i), instr); |
| 5989 } | 5949 } |
| 5990 } | 5950 } |
| 5991 } | 5951 } |
| 5992 | 5952 |
| 5993 | 5953 |
| 5954 void LCodeGen::DoAllocateObject(LAllocateObject* instr) { |
| 5955 class DeferredAllocateObject: public LDeferredCode { |
| 5956 public: |
| 5957 DeferredAllocateObject(LCodeGen* codegen, LAllocateObject* instr) |
| 5958 : LDeferredCode(codegen), instr_(instr) { } |
| 5959 virtual void Generate() { codegen()->DoDeferredAllocateObject(instr_); } |
| 5960 virtual LInstruction* instr() { return instr_; } |
| 5961 private: |
| 5962 LAllocateObject* instr_; |
| 5963 }; |
| 5964 |
| 5965 DeferredAllocateObject* deferred = |
| 5966 new(zone()) DeferredAllocateObject(this, instr); |
| 5967 |
| 5968 Register result = ToRegister(instr->result()); |
| 5969 Register scratch = ToRegister(instr->temp()); |
| 5970 Handle<JSFunction> constructor = instr->hydrogen()->constructor(); |
| 5971 Handle<Map> initial_map = instr->hydrogen()->constructor_initial_map(); |
| 5972 int instance_size = initial_map->instance_size(); |
| 5973 ASSERT(initial_map->pre_allocated_property_fields() + |
| 5974 initial_map->unused_property_fields() - |
| 5975 initial_map->inobject_properties() == 0); |
| 5976 |
| 5977 __ Allocate(instance_size, result, no_reg, scratch, deferred->entry(), |
| 5978 TAG_OBJECT); |
| 5979 |
| 5980 __ bind(deferred->exit()); |
| 5981 if (FLAG_debug_code) { |
| 5982 Label is_in_new_space; |
| 5983 __ JumpIfInNewSpace(result, scratch, &is_in_new_space); |
| 5984 __ Abort("Allocated object is not in new-space"); |
| 5985 __ bind(&is_in_new_space); |
| 5986 } |
| 5987 |
| 5988 // Load the initial map. |
| 5989 Register map = scratch; |
| 5990 __ LoadHeapObject(scratch, constructor); |
| 5991 __ mov(map, FieldOperand(scratch, JSFunction::kPrototypeOrInitialMapOffset)); |
| 5992 |
| 5993 if (FLAG_debug_code) { |
| 5994 __ AssertNotSmi(map); |
| 5995 __ cmpb(FieldOperand(map, Map::kInstanceSizeOffset), |
| 5996 instance_size >> kPointerSizeLog2); |
| 5997 __ Assert(equal, "Unexpected instance size"); |
| 5998 __ cmpb(FieldOperand(map, Map::kPreAllocatedPropertyFieldsOffset), |
| 5999 initial_map->pre_allocated_property_fields()); |
| 6000 __ Assert(equal, "Unexpected pre-allocated property fields count"); |
| 6001 __ cmpb(FieldOperand(map, Map::kUnusedPropertyFieldsOffset), |
| 6002 initial_map->unused_property_fields()); |
| 6003 __ Assert(equal, "Unexpected unused property fields count"); |
| 6004 __ cmpb(FieldOperand(map, Map::kInObjectPropertiesOffset), |
| 6005 initial_map->inobject_properties()); |
| 6006 __ Assert(equal, "Unexpected in-object property fields count"); |
| 6007 } |
| 6008 |
| 6009 // Initialize map and fields of the newly allocated object. |
| 6010 ASSERT(initial_map->instance_type() == JS_OBJECT_TYPE); |
| 6011 __ mov(FieldOperand(result, JSObject::kMapOffset), map); |
| 6012 __ mov(scratch, factory()->empty_fixed_array()); |
| 6013 __ mov(FieldOperand(result, JSObject::kElementsOffset), scratch); |
| 6014 __ mov(FieldOperand(result, JSObject::kPropertiesOffset), scratch); |
| 6015 if (initial_map->inobject_properties() != 0) { |
| 6016 __ mov(scratch, factory()->undefined_value()); |
| 6017 for (int i = 0; i < initial_map->inobject_properties(); i++) { |
| 6018 int property_offset = JSObject::kHeaderSize + i * kPointerSize; |
| 6019 __ mov(FieldOperand(result, property_offset), scratch); |
| 6020 } |
| 6021 } |
| 6022 } |
| 6023 |
| 6024 |
| 6025 void LCodeGen::DoDeferredAllocateObject(LAllocateObject* instr) { |
| 6026 Register result = ToRegister(instr->result()); |
| 6027 Handle<Map> initial_map = instr->hydrogen()->constructor_initial_map(); |
| 6028 int instance_size = initial_map->instance_size(); |
| 6029 |
| 6030 // TODO(3095996): Get rid of this. For now, we need to make the |
| 6031 // result register contain a valid pointer because it is already |
| 6032 // contained in the register pointer map. |
| 6033 __ Set(result, Immediate(0)); |
| 6034 |
| 6035 PushSafepointRegistersScope scope(this); |
| 6036 __ push(Immediate(Smi::FromInt(instance_size))); |
| 6037 CallRuntimeFromDeferred( |
| 6038 Runtime::kAllocateInNewSpace, 1, instr, instr->context()); |
| 6039 __ StoreToSafepointRegisterSlot(result, eax); |
| 6040 } |
| 6041 |
| 6042 |
| 5994 void LCodeGen::DoAllocate(LAllocate* instr) { | 6043 void LCodeGen::DoAllocate(LAllocate* instr) { |
| 5995 class DeferredAllocate: public LDeferredCode { | 6044 class DeferredAllocate: public LDeferredCode { |
| 5996 public: | 6045 public: |
| 5997 DeferredAllocate(LCodeGen* codegen, LAllocate* instr) | 6046 DeferredAllocate(LCodeGen* codegen, LAllocate* instr) |
| 5998 : LDeferredCode(codegen), instr_(instr) { } | 6047 : LDeferredCode(codegen), instr_(instr) { } |
| 5999 virtual void Generate() { codegen()->DoDeferredAllocate(instr_); } | 6048 virtual void Generate() { codegen()->DoDeferredAllocate(instr_); } |
| 6000 virtual LInstruction* instr() { return instr_; } | 6049 virtual LInstruction* instr() { return instr_; } |
| 6001 private: | 6050 private: |
| 6002 LAllocate* instr_; | 6051 LAllocate* instr_; |
| 6003 }; | 6052 }; |
| (...skipping 143 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 6147 | 6196 |
| 6148 void LCodeGen::DoTypeof(LTypeof* instr) { | 6197 void LCodeGen::DoTypeof(LTypeof* instr) { |
| 6149 LOperand* input = instr->value(); | 6198 LOperand* input = instr->value(); |
| 6150 EmitPushTaggedOperand(input); | 6199 EmitPushTaggedOperand(input); |
| 6151 CallRuntime(Runtime::kTypeof, 1, instr); | 6200 CallRuntime(Runtime::kTypeof, 1, instr); |
| 6152 } | 6201 } |
| 6153 | 6202 |
| 6154 | 6203 |
| 6155 void LCodeGen::DoTypeofIsAndBranch(LTypeofIsAndBranch* instr) { | 6204 void LCodeGen::DoTypeofIsAndBranch(LTypeofIsAndBranch* instr) { |
| 6156 Register input = ToRegister(instr->value()); | 6205 Register input = ToRegister(instr->value()); |
| 6157 int true_block = chunk_->LookupDestination(instr->true_block_id()); | |
| 6158 int false_block = chunk_->LookupDestination(instr->false_block_id()); | |
| 6159 Label* true_label = chunk_->GetAssemblyLabel(true_block); | |
| 6160 Label* false_label = chunk_->GetAssemblyLabel(false_block); | |
| 6161 | 6206 |
| 6162 Condition final_branch_condition = | 6207 Condition final_branch_condition = |
| 6163 EmitTypeofIs(true_label, false_label, input, instr->type_literal()); | 6208 EmitTypeofIs(instr->TrueLabel(chunk_), instr->FalseLabel(chunk_), |
| 6209 input, instr->type_literal()); |
| 6164 if (final_branch_condition != no_condition) { | 6210 if (final_branch_condition != no_condition) { |
| 6165 EmitBranch(true_block, false_block, final_branch_condition); | 6211 EmitBranch(instr, final_branch_condition); |
| 6166 } | 6212 } |
| 6167 } | 6213 } |
| 6168 | 6214 |
| 6169 | 6215 |
| 6170 Condition LCodeGen::EmitTypeofIs(Label* true_label, | 6216 Condition LCodeGen::EmitTypeofIs(Label* true_label, |
| 6171 Label* false_label, | 6217 Label* false_label, |
| 6172 Register input, | 6218 Register input, |
| 6173 Handle<String> type_name) { | 6219 Handle<String> type_name) { |
| 6174 Condition final_branch_condition = no_condition; | 6220 Condition final_branch_condition = no_condition; |
| 6175 if (type_name->Equals(heap()->number_string())) { | 6221 if (type_name->Equals(heap()->number_string())) { |
| (...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 6236 | 6282 |
| 6237 } else { | 6283 } else { |
| 6238 __ jmp(false_label); | 6284 __ jmp(false_label); |
| 6239 } | 6285 } |
| 6240 return final_branch_condition; | 6286 return final_branch_condition; |
| 6241 } | 6287 } |
| 6242 | 6288 |
| 6243 | 6289 |
| 6244 void LCodeGen::DoIsConstructCallAndBranch(LIsConstructCallAndBranch* instr) { | 6290 void LCodeGen::DoIsConstructCallAndBranch(LIsConstructCallAndBranch* instr) { |
| 6245 Register temp = ToRegister(instr->temp()); | 6291 Register temp = ToRegister(instr->temp()); |
| 6246 int true_block = chunk_->LookupDestination(instr->true_block_id()); | |
| 6247 int false_block = chunk_->LookupDestination(instr->false_block_id()); | |
| 6248 | 6292 |
| 6249 EmitIsConstructCall(temp); | 6293 EmitIsConstructCall(temp); |
| 6250 EmitBranch(true_block, false_block, equal); | 6294 EmitBranch(instr, equal); |
| 6251 } | 6295 } |
| 6252 | 6296 |
| 6253 | 6297 |
| 6254 void LCodeGen::EmitIsConstructCall(Register temp) { | 6298 void LCodeGen::EmitIsConstructCall(Register temp) { |
| 6255 // Get the frame pointer for the calling frame. | 6299 // Get the frame pointer for the calling frame. |
| 6256 __ mov(temp, Operand(ebp, StandardFrameConstants::kCallerFPOffset)); | 6300 __ mov(temp, Operand(ebp, StandardFrameConstants::kCallerFPOffset)); |
| 6257 | 6301 |
| 6258 // Skip the arguments adaptor frame if it exists. | 6302 // Skip the arguments adaptor frame if it exists. |
| 6259 Label check_frame_marker; | 6303 Label check_frame_marker; |
| 6260 __ cmp(Operand(temp, StandardFrameConstants::kContextOffset), | 6304 __ cmp(Operand(temp, StandardFrameConstants::kContextOffset), |
| (...skipping 125 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 6386 // the deferred code. | 6430 // the deferred code. |
| 6387 } | 6431 } |
| 6388 } | 6432 } |
| 6389 | 6433 |
| 6390 | 6434 |
| 6391 void LCodeGen::DoOsrEntry(LOsrEntry* instr) { | 6435 void LCodeGen::DoOsrEntry(LOsrEntry* instr) { |
| 6392 // This is a pseudo-instruction that ensures that the environment here is | 6436 // This is a pseudo-instruction that ensures that the environment here is |
| 6393 // properly registered for deoptimization and records the assembler's PC | 6437 // properly registered for deoptimization and records the assembler's PC |
| 6394 // offset. | 6438 // offset. |
| 6395 LEnvironment* environment = instr->environment(); | 6439 LEnvironment* environment = instr->environment(); |
| 6396 environment->SetSpilledRegisters(instr->SpilledRegisterArray(), | |
| 6397 instr->SpilledDoubleRegisterArray()); | |
| 6398 | 6440 |
| 6399 // If the environment were already registered, we would have no way of | 6441 // If the environment were already registered, we would have no way of |
| 6400 // backpatching it with the spill slot operands. | 6442 // backpatching it with the spill slot operands. |
| 6401 ASSERT(!environment->HasBeenRegistered()); | 6443 ASSERT(!environment->HasBeenRegistered()); |
| 6402 RegisterEnvironmentForDeoptimization(environment, Safepoint::kNoLazyDeopt); | 6444 RegisterEnvironmentForDeoptimization(environment, Safepoint::kNoLazyDeopt); |
| 6403 ASSERT(osr_pc_offset_ == -1); | 6445 |
| 6404 osr_pc_offset_ = masm()->pc_offset(); | 6446 // Normally we record the first unknown OSR value as the entrypoint to the OSR |
| 6447 // code, but if there were none, record the entrypoint here. |
| 6448 if (osr_pc_offset_ == -1) osr_pc_offset_ = masm()->pc_offset(); |
| 6405 } | 6449 } |
| 6406 | 6450 |
| 6407 | 6451 |
| 6408 void LCodeGen::DoIn(LIn* instr) { | 6452 void LCodeGen::DoIn(LIn* instr) { |
| 6409 LOperand* obj = instr->object(); | 6453 LOperand* obj = instr->object(); |
| 6410 LOperand* key = instr->key(); | 6454 LOperand* key = instr->key(); |
| 6411 EmitPushTaggedOperand(key); | 6455 EmitPushTaggedOperand(key); |
| 6412 EmitPushTaggedOperand(obj); | 6456 EmitPushTaggedOperand(obj); |
| 6413 ASSERT(instr->HasPointerMap()); | 6457 ASSERT(instr->HasPointerMap()); |
| 6414 LPointerMap* pointers = instr->pointer_map(); | 6458 LPointerMap* pointers = instr->pointer_map(); |
| (...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 6504 FixedArray::kHeaderSize - kPointerSize)); | 6548 FixedArray::kHeaderSize - kPointerSize)); |
| 6505 __ bind(&done); | 6549 __ bind(&done); |
| 6506 } | 6550 } |
| 6507 | 6551 |
| 6508 | 6552 |
| 6509 #undef __ | 6553 #undef __ |
| 6510 | 6554 |
| 6511 } } // namespace v8::internal | 6555 } } // namespace v8::internal |
| 6512 | 6556 |
| 6513 #endif // V8_TARGET_ARCH_IA32 | 6557 #endif // V8_TARGET_ARCH_IA32 |
| OLD | NEW |