| OLD | NEW |
| 1 // Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 #include "vm/globals.h" // Needed here to get TARGET_ARCH_DBC. | 5 #include "vm/globals.h" // Needed here to get TARGET_ARCH_DBC. |
| 6 #if defined(TARGET_ARCH_DBC) | 6 #if defined(TARGET_ARCH_DBC) |
| 7 | 7 |
| 8 #include "vm/intermediate_language.h" | 8 #include "vm/intermediate_language.h" |
| 9 | 9 |
| 10 #include "vm/cpu.h" | 10 #include "vm/cpu.h" |
| (...skipping 25 matching lines...) Expand all Loading... |
| 36 M(DoubleToInteger) \ | 36 M(DoubleToInteger) \ |
| 37 M(BoxInt64) \ | 37 M(BoxInt64) \ |
| 38 M(MergedMath) \ | 38 M(MergedMath) \ |
| 39 M(GuardFieldClass) \ | 39 M(GuardFieldClass) \ |
| 40 M(GuardFieldLength) \ | 40 M(GuardFieldLength) \ |
| 41 M(IfThenElse) \ | 41 M(IfThenElse) \ |
| 42 M(ExtractNthOutput) \ | 42 M(ExtractNthOutput) \ |
| 43 M(BinaryUint32Op) \ | 43 M(BinaryUint32Op) \ |
| 44 M(ShiftUint32Op) \ | 44 M(ShiftUint32Op) \ |
| 45 M(UnaryUint32Op) \ | 45 M(UnaryUint32Op) \ |
| 46 M(UnboxedIntConverter) \ | 46 M(UnboxedIntConverter) |
| 47 | 47 |
| 48 // List of instructions that are not used by DBC. | 48 // List of instructions that are not used by DBC. |
| 49 // Things we aren't planning to implement for DBC: | 49 // Things we aren't planning to implement for DBC: |
| 50 // - Unboxed SIMD, | 50 // - Unboxed SIMD, |
| 51 // - Unboxed Mint, | 51 // - Unboxed Mint, |
| 52 // - Optimized RegExps, | 52 // - Optimized RegExps, |
| 53 // - Precompilation. | 53 // - Precompilation. |
| 54 #define FOR_EACH_UNREACHABLE_INSTRUCTION(M) \ | 54 #define FOR_EACH_UNREACHABLE_INSTRUCTION(M) \ |
| 55 M(CaseInsensitiveCompareUC16) \ | 55 M(CaseInsensitiveCompareUC16) \ |
| 56 M(GenericCheckBound) \ | 56 M(GenericCheckBound) \ |
| (...skipping 28 matching lines...) Expand all Loading... |
| 85 M(BinaryFloat64x2Op) \ | 85 M(BinaryFloat64x2Op) \ |
| 86 M(Float64x2Zero) \ | 86 M(Float64x2Zero) \ |
| 87 M(Float64x2Constructor) \ | 87 M(Float64x2Constructor) \ |
| 88 M(Float64x2Splat) \ | 88 M(Float64x2Splat) \ |
| 89 M(Float32x4ToFloat64x2) \ | 89 M(Float32x4ToFloat64x2) \ |
| 90 M(Float64x2ToFloat32x4) \ | 90 M(Float64x2ToFloat32x4) \ |
| 91 M(Simd64x2Shuffle) \ | 91 M(Simd64x2Shuffle) \ |
| 92 M(Float64x2ZeroArg) \ | 92 M(Float64x2ZeroArg) \ |
| 93 M(Float64x2OneArg) \ | 93 M(Float64x2OneArg) \ |
| 94 M(CheckedSmiOp) \ | 94 M(CheckedSmiOp) \ |
| 95 M(CheckedSmiComparison) \ | 95 M(CheckedSmiComparison) |
| 96 | 96 |
| 97 // Location summaries actually are not used by the unoptimizing DBC compiler | 97 // Location summaries actually are not used by the unoptimizing DBC compiler |
| 98 // because we don't allocate any registers. | 98 // because we don't allocate any registers. |
| 99 static LocationSummary* CreateLocationSummary( | 99 static LocationSummary* CreateLocationSummary( |
| 100 Zone* zone, | 100 Zone* zone, |
| 101 intptr_t num_inputs, | 101 intptr_t num_inputs, |
| 102 Location output = Location::NoLocation(), | 102 Location output = Location::NoLocation(), |
| 103 LocationSummary::ContainsCall contains_call = LocationSummary::kNoCall, | 103 LocationSummary::ContainsCall contains_call = LocationSummary::kNoCall, |
| 104 intptr_t num_temps = 0) { | 104 intptr_t num_temps = 0) { |
| 105 LocationSummary* locs = new(zone) LocationSummary( | 105 LocationSummary* locs = |
| 106 zone, num_inputs, num_temps, contains_call); | 106 new (zone) LocationSummary(zone, num_inputs, num_temps, contains_call); |
| 107 for (intptr_t i = 0; i < num_inputs; i++) { | 107 for (intptr_t i = 0; i < num_inputs; i++) { |
| 108 locs->set_in(i, (contains_call == LocationSummary::kNoCall) ? | 108 locs->set_in(i, (contains_call == LocationSummary::kNoCall) |
| 109 Location::RequiresRegister() : Location::RegisterLocation(i)); | 109 ? Location::RequiresRegister() |
| 110 : Location::RegisterLocation(i)); |
| 110 } | 111 } |
| 111 for (intptr_t i = 0; i < num_temps; i++) { | 112 for (intptr_t i = 0; i < num_temps; i++) { |
| 112 locs->set_temp(i, Location::RequiresRegister()); | 113 locs->set_temp(i, Location::RequiresRegister()); |
| 113 } | 114 } |
| 114 if (!output.IsInvalid()) { | 115 if (!output.IsInvalid()) { |
| 115 // For instructions that call we default to returning result in R0. | 116 // For instructions that call we default to returning result in R0. |
| 116 locs->set_out(0, output); | 117 locs->set_out(0, output); |
| 117 } | 118 } |
| 118 return locs; | 119 return locs; |
| 119 } | 120 } |
| 120 | 121 |
| 121 | 122 |
| 122 #define DEFINE_MAKE_LOCATION_SUMMARY(Name, ...) \ | 123 #define DEFINE_MAKE_LOCATION_SUMMARY(Name, ...) \ |
| 123 LocationSummary* Name##Instr::MakeLocationSummary(Zone* zone, bool opt) \ | 124 LocationSummary* Name##Instr::MakeLocationSummary(Zone* zone, bool opt) \ |
| 124 const { \ | 125 const { \ |
| 125 return CreateLocationSummary(zone, __VA_ARGS__); \ | 126 return CreateLocationSummary(zone, __VA_ARGS__); \ |
| 126 } \ | 127 } |
| 127 | 128 |
| 128 #define EMIT_NATIVE_CODE(Name, ...) \ | 129 #define EMIT_NATIVE_CODE(Name, ...) \ |
| 129 DEFINE_MAKE_LOCATION_SUMMARY(Name, __VA_ARGS__); \ | 130 DEFINE_MAKE_LOCATION_SUMMARY(Name, __VA_ARGS__); \ |
| 130 void Name##Instr::EmitNativeCode(FlowGraphCompiler* compiler) \ | 131 void Name##Instr::EmitNativeCode(FlowGraphCompiler* compiler) |
| 131 | 132 |
| 132 #define DEFINE_UNIMPLEMENTED_MAKE_LOCATION_SUMMARY(Name) \ | 133 #define DEFINE_UNIMPLEMENTED_MAKE_LOCATION_SUMMARY(Name) \ |
| 133 LocationSummary* Name##Instr::MakeLocationSummary(Zone* zone, bool opt) \ | 134 LocationSummary* Name##Instr::MakeLocationSummary(Zone* zone, bool opt) \ |
| 134 const { \ | 135 const { \ |
| 135 if (!opt) UNIMPLEMENTED(); \ | 136 if (!opt) UNIMPLEMENTED(); \ |
| 136 return NULL; \ | 137 return NULL; \ |
| 137 } \ | 138 } |
| 138 | 139 |
| 139 #define DEFINE_UNREACHABLE_MAKE_LOCATION_SUMMARY(Name) \ | 140 #define DEFINE_UNREACHABLE_MAKE_LOCATION_SUMMARY(Name) \ |
| 140 LocationSummary* Name##Instr::MakeLocationSummary(Zone* zone, bool opt) \ | 141 LocationSummary* Name##Instr::MakeLocationSummary(Zone* zone, bool opt) \ |
| 141 const { \ | 142 const { \ |
| 142 UNREACHABLE(); \ | 143 UNREACHABLE(); \ |
| 143 return NULL; \ | 144 return NULL; \ |
| 144 } \ | 145 } |
| 145 | 146 |
| 146 #define DEFINE_UNIMPLEMENTED_EMIT_NATIVE_CODE(Name) \ | 147 #define DEFINE_UNIMPLEMENTED_EMIT_NATIVE_CODE(Name) \ |
| 147 void Name##Instr::EmitNativeCode(FlowGraphCompiler* compiler) { \ | 148 void Name##Instr::EmitNativeCode(FlowGraphCompiler* compiler) { \ |
| 148 UNIMPLEMENTED(); \ | 149 UNIMPLEMENTED(); \ |
| 149 } | 150 } |
| 150 | 151 |
| 151 #define DEFINE_UNREACHABLE_EMIT_NATIVE_CODE(Name) \ | 152 #define DEFINE_UNREACHABLE_EMIT_NATIVE_CODE(Name) \ |
| 152 void Name##Instr::EmitNativeCode(FlowGraphCompiler* compiler) { \ | 153 void Name##Instr::EmitNativeCode(FlowGraphCompiler* compiler) { \ |
| 153 UNREACHABLE(); \ | 154 UNREACHABLE(); \ |
| 154 } | 155 } |
| 155 | 156 |
| 156 #define DEFINE_UNIMPLEMENTED_EMIT_BRANCH_CODE(Name) \ | 157 #define DEFINE_UNIMPLEMENTED_EMIT_BRANCH_CODE(Name) \ |
| 157 void Name##Instr::EmitBranchCode(FlowGraphCompiler*, BranchInstr*) { \ | 158 void Name##Instr::EmitBranchCode(FlowGraphCompiler*, BranchInstr*) { \ |
| 158 UNIMPLEMENTED(); \ | 159 UNIMPLEMENTED(); \ |
| 159 } \ | 160 } \ |
| 160 Condition Name##Instr::EmitComparisonCode(FlowGraphCompiler*, \ | 161 Condition Name##Instr::EmitComparisonCode(FlowGraphCompiler*, \ |
| 161 BranchLabels) { \ | 162 BranchLabels) { \ |
| 162 UNIMPLEMENTED(); \ | 163 UNIMPLEMENTED(); \ |
| 163 return NEXT_IS_TRUE; \ | 164 return NEXT_IS_TRUE; \ |
| 164 } | 165 } |
| 165 | 166 |
| 166 #define DEFINE_UNIMPLEMENTED(Name) \ | 167 #define DEFINE_UNIMPLEMENTED(Name) \ |
| 167 DEFINE_UNIMPLEMENTED_MAKE_LOCATION_SUMMARY(Name) \ | 168 DEFINE_UNIMPLEMENTED_MAKE_LOCATION_SUMMARY(Name) \ |
| 168 DEFINE_UNIMPLEMENTED_EMIT_NATIVE_CODE(Name) \ | 169 DEFINE_UNIMPLEMENTED_EMIT_NATIVE_CODE(Name) |
| 169 | 170 |
| 170 FOR_EACH_UNIMPLEMENTED_INSTRUCTION(DEFINE_UNIMPLEMENTED) | 171 FOR_EACH_UNIMPLEMENTED_INSTRUCTION(DEFINE_UNIMPLEMENTED) |
| 171 | 172 |
| 172 #undef DEFINE_UNIMPLEMENTED | 173 #undef DEFINE_UNIMPLEMENTED |
| 173 | 174 |
| 174 #define DEFINE_UNREACHABLE(Name) \ | 175 #define DEFINE_UNREACHABLE(Name) \ |
| 175 DEFINE_UNREACHABLE_MAKE_LOCATION_SUMMARY(Name) \ | 176 DEFINE_UNREACHABLE_MAKE_LOCATION_SUMMARY(Name) \ |
| 176 DEFINE_UNREACHABLE_EMIT_NATIVE_CODE(Name) \ | 177 DEFINE_UNREACHABLE_EMIT_NATIVE_CODE(Name) |
| 177 | 178 |
| 178 FOR_EACH_UNREACHABLE_INSTRUCTION(DEFINE_UNREACHABLE) | 179 FOR_EACH_UNREACHABLE_INSTRUCTION(DEFINE_UNREACHABLE) |
| 179 | 180 |
| 180 #undef DEFINE_UNREACHABLE | 181 #undef DEFINE_UNREACHABLE |
| 181 | 182 |
| 182 | 183 |
| 183 // Only used in AOT compilation. | 184 // Only used in AOT compilation. |
| 184 DEFINE_UNIMPLEMENTED_EMIT_BRANCH_CODE(CheckedSmiComparison) | 185 DEFINE_UNIMPLEMENTED_EMIT_BRANCH_CODE(CheckedSmiComparison) |
| 185 | 186 |
| 186 | 187 |
| 187 EMIT_NATIVE_CODE(InstanceOf, 2, Location::SameAsFirstInput(), | 188 EMIT_NATIVE_CODE(InstanceOf, |
| 189 2, |
| 190 Location::SameAsFirstInput(), |
| 188 LocationSummary::kCall) { | 191 LocationSummary::kCall) { |
| 189 SubtypeTestCache& test_cache = SubtypeTestCache::Handle(); | 192 SubtypeTestCache& test_cache = SubtypeTestCache::Handle(); |
| 190 if (!type().IsVoidType() && type().IsInstantiated()) { | 193 if (!type().IsVoidType() && type().IsInstantiated()) { |
| 191 test_cache = SubtypeTestCache::New(); | 194 test_cache = SubtypeTestCache::New(); |
| 192 } | 195 } |
| 193 | 196 |
| 194 if (compiler->is_optimizing()) { | 197 if (compiler->is_optimizing()) { |
| 195 __ Push(locs()->in(0).reg()); // Value. | 198 __ Push(locs()->in(0).reg()); // Value. |
| 196 __ Push(locs()->in(1).reg()); // Instantiator type arguments. | 199 __ Push(locs()->in(1).reg()); // Instantiator type arguments. |
| 197 } | 200 } |
| 198 | 201 |
| 199 __ PushConstant(type()); | 202 __ PushConstant(type()); |
| 200 __ PushConstant(test_cache); | 203 __ PushConstant(test_cache); |
| 201 __ InstanceOf(negate_result() ? 1 : 0); | 204 __ InstanceOf(negate_result() ? 1 : 0); |
| 202 compiler->RecordSafepoint(locs()); | 205 compiler->RecordSafepoint(locs()); |
| 203 compiler->AddCurrentDescriptor(RawPcDescriptors::kOther, | 206 compiler->AddCurrentDescriptor(RawPcDescriptors::kOther, deopt_id(), |
| 204 deopt_id(), | |
| 205 token_pos()); | 207 token_pos()); |
| 206 | 208 |
| 207 if (compiler->is_optimizing()) { | 209 if (compiler->is_optimizing()) { |
| 208 __ PopLocal(locs()->out(0).reg()); | 210 __ PopLocal(locs()->out(0).reg()); |
| 209 } | 211 } |
| 210 } | 212 } |
| 211 | 213 |
| 212 | 214 |
| 213 DEFINE_MAKE_LOCATION_SUMMARY(AssertAssignable, 2, | 215 DEFINE_MAKE_LOCATION_SUMMARY(AssertAssignable, |
| 216 2, |
| 214 Location::SameAsFirstInput(), | 217 Location::SameAsFirstInput(), |
| 215 LocationSummary::kCall); | 218 LocationSummary::kCall); |
| 216 | 219 |
| 217 | 220 |
| 218 EMIT_NATIVE_CODE(AssertBoolean, | 221 EMIT_NATIVE_CODE(AssertBoolean, |
| 219 1, Location::SameAsFirstInput(), | 222 1, |
| 223 Location::SameAsFirstInput(), |
| 220 LocationSummary::kCall) { | 224 LocationSummary::kCall) { |
| 221 if (compiler->is_optimizing()) { | 225 if (compiler->is_optimizing()) { |
| 222 __ Push(locs()->in(0).reg()); | 226 __ Push(locs()->in(0).reg()); |
| 223 } | 227 } |
| 224 __ AssertBoolean(Isolate::Current()->type_checks() ? 1 : 0); | 228 __ AssertBoolean(Isolate::Current()->type_checks() ? 1 : 0); |
| 225 compiler->RecordSafepoint(locs()); | 229 compiler->RecordSafepoint(locs()); |
| 226 compiler->AddCurrentDescriptor(RawPcDescriptors::kOther, | 230 compiler->AddCurrentDescriptor(RawPcDescriptors::kOther, deopt_id(), |
| 227 deopt_id(), | |
| 228 token_pos()); | 231 token_pos()); |
| 229 if (compiler->is_optimizing()) { | 232 if (compiler->is_optimizing()) { |
| 230 __ Drop1(); | 233 __ Drop1(); |
| 231 } | 234 } |
| 232 } | 235 } |
| 233 | 236 |
| 234 | 237 |
| 235 EMIT_NATIVE_CODE(PolymorphicInstanceCall, | 238 EMIT_NATIVE_CODE(PolymorphicInstanceCall, |
| 236 0, Location::RegisterLocation(0), | 239 0, |
| 240 Location::RegisterLocation(0), |
| 237 LocationSummary::kCall) { | 241 LocationSummary::kCall) { |
| 238 ASSERT(ic_data().NumArgsTested() == 1); | 242 ASSERT(ic_data().NumArgsTested() == 1); |
| 239 const Array& arguments_descriptor = | 243 const Array& arguments_descriptor = Array::Handle(ArgumentsDescriptor::New( |
| 240 Array::Handle(ArgumentsDescriptor::New( | 244 instance_call()->ArgumentCount(), instance_call()->argument_names())); |
| 241 instance_call()->ArgumentCount(), | |
| 242 instance_call()->argument_names())); | |
| 243 const intptr_t argdesc_kidx = __ AddConstant(arguments_descriptor); | 245 const intptr_t argdesc_kidx = __ AddConstant(arguments_descriptor); |
| 244 | 246 |
| 245 // Push the target onto the stack. | 247 // Push the target onto the stack. |
| 246 if (with_checks()) { | 248 if (with_checks()) { |
| 247 const intptr_t may_be_smi = | 249 const intptr_t may_be_smi = |
| 248 (ic_data().GetReceiverClassIdAt(0) == kSmiCid) ? 1 : 0; | 250 (ic_data().GetReceiverClassIdAt(0) == kSmiCid) ? 1 : 0; |
| 249 GrowableArray<CidTarget> sorted_ic_data; | 251 GrowableArray<CidTarget> sorted_ic_data; |
| 250 FlowGraphCompiler::SortICDataByCount(ic_data(), | 252 FlowGraphCompiler::SortICDataByCount(ic_data(), &sorted_ic_data, |
| 251 &sorted_ic_data, | |
| 252 /* drop_smi = */ true); | 253 /* drop_smi = */ true); |
| 253 const intptr_t sorted_length = sorted_ic_data.length(); | 254 const intptr_t sorted_length = sorted_ic_data.length(); |
| 254 if (!Utils::IsUint(8, sorted_length)) { | 255 if (!Utils::IsUint(8, sorted_length)) { |
| 255 Unsupported(compiler); | 256 Unsupported(compiler); |
| 256 UNREACHABLE(); | 257 UNREACHABLE(); |
| 257 } | 258 } |
| 258 __ PushPolymorphicInstanceCall( | 259 __ PushPolymorphicInstanceCall(instance_call()->ArgumentCount(), |
| 259 instance_call()->ArgumentCount(), sorted_length + may_be_smi); | 260 sorted_length + may_be_smi); |
| 260 if (may_be_smi == 1) { | 261 if (may_be_smi == 1) { |
| 261 const Function& target = Function::ZoneHandle( | 262 const Function& target = |
| 262 compiler->zone(), ic_data().GetTargetAt(0)); | 263 Function::ZoneHandle(compiler->zone(), ic_data().GetTargetAt(0)); |
| 263 __ Nop(compiler->ToEmbeddableCid(kSmiCid, this)); | 264 __ Nop(compiler->ToEmbeddableCid(kSmiCid, this)); |
| 264 __ Nop(__ AddConstant(target)); | 265 __ Nop(__ AddConstant(target)); |
| 265 } | 266 } |
| 266 for (intptr_t i = 0; i < sorted_length; i++) { | 267 for (intptr_t i = 0; i < sorted_length; i++) { |
| 267 const Function& target = *sorted_ic_data[i].target; | 268 const Function& target = *sorted_ic_data[i].target; |
| 268 __ Nop(compiler->ToEmbeddableCid(sorted_ic_data[i].cid, this)); | 269 __ Nop(compiler->ToEmbeddableCid(sorted_ic_data[i].cid, this)); |
| 269 __ Nop(__ AddConstant(target)); | 270 __ Nop(__ AddConstant(target)); |
| 270 } | 271 } |
| 271 compiler->EmitDeopt( | 272 compiler->EmitDeopt(deopt_id(), |
| 272 deopt_id(), ICData::kDeoptPolymorphicInstanceCallTestFail, 0); | 273 ICData::kDeoptPolymorphicInstanceCallTestFail, 0); |
| 273 } else { | 274 } else { |
| 274 ASSERT(ic_data().HasOneTarget()); | 275 ASSERT(ic_data().HasOneTarget()); |
| 275 const Function& target = Function::ZoneHandle(ic_data().GetTargetAt(0)); | 276 const Function& target = Function::ZoneHandle(ic_data().GetTargetAt(0)); |
| 276 __ PushConstant(target); | 277 __ PushConstant(target); |
| 277 } | 278 } |
| 278 | 279 |
| 279 // Call the function. | 280 // Call the function. |
| 280 __ StaticCall(instance_call()->ArgumentCount(), argdesc_kidx); | 281 __ StaticCall(instance_call()->ArgumentCount(), argdesc_kidx); |
| 281 compiler->AddCurrentDescriptor(RawPcDescriptors::kOther, | 282 compiler->AddCurrentDescriptor(RawPcDescriptors::kOther, deopt_id(), |
| 282 deopt_id(), instance_call()->token_pos()); | 283 instance_call()->token_pos()); |
| 283 compiler->RecordAfterCall(this); | 284 compiler->RecordAfterCall(this); |
| 284 __ PopLocal(locs()->out(0).reg()); | 285 __ PopLocal(locs()->out(0).reg()); |
| 285 } | 286 } |
| 286 | 287 |
| 287 | 288 |
| 288 EMIT_NATIVE_CODE(Stop, 0) { | 289 EMIT_NATIVE_CODE(Stop, 0) { |
| 289 __ Stop(message()); | 290 __ Stop(message()); |
| 290 } | 291 } |
| 291 | 292 |
| 292 | 293 |
| 293 EMIT_NATIVE_CODE(CheckStackOverflow, | 294 EMIT_NATIVE_CODE(CheckStackOverflow, |
| 294 0, Location::NoLocation(), | 295 0, |
| 296 Location::NoLocation(), |
| 295 LocationSummary::kCall) { | 297 LocationSummary::kCall) { |
| 296 __ CheckStack(); | 298 __ CheckStack(); |
| 297 compiler->AddCurrentDescriptor(RawPcDescriptors::kOther, | 299 compiler->AddCurrentDescriptor(RawPcDescriptors::kOther, deopt_id(), |
| 298 deopt_id(), | |
| 299 token_pos()); | 300 token_pos()); |
| 300 compiler->RecordAfterCall(this); | 301 compiler->RecordAfterCall(this); |
| 301 } | 302 } |
| 302 | 303 |
| 303 | 304 |
| 304 EMIT_NATIVE_CODE(PushArgument, 1) { | 305 EMIT_NATIVE_CODE(PushArgument, 1) { |
| 305 if (compiler->is_optimizing()) { | 306 if (compiler->is_optimizing()) { |
| 306 __ Push(locs()->in(0).reg()); | 307 __ Push(locs()->in(0).reg()); |
| 307 } | 308 } |
| 308 } | 309 } |
| 309 | 310 |
| 310 | 311 |
| 311 EMIT_NATIVE_CODE(LoadLocal, 0) { | 312 EMIT_NATIVE_CODE(LoadLocal, 0) { |
| 312 ASSERT(!compiler->is_optimizing()); | 313 ASSERT(!compiler->is_optimizing()); |
| 313 ASSERT(local().index() != 0); | 314 ASSERT(local().index() != 0); |
| 314 __ Push((local().index() > 0) ? (-local().index()) : (-local().index() - 1)); | 315 __ Push((local().index() > 0) ? (-local().index()) : (-local().index() - 1)); |
| 315 } | 316 } |
| 316 | 317 |
| 317 | 318 |
| 318 EMIT_NATIVE_CODE(StoreLocal, 0) { | 319 EMIT_NATIVE_CODE(StoreLocal, 0) { |
| 319 ASSERT(!compiler->is_optimizing()); | 320 ASSERT(!compiler->is_optimizing()); |
| 320 ASSERT(local().index() != 0); | 321 ASSERT(local().index() != 0); |
| 321 if (HasTemp()) { | 322 if (HasTemp()) { |
| 322 __ StoreLocal( | 323 __ StoreLocal((local().index() > 0) ? (-local().index()) |
| 323 (local().index() > 0) ? (-local().index()) : (-local().index() - 1)); | 324 : (-local().index() - 1)); |
| 324 } else { | 325 } else { |
| 325 __ PopLocal( | 326 __ PopLocal((local().index() > 0) ? (-local().index()) |
| 326 (local().index() > 0) ? (-local().index()) : (-local().index() - 1)); | 327 : (-local().index() - 1)); |
| 327 } | 328 } |
| 328 } | 329 } |
| 329 | 330 |
| 330 | 331 |
| 331 EMIT_NATIVE_CODE(LoadClassId, 1, Location::RequiresRegister()) { | 332 EMIT_NATIVE_CODE(LoadClassId, 1, Location::RequiresRegister()) { |
| 332 if (compiler->is_optimizing()) { | 333 if (compiler->is_optimizing()) { |
| 333 __ LoadClassId(locs()->out(0).reg(), locs()->in(0).reg()); | 334 __ LoadClassId(locs()->out(0).reg(), locs()->in(0).reg()); |
| 334 } else { | 335 } else { |
| 335 __ LoadClassIdTOS(); | 336 __ LoadClassIdTOS(); |
| 336 } | 337 } |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 369 | 370 |
| 370 EMIT_NATIVE_CODE(Return, 1) { | 371 EMIT_NATIVE_CODE(Return, 1) { |
| 371 if (compiler->is_optimizing()) { | 372 if (compiler->is_optimizing()) { |
| 372 __ Return(locs()->in(0).reg()); | 373 __ Return(locs()->in(0).reg()); |
| 373 } else { | 374 } else { |
| 374 __ ReturnTOS(); | 375 __ ReturnTOS(); |
| 375 } | 376 } |
| 376 } | 377 } |
| 377 | 378 |
| 378 | 379 |
| 379 LocationSummary* StoreStaticFieldInstr::MakeLocationSummary( | 380 LocationSummary* StoreStaticFieldInstr::MakeLocationSummary(Zone* zone, |
| 380 Zone* zone, bool opt) const { | 381 bool opt) const { |
| 381 const intptr_t kNumInputs = 1; | 382 const intptr_t kNumInputs = 1; |
| 382 const intptr_t kNumTemps = 1; | 383 const intptr_t kNumTemps = 1; |
| 383 LocationSummary* locs = new(zone) LocationSummary( | 384 LocationSummary* locs = new (zone) |
| 384 zone, kNumInputs, kNumTemps, LocationSummary::kNoCall); | 385 LocationSummary(zone, kNumInputs, kNumTemps, LocationSummary::kNoCall); |
| 385 for (intptr_t i = 0; i < kNumInputs; i++) { | 386 for (intptr_t i = 0; i < kNumInputs; i++) { |
| 386 locs->set_in(i, Location::RequiresRegister()); | 387 locs->set_in(i, Location::RequiresRegister()); |
| 387 } | 388 } |
| 388 for (intptr_t i = 0; i < kNumTemps; i++) { | 389 for (intptr_t i = 0; i < kNumTemps; i++) { |
| 389 locs->set_temp(i, Location::RequiresRegister()); | 390 locs->set_temp(i, Location::RequiresRegister()); |
| 390 } | 391 } |
| 391 return locs; | 392 return locs; |
| 392 } | 393 } |
| 393 | 394 |
| 394 | 395 |
| 395 void StoreStaticFieldInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | 396 void StoreStaticFieldInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
| 396 if (compiler->is_optimizing()) { | 397 if (compiler->is_optimizing()) { |
| 397 __ LoadConstant(locs()->temp(0).reg(), | 398 __ LoadConstant(locs()->temp(0).reg(), |
| 398 Field::ZoneHandle(field().Original())); | 399 Field::ZoneHandle(field().Original())); |
| 399 __ StoreField(locs()->temp(0).reg(), | 400 __ StoreField(locs()->temp(0).reg(), |
| 400 Field::static_value_offset() / kWordSize, | 401 Field::static_value_offset() / kWordSize, |
| 401 locs()->in(0).reg()); | 402 locs()->in(0).reg()); |
| 402 } else { | 403 } else { |
| 403 const intptr_t kidx = __ AddConstant(field()); | 404 const intptr_t kidx = __ AddConstant(field()); |
| 404 __ StoreStaticTOS(kidx); | 405 __ StoreStaticTOS(kidx); |
| 405 } | 406 } |
| 406 } | 407 } |
| 407 | 408 |
| 408 | 409 |
| 409 EMIT_NATIVE_CODE(LoadStaticField, 1, Location::RequiresRegister()) { | 410 EMIT_NATIVE_CODE(LoadStaticField, 1, Location::RequiresRegister()) { |
| 410 if (compiler->is_optimizing()) { | 411 if (compiler->is_optimizing()) { |
| 411 __ LoadField(locs()->out(0).reg(), | 412 __ LoadField(locs()->out(0).reg(), locs()->in(0).reg(), |
| 412 locs()->in(0).reg(), | |
| 413 Field::static_value_offset() / kWordSize); | 413 Field::static_value_offset() / kWordSize); |
| 414 } else { | 414 } else { |
| 415 const intptr_t kidx = __ AddConstant(StaticField()); | 415 const intptr_t kidx = __ AddConstant(StaticField()); |
| 416 __ PushStatic(kidx); | 416 __ PushStatic(kidx); |
| 417 } | 417 } |
| 418 } | 418 } |
| 419 | 419 |
| 420 | 420 |
| 421 EMIT_NATIVE_CODE(InitStaticField, 1) { | 421 EMIT_NATIVE_CODE(InitStaticField, 1) { |
| 422 if (compiler->is_optimizing()) { | 422 if (compiler->is_optimizing()) { |
| 423 __ Push(locs()->in(0).reg()); | 423 __ Push(locs()->in(0).reg()); |
| 424 __ InitStaticTOS(); | 424 __ InitStaticTOS(); |
| 425 } else { | 425 } else { |
| 426 __ InitStaticTOS(); | 426 __ InitStaticTOS(); |
| 427 } | 427 } |
| 428 } | 428 } |
| 429 | 429 |
| 430 | 430 |
| 431 EMIT_NATIVE_CODE(ClosureCall, | 431 EMIT_NATIVE_CODE(ClosureCall, |
| 432 1, | 432 1, |
| 433 Location::RegisterLocation(0), | 433 Location::RegisterLocation(0), |
| 434 LocationSummary::kCall) { | 434 LocationSummary::kCall) { |
| 435 if (compiler->is_optimizing()) { | 435 if (compiler->is_optimizing()) { |
| 436 __ Push(locs()->in(0).reg()); | 436 __ Push(locs()->in(0).reg()); |
| 437 } | 437 } |
| 438 | 438 |
| 439 intptr_t argument_count = ArgumentCount(); | 439 intptr_t argument_count = ArgumentCount(); |
| 440 const Array& arguments_descriptor = | 440 const Array& arguments_descriptor = Array::ZoneHandle( |
| 441 Array::ZoneHandle(ArgumentsDescriptor::New(argument_count, | 441 ArgumentsDescriptor::New(argument_count, argument_names())); |
| 442 argument_names())); | |
| 443 const intptr_t argdesc_kidx = | 442 const intptr_t argdesc_kidx = |
| 444 compiler->assembler()->AddConstant(arguments_descriptor); | 443 compiler->assembler()->AddConstant(arguments_descriptor); |
| 445 __ StaticCall(argument_count, argdesc_kidx); | 444 __ StaticCall(argument_count, argdesc_kidx); |
| 446 compiler->RecordAfterCall(this); | 445 compiler->RecordAfterCall(this); |
| 447 if (compiler->is_optimizing()) { | 446 if (compiler->is_optimizing()) { |
| 448 __ PopLocal(locs()->out(0).reg()); | 447 __ PopLocal(locs()->out(0).reg()); |
| 449 } | 448 } |
| 450 } | 449 } |
| 451 | 450 |
| 452 | 451 |
| (...skipping 21 matching lines...) Expand all Loading... |
| 474 // If we aren't falling through to the true case, then we have to do | 473 // If we aren't falling through to the true case, then we have to do |
| 475 // a Jump to it here. | 474 // a Jump to it here. |
| 476 __ Jump(labels.true_label); | 475 __ Jump(labels.true_label); |
| 477 } | 476 } |
| 478 } | 477 } |
| 479 } | 478 } |
| 480 | 479 |
| 481 | 480 |
| 482 Condition StrictCompareInstr::EmitComparisonCode(FlowGraphCompiler* compiler, | 481 Condition StrictCompareInstr::EmitComparisonCode(FlowGraphCompiler* compiler, |
| 483 BranchLabels labels) { | 482 BranchLabels labels) { |
| 484 ASSERT((kind() == Token::kNE_STRICT) || | 483 ASSERT((kind() == Token::kNE_STRICT) || (kind() == Token::kEQ_STRICT)); |
| 485 (kind() == Token::kEQ_STRICT)); | |
| 486 | 484 |
| 487 Token::Kind comparison; | 485 Token::Kind comparison; |
| 488 Condition condition; | 486 Condition condition; |
| 489 if (labels.fall_through == labels.false_label) { | 487 if (labels.fall_through == labels.false_label) { |
| 490 condition = NEXT_IS_TRUE; | 488 condition = NEXT_IS_TRUE; |
| 491 comparison = kind(); | 489 comparison = kind(); |
| 492 } else { | 490 } else { |
| 493 // Flip comparison to save a jump. | 491 // Flip comparison to save a jump. |
| 494 condition = NEXT_IS_FALSE; | 492 condition = NEXT_IS_FALSE; |
| 495 comparison = (kind() == Token::kEQ_STRICT) ? Token::kNE_STRICT | 493 comparison = |
| 496 : Token::kEQ_STRICT; | 494 (kind() == Token::kEQ_STRICT) ? Token::kNE_STRICT : Token::kEQ_STRICT; |
| 497 } | 495 } |
| 498 | 496 |
| 499 if (!compiler->is_optimizing()) { | 497 if (!compiler->is_optimizing()) { |
| 500 const Bytecode::Opcode eq_op = needs_number_check() ? | 498 const Bytecode::Opcode eq_op = needs_number_check() |
| 501 Bytecode::kIfEqStrictNumTOS : Bytecode::kIfEqStrictTOS; | 499 ? Bytecode::kIfEqStrictNumTOS |
| 502 const Bytecode::Opcode ne_op = needs_number_check() ? | 500 : Bytecode::kIfEqStrictTOS; |
| 503 Bytecode::kIfNeStrictNumTOS : Bytecode::kIfNeStrictTOS; | 501 const Bytecode::Opcode ne_op = needs_number_check() |
| 502 ? Bytecode::kIfNeStrictNumTOS |
| 503 : Bytecode::kIfNeStrictTOS; |
| 504 __ Emit(comparison == Token::kEQ_STRICT ? eq_op : ne_op); | 504 __ Emit(comparison == Token::kEQ_STRICT ? eq_op : ne_op); |
| 505 } else { | 505 } else { |
| 506 const Bytecode::Opcode eq_op = needs_number_check() ? | 506 const Bytecode::Opcode eq_op = |
| 507 Bytecode::kIfEqStrictNum : Bytecode::kIfEqStrict; | 507 needs_number_check() ? Bytecode::kIfEqStrictNum : Bytecode::kIfEqStrict; |
| 508 const Bytecode::Opcode ne_op = needs_number_check() ? | 508 const Bytecode::Opcode ne_op = |
| 509 Bytecode::kIfNeStrictNum : Bytecode::kIfNeStrict; | 509 needs_number_check() ? Bytecode::kIfNeStrictNum : Bytecode::kIfNeStrict; |
| 510 __ Emit(Bytecode::Encode( | 510 __ Emit(Bytecode::Encode((comparison == Token::kEQ_STRICT) ? eq_op : ne_op, |
| 511 (comparison == Token::kEQ_STRICT) ? eq_op : ne_op, | 511 locs()->in(0).reg(), locs()->in(1).reg())); |
| 512 locs()->in(0).reg(), | |
| 513 locs()->in(1).reg())); | |
| 514 } | 512 } |
| 515 | 513 |
| 516 if (needs_number_check() && token_pos().IsReal()) { | 514 if (needs_number_check() && token_pos().IsReal()) { |
| 517 compiler->RecordSafepoint(locs()); | 515 compiler->RecordSafepoint(locs()); |
| 518 compiler->AddCurrentDescriptor(RawPcDescriptors::kRuntimeCall, | 516 compiler->AddCurrentDescriptor(RawPcDescriptors::kRuntimeCall, |
| 519 Thread::kNoDeoptId, | 517 Thread::kNoDeoptId, token_pos()); |
| 520 token_pos()); | |
| 521 } | 518 } |
| 522 | 519 |
| 523 return condition; | 520 return condition; |
| 524 } | 521 } |
| 525 | 522 |
| 526 | 523 |
| 527 void StrictCompareInstr::EmitBranchCode(FlowGraphCompiler* compiler, | 524 void StrictCompareInstr::EmitBranchCode(FlowGraphCompiler* compiler, |
| 528 BranchInstr* branch) { | 525 BranchInstr* branch) { |
| 529 ASSERT((kind() == Token::kEQ_STRICT) || | 526 ASSERT((kind() == Token::kEQ_STRICT) || (kind() == Token::kNE_STRICT)); |
| 530 (kind() == Token::kNE_STRICT)); | |
| 531 | 527 |
| 532 BranchLabels labels = compiler->CreateBranchLabels(branch); | 528 BranchLabels labels = compiler->CreateBranchLabels(branch); |
| 533 Condition true_condition = EmitComparisonCode(compiler, labels); | 529 Condition true_condition = EmitComparisonCode(compiler, labels); |
| 534 EmitBranchOnCondition(compiler, true_condition, labels); | 530 EmitBranchOnCondition(compiler, true_condition, labels); |
| 535 } | 531 } |
| 536 | 532 |
| 537 | 533 |
| 538 EMIT_NATIVE_CODE(StrictCompare, | 534 EMIT_NATIVE_CODE(StrictCompare, |
| 539 2, | 535 2, |
| 540 Location::RequiresRegister(), | 536 Location::RequiresRegister(), |
| 541 needs_number_check() ? LocationSummary::kCall | 537 needs_number_check() ? LocationSummary::kCall |
| 542 : LocationSummary::kNoCall) { | 538 : LocationSummary::kNoCall) { |
| 543 ASSERT((kind() == Token::kEQ_STRICT) || | 539 ASSERT((kind() == Token::kEQ_STRICT) || (kind() == Token::kNE_STRICT)); |
| 544 (kind() == Token::kNE_STRICT)); | |
| 545 | 540 |
| 546 Label is_true, is_false; | 541 Label is_true, is_false; |
| 547 BranchLabels labels = { &is_true, &is_false, &is_false }; | 542 BranchLabels labels = {&is_true, &is_false, &is_false}; |
| 548 Condition true_condition = EmitComparisonCode(compiler, labels); | 543 Condition true_condition = EmitComparisonCode(compiler, labels); |
| 549 EmitBranchOnCondition(compiler, true_condition, labels); | 544 EmitBranchOnCondition(compiler, true_condition, labels); |
| 550 Label done; | 545 Label done; |
| 551 if (compiler->is_optimizing()) { | 546 if (compiler->is_optimizing()) { |
| 552 const Register result = locs()->out(0).reg(); | 547 const Register result = locs()->out(0).reg(); |
| 553 __ Bind(&is_false); | 548 __ Bind(&is_false); |
| 554 __ LoadConstant(result, Bool::False()); | 549 __ LoadConstant(result, Bool::False()); |
| 555 __ Jump(&done); | 550 __ Jump(&done); |
| 556 __ Bind(&is_true); | 551 __ Bind(&is_true); |
| 557 __ LoadConstant(result, Bool::True()); | 552 __ LoadConstant(result, Bool::True()); |
| 558 __ Bind(&done); | 553 __ Bind(&done); |
| 559 } else { | 554 } else { |
| 560 __ Bind(&is_false); | 555 __ Bind(&is_false); |
| 561 __ PushConstant(Bool::False()); | 556 __ PushConstant(Bool::False()); |
| 562 __ Jump(&done); | 557 __ Jump(&done); |
| 563 __ Bind(&is_true); | 558 __ Bind(&is_true); |
| 564 __ PushConstant(Bool::True()); | 559 __ PushConstant(Bool::True()); |
| 565 __ Bind(&done); | 560 __ Bind(&done); |
| 566 } | 561 } |
| 567 } | 562 } |
| 568 | 563 |
| 569 | 564 |
| 570 LocationSummary* BranchInstr::MakeLocationSummary(Zone* zone, | 565 LocationSummary* BranchInstr::MakeLocationSummary(Zone* zone, bool opt) const { |
| 571 bool opt) const { | |
| 572 comparison()->InitializeLocationSummary(zone, opt); | 566 comparison()->InitializeLocationSummary(zone, opt); |
| 573 if (!comparison()->HasLocs()) { | 567 if (!comparison()->HasLocs()) { |
| 574 return NULL; | 568 return NULL; |
| 575 } | 569 } |
| 576 // Branches don't produce a result. | 570 // Branches don't produce a result. |
| 577 comparison()->locs()->set_out(0, Location::NoLocation()); | 571 comparison()->locs()->set_out(0, Location::NoLocation()); |
| 578 return comparison()->locs(); | 572 return comparison()->locs(); |
| 579 } | 573 } |
| 580 | 574 |
| 581 | 575 |
| 582 void BranchInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | 576 void BranchInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
| 583 comparison()->EmitBranchCode(compiler, this); | 577 comparison()->EmitBranchCode(compiler, this); |
| 584 } | 578 } |
| 585 | 579 |
| 586 | 580 |
| 587 EMIT_NATIVE_CODE(Goto, 0) { | 581 EMIT_NATIVE_CODE(Goto, 0) { |
| 588 if (!compiler->is_optimizing()) { | 582 if (!compiler->is_optimizing()) { |
| 589 // Add a deoptimization descriptor for deoptimizing instructions that | 583 // Add a deoptimization descriptor for deoptimizing instructions that |
| 590 // may be inserted before this instruction. | 584 // may be inserted before this instruction. |
| 591 compiler->AddCurrentDescriptor(RawPcDescriptors::kDeopt, | 585 compiler->AddCurrentDescriptor(RawPcDescriptors::kDeopt, GetDeoptId(), |
| 592 GetDeoptId(), | |
| 593 TokenPosition::kNoSource); | 586 TokenPosition::kNoSource); |
| 594 } | 587 } |
| 595 if (HasParallelMove()) { | 588 if (HasParallelMove()) { |
| 596 compiler->parallel_move_resolver()->EmitNativeCode(parallel_move()); | 589 compiler->parallel_move_resolver()->EmitNativeCode(parallel_move()); |
| 597 } | 590 } |
| 598 // We can fall through if the successor is the next block in the list. | 591 // We can fall through if the successor is the next block in the list. |
| 599 // Otherwise, we need a jump. | 592 // Otherwise, we need a jump. |
| 600 if (!compiler->CanFallThroughTo(successor())) { | 593 if (!compiler->CanFallThroughTo(successor())) { |
| 601 __ Jump(compiler->GetJumpLabel(successor())); | 594 __ Jump(compiler->GetJumpLabel(successor())); |
| 602 } | 595 } |
| 603 } | 596 } |
| 604 | 597 |
| 605 | 598 |
| 606 Condition TestSmiInstr::EmitComparisonCode(FlowGraphCompiler* compiler, | 599 Condition TestSmiInstr::EmitComparisonCode(FlowGraphCompiler* compiler, |
| 607 BranchLabels labels) { | 600 BranchLabels labels) { |
| 608 ASSERT((kind() == Token::kEQ) || | 601 ASSERT((kind() == Token::kEQ) || (kind() == Token::kNE)); |
| 609 (kind() == Token::kNE)); | |
| 610 Register left = locs()->in(0).reg(); | 602 Register left = locs()->in(0).reg(); |
| 611 Register right = locs()->in(1).reg(); | 603 Register right = locs()->in(1).reg(); |
| 612 __ TestSmi(left, right); | 604 __ TestSmi(left, right); |
| 613 return (kind() == Token::kEQ) ? NEXT_IS_TRUE : NEXT_IS_FALSE; | 605 return (kind() == Token::kEQ) ? NEXT_IS_TRUE : NEXT_IS_FALSE; |
| 614 } | 606 } |
| 615 | 607 |
| 616 | 608 |
| 617 void TestSmiInstr::EmitBranchCode(FlowGraphCompiler* compiler, | 609 void TestSmiInstr::EmitBranchCode(FlowGraphCompiler* compiler, |
| 618 BranchInstr* branch) { | 610 BranchInstr* branch) { |
| 619 BranchLabels labels = compiler->CreateBranchLabels(branch); | 611 BranchLabels labels = compiler->CreateBranchLabels(branch); |
| 620 Condition true_condition = EmitComparisonCode(compiler, labels); | 612 Condition true_condition = EmitComparisonCode(compiler, labels); |
| 621 EmitBranchOnCondition(compiler, true_condition, labels); | 613 EmitBranchOnCondition(compiler, true_condition, labels); |
| 622 } | 614 } |
| 623 | 615 |
| 624 | 616 |
| 625 EMIT_NATIVE_CODE(TestSmi, | 617 EMIT_NATIVE_CODE(TestSmi, |
| 626 2, | 618 2, |
| 627 Location::RequiresRegister(), | 619 Location::RequiresRegister(), |
| 628 LocationSummary::kNoCall) { | 620 LocationSummary::kNoCall) { |
| 629 // Never emitted outside of the BranchInstr. | 621 // Never emitted outside of the BranchInstr. |
| 630 UNREACHABLE(); | 622 UNREACHABLE(); |
| 631 } | 623 } |
| 632 | 624 |
| 633 | 625 |
| 634 Condition TestCidsInstr::EmitComparisonCode(FlowGraphCompiler* compiler, | 626 Condition TestCidsInstr::EmitComparisonCode(FlowGraphCompiler* compiler, |
| 635 BranchLabels labels) { | 627 BranchLabels labels) { |
| 636 ASSERT((kind() == Token::kIS) || (kind() == Token::kISNOT)); | 628 ASSERT((kind() == Token::kIS) || (kind() == Token::kISNOT)); |
| 637 const Register value = locs()->in(0).reg(); | 629 const Register value = locs()->in(0).reg(); |
| 638 const intptr_t true_result = (kind() == Token::kIS) ? 1 : 0; | 630 const intptr_t true_result = (kind() == Token::kIS) ? 1 : 0; |
| 639 | 631 |
| 640 const ZoneGrowableArray<intptr_t>& data = cid_results(); | 632 const ZoneGrowableArray<intptr_t>& data = cid_results(); |
| 641 const intptr_t num_cases = data.length() / 2; | 633 const intptr_t num_cases = data.length() / 2; |
| 642 ASSERT(num_cases <= 255); | 634 ASSERT(num_cases <= 255); |
| 643 __ TestCids(value, num_cases); | 635 __ TestCids(value, num_cases); |
| 644 | 636 |
| 645 bool result = false; | 637 bool result = false; |
| 646 for (intptr_t i = 0; i < data.length(); i += 2) { | 638 for (intptr_t i = 0; i < data.length(); i += 2) { |
| 647 const intptr_t test_cid = data[i]; | 639 const intptr_t test_cid = data[i]; |
| 648 result = data[i + 1] == true_result; | 640 result = data[i + 1] == true_result; |
| 649 __ Nop(result ? 1 : 0, compiler->ToEmbeddableCid(test_cid, this)); | 641 __ Nop(result ? 1 : 0, compiler->ToEmbeddableCid(test_cid, this)); |
| 650 } | 642 } |
| 651 | 643 |
| 652 // No match found, deoptimize or false. | 644 // No match found, deoptimize or false. |
| 653 if (CanDeoptimize()) { | 645 if (CanDeoptimize()) { |
| 654 compiler->EmitDeopt(deopt_id(), | 646 compiler->EmitDeopt(deopt_id(), ICData::kDeoptTestCids, |
| 655 ICData::kDeoptTestCids, | |
| 656 licm_hoisted_ ? ICData::kHoisted : 0); | 647 licm_hoisted_ ? ICData::kHoisted : 0); |
| 657 } else { | 648 } else { |
| 658 Label* target = result ? labels.false_label : labels.true_label; | 649 Label* target = result ? labels.false_label : labels.true_label; |
| 659 __ Jump(target); | 650 __ Jump(target); |
| 660 } | 651 } |
| 661 | 652 |
| 662 return NEXT_IS_TRUE; | 653 return NEXT_IS_TRUE; |
| 663 } | 654 } |
| 664 | 655 |
| 665 | 656 |
| 666 void TestCidsInstr::EmitBranchCode(FlowGraphCompiler* compiler, | 657 void TestCidsInstr::EmitBranchCode(FlowGraphCompiler* compiler, |
| 667 BranchInstr* branch) { | 658 BranchInstr* branch) { |
| 668 BranchLabels labels = compiler->CreateBranchLabels(branch); | 659 BranchLabels labels = compiler->CreateBranchLabels(branch); |
| 669 Condition true_condition = EmitComparisonCode(compiler, labels); | 660 Condition true_condition = EmitComparisonCode(compiler, labels); |
| 670 EmitBranchOnCondition(compiler, true_condition, labels); | 661 EmitBranchOnCondition(compiler, true_condition, labels); |
| 671 } | 662 } |
| 672 | 663 |
| 673 | 664 |
| 674 EMIT_NATIVE_CODE(TestCids, 1, Location::RequiresRegister(), | 665 EMIT_NATIVE_CODE(TestCids, |
| 666 1, |
| 667 Location::RequiresRegister(), |
| 675 LocationSummary::kNoCall) { | 668 LocationSummary::kNoCall) { |
| 676 Register result_reg = locs()->out(0).reg(); | 669 Register result_reg = locs()->out(0).reg(); |
| 677 Label is_true, is_false, done; | 670 Label is_true, is_false, done; |
| 678 BranchLabels labels = { &is_true, &is_false, &is_false }; | 671 BranchLabels labels = {&is_true, &is_false, &is_false}; |
| 679 EmitComparisonCode(compiler, labels); | 672 EmitComparisonCode(compiler, labels); |
| 680 __ Jump(&is_true); | 673 __ Jump(&is_true); |
| 681 __ Bind(&is_false); | 674 __ Bind(&is_false); |
| 682 __ LoadConstant(result_reg, Bool::False()); | 675 __ LoadConstant(result_reg, Bool::False()); |
| 683 __ Jump(&done); | 676 __ Jump(&done); |
| 684 __ Bind(&is_true); | 677 __ Bind(&is_true); |
| 685 __ LoadConstant(result_reg, Bool::True()); | 678 __ LoadConstant(result_reg, Bool::True()); |
| 686 __ Bind(&done); | 679 __ Bind(&done); |
| 687 } | 680 } |
| 688 | 681 |
| 689 | 682 |
| 690 EMIT_NATIVE_CODE(CreateArray, | 683 EMIT_NATIVE_CODE(CreateArray, |
| 691 2, Location::RequiresRegister(), | 684 2, |
| 685 Location::RequiresRegister(), |
| 692 LocationSummary::kCall) { | 686 LocationSummary::kCall) { |
| 693 if (compiler->is_optimizing()) { | 687 if (compiler->is_optimizing()) { |
| 694 const Register length = locs()->in(kLengthPos).reg(); | 688 const Register length = locs()->in(kLengthPos).reg(); |
| 695 const Register type_arguments = locs()->in(kElementTypePos).reg(); | 689 const Register type_arguments = locs()->in(kElementTypePos).reg(); |
| 696 const Register out = locs()->out(0).reg(); | 690 const Register out = locs()->out(0).reg(); |
| 697 __ CreateArrayOpt(out, length, type_arguments); | 691 __ CreateArrayOpt(out, length, type_arguments); |
| 698 __ Push(type_arguments); | 692 __ Push(type_arguments); |
| 699 __ Push(length); | 693 __ Push(length); |
| 700 __ CreateArrayTOS(); | 694 __ CreateArrayTOS(); |
| 701 compiler->RecordSafepoint(locs()); | 695 compiler->RecordSafepoint(locs()); |
| 702 __ PopLocal(out); | 696 __ PopLocal(out); |
| 703 } else { | 697 } else { |
| 704 __ CreateArrayTOS(); | 698 __ CreateArrayTOS(); |
| 705 compiler->RecordSafepoint(locs()); | 699 compiler->RecordSafepoint(locs()); |
| 706 } | 700 } |
| 707 } | 701 } |
| 708 | 702 |
| 709 | 703 |
| 710 EMIT_NATIVE_CODE(StoreIndexed, 3, Location::NoLocation(), | 704 EMIT_NATIVE_CODE(StoreIndexed, |
| 711 LocationSummary::kNoCall, 1) { | 705 3, |
| 706 Location::NoLocation(), |
| 707 LocationSummary::kNoCall, |
| 708 1) { |
| 712 if (!compiler->is_optimizing()) { | 709 if (!compiler->is_optimizing()) { |
| 713 ASSERT(class_id() == kArrayCid); | 710 ASSERT(class_id() == kArrayCid); |
| 714 __ StoreIndexedTOS(); | 711 __ StoreIndexedTOS(); |
| 715 return; | 712 return; |
| 716 } | 713 } |
| 717 const Register array = locs()->in(kArrayPos).reg(); | 714 const Register array = locs()->in(kArrayPos).reg(); |
| 718 const Register index = locs()->in(kIndexPos).reg(); | 715 const Register index = locs()->in(kIndexPos).reg(); |
| 719 const Register value = locs()->in(kValuePos).reg(); | 716 const Register value = locs()->in(kValuePos).reg(); |
| 720 const Register temp = locs()->temp(0).reg(); | 717 const Register temp = locs()->temp(0).reg(); |
| 721 switch (class_id()) { | 718 switch (class_id()) { |
| (...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 780 } | 777 } |
| 781 break; | 778 break; |
| 782 default: | 779 default: |
| 783 Unsupported(compiler); | 780 Unsupported(compiler); |
| 784 UNREACHABLE(); | 781 UNREACHABLE(); |
| 785 break; | 782 break; |
| 786 } | 783 } |
| 787 } | 784 } |
| 788 | 785 |
| 789 | 786 |
| 790 EMIT_NATIVE_CODE(LoadIndexed, 2, Location::RequiresRegister(), | 787 EMIT_NATIVE_CODE(LoadIndexed, |
| 791 LocationSummary::kNoCall, 1) { | 788 2, |
| 789 Location::RequiresRegister(), |
| 790 LocationSummary::kNoCall, |
| 791 1) { |
| 792 ASSERT(compiler->is_optimizing()); | 792 ASSERT(compiler->is_optimizing()); |
| 793 const Register array = locs()->in(0).reg(); | 793 const Register array = locs()->in(0).reg(); |
| 794 const Register index = locs()->in(1).reg(); | 794 const Register index = locs()->in(1).reg(); |
| 795 const Register temp = locs()->temp(0).reg(); | 795 const Register temp = locs()->temp(0).reg(); |
| 796 const Register result = locs()->out(0).reg(); | 796 const Register result = locs()->out(0).reg(); |
| 797 switch (class_id()) { | 797 switch (class_id()) { |
| 798 case kArrayCid: | 798 case kArrayCid: |
| 799 case kImmutableArrayCid: | 799 case kImmutableArrayCid: |
| 800 __ LoadIndexed(result, array, index); | 800 __ LoadIndexed(result, array, index); |
| 801 break; | 801 break; |
| (...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 891 break; | 891 break; |
| 892 default: | 892 default: |
| 893 Unsupported(compiler); | 893 Unsupported(compiler); |
| 894 UNREACHABLE(); | 894 UNREACHABLE(); |
| 895 break; | 895 break; |
| 896 } | 896 } |
| 897 } | 897 } |
| 898 | 898 |
| 899 | 899 |
| 900 EMIT_NATIVE_CODE(StringInterpolate, | 900 EMIT_NATIVE_CODE(StringInterpolate, |
| 901 1, Location::RegisterLocation(0), | 901 1, |
| 902 Location::RegisterLocation(0), |
| 902 LocationSummary::kCall) { | 903 LocationSummary::kCall) { |
| 903 if (compiler->is_optimizing()) { | 904 if (compiler->is_optimizing()) { |
| 904 __ Push(locs()->in(0).reg()); | 905 __ Push(locs()->in(0).reg()); |
| 905 } | 906 } |
| 906 const intptr_t kArgumentCount = 1; | 907 const intptr_t kArgumentCount = 1; |
| 907 const Array& arguments_descriptor = Array::Handle( | 908 const Array& arguments_descriptor = Array::Handle( |
| 908 ArgumentsDescriptor::New(kArgumentCount, Object::null_array())); | 909 ArgumentsDescriptor::New(kArgumentCount, Object::null_array())); |
| 909 __ PushConstant(CallFunction()); | 910 __ PushConstant(CallFunction()); |
| 910 const intptr_t argdesc_kidx = __ AddConstant(arguments_descriptor); | 911 const intptr_t argdesc_kidx = __ AddConstant(arguments_descriptor); |
| 911 __ StaticCall(kArgumentCount, argdesc_kidx); | 912 __ StaticCall(kArgumentCount, argdesc_kidx); |
| 912 compiler->RecordAfterCall(this); | 913 compiler->RecordAfterCall(this); |
| 913 if (compiler->is_optimizing()) { | 914 if (compiler->is_optimizing()) { |
| 914 __ PopLocal(locs()->out(0).reg()); | 915 __ PopLocal(locs()->out(0).reg()); |
| 915 } | 916 } |
| 916 } | 917 } |
| 917 | 918 |
| 918 | 919 |
| 919 EMIT_NATIVE_CODE(NativeCall, | 920 EMIT_NATIVE_CODE(NativeCall, |
| 920 0, Location::NoLocation(), | 921 0, |
| 922 Location::NoLocation(), |
| 921 LocationSummary::kCall) { | 923 LocationSummary::kCall) { |
| 922 SetupNative(); | 924 SetupNative(); |
| 923 | 925 |
| 924 const intptr_t argc_tag = NativeArguments::ComputeArgcTag(function()); | 926 const intptr_t argc_tag = NativeArguments::ComputeArgcTag(function()); |
| 925 | 927 |
| 926 ASSERT(!link_lazily()); | 928 ASSERT(!link_lazily()); |
| 927 const ExternalLabel label(reinterpret_cast<uword>(native_c_function())); | 929 const ExternalLabel label(reinterpret_cast<uword>(native_c_function())); |
| 928 const intptr_t target_kidx = | 930 const intptr_t target_kidx = |
| 929 __ object_pool_wrapper().FindNativeEntry(&label, kNotPatchable); | 931 __ object_pool_wrapper().FindNativeEntry(&label, kNotPatchable); |
| 930 const intptr_t argc_tag_kidx = | 932 const intptr_t argc_tag_kidx = |
| 931 __ object_pool_wrapper().FindImmediate(static_cast<uword>(argc_tag)); | 933 __ object_pool_wrapper().FindImmediate(static_cast<uword>(argc_tag)); |
| 932 __ PushConstant(target_kidx); | 934 __ PushConstant(target_kidx); |
| 933 __ PushConstant(argc_tag_kidx); | 935 __ PushConstant(argc_tag_kidx); |
| 934 if (is_bootstrap_native()) { | 936 if (is_bootstrap_native()) { |
| 935 __ NativeBootstrapCall(); | 937 __ NativeBootstrapCall(); |
| 936 } else { | 938 } else { |
| 937 __ NativeCall(); | 939 __ NativeCall(); |
| 938 } | 940 } |
| 939 compiler->RecordSafepoint(locs()); | 941 compiler->RecordSafepoint(locs()); |
| 940 compiler->AddCurrentDescriptor(RawPcDescriptors::kOther, | 942 compiler->AddCurrentDescriptor(RawPcDescriptors::kOther, Thread::kNoDeoptId, |
| 941 Thread::kNoDeoptId, | |
| 942 token_pos()); | 943 token_pos()); |
| 943 } | 944 } |
| 944 | 945 |
| 945 | 946 |
| 946 EMIT_NATIVE_CODE(OneByteStringFromCharCode, | 947 EMIT_NATIVE_CODE(OneByteStringFromCharCode, |
| 947 1, Location::RequiresRegister(), | 948 1, |
| 949 Location::RequiresRegister(), |
| 948 LocationSummary::kNoCall) { | 950 LocationSummary::kNoCall) { |
| 949 ASSERT(compiler->is_optimizing()); | 951 ASSERT(compiler->is_optimizing()); |
| 950 const Register char_code = locs()->in(0).reg(); // Char code is a smi. | 952 const Register char_code = locs()->in(0).reg(); // Char code is a smi. |
| 951 const Register result = locs()->out(0).reg(); | 953 const Register result = locs()->out(0).reg(); |
| 952 __ OneByteStringFromCharCode(result, char_code); | 954 __ OneByteStringFromCharCode(result, char_code); |
| 953 } | 955 } |
| 954 | 956 |
| 955 | 957 |
| 956 EMIT_NATIVE_CODE(StringToCharCode, | 958 EMIT_NATIVE_CODE(StringToCharCode, |
| 957 1, Location::RequiresRegister(), | 959 1, |
| 960 Location::RequiresRegister(), |
| 958 LocationSummary::kNoCall) { | 961 LocationSummary::kNoCall) { |
| 959 ASSERT(cid_ == kOneByteStringCid); | 962 ASSERT(cid_ == kOneByteStringCid); |
| 960 const Register str = locs()->in(0).reg(); | 963 const Register str = locs()->in(0).reg(); |
| 961 const Register result = locs()->out(0).reg(); // Result char code is a smi. | 964 const Register result = locs()->out(0).reg(); // Result char code is a smi. |
| 962 __ StringToCharCode(result, str); | 965 __ StringToCharCode(result, str); |
| 963 } | 966 } |
| 964 | 967 |
| 965 | 968 |
| 966 EMIT_NATIVE_CODE(AllocateObject, | 969 EMIT_NATIVE_CODE(AllocateObject, |
| 967 0, Location::RequiresRegister(), | 970 0, |
| 971 Location::RequiresRegister(), |
| 968 LocationSummary::kCall) { | 972 LocationSummary::kCall) { |
| 969 if (ArgumentCount() == 1) { | 973 if (ArgumentCount() == 1) { |
| 970 // Allocate with type arguments. | 974 // Allocate with type arguments. |
| 971 if (compiler->is_optimizing()) { | 975 if (compiler->is_optimizing()) { |
| 972 // If we're optimizing, try a streamlined fastpath. | 976 // If we're optimizing, try a streamlined fastpath. |
| 973 const intptr_t instance_size = cls().instance_size(); | 977 const intptr_t instance_size = cls().instance_size(); |
| 974 Isolate* isolate = Isolate::Current(); | 978 Isolate* isolate = Isolate::Current(); |
| 975 if (Heap::IsAllocatableInNewSpace(instance_size) && | 979 if (Heap::IsAllocatableInNewSpace(instance_size) && |
| 976 !cls().TraceAllocation(isolate)) { | 980 !cls().TraceAllocation(isolate)) { |
| 977 uword tags = 0; | 981 uword tags = 0; |
| 978 tags = RawObject::SizeTag::update(instance_size, tags); | 982 tags = RawObject::SizeTag::update(instance_size, tags); |
| 979 ASSERT(cls().id() != kIllegalCid); | 983 ASSERT(cls().id() != kIllegalCid); |
| 980 tags = RawObject::ClassIdTag::update(cls().id(), tags); | 984 tags = RawObject::ClassIdTag::update(cls().id(), tags); |
| 981 if (Smi::IsValid(tags)) { | 985 if (Smi::IsValid(tags)) { |
| 982 const intptr_t tags_kidx = __ AddConstant( | 986 const intptr_t tags_kidx = |
| 983 Smi::Handle(Smi::New(tags))); | 987 __ AddConstant(Smi::Handle(Smi::New(tags))); |
| 984 __ AllocateTOpt(locs()->out(0).reg(), tags_kidx); | 988 __ AllocateTOpt(locs()->out(0).reg(), tags_kidx); |
| 985 __ Nop(cls().type_arguments_field_offset()); | 989 __ Nop(cls().type_arguments_field_offset()); |
| 986 } | 990 } |
| 987 } | 991 } |
| 988 __ PushConstant(cls()); | 992 __ PushConstant(cls()); |
| 989 __ AllocateT(); | 993 __ AllocateT(); |
| 990 compiler->AddCurrentDescriptor(RawPcDescriptors::kOther, | 994 compiler->AddCurrentDescriptor(RawPcDescriptors::kOther, |
| 991 Thread::kNoDeoptId, | 995 Thread::kNoDeoptId, token_pos()); |
| 992 token_pos()); | |
| 993 compiler->RecordSafepoint(locs()); | 996 compiler->RecordSafepoint(locs()); |
| 994 __ PopLocal(locs()->out(0).reg()); | 997 __ PopLocal(locs()->out(0).reg()); |
| 995 } else { | 998 } else { |
| 996 __ PushConstant(cls()); | 999 __ PushConstant(cls()); |
| 997 __ AllocateT(); | 1000 __ AllocateT(); |
| 998 compiler->AddCurrentDescriptor(RawPcDescriptors::kOther, | 1001 compiler->AddCurrentDescriptor(RawPcDescriptors::kOther, |
| 999 Thread::kNoDeoptId, | 1002 Thread::kNoDeoptId, token_pos()); |
| 1000 token_pos()); | |
| 1001 compiler->RecordSafepoint(locs()); | 1003 compiler->RecordSafepoint(locs()); |
| 1002 } | 1004 } |
| 1003 } else if (compiler->is_optimizing()) { | 1005 } else if (compiler->is_optimizing()) { |
| 1004 // If we're optimizing, try a streamlined fastpath. | 1006 // If we're optimizing, try a streamlined fastpath. |
| 1005 const intptr_t instance_size = cls().instance_size(); | 1007 const intptr_t instance_size = cls().instance_size(); |
| 1006 Isolate* isolate = Isolate::Current(); | 1008 Isolate* isolate = Isolate::Current(); |
| 1007 if (Heap::IsAllocatableInNewSpace(instance_size) && | 1009 if (Heap::IsAllocatableInNewSpace(instance_size) && |
| 1008 !cls().TraceAllocation(isolate)) { | 1010 !cls().TraceAllocation(isolate)) { |
| 1009 uword tags = 0; | 1011 uword tags = 0; |
| 1010 tags = RawObject::SizeTag::update(instance_size, tags); | 1012 tags = RawObject::SizeTag::update(instance_size, tags); |
| 1011 ASSERT(cls().id() != kIllegalCid); | 1013 ASSERT(cls().id() != kIllegalCid); |
| 1012 tags = RawObject::ClassIdTag::update(cls().id(), tags); | 1014 tags = RawObject::ClassIdTag::update(cls().id(), tags); |
| 1013 if (Smi::IsValid(tags)) { | 1015 if (Smi::IsValid(tags)) { |
| 1014 const intptr_t tags_kidx = __ AddConstant(Smi::Handle(Smi::New(tags))); | 1016 const intptr_t tags_kidx = __ AddConstant(Smi::Handle(Smi::New(tags))); |
| 1015 __ AllocateOpt(locs()->out(0).reg(), tags_kidx); | 1017 __ AllocateOpt(locs()->out(0).reg(), tags_kidx); |
| 1016 } | 1018 } |
| 1017 } | 1019 } |
| 1018 const intptr_t kidx = __ AddConstant(cls()); | 1020 const intptr_t kidx = __ AddConstant(cls()); |
| 1019 __ Allocate(kidx); | 1021 __ Allocate(kidx); |
| 1020 compiler->AddCurrentDescriptor(RawPcDescriptors::kOther, | 1022 compiler->AddCurrentDescriptor(RawPcDescriptors::kOther, Thread::kNoDeoptId, |
| 1021 Thread::kNoDeoptId, | |
| 1022 token_pos()); | 1023 token_pos()); |
| 1023 compiler->RecordSafepoint(locs()); | 1024 compiler->RecordSafepoint(locs()); |
| 1024 __ PopLocal(locs()->out(0).reg()); | 1025 __ PopLocal(locs()->out(0).reg()); |
| 1025 } else { | 1026 } else { |
| 1026 const intptr_t kidx = __ AddConstant(cls()); | 1027 const intptr_t kidx = __ AddConstant(cls()); |
| 1027 __ Allocate(kidx); | 1028 __ Allocate(kidx); |
| 1028 compiler->AddCurrentDescriptor(RawPcDescriptors::kOther, | 1029 compiler->AddCurrentDescriptor(RawPcDescriptors::kOther, Thread::kNoDeoptId, |
| 1029 Thread::kNoDeoptId, | |
| 1030 token_pos()); | 1030 token_pos()); |
| 1031 compiler->RecordSafepoint(locs()); | 1031 compiler->RecordSafepoint(locs()); |
| 1032 } | 1032 } |
| 1033 } | 1033 } |
| 1034 | 1034 |
| 1035 | 1035 |
| 1036 EMIT_NATIVE_CODE(StoreInstanceField, 2) { | 1036 EMIT_NATIVE_CODE(StoreInstanceField, 2) { |
| 1037 ASSERT(!HasTemp()); | 1037 ASSERT(!HasTemp()); |
| 1038 ASSERT(offset_in_bytes() % kWordSize == 0); | 1038 ASSERT(offset_in_bytes() % kWordSize == 0); |
| 1039 if (compiler->is_optimizing()) { | 1039 if (compiler->is_optimizing()) { |
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1083 EMIT_NATIVE_CODE(BooleanNegate, 1, Location::RequiresRegister()) { | 1083 EMIT_NATIVE_CODE(BooleanNegate, 1, Location::RequiresRegister()) { |
| 1084 if (compiler->is_optimizing()) { | 1084 if (compiler->is_optimizing()) { |
| 1085 __ BooleanNegate(locs()->out(0).reg(), locs()->in(0).reg()); | 1085 __ BooleanNegate(locs()->out(0).reg(), locs()->in(0).reg()); |
| 1086 } else { | 1086 } else { |
| 1087 __ BooleanNegateTOS(); | 1087 __ BooleanNegateTOS(); |
| 1088 } | 1088 } |
| 1089 } | 1089 } |
| 1090 | 1090 |
| 1091 | 1091 |
| 1092 EMIT_NATIVE_CODE(AllocateContext, | 1092 EMIT_NATIVE_CODE(AllocateContext, |
| 1093 0, Location::RequiresRegister(), | 1093 0, |
| 1094 Location::RequiresRegister(), |
| 1094 LocationSummary::kCall) { | 1095 LocationSummary::kCall) { |
| 1095 ASSERT(!compiler->is_optimizing()); | 1096 ASSERT(!compiler->is_optimizing()); |
| 1096 __ AllocateContext(num_context_variables()); | 1097 __ AllocateContext(num_context_variables()); |
| 1097 compiler->RecordSafepoint(locs()); | 1098 compiler->RecordSafepoint(locs()); |
| 1098 compiler->AddCurrentDescriptor(RawPcDescriptors::kOther, | 1099 compiler->AddCurrentDescriptor(RawPcDescriptors::kOther, Thread::kNoDeoptId, |
| 1099 Thread::kNoDeoptId, | |
| 1100 token_pos()); | 1100 token_pos()); |
| 1101 } | 1101 } |
| 1102 | 1102 |
| 1103 | 1103 |
| 1104 EMIT_NATIVE_CODE(AllocateUninitializedContext, | 1104 EMIT_NATIVE_CODE(AllocateUninitializedContext, |
| 1105 0, Location::RequiresRegister(), | 1105 0, |
| 1106 Location::RequiresRegister(), |
| 1106 LocationSummary::kCall) { | 1107 LocationSummary::kCall) { |
| 1107 ASSERT(compiler->is_optimizing()); | 1108 ASSERT(compiler->is_optimizing()); |
| 1108 __ AllocateUninitializedContext(locs()->out(0).reg(), | 1109 __ AllocateUninitializedContext(locs()->out(0).reg(), |
| 1109 num_context_variables()); | 1110 num_context_variables()); |
| 1110 __ AllocateContext(num_context_variables()); | 1111 __ AllocateContext(num_context_variables()); |
| 1111 compiler->RecordSafepoint(locs()); | 1112 compiler->RecordSafepoint(locs()); |
| 1112 compiler->AddCurrentDescriptor(RawPcDescriptors::kOther, | 1113 compiler->AddCurrentDescriptor(RawPcDescriptors::kOther, Thread::kNoDeoptId, |
| 1113 Thread::kNoDeoptId, | |
| 1114 token_pos()); | 1114 token_pos()); |
| 1115 __ PopLocal(locs()->out(0).reg()); | 1115 __ PopLocal(locs()->out(0).reg()); |
| 1116 } | 1116 } |
| 1117 | 1117 |
| 1118 | 1118 |
| 1119 EMIT_NATIVE_CODE(CloneContext, | 1119 EMIT_NATIVE_CODE(CloneContext, |
| 1120 1, Location::RequiresRegister(), | 1120 1, |
| 1121 Location::RequiresRegister(), |
| 1121 LocationSummary::kCall) { | 1122 LocationSummary::kCall) { |
| 1122 if (compiler->is_optimizing()) { | 1123 if (compiler->is_optimizing()) { |
| 1123 __ Push(locs()->in(0).reg()); | 1124 __ Push(locs()->in(0).reg()); |
| 1124 } | 1125 } |
| 1125 __ CloneContext(); | 1126 __ CloneContext(); |
| 1126 compiler->RecordSafepoint(locs()); | 1127 compiler->RecordSafepoint(locs()); |
| 1127 compiler->AddCurrentDescriptor(RawPcDescriptors::kOther, | 1128 compiler->AddCurrentDescriptor(RawPcDescriptors::kOther, Thread::kNoDeoptId, |
| 1128 Thread::kNoDeoptId, | |
| 1129 token_pos()); | 1129 token_pos()); |
| 1130 if (compiler->is_optimizing()) { | 1130 if (compiler->is_optimizing()) { |
| 1131 __ PopLocal(locs()->out(0).reg()); | 1131 __ PopLocal(locs()->out(0).reg()); |
| 1132 } | 1132 } |
| 1133 } | 1133 } |
| 1134 | 1134 |
| 1135 | 1135 |
| 1136 EMIT_NATIVE_CODE(CatchBlockEntry, 0) { | 1136 EMIT_NATIVE_CODE(CatchBlockEntry, 0) { |
| 1137 __ Bind(compiler->GetJumpLabel(this)); | 1137 __ Bind(compiler->GetJumpLabel(this)); |
| 1138 compiler->AddExceptionHandler(catch_try_index(), | 1138 compiler->AddExceptionHandler(catch_try_index(), try_index(), |
| 1139 try_index(), | |
| 1140 compiler->assembler()->CodeSize(), | 1139 compiler->assembler()->CodeSize(), |
| 1141 catch_handler_types_, | 1140 catch_handler_types_, needs_stacktrace()); |
| 1142 needs_stacktrace()); | |
| 1143 | 1141 |
| 1144 if (HasParallelMove()) { | 1142 if (HasParallelMove()) { |
| 1145 compiler->parallel_move_resolver()->EmitNativeCode(parallel_move()); | 1143 compiler->parallel_move_resolver()->EmitNativeCode(parallel_move()); |
| 1146 } | 1144 } |
| 1147 if (compiler->is_optimizing()) { | 1145 if (compiler->is_optimizing()) { |
| 1148 // In optimized code, variables at the catch block entry reside at the top | 1146 // In optimized code, variables at the catch block entry reside at the top |
| 1149 // of the allocatable register range. | 1147 // of the allocatable register range. |
| 1150 const intptr_t num_non_copied_params = | 1148 const intptr_t num_non_copied_params = |
| 1151 compiler->flow_graph().num_non_copied_params(); | 1149 compiler->flow_graph().num_non_copied_params(); |
| 1152 const intptr_t exception_reg = kNumberOfCpuRegisters - | 1150 const intptr_t exception_reg = |
| 1151 kNumberOfCpuRegisters - |
| 1153 (-exception_var().index() + num_non_copied_params); | 1152 (-exception_var().index() + num_non_copied_params); |
| 1154 const intptr_t stacktrace_reg = kNumberOfCpuRegisters - | 1153 const intptr_t stacktrace_reg = |
| 1154 kNumberOfCpuRegisters - |
| 1155 (-stacktrace_var().index() + num_non_copied_params); | 1155 (-stacktrace_var().index() + num_non_copied_params); |
| 1156 __ MoveSpecial(exception_reg, Simulator::kExceptionSpecialIndex); | 1156 __ MoveSpecial(exception_reg, Simulator::kExceptionSpecialIndex); |
| 1157 __ MoveSpecial(stacktrace_reg, Simulator::kStacktraceSpecialIndex); | 1157 __ MoveSpecial(stacktrace_reg, Simulator::kStacktraceSpecialIndex); |
| 1158 } else { | 1158 } else { |
| 1159 __ MoveSpecial(LocalVarIndex(0, exception_var().index()), | 1159 __ MoveSpecial(LocalVarIndex(0, exception_var().index()), |
| 1160 Simulator::kExceptionSpecialIndex); | 1160 Simulator::kExceptionSpecialIndex); |
| 1161 __ MoveSpecial(LocalVarIndex(0, stacktrace_var().index()), | 1161 __ MoveSpecial(LocalVarIndex(0, stacktrace_var().index()), |
| 1162 Simulator::kStacktraceSpecialIndex); | 1162 Simulator::kStacktraceSpecialIndex); |
| 1163 } | 1163 } |
| 1164 __ SetFrame(compiler->StackSize()); | 1164 __ SetFrame(compiler->StackSize()); |
| 1165 } | 1165 } |
| 1166 | 1166 |
| 1167 | 1167 |
| 1168 EMIT_NATIVE_CODE(Throw, 0, Location::NoLocation(), LocationSummary::kCall) { | 1168 EMIT_NATIVE_CODE(Throw, 0, Location::NoLocation(), LocationSummary::kCall) { |
| 1169 __ Throw(0); | 1169 __ Throw(0); |
| 1170 compiler->AddCurrentDescriptor(RawPcDescriptors::kOther, | 1170 compiler->AddCurrentDescriptor(RawPcDescriptors::kOther, deopt_id(), |
| 1171 deopt_id(), | |
| 1172 token_pos()); | 1171 token_pos()); |
| 1173 compiler->RecordAfterCall(this); | 1172 compiler->RecordAfterCall(this); |
| 1174 __ Trap(); | 1173 __ Trap(); |
| 1175 } | 1174 } |
| 1176 | 1175 |
| 1177 | 1176 |
| 1178 EMIT_NATIVE_CODE(ReThrow, 0, Location::NoLocation(), LocationSummary::kCall) { | 1177 EMIT_NATIVE_CODE(ReThrow, 0, Location::NoLocation(), LocationSummary::kCall) { |
| 1179 compiler->SetNeedsStacktrace(catch_try_index()); | 1178 compiler->SetNeedsStacktrace(catch_try_index()); |
| 1180 __ Throw(1); | 1179 __ Throw(1); |
| 1181 compiler->AddCurrentDescriptor(RawPcDescriptors::kOther, | 1180 compiler->AddCurrentDescriptor(RawPcDescriptors::kOther, deopt_id(), |
| 1182 deopt_id(), | |
| 1183 token_pos()); | 1181 token_pos()); |
| 1184 compiler->RecordAfterCall(this); | 1182 compiler->RecordAfterCall(this); |
| 1185 __ Trap(); | 1183 __ Trap(); |
| 1186 } | 1184 } |
| 1187 | 1185 |
| 1188 EMIT_NATIVE_CODE(InstantiateType, | 1186 EMIT_NATIVE_CODE(InstantiateType, |
| 1189 1, Location::RequiresRegister(), | 1187 1, |
| 1188 Location::RequiresRegister(), |
| 1190 LocationSummary::kCall) { | 1189 LocationSummary::kCall) { |
| 1191 if (compiler->is_optimizing()) { | 1190 if (compiler->is_optimizing()) { |
| 1192 __ Push(locs()->in(0).reg()); | 1191 __ Push(locs()->in(0).reg()); |
| 1193 } | 1192 } |
| 1194 __ InstantiateType(__ AddConstant(type())); | 1193 __ InstantiateType(__ AddConstant(type())); |
| 1195 compiler->RecordSafepoint(locs()); | 1194 compiler->RecordSafepoint(locs()); |
| 1196 compiler->AddCurrentDescriptor(RawPcDescriptors::kOther, | 1195 compiler->AddCurrentDescriptor(RawPcDescriptors::kOther, deopt_id(), |
| 1197 deopt_id(), | |
| 1198 token_pos()); | 1196 token_pos()); |
| 1199 if (compiler->is_optimizing()) { | 1197 if (compiler->is_optimizing()) { |
| 1200 __ PopLocal(locs()->out(0).reg()); | 1198 __ PopLocal(locs()->out(0).reg()); |
| 1201 } | 1199 } |
| 1202 } | 1200 } |
| 1203 | 1201 |
| 1204 EMIT_NATIVE_CODE(InstantiateTypeArguments, | 1202 EMIT_NATIVE_CODE(InstantiateTypeArguments, |
| 1205 1, Location::RequiresRegister(), | 1203 1, |
| 1204 Location::RequiresRegister(), |
| 1206 LocationSummary::kCall) { | 1205 LocationSummary::kCall) { |
| 1207 if (compiler->is_optimizing()) { | 1206 if (compiler->is_optimizing()) { |
| 1208 __ Push(locs()->in(0).reg()); | 1207 __ Push(locs()->in(0).reg()); |
| 1209 } | 1208 } |
| 1210 __ InstantiateTypeArgumentsTOS( | 1209 __ InstantiateTypeArgumentsTOS( |
| 1211 type_arguments().IsRawInstantiatedRaw(type_arguments().Length()), | 1210 type_arguments().IsRawInstantiatedRaw(type_arguments().Length()), |
| 1212 __ AddConstant(type_arguments())); | 1211 __ AddConstant(type_arguments())); |
| 1213 compiler->RecordSafepoint(locs()); | 1212 compiler->RecordSafepoint(locs()); |
| 1214 compiler->AddCurrentDescriptor(RawPcDescriptors::kOther, | 1213 compiler->AddCurrentDescriptor(RawPcDescriptors::kOther, deopt_id(), |
| 1215 deopt_id(), | |
| 1216 token_pos()); | 1214 token_pos()); |
| 1217 if (compiler->is_optimizing()) { | 1215 if (compiler->is_optimizing()) { |
| 1218 __ PopLocal(locs()->out(0).reg()); | 1216 __ PopLocal(locs()->out(0).reg()); |
| 1219 } | 1217 } |
| 1220 } | 1218 } |
| 1221 | 1219 |
| 1222 | 1220 |
| 1223 void DebugStepCheckInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | 1221 void DebugStepCheckInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
| 1224 __ DebugStep(); | 1222 __ DebugStep(); |
| 1225 compiler->AddCurrentDescriptor(stub_kind_, Thread::kNoDeoptId, token_pos()); | 1223 compiler->AddCurrentDescriptor(stub_kind_, Thread::kNoDeoptId, token_pos()); |
| 1226 } | 1224 } |
| 1227 | 1225 |
| 1228 | 1226 |
| 1229 void GraphEntryInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | 1227 void GraphEntryInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
| 1230 if (!compiler->CanFallThroughTo(normal_entry())) { | 1228 if (!compiler->CanFallThroughTo(normal_entry())) { |
| 1231 __ Jump(compiler->GetJumpLabel(normal_entry())); | 1229 __ Jump(compiler->GetJumpLabel(normal_entry())); |
| 1232 } | 1230 } |
| 1233 } | 1231 } |
| 1234 | 1232 |
| 1235 | 1233 |
| 1236 LocationSummary* Instruction::MakeCallSummary(Zone* zone) { | 1234 LocationSummary* Instruction::MakeCallSummary(Zone* zone) { |
| 1237 LocationSummary* result = new(zone) LocationSummary( | 1235 LocationSummary* result = |
| 1238 zone, 0, 0, LocationSummary::kCall); | 1236 new (zone) LocationSummary(zone, 0, 0, LocationSummary::kCall); |
| 1239 // TODO(vegorov) support allocating out registers for calls. | 1237 // TODO(vegorov) support allocating out registers for calls. |
| 1240 // Currently we require them to be fixed. | 1238 // Currently we require them to be fixed. |
| 1241 result->set_out(0, Location::RegisterLocation(0)); | 1239 result->set_out(0, Location::RegisterLocation(0)); |
| 1242 return result; | 1240 return result; |
| 1243 } | 1241 } |
| 1244 | 1242 |
| 1245 | 1243 |
| 1246 CompileType BinaryUint32OpInstr::ComputeType() const { | 1244 CompileType BinaryUint32OpInstr::ComputeType() const { |
| 1247 return CompileType::Int(); | 1245 return CompileType::Int(); |
| 1248 } | 1246 } |
| 1249 | 1247 |
| 1250 | 1248 |
| 1251 CompileType ShiftUint32OpInstr::ComputeType() const { | 1249 CompileType ShiftUint32OpInstr::ComputeType() const { |
| 1252 return CompileType::Int(); | 1250 return CompileType::Int(); |
| 1253 } | 1251 } |
| 1254 | 1252 |
| 1255 | 1253 |
| 1256 CompileType UnaryUint32OpInstr::ComputeType() const { | 1254 CompileType UnaryUint32OpInstr::ComputeType() const { |
| 1257 return CompileType::Int(); | 1255 return CompileType::Int(); |
| 1258 } | 1256 } |
| 1259 | 1257 |
| 1260 | 1258 |
| 1261 static const intptr_t kMintShiftCountLimit = 63; | 1259 static const intptr_t kMintShiftCountLimit = 63; |
| 1262 | 1260 |
| 1263 | 1261 |
| 1264 bool ShiftMintOpInstr::has_shift_count_check() const { | 1262 bool ShiftMintOpInstr::has_shift_count_check() const { |
| 1265 return !RangeUtils::IsWithin( | 1263 return !RangeUtils::IsWithin(right()->definition()->range(), 0, |
| 1266 right()->definition()->range(), 0, kMintShiftCountLimit); | 1264 kMintShiftCountLimit); |
| 1267 } | 1265 } |
| 1268 | 1266 |
| 1269 | 1267 |
| 1270 CompileType LoadIndexedInstr::ComputeType() const { | 1268 CompileType LoadIndexedInstr::ComputeType() const { |
| 1271 switch (class_id_) { | 1269 switch (class_id_) { |
| 1272 case kArrayCid: | 1270 case kArrayCid: |
| 1273 case kImmutableArrayCid: | 1271 case kImmutableArrayCid: |
| 1274 return CompileType::Dynamic(); | 1272 return CompileType::Dynamic(); |
| 1275 | 1273 |
| 1276 case kTypedDataFloat32ArrayCid: | 1274 case kTypedDataFloat32ArrayCid: |
| (...skipping 105 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1382 return kUnboxedFloat64x2; | 1380 return kUnboxedFloat64x2; |
| 1383 default: | 1381 default: |
| 1384 UNREACHABLE(); | 1382 UNREACHABLE(); |
| 1385 return kTagged; | 1383 return kTagged; |
| 1386 } | 1384 } |
| 1387 } | 1385 } |
| 1388 | 1386 |
| 1389 | 1387 |
| 1390 void Environment::DropArguments(intptr_t argc) { | 1388 void Environment::DropArguments(intptr_t argc) { |
| 1391 #if defined(DEBUG) | 1389 #if defined(DEBUG) |
| 1392 // Check that we are in the backend - register allocation has been run. | 1390 // Check that we are in the backend - register allocation has been run. |
| 1393 ASSERT(locations_ != NULL); | 1391 ASSERT(locations_ != NULL); |
| 1394 | 1392 |
| 1395 // Check that we are only dropping a valid number of instructions from the | 1393 // Check that we are only dropping a valid number of instructions from the |
| 1396 // environment. | 1394 // environment. |
| 1397 ASSERT(argc <= values_.length()); | 1395 ASSERT(argc <= values_.length()); |
| 1398 #endif | 1396 #endif |
| 1399 values_.TruncateTo(values_.length() - argc); | 1397 values_.TruncateTo(values_.length() - argc); |
| 1400 } | 1398 } |
| 1401 | 1399 |
| 1402 | 1400 |
| 1403 EMIT_NATIVE_CODE(CheckSmi, 1) { | 1401 EMIT_NATIVE_CODE(CheckSmi, 1) { |
| 1404 __ CheckSmi(locs()->in(0).reg()); | 1402 __ CheckSmi(locs()->in(0).reg()); |
| 1405 compiler->EmitDeopt(deopt_id(), | 1403 compiler->EmitDeopt(deopt_id(), ICData::kDeoptCheckSmi, |
| 1406 ICData::kDeoptCheckSmi, | |
| 1407 licm_hoisted_ ? ICData::kHoisted : 0); | 1404 licm_hoisted_ ? ICData::kHoisted : 0); |
| 1408 } | 1405 } |
| 1409 | 1406 |
| 1410 | 1407 |
| 1411 EMIT_NATIVE_CODE(CheckEitherNonSmi, 2) { | 1408 EMIT_NATIVE_CODE(CheckEitherNonSmi, 2) { |
| 1412 const Register left = locs()->in(0).reg(); | 1409 const Register left = locs()->in(0).reg(); |
| 1413 const Register right = locs()->in(1).reg(); | 1410 const Register right = locs()->in(1).reg(); |
| 1414 __ CheckEitherNonSmi(left, right); | 1411 __ CheckEitherNonSmi(left, right); |
| 1415 compiler->EmitDeopt(deopt_id(), ICData::kDeoptBinaryDoubleOp, | 1412 compiler->EmitDeopt(deopt_id(), ICData::kDeoptBinaryDoubleOp, |
| 1416 licm_hoisted_ ? ICData::kHoisted : 0); | 1413 licm_hoisted_ ? ICData::kHoisted : 0); |
| 1417 } | 1414 } |
| 1418 | 1415 |
| 1419 | 1416 |
| 1420 EMIT_NATIVE_CODE(CheckClassId, 1) { | 1417 EMIT_NATIVE_CODE(CheckClassId, 1) { |
| 1421 __ CheckClassId(locs()->in(0).reg(), | 1418 __ CheckClassId(locs()->in(0).reg(), compiler->ToEmbeddableCid(cid_, this)); |
| 1422 compiler->ToEmbeddableCid(cid_, this)); | |
| 1423 compiler->EmitDeopt(deopt_id(), ICData::kDeoptCheckClass); | 1419 compiler->EmitDeopt(deopt_id(), ICData::kDeoptCheckClass); |
| 1424 } | 1420 } |
| 1425 | 1421 |
| 1426 | 1422 |
| 1427 EMIT_NATIVE_CODE(CheckClass, 1) { | 1423 EMIT_NATIVE_CODE(CheckClass, 1) { |
| 1428 const Register value = locs()->in(0).reg(); | 1424 const Register value = locs()->in(0).reg(); |
| 1429 if (IsNullCheck()) { | 1425 if (IsNullCheck()) { |
| 1430 ASSERT(DeoptIfNull() || DeoptIfNotNull()); | 1426 ASSERT(DeoptIfNull() || DeoptIfNotNull()); |
| 1431 if (DeoptIfNull()) { | 1427 if (DeoptIfNull()) { |
| 1432 __ IfEqNull(value); | 1428 __ IfEqNull(value); |
| (...skipping 12 matching lines...) Expand all Loading... |
| 1445 cid_mask = ComputeCidMask(); | 1441 cid_mask = ComputeCidMask(); |
| 1446 is_dense_switch = Smi::IsValid(cid_mask); | 1442 is_dense_switch = Smi::IsValid(cid_mask); |
| 1447 } | 1443 } |
| 1448 if (is_dense_switch) { | 1444 if (is_dense_switch) { |
| 1449 const intptr_t low_cid = cids_[0]; | 1445 const intptr_t low_cid = cids_[0]; |
| 1450 __ CheckDenseSwitch(value, may_be_smi); | 1446 __ CheckDenseSwitch(value, may_be_smi); |
| 1451 __ Nop(compiler->ToEmbeddableCid(low_cid, this)); | 1447 __ Nop(compiler->ToEmbeddableCid(low_cid, this)); |
| 1452 __ Nop(__ AddConstant(Smi::Handle(Smi::New(cid_mask)))); | 1448 __ Nop(__ AddConstant(Smi::Handle(Smi::New(cid_mask)))); |
| 1453 } else { | 1449 } else { |
| 1454 GrowableArray<CidTarget> sorted_ic_data; | 1450 GrowableArray<CidTarget> sorted_ic_data; |
| 1455 FlowGraphCompiler::SortICDataByCount(unary_checks(), | 1451 FlowGraphCompiler::SortICDataByCount(unary_checks(), &sorted_ic_data, |
| 1456 &sorted_ic_data, | |
| 1457 /* drop_smi = */ true); | 1452 /* drop_smi = */ true); |
| 1458 const intptr_t sorted_length = sorted_ic_data.length(); | 1453 const intptr_t sorted_length = sorted_ic_data.length(); |
| 1459 if (!Utils::IsUint(8, sorted_length)) { | 1454 if (!Utils::IsUint(8, sorted_length)) { |
| 1460 Unsupported(compiler); | 1455 Unsupported(compiler); |
| 1461 UNREACHABLE(); | 1456 UNREACHABLE(); |
| 1462 } | 1457 } |
| 1463 __ CheckCids(value, may_be_smi, sorted_length); | 1458 __ CheckCids(value, may_be_smi, sorted_length); |
| 1464 for (intptr_t i = 0; i < sorted_length; i++) { | 1459 for (intptr_t i = 0; i < sorted_length; i++) { |
| 1465 __ Nop(compiler->ToEmbeddableCid(sorted_ic_data[i].cid, this)); | 1460 __ Nop(compiler->ToEmbeddableCid(sorted_ic_data[i].cid, this)); |
| 1466 } | 1461 } |
| 1467 } | 1462 } |
| 1468 } | 1463 } |
| 1469 compiler->EmitDeopt(deopt_id(), | 1464 compiler->EmitDeopt(deopt_id(), ICData::kDeoptCheckClass, |
| 1470 ICData::kDeoptCheckClass, | |
| 1471 licm_hoisted_ ? ICData::kHoisted : 0); | 1465 licm_hoisted_ ? ICData::kHoisted : 0); |
| 1472 } | 1466 } |
| 1473 | 1467 |
| 1474 | 1468 |
| 1475 EMIT_NATIVE_CODE(BinarySmiOp, 2, Location::RequiresRegister()) { | 1469 EMIT_NATIVE_CODE(BinarySmiOp, 2, Location::RequiresRegister()) { |
| 1476 const Register left = locs()->in(0).reg(); | 1470 const Register left = locs()->in(0).reg(); |
| 1477 const Register right = locs()->in(1).reg(); | 1471 const Register right = locs()->in(1).reg(); |
| 1478 const Register out = locs()->out(0).reg(); | 1472 const Register out = locs()->out(0).reg(); |
| 1479 const bool can_deopt = CanDeoptimize(); | 1473 const bool can_deopt = CanDeoptimize(); |
| 1480 bool needs_nop = false; | 1474 bool needs_nop = false; |
| (...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1558 uword tags = 0; | 1552 uword tags = 0; |
| 1559 tags = RawObject::SizeTag::update(instance_size, tags); | 1553 tags = RawObject::SizeTag::update(instance_size, tags); |
| 1560 tags = RawObject::ClassIdTag::update(compiler->double_class().id(), tags); | 1554 tags = RawObject::ClassIdTag::update(compiler->double_class().id(), tags); |
| 1561 if (Smi::IsValid(tags)) { | 1555 if (Smi::IsValid(tags)) { |
| 1562 const intptr_t tags_kidx = __ AddConstant(Smi::Handle(Smi::New(tags))); | 1556 const intptr_t tags_kidx = __ AddConstant(Smi::Handle(Smi::New(tags))); |
| 1563 __ AllocateOpt(out, tags_kidx); | 1557 __ AllocateOpt(out, tags_kidx); |
| 1564 } | 1558 } |
| 1565 } | 1559 } |
| 1566 const intptr_t kidx = __ AddConstant(compiler->double_class()); | 1560 const intptr_t kidx = __ AddConstant(compiler->double_class()); |
| 1567 __ Allocate(kidx); | 1561 __ Allocate(kidx); |
| 1568 compiler->AddCurrentDescriptor(RawPcDescriptors::kOther, | 1562 compiler->AddCurrentDescriptor(RawPcDescriptors::kOther, Thread::kNoDeoptId, |
| 1569 Thread::kNoDeoptId, | |
| 1570 token_pos()); | 1563 token_pos()); |
| 1571 compiler->RecordSafepoint(locs()); | 1564 compiler->RecordSafepoint(locs()); |
| 1572 __ PopLocal(out); | 1565 __ PopLocal(out); |
| 1573 __ WriteIntoDouble(out, value); | 1566 __ WriteIntoDouble(out, value); |
| 1574 } | 1567 } |
| 1575 | 1568 |
| 1576 | 1569 |
| 1577 EMIT_NATIVE_CODE(Unbox, 1, Location::RequiresRegister()) { | 1570 EMIT_NATIVE_CODE(Unbox, 1, Location::RequiresRegister()) { |
| 1578 ASSERT(representation() == kUnboxedDouble); | 1571 ASSERT(representation() == kUnboxedDouble); |
| 1579 const intptr_t value_cid = value()->Type()->ToCid(); | 1572 const intptr_t value_cid = value()->Type()->ToCid(); |
| 1580 const intptr_t box_cid = BoxCid(); | 1573 const intptr_t box_cid = BoxCid(); |
| 1581 const Register box = locs()->in(0).reg(); | 1574 const Register box = locs()->in(0).reg(); |
| 1582 const Register result = locs()->out(0).reg(); | 1575 const Register result = locs()->out(0).reg(); |
| 1583 if (value_cid == box_cid) { | 1576 if (value_cid == box_cid) { |
| 1584 __ UnboxDouble(result, box); | 1577 __ UnboxDouble(result, box); |
| 1585 } else if (CanConvertSmi() && (value_cid == kSmiCid)) { | 1578 } else if (CanConvertSmi() && (value_cid == kSmiCid)) { |
| 1586 __ SmiToDouble(result, box); | 1579 __ SmiToDouble(result, box); |
| 1587 } else if ((value()->Type()->ToNullableCid() == box_cid) && | 1580 } else if ((value()->Type()->ToNullableCid() == box_cid) && |
| 1588 value()->Type()->is_nullable()) { | 1581 value()->Type()->is_nullable()) { |
| 1589 __ IfEqNull(box); | 1582 __ IfEqNull(box); |
| 1590 compiler->EmitDeopt(GetDeoptId(), ICData::kDeoptCheckClass); | 1583 compiler->EmitDeopt(GetDeoptId(), ICData::kDeoptCheckClass); |
| 1591 __ UnboxDouble(result, box); | 1584 __ UnboxDouble(result, box); |
| 1592 } else { | 1585 } else { |
| 1593 __ CheckedUnboxDouble(result, box); | 1586 __ CheckedUnboxDouble(result, box); |
| 1594 compiler->EmitDeopt(GetDeoptId(), ICData::kDeoptCheckClass); | 1587 compiler->EmitDeopt(GetDeoptId(), ICData::kDeoptCheckClass); |
| 1595 } | 1588 } |
| 1596 } | 1589 } |
| 1597 | 1590 |
| 1598 | 1591 |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1644 const Register result = locs()->out(0).reg(); | 1637 const Register result = locs()->out(0).reg(); |
| 1645 __ SmiToDouble(result, value); | 1638 __ SmiToDouble(result, value); |
| 1646 } | 1639 } |
| 1647 | 1640 |
| 1648 | 1641 |
| 1649 EMIT_NATIVE_CODE(BinaryDoubleOp, 2, Location::RequiresRegister()) { | 1642 EMIT_NATIVE_CODE(BinaryDoubleOp, 2, Location::RequiresRegister()) { |
| 1650 const Register left = locs()->in(0).reg(); | 1643 const Register left = locs()->in(0).reg(); |
| 1651 const Register right = locs()->in(1).reg(); | 1644 const Register right = locs()->in(1).reg(); |
| 1652 const Register result = locs()->out(0).reg(); | 1645 const Register result = locs()->out(0).reg(); |
| 1653 switch (op_kind()) { | 1646 switch (op_kind()) { |
| 1654 case Token::kADD: __ DAdd(result, left, right); break; | 1647 case Token::kADD: |
| 1655 case Token::kSUB: __ DSub(result, left, right); break; | 1648 __ DAdd(result, left, right); |
| 1656 case Token::kMUL: __ DMul(result, left, right); break; | 1649 break; |
| 1657 case Token::kDIV: __ DDiv(result, left, right); break; | 1650 case Token::kSUB: |
| 1658 default: UNREACHABLE(); | 1651 __ DSub(result, left, right); |
| 1652 break; |
| 1653 case Token::kMUL: |
| 1654 __ DMul(result, left, right); |
| 1655 break; |
| 1656 case Token::kDIV: |
| 1657 __ DDiv(result, left, right); |
| 1658 break; |
| 1659 default: |
| 1660 UNREACHABLE(); |
| 1659 } | 1661 } |
| 1660 } | 1662 } |
| 1661 | 1663 |
| 1662 | 1664 |
| 1663 Condition DoubleTestOpInstr::EmitComparisonCode(FlowGraphCompiler* compiler, | 1665 Condition DoubleTestOpInstr::EmitComparisonCode(FlowGraphCompiler* compiler, |
| 1664 BranchLabels labels) { | 1666 BranchLabels labels) { |
| 1665 UNREACHABLE(); | 1667 UNREACHABLE(); |
| 1666 return Condition(); | 1668 return Condition(); |
| 1667 } | 1669 } |
| 1668 | 1670 |
| 1669 | 1671 |
| 1670 void DoubleTestOpInstr::EmitBranchCode(FlowGraphCompiler* compiler, | 1672 void DoubleTestOpInstr::EmitBranchCode(FlowGraphCompiler* compiler, |
| 1671 BranchInstr* branch) { | 1673 BranchInstr* branch) { |
| 1672 ASSERT(compiler->is_optimizing()); | 1674 ASSERT(compiler->is_optimizing()); |
| 1673 BranchLabels labels = compiler->CreateBranchLabels(branch); | 1675 BranchLabels labels = compiler->CreateBranchLabels(branch); |
| 1674 const Register value = locs()->in(0).reg(); | 1676 const Register value = locs()->in(0).reg(); |
| 1675 switch (op_kind()) { | 1677 switch (op_kind()) { |
| 1676 case MethodRecognizer::kDouble_getIsNaN: | 1678 case MethodRecognizer::kDouble_getIsNaN: |
| 1677 __ DoubleIsNaN(value); | 1679 __ DoubleIsNaN(value); |
| 1678 break; | 1680 break; |
| 1679 case MethodRecognizer::kDouble_getIsInfinite: | 1681 case MethodRecognizer::kDouble_getIsInfinite: |
| 1680 __ DoubleIsInfinite(value); | 1682 __ DoubleIsInfinite(value); |
| 1681 break; | 1683 break; |
| 1682 default: | 1684 default: |
| 1683 UNREACHABLE(); | 1685 UNREACHABLE(); |
| 1684 } | 1686 } |
| 1685 const bool is_negated = kind() != Token::kEQ; | 1687 const bool is_negated = kind() != Token::kEQ; |
| 1686 EmitBranchOnCondition( | 1688 EmitBranchOnCondition(compiler, is_negated ? NEXT_IS_FALSE : NEXT_IS_TRUE, |
| 1687 compiler, is_negated ? NEXT_IS_FALSE : NEXT_IS_TRUE, labels); | 1689 labels); |
| 1688 } | 1690 } |
| 1689 | 1691 |
| 1690 | 1692 |
| 1691 EMIT_NATIVE_CODE(DoubleTestOp, 1, Location::RequiresRegister()) { | 1693 EMIT_NATIVE_CODE(DoubleTestOp, 1, Location::RequiresRegister()) { |
| 1692 ASSERT(compiler->is_optimizing()); | 1694 ASSERT(compiler->is_optimizing()); |
| 1693 const Register value = locs()->in(0).reg(); | 1695 const Register value = locs()->in(0).reg(); |
| 1694 const Register result = locs()->out(0).reg(); | 1696 const Register result = locs()->out(0).reg(); |
| 1695 const bool is_negated = kind() != Token::kEQ; | 1697 const bool is_negated = kind() != Token::kEQ; |
| 1696 __ LoadConstant(result, is_negated ? Bool::True() : Bool::False()); | 1698 __ LoadConstant(result, is_negated ? Bool::True() : Bool::False()); |
| 1697 switch (op_kind()) { | 1699 switch (op_kind()) { |
| (...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1756 | 1758 |
| 1757 | 1759 |
| 1758 EMIT_NATIVE_CODE(FloatToDouble, 1, Location::RequiresRegister()) { | 1760 EMIT_NATIVE_CODE(FloatToDouble, 1, Location::RequiresRegister()) { |
| 1759 const Register in = locs()->in(0).reg(); | 1761 const Register in = locs()->in(0).reg(); |
| 1760 const Register result = locs()->out(0).reg(); | 1762 const Register result = locs()->out(0).reg(); |
| 1761 __ FloatToDouble(result, in); | 1763 __ FloatToDouble(result, in); |
| 1762 } | 1764 } |
| 1763 | 1765 |
| 1764 | 1766 |
| 1765 EMIT_NATIVE_CODE(InvokeMathCFunction, | 1767 EMIT_NATIVE_CODE(InvokeMathCFunction, |
| 1766 InputCount(), Location::RequiresRegister()) { | 1768 InputCount(), |
| 1769 Location::RequiresRegister()) { |
| 1767 const Register left = locs()->in(0).reg(); | 1770 const Register left = locs()->in(0).reg(); |
| 1768 const Register result = locs()->out(0).reg(); | 1771 const Register result = locs()->out(0).reg(); |
| 1769 if (recognized_kind() == MethodRecognizer::kMathDoublePow) { | 1772 if (recognized_kind() == MethodRecognizer::kMathDoublePow) { |
| 1770 const Register right = locs()->in(1).reg(); | 1773 const Register right = locs()->in(1).reg(); |
| 1771 __ DPow(result, left, right); | 1774 __ DPow(result, left, right); |
| 1772 } else if (recognized_kind() == MethodRecognizer::kDoubleMod) { | 1775 } else if (recognized_kind() == MethodRecognizer::kDoubleMod) { |
| 1773 const Register right = locs()->in(1).reg(); | 1776 const Register right = locs()->in(1).reg(); |
| 1774 __ DMod(result, left, right); | 1777 __ DMod(result, left, right); |
| 1775 } else if (recognized_kind() == MethodRecognizer::kMathSin) { | 1778 } else if (recognized_kind() == MethodRecognizer::kMathSin) { |
| 1776 __ DSin(result, left); | 1779 __ DSin(result, left); |
| (...skipping 24 matching lines...) Expand all Loading... |
| 1801 __ Min(result, left, right); | 1804 __ Min(result, left, right); |
| 1802 } else { | 1805 } else { |
| 1803 __ Max(result, left, right); | 1806 __ Max(result, left, right); |
| 1804 } | 1807 } |
| 1805 } | 1808 } |
| 1806 } | 1809 } |
| 1807 | 1810 |
| 1808 | 1811 |
| 1809 static Token::Kind FlipCondition(Token::Kind kind) { | 1812 static Token::Kind FlipCondition(Token::Kind kind) { |
| 1810 switch (kind) { | 1813 switch (kind) { |
| 1811 case Token::kEQ: return Token::kNE; | 1814 case Token::kEQ: |
| 1812 case Token::kNE: return Token::kEQ; | 1815 return Token::kNE; |
| 1813 case Token::kLT: return Token::kGTE; | 1816 case Token::kNE: |
| 1814 case Token::kGT: return Token::kLTE; | 1817 return Token::kEQ; |
| 1815 case Token::kLTE: return Token::kGT; | 1818 case Token::kLT: |
| 1816 case Token::kGTE: return Token::kLT; | 1819 return Token::kGTE; |
| 1820 case Token::kGT: |
| 1821 return Token::kLTE; |
| 1822 case Token::kLTE: |
| 1823 return Token::kGT; |
| 1824 case Token::kGTE: |
| 1825 return Token::kLT; |
| 1817 default: | 1826 default: |
| 1818 UNREACHABLE(); | 1827 UNREACHABLE(); |
| 1819 return Token::kNE; | 1828 return Token::kNE; |
| 1820 } | 1829 } |
| 1821 } | 1830 } |
| 1822 | 1831 |
| 1823 | 1832 |
| 1824 static Bytecode::Opcode OpcodeForSmiCondition(Token::Kind kind) { | 1833 static Bytecode::Opcode OpcodeForSmiCondition(Token::Kind kind) { |
| 1825 switch (kind) { | 1834 switch (kind) { |
| 1826 case Token::kEQ: return Bytecode::kIfEqStrict; | 1835 case Token::kEQ: |
| 1827 case Token::kNE: return Bytecode::kIfNeStrict; | 1836 return Bytecode::kIfEqStrict; |
| 1828 case Token::kLT: return Bytecode::kIfLt; | 1837 case Token::kNE: |
| 1829 case Token::kGT: return Bytecode::kIfGt; | 1838 return Bytecode::kIfNeStrict; |
| 1830 case Token::kLTE: return Bytecode::kIfLe; | 1839 case Token::kLT: |
| 1831 case Token::kGTE: return Bytecode::kIfGe; | 1840 return Bytecode::kIfLt; |
| 1841 case Token::kGT: |
| 1842 return Bytecode::kIfGt; |
| 1843 case Token::kLTE: |
| 1844 return Bytecode::kIfLe; |
| 1845 case Token::kGTE: |
| 1846 return Bytecode::kIfGe; |
| 1832 default: | 1847 default: |
| 1833 UNREACHABLE(); | 1848 UNREACHABLE(); |
| 1834 return Bytecode::kTrap; | 1849 return Bytecode::kTrap; |
| 1835 } | 1850 } |
| 1836 } | 1851 } |
| 1837 | 1852 |
| 1838 | 1853 |
| 1839 static Bytecode::Opcode OpcodeForDoubleCondition(Token::Kind kind) { | 1854 static Bytecode::Opcode OpcodeForDoubleCondition(Token::Kind kind) { |
| 1840 switch (kind) { | 1855 switch (kind) { |
| 1841 case Token::kEQ: return Bytecode::kIfDEq; | 1856 case Token::kEQ: |
| 1842 case Token::kNE: return Bytecode::kIfDNe; | 1857 return Bytecode::kIfDEq; |
| 1843 case Token::kLT: return Bytecode::kIfDLt; | 1858 case Token::kNE: |
| 1844 case Token::kGT: return Bytecode::kIfDGt; | 1859 return Bytecode::kIfDNe; |
| 1845 case Token::kLTE: return Bytecode::kIfDLe; | 1860 case Token::kLT: |
| 1846 case Token::kGTE: return Bytecode::kIfDGe; | 1861 return Bytecode::kIfDLt; |
| 1862 case Token::kGT: |
| 1863 return Bytecode::kIfDGt; |
| 1864 case Token::kLTE: |
| 1865 return Bytecode::kIfDLe; |
| 1866 case Token::kGTE: |
| 1867 return Bytecode::kIfDGe; |
| 1847 default: | 1868 default: |
| 1848 UNREACHABLE(); | 1869 UNREACHABLE(); |
| 1849 return Bytecode::kTrap; | 1870 return Bytecode::kTrap; |
| 1850 } | 1871 } |
| 1851 } | 1872 } |
| 1852 | 1873 |
| 1853 | 1874 |
| 1854 static Condition EmitSmiComparisonOp(FlowGraphCompiler* compiler, | 1875 static Condition EmitSmiComparisonOp(FlowGraphCompiler* compiler, |
| 1855 LocationSummary* locs, | 1876 LocationSummary* locs, |
| 1856 Token::Kind kind, | 1877 Token::Kind kind, |
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1900 } | 1921 } |
| 1901 | 1922 |
| 1902 | 1923 |
| 1903 EMIT_NATIVE_CODE(EqualityCompare, 2, Location::RequiresRegister()) { | 1924 EMIT_NATIVE_CODE(EqualityCompare, 2, Location::RequiresRegister()) { |
| 1904 ASSERT(compiler->is_optimizing()); | 1925 ASSERT(compiler->is_optimizing()); |
| 1905 ASSERT((kind() == Token::kEQ) || (kind() == Token::kNE)); | 1926 ASSERT((kind() == Token::kEQ) || (kind() == Token::kNE)); |
| 1906 Label is_true, is_false; | 1927 Label is_true, is_false; |
| 1907 // These labels are not used. They are arranged so that EmitComparisonCode | 1928 // These labels are not used. They are arranged so that EmitComparisonCode |
| 1908 // emits a test that executes the following instruction when the test | 1929 // emits a test that executes the following instruction when the test |
| 1909 // succeeds. | 1930 // succeeds. |
| 1910 BranchLabels labels = { &is_true, &is_false, &is_false }; | 1931 BranchLabels labels = {&is_true, &is_false, &is_false}; |
| 1911 const Register result = locs()->out(0).reg(); | 1932 const Register result = locs()->out(0).reg(); |
| 1912 __ LoadConstant(result, Bool::False()); | 1933 __ LoadConstant(result, Bool::False()); |
| 1913 Condition true_condition = EmitComparisonCode(compiler, labels); | 1934 Condition true_condition = EmitComparisonCode(compiler, labels); |
| 1914 ASSERT(true_condition == NEXT_IS_TRUE); | 1935 ASSERT(true_condition == NEXT_IS_TRUE); |
| 1915 __ LoadConstant(result, Bool::True()); | 1936 __ LoadConstant(result, Bool::True()); |
| 1916 } | 1937 } |
| 1917 | 1938 |
| 1918 | 1939 |
| 1919 void EqualityCompareInstr::EmitBranchCode(FlowGraphCompiler* compiler, | 1940 void EqualityCompareInstr::EmitBranchCode(FlowGraphCompiler* compiler, |
| 1920 BranchInstr* branch) { | 1941 BranchInstr* branch) { |
| (...skipping 11 matching lines...) Expand all Loading... |
| 1932 } else { | 1953 } else { |
| 1933 ASSERT(operation_cid() == kDoubleCid); | 1954 ASSERT(operation_cid() == kDoubleCid); |
| 1934 return EmitDoubleComparisonOp(compiler, locs(), kind()); | 1955 return EmitDoubleComparisonOp(compiler, locs(), kind()); |
| 1935 } | 1956 } |
| 1936 } | 1957 } |
| 1937 | 1958 |
| 1938 | 1959 |
| 1939 EMIT_NATIVE_CODE(RelationalOp, 2, Location::RequiresRegister()) { | 1960 EMIT_NATIVE_CODE(RelationalOp, 2, Location::RequiresRegister()) { |
| 1940 ASSERT(compiler->is_optimizing()); | 1961 ASSERT(compiler->is_optimizing()); |
| 1941 Label is_true, is_false; | 1962 Label is_true, is_false; |
| 1942 BranchLabels labels = { &is_true, &is_false, &is_false }; | 1963 BranchLabels labels = {&is_true, &is_false, &is_false}; |
| 1943 const Register result = locs()->out(0).reg(); | 1964 const Register result = locs()->out(0).reg(); |
| 1944 __ LoadConstant(result, Bool::False()); | 1965 __ LoadConstant(result, Bool::False()); |
| 1945 Condition true_condition = EmitComparisonCode(compiler, labels); | 1966 Condition true_condition = EmitComparisonCode(compiler, labels); |
| 1946 ASSERT(true_condition == NEXT_IS_TRUE); | 1967 ASSERT(true_condition == NEXT_IS_TRUE); |
| 1947 __ LoadConstant(result, Bool::True()); | 1968 __ LoadConstant(result, Bool::True()); |
| 1948 } | 1969 } |
| 1949 | 1970 |
| 1950 | 1971 |
| 1951 void RelationalOpInstr::EmitBranchCode(FlowGraphCompiler* compiler, | 1972 void RelationalOpInstr::EmitBranchCode(FlowGraphCompiler* compiler, |
| 1952 BranchInstr* branch) { | 1973 BranchInstr* branch) { |
| 1953 BranchLabels labels = compiler->CreateBranchLabels(branch); | 1974 BranchLabels labels = compiler->CreateBranchLabels(branch); |
| 1954 Condition true_condition = EmitComparisonCode(compiler, labels); | 1975 Condition true_condition = EmitComparisonCode(compiler, labels); |
| 1955 EmitBranchOnCondition(compiler, true_condition, labels); | 1976 EmitBranchOnCondition(compiler, true_condition, labels); |
| 1956 } | 1977 } |
| 1957 | 1978 |
| 1958 | 1979 |
| 1959 EMIT_NATIVE_CODE(CheckArrayBound, 2) { | 1980 EMIT_NATIVE_CODE(CheckArrayBound, 2) { |
| 1960 const Register length = locs()->in(kLengthPos).reg(); | 1981 const Register length = locs()->in(kLengthPos).reg(); |
| 1961 const Register index = locs()->in(kIndexPos).reg(); | 1982 const Register index = locs()->in(kIndexPos).reg(); |
| 1962 const intptr_t index_cid = this->index()->Type()->ToCid(); | 1983 const intptr_t index_cid = this->index()->Type()->ToCid(); |
| 1963 if (index_cid != kSmiCid) { | 1984 if (index_cid != kSmiCid) { |
| 1964 __ CheckSmi(index); | 1985 __ CheckSmi(index); |
| 1965 compiler->EmitDeopt(deopt_id(), | 1986 compiler->EmitDeopt(deopt_id(), ICData::kDeoptCheckArrayBound, |
| 1966 ICData::kDeoptCheckArrayBound, | |
| 1967 (generalized_ ? ICData::kGeneralized : 0) | | 1987 (generalized_ ? ICData::kGeneralized : 0) | |
| 1968 (licm_hoisted_ ? ICData::kHoisted : 0)); | 1988 (licm_hoisted_ ? ICData::kHoisted : 0)); |
| 1969 } | 1989 } |
| 1970 __ IfULe(length, index); | 1990 __ IfULe(length, index); |
| 1971 compiler->EmitDeopt(deopt_id(), | 1991 compiler->EmitDeopt(deopt_id(), ICData::kDeoptCheckArrayBound, |
| 1972 ICData::kDeoptCheckArrayBound, | |
| 1973 (generalized_ ? ICData::kGeneralized : 0) | | 1992 (generalized_ ? ICData::kGeneralized : 0) | |
| 1974 (licm_hoisted_ ? ICData::kHoisted : 0)); | 1993 (licm_hoisted_ ? ICData::kHoisted : 0)); |
| 1975 } | 1994 } |
| 1976 | 1995 |
| 1977 } // namespace dart | 1996 } // namespace dart |
| 1978 | 1997 |
| 1979 #endif // defined TARGET_ARCH_DBC | 1998 #endif // defined TARGET_ARCH_DBC |
| OLD | NEW |