OLD | NEW |
1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2014, 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_ARM64. | 5 #include "vm/globals.h" // Needed here to get TARGET_ARCH_ARM64. |
6 #if defined(TARGET_ARCH_ARM64) | 6 #if defined(TARGET_ARCH_ARM64) |
7 | 7 |
8 #include "vm/intermediate_language.h" | 8 #include "vm/intermediate_language.h" |
9 | 9 |
10 #include "vm/dart_entry.h" | 10 #include "vm/dart_entry.h" |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
49 | 49 |
50 | 50 |
51 void PushArgumentInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | 51 void PushArgumentInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
52 // In SSA mode, we need an explicit push. Nothing to do in non-SSA mode | 52 // In SSA mode, we need an explicit push. Nothing to do in non-SSA mode |
53 // where PushArgument is handled by BindInstr::EmitNativeCode. | 53 // where PushArgument is handled by BindInstr::EmitNativeCode. |
54 if (compiler->is_optimizing()) { | 54 if (compiler->is_optimizing()) { |
55 Location value = locs()->in(0); | 55 Location value = locs()->in(0); |
56 if (value.IsRegister()) { | 56 if (value.IsRegister()) { |
57 __ Push(value.reg()); | 57 __ Push(value.reg()); |
58 } else if (value.IsConstant()) { | 58 } else if (value.IsConstant()) { |
59 __ PushObject(value.constant(), PP); | 59 __ PushObject(value.constant()); |
60 } else { | 60 } else { |
61 ASSERT(value.IsStackSlot()); | 61 ASSERT(value.IsStackSlot()); |
62 const intptr_t value_offset = value.ToStackSlotOffset(); | 62 const intptr_t value_offset = value.ToStackSlotOffset(); |
63 __ LoadFromOffset(TMP, value.base_reg(), value_offset, PP); | 63 __ LoadFromOffset(TMP, value.base_reg(), value_offset); |
64 __ Push(TMP); | 64 __ Push(TMP); |
65 } | 65 } |
66 } | 66 } |
67 } | 67 } |
68 | 68 |
69 | 69 |
70 LocationSummary* ReturnInstr::MakeLocationSummary(Zone* zone, | 70 LocationSummary* ReturnInstr::MakeLocationSummary(Zone* zone, |
71 bool opt) const { | 71 bool opt) const { |
72 const intptr_t kNumInputs = 1; | 72 const intptr_t kNumInputs = 1; |
73 const intptr_t kNumTemps = 0; | 73 const intptr_t kNumTemps = 0; |
(...skipping 17 matching lines...) Expand all Loading... |
91 return; | 91 return; |
92 } | 92 } |
93 | 93 |
94 #if defined(DEBUG) | 94 #if defined(DEBUG) |
95 Label stack_ok; | 95 Label stack_ok; |
96 __ Comment("Stack Check"); | 96 __ Comment("Stack Check"); |
97 const intptr_t fp_sp_dist = | 97 const intptr_t fp_sp_dist = |
98 (kFirstLocalSlotFromFp + 1 - compiler->StackSize()) * kWordSize; | 98 (kFirstLocalSlotFromFp + 1 - compiler->StackSize()) * kWordSize; |
99 ASSERT(fp_sp_dist <= 0); | 99 ASSERT(fp_sp_dist <= 0); |
100 __ sub(R2, SP, Operand(FP)); | 100 __ sub(R2, SP, Operand(FP)); |
101 __ CompareImmediate(R2, fp_sp_dist, PP); | 101 __ CompareImmediate(R2, fp_sp_dist); |
102 __ b(&stack_ok, EQ); | 102 __ b(&stack_ok, EQ); |
103 __ brk(0); | 103 __ brk(0); |
104 __ Bind(&stack_ok); | 104 __ Bind(&stack_ok); |
105 #endif | 105 #endif |
106 __ LeaveDartFrame(); | 106 __ LeaveDartFrame(); // Disallows constant pool use. |
107 __ ret(); | 107 __ ret(); |
| 108 // This ReturnInstr may be emitted out of order by the optimizer. The next |
| 109 // block may be a target expecting a properly set constant pool pointer. |
| 110 __ set_constant_pool_allowed(true); |
108 } | 111 } |
109 | 112 |
110 | 113 |
111 static Condition NegateCondition(Condition condition) { | 114 static Condition NegateCondition(Condition condition) { |
112 switch (condition) { | 115 switch (condition) { |
113 case EQ: return NE; | 116 case EQ: return NE; |
114 case NE: return EQ; | 117 case NE: return EQ; |
115 case LT: return GE; | 118 case LT: return GE; |
116 case LE: return GT; | 119 case LE: return GT; |
117 case GT: return LE; | 120 case GT: return LE; |
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
176 __ cset(result, true_condition); | 179 __ cset(result, true_condition); |
177 | 180 |
178 if (is_power_of_two_kind) { | 181 if (is_power_of_two_kind) { |
179 const intptr_t shift = | 182 const intptr_t shift = |
180 Utils::ShiftForPowerOfTwo(Utils::Maximum(true_value, false_value)); | 183 Utils::ShiftForPowerOfTwo(Utils::Maximum(true_value, false_value)); |
181 __ LslImmediate(result, result, shift + kSmiTagSize); | 184 __ LslImmediate(result, result, shift + kSmiTagSize); |
182 } else { | 185 } else { |
183 __ sub(result, result, Operand(1)); | 186 __ sub(result, result, Operand(1)); |
184 const int64_t val = | 187 const int64_t val = |
185 Smi::RawValue(true_value) - Smi::RawValue(false_value); | 188 Smi::RawValue(true_value) - Smi::RawValue(false_value); |
186 __ AndImmediate(result, result, val, PP); | 189 __ AndImmediate(result, result, val); |
187 if (false_value != 0) { | 190 if (false_value != 0) { |
188 __ AddImmediate(result, result, Smi::RawValue(false_value), PP); | 191 __ AddImmediate(result, result, Smi::RawValue(false_value)); |
189 } | 192 } |
190 } | 193 } |
191 } | 194 } |
192 | 195 |
193 | 196 |
194 LocationSummary* ClosureCallInstr::MakeLocationSummary(Zone* zone, | 197 LocationSummary* ClosureCallInstr::MakeLocationSummary(Zone* zone, |
195 bool opt) const { | 198 bool opt) const { |
196 const intptr_t kNumInputs = 1; | 199 const intptr_t kNumInputs = 1; |
197 const intptr_t kNumTemps = 0; | 200 const intptr_t kNumTemps = 0; |
198 LocationSummary* summary = new(zone) LocationSummary( | 201 LocationSummary* summary = new(zone) LocationSummary( |
199 zone, kNumInputs, kNumTemps, LocationSummary::kCall); | 202 zone, kNumInputs, kNumTemps, LocationSummary::kCall); |
200 summary->set_in(0, Location::RegisterLocation(R0)); // Function. | 203 summary->set_in(0, Location::RegisterLocation(R0)); // Function. |
201 summary->set_out(0, Location::RegisterLocation(R0)); | 204 summary->set_out(0, Location::RegisterLocation(R0)); |
202 return summary; | 205 return summary; |
203 } | 206 } |
204 | 207 |
205 | 208 |
206 void ClosureCallInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | 209 void ClosureCallInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
207 // Load arguments descriptor in R4. | 210 // Load arguments descriptor in R4. |
208 int argument_count = ArgumentCount(); | 211 int argument_count = ArgumentCount(); |
209 const Array& arguments_descriptor = | 212 const Array& arguments_descriptor = |
210 Array::ZoneHandle(ArgumentsDescriptor::New(argument_count, | 213 Array::ZoneHandle(ArgumentsDescriptor::New(argument_count, |
211 argument_names())); | 214 argument_names())); |
212 __ LoadObject(R4, arguments_descriptor, PP); | 215 __ LoadObject(R4, arguments_descriptor); |
213 | 216 |
214 // R4: Arguments descriptor. | 217 // R4: Arguments descriptor. |
215 // R0: Function. | 218 // R0: Function. |
216 ASSERT(locs()->in(0).reg() == R0); | 219 ASSERT(locs()->in(0).reg() == R0); |
217 __ LoadFieldFromOffset(R2, R0, Function::instructions_offset(), PP); | 220 __ LoadFieldFromOffset(R2, R0, Function::instructions_offset()); |
218 | 221 |
219 // R2: instructions. | 222 // R2: instructions. |
220 // R5: Smi 0 (no IC data; the lazy-compile stub expects a GC-safe value). | 223 // R5: Smi 0 (no IC data; the lazy-compile stub expects a GC-safe value). |
221 __ LoadImmediate(R5, 0, PP); | 224 __ LoadImmediate(R5, 0); |
222 __ AddImmediate(R2, R2, Instructions::HeaderSize() - kHeapObjectTag, PP); | 225 __ AddImmediate(R2, R2, Instructions::HeaderSize() - kHeapObjectTag); |
223 __ blr(R2); | 226 __ blr(R2); |
224 compiler->RecordSafepoint(locs()); | 227 compiler->RecordSafepoint(locs()); |
225 // Marks either the continuation point in unoptimized code or the | 228 // Marks either the continuation point in unoptimized code or the |
226 // deoptimization point in optimized code, after call. | 229 // deoptimization point in optimized code, after call. |
227 const intptr_t deopt_id_after = Isolate::ToDeoptAfter(deopt_id()); | 230 const intptr_t deopt_id_after = Isolate::ToDeoptAfter(deopt_id()); |
228 if (compiler->is_optimizing()) { | 231 if (compiler->is_optimizing()) { |
229 compiler->AddDeoptIndexAtCall(deopt_id_after, token_pos()); | 232 compiler->AddDeoptIndexAtCall(deopt_id_after, token_pos()); |
230 } | 233 } |
231 // Add deoptimization continuation point after the call and before the | 234 // Add deoptimization continuation point after the call and before the |
232 // arguments are removed. | 235 // arguments are removed. |
233 // In optimized code this descriptor is needed for exception handling. | 236 // In optimized code this descriptor is needed for exception handling. |
234 compiler->AddCurrentDescriptor(RawPcDescriptors::kDeopt, | 237 compiler->AddCurrentDescriptor(RawPcDescriptors::kDeopt, |
235 deopt_id_after, | 238 deopt_id_after, |
236 token_pos()); | 239 token_pos()); |
237 __ Drop(argument_count); | 240 __ Drop(argument_count); |
238 } | 241 } |
239 | 242 |
240 | 243 |
241 LocationSummary* LoadLocalInstr::MakeLocationSummary(Zone* zone, | 244 LocationSummary* LoadLocalInstr::MakeLocationSummary(Zone* zone, |
242 bool opt) const { | 245 bool opt) const { |
243 return LocationSummary::Make(zone, | 246 return LocationSummary::Make(zone, |
244 0, | 247 0, |
245 Location::RequiresRegister(), | 248 Location::RequiresRegister(), |
246 LocationSummary::kNoCall); | 249 LocationSummary::kNoCall); |
247 } | 250 } |
248 | 251 |
249 | 252 |
250 void LoadLocalInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | 253 void LoadLocalInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
251 const Register result = locs()->out(0).reg(); | 254 const Register result = locs()->out(0).reg(); |
252 __ LoadFromOffset(result, FP, local().index() * kWordSize, PP); | 255 __ LoadFromOffset(result, FP, local().index() * kWordSize); |
253 } | 256 } |
254 | 257 |
255 | 258 |
256 LocationSummary* StoreLocalInstr::MakeLocationSummary(Zone* zone, | 259 LocationSummary* StoreLocalInstr::MakeLocationSummary(Zone* zone, |
257 bool opt) const { | 260 bool opt) const { |
258 return LocationSummary::Make(zone, | 261 return LocationSummary::Make(zone, |
259 1, | 262 1, |
260 Location::SameAsFirstInput(), | 263 Location::SameAsFirstInput(), |
261 LocationSummary::kNoCall); | 264 LocationSummary::kNoCall); |
262 } | 265 } |
263 | 266 |
264 | 267 |
265 void StoreLocalInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | 268 void StoreLocalInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
266 const Register value = locs()->in(0).reg(); | 269 const Register value = locs()->in(0).reg(); |
267 const Register result = locs()->out(0).reg(); | 270 const Register result = locs()->out(0).reg(); |
268 ASSERT(result == value); // Assert that register assignment is correct. | 271 ASSERT(result == value); // Assert that register assignment is correct. |
269 __ StoreToOffset(value, FP, local().index() * kWordSize, PP); | 272 __ StoreToOffset(value, FP, local().index() * kWordSize); |
270 } | 273 } |
271 | 274 |
272 | 275 |
273 LocationSummary* ConstantInstr::MakeLocationSummary(Zone* zone, | 276 LocationSummary* ConstantInstr::MakeLocationSummary(Zone* zone, |
274 bool opt) const { | 277 bool opt) const { |
275 return LocationSummary::Make(zone, | 278 return LocationSummary::Make(zone, |
276 0, | 279 0, |
277 Location::RequiresRegister(), | 280 Location::RequiresRegister(), |
278 LocationSummary::kNoCall); | 281 LocationSummary::kNoCall); |
279 } | 282 } |
280 | 283 |
281 | 284 |
282 void ConstantInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | 285 void ConstantInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
283 // The register allocator drops constant definitions that have no uses. | 286 // The register allocator drops constant definitions that have no uses. |
284 if (!locs()->out(0).IsInvalid()) { | 287 if (!locs()->out(0).IsInvalid()) { |
285 const Register result = locs()->out(0).reg(); | 288 const Register result = locs()->out(0).reg(); |
286 __ LoadObject(result, value(), PP); | 289 __ LoadObject(result, value()); |
287 } | 290 } |
288 } | 291 } |
289 | 292 |
290 | 293 |
291 LocationSummary* UnboxedConstantInstr::MakeLocationSummary(Zone* zone, | 294 LocationSummary* UnboxedConstantInstr::MakeLocationSummary(Zone* zone, |
292 bool opt) const { | 295 bool opt) const { |
293 const intptr_t kNumInputs = 0; | 296 const intptr_t kNumInputs = 0; |
294 const Location out = (representation_ == kUnboxedInt32) ? | 297 const Location out = (representation_ == kUnboxedInt32) ? |
295 Location::RequiresRegister() : Location::RequiresFpuRegister(); | 298 Location::RequiresRegister() : Location::RequiresFpuRegister(); |
296 return LocationSummary::Make(zone, | 299 return LocationSummary::Make(zone, |
297 kNumInputs, | 300 kNumInputs, |
298 out, | 301 out, |
299 LocationSummary::kNoCall); | 302 LocationSummary::kNoCall); |
300 } | 303 } |
301 | 304 |
302 | 305 |
303 void UnboxedConstantInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | 306 void UnboxedConstantInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
304 if (!locs()->out(0).IsInvalid()) { | 307 if (!locs()->out(0).IsInvalid()) { |
305 switch (representation_) { | 308 switch (representation_) { |
306 case kUnboxedDouble: | 309 case kUnboxedDouble: |
307 if (Utils::DoublesBitEqual(Double::Cast(value()).value(), 0.0)) { | 310 if (Utils::DoublesBitEqual(Double::Cast(value()).value(), 0.0)) { |
308 const VRegister dst = locs()->out(0).fpu_reg(); | 311 const VRegister dst = locs()->out(0).fpu_reg(); |
309 __ veor(dst, dst, dst); | 312 __ veor(dst, dst, dst); |
310 } else { | 313 } else { |
311 const VRegister dst = locs()->out(0).fpu_reg(); | 314 const VRegister dst = locs()->out(0).fpu_reg(); |
312 __ LoadDImmediate(dst, Double::Cast(value()).value(), PP); | 315 __ LoadDImmediate(dst, Double::Cast(value()).value()); |
313 } | 316 } |
314 break; | 317 break; |
315 case kUnboxedInt32: | 318 case kUnboxedInt32: |
316 __ LoadImmediate(locs()->out(0).reg(), | 319 __ LoadImmediate(locs()->out(0).reg(), |
317 static_cast<int32_t>(Smi::Cast(value()).Value()), | 320 static_cast<int32_t>(Smi::Cast(value()).Value())); |
318 PP); | |
319 break; | 321 break; |
320 default: | 322 default: |
321 UNREACHABLE(); | 323 UNREACHABLE(); |
322 break; | 324 break; |
323 } | 325 } |
324 } | 326 } |
325 } | 327 } |
326 | 328 |
327 | 329 |
328 LocationSummary* AssertAssignableInstr::MakeLocationSummary(Zone* zone, | 330 LocationSummary* AssertAssignableInstr::MakeLocationSummary(Zone* zone, |
(...skipping 26 matching lines...) Expand all Loading... |
355 intptr_t token_pos, | 357 intptr_t token_pos, |
356 intptr_t deopt_id, | 358 intptr_t deopt_id, |
357 LocationSummary* locs, | 359 LocationSummary* locs, |
358 FlowGraphCompiler* compiler) { | 360 FlowGraphCompiler* compiler) { |
359 // Check that the type of the value is allowed in conditional context. | 361 // Check that the type of the value is allowed in conditional context. |
360 // Call the runtime if the object is not bool::true or bool::false. | 362 // Call the runtime if the object is not bool::true or bool::false. |
361 ASSERT(locs->always_calls()); | 363 ASSERT(locs->always_calls()); |
362 Label done; | 364 Label done; |
363 | 365 |
364 if (Isolate::Current()->flags().type_checks()) { | 366 if (Isolate::Current()->flags().type_checks()) { |
365 __ CompareObject(reg, Bool::True(), PP); | 367 __ CompareObject(reg, Bool::True()); |
366 __ b(&done, EQ); | 368 __ b(&done, EQ); |
367 __ CompareObject(reg, Bool::False(), PP); | 369 __ CompareObject(reg, Bool::False()); |
368 __ b(&done, EQ); | 370 __ b(&done, EQ); |
369 } else { | 371 } else { |
370 ASSERT(Isolate::Current()->flags().asserts()); | 372 ASSERT(Isolate::Current()->flags().asserts()); |
371 __ CompareObject(reg, Object::null_instance(), PP); | 373 __ CompareObject(reg, Object::null_instance()); |
372 __ b(&done, NE); | 374 __ b(&done, NE); |
373 } | 375 } |
374 | 376 |
375 __ Push(reg); // Push the source object. | 377 __ Push(reg); // Push the source object. |
376 compiler->GenerateRuntimeCall(token_pos, | 378 compiler->GenerateRuntimeCall(token_pos, |
377 deopt_id, | 379 deopt_id, |
378 kNonBoolTypeErrorRuntimeEntry, | 380 kNonBoolTypeErrorRuntimeEntry, |
379 1, | 381 1, |
380 locs); | 382 locs); |
381 // We should never return here. | 383 // We should never return here. |
(...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
449 static Condition EmitSmiComparisonOp(FlowGraphCompiler* compiler, | 451 static Condition EmitSmiComparisonOp(FlowGraphCompiler* compiler, |
450 LocationSummary* locs, | 452 LocationSummary* locs, |
451 Token::Kind kind) { | 453 Token::Kind kind) { |
452 Location left = locs->in(0); | 454 Location left = locs->in(0); |
453 Location right = locs->in(1); | 455 Location right = locs->in(1); |
454 ASSERT(!left.IsConstant() || !right.IsConstant()); | 456 ASSERT(!left.IsConstant() || !right.IsConstant()); |
455 | 457 |
456 Condition true_condition = TokenKindToSmiCondition(kind); | 458 Condition true_condition = TokenKindToSmiCondition(kind); |
457 | 459 |
458 if (left.IsConstant()) { | 460 if (left.IsConstant()) { |
459 __ CompareObject(right.reg(), left.constant(), PP); | 461 __ CompareObject(right.reg(), left.constant()); |
460 true_condition = FlipCondition(true_condition); | 462 true_condition = FlipCondition(true_condition); |
461 } else if (right.IsConstant()) { | 463 } else if (right.IsConstant()) { |
462 __ CompareObject(left.reg(), right.constant(), PP); | 464 __ CompareObject(left.reg(), right.constant()); |
463 } else { | 465 } else { |
464 __ CompareRegisters(left.reg(), right.reg()); | 466 __ CompareRegisters(left.reg(), right.reg()); |
465 } | 467 } |
466 return true_condition; | 468 return true_condition; |
467 } | 469 } |
468 | 470 |
469 | 471 |
470 LocationSummary* EqualityCompareInstr::MakeLocationSummary(Zone* zone, | 472 LocationSummary* EqualityCompareInstr::MakeLocationSummary(Zone* zone, |
471 bool opt) const { | 473 bool opt) const { |
472 const intptr_t kNumInputs = 2; | 474 const intptr_t kNumInputs = 2; |
(...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
544 // Special case for NaN comparison. Result is always false unless | 546 // Special case for NaN comparison. Result is always false unless |
545 // relational operator is !=. | 547 // relational operator is !=. |
546 __ b(&is_false, VS); | 548 __ b(&is_false, VS); |
547 } | 549 } |
548 EmitBranchOnCondition(compiler, true_condition, labels); | 550 EmitBranchOnCondition(compiler, true_condition, labels); |
549 // TODO(zra): instead of branching, use the csel instruction to get | 551 // TODO(zra): instead of branching, use the csel instruction to get |
550 // True or False into result. | 552 // True or False into result. |
551 const Register result = locs()->out(0).reg(); | 553 const Register result = locs()->out(0).reg(); |
552 Label done; | 554 Label done; |
553 __ Bind(&is_false); | 555 __ Bind(&is_false); |
554 __ LoadObject(result, Bool::False(), PP); | 556 __ LoadObject(result, Bool::False()); |
555 __ b(&done); | 557 __ b(&done); |
556 __ Bind(&is_true); | 558 __ Bind(&is_true); |
557 __ LoadObject(result, Bool::True(), PP); | 559 __ LoadObject(result, Bool::True()); |
558 __ Bind(&done); | 560 __ Bind(&done); |
559 } | 561 } |
560 | 562 |
561 | 563 |
562 void EqualityCompareInstr::EmitBranchCode(FlowGraphCompiler* compiler, | 564 void EqualityCompareInstr::EmitBranchCode(FlowGraphCompiler* compiler, |
563 BranchInstr* branch) { | 565 BranchInstr* branch) { |
564 ASSERT((kind() == Token::kNE) || (kind() == Token::kEQ)); | 566 ASSERT((kind() == Token::kNE) || (kind() == Token::kEQ)); |
565 | 567 |
566 BranchLabels labels = compiler->CreateBranchLabels(branch); | 568 BranchLabels labels = compiler->CreateBranchLabels(branch); |
567 Condition true_condition = EmitComparisonCode(compiler, labels); | 569 Condition true_condition = EmitComparisonCode(compiler, labels); |
(...skipping 21 matching lines...) Expand all Loading... |
589 | 591 |
590 | 592 |
591 Condition TestSmiInstr::EmitComparisonCode(FlowGraphCompiler* compiler, | 593 Condition TestSmiInstr::EmitComparisonCode(FlowGraphCompiler* compiler, |
592 BranchLabels labels) { | 594 BranchLabels labels) { |
593 const Register left = locs()->in(0).reg(); | 595 const Register left = locs()->in(0).reg(); |
594 Location right = locs()->in(1); | 596 Location right = locs()->in(1); |
595 if (right.IsConstant()) { | 597 if (right.IsConstant()) { |
596 ASSERT(right.constant().IsSmi()); | 598 ASSERT(right.constant().IsSmi()); |
597 const int64_t imm = | 599 const int64_t imm = |
598 reinterpret_cast<int64_t>(right.constant().raw()); | 600 reinterpret_cast<int64_t>(right.constant().raw()); |
599 __ TestImmediate(left, imm, PP); | 601 __ TestImmediate(left, imm); |
600 } else { | 602 } else { |
601 __ tst(left, Operand(right.reg())); | 603 __ tst(left, Operand(right.reg())); |
602 } | 604 } |
603 Condition true_condition = (kind() == Token::kNE) ? NE : EQ; | 605 Condition true_condition = (kind() == Token::kNE) ? NE : EQ; |
604 return true_condition; | 606 return true_condition; |
605 } | 607 } |
606 | 608 |
607 | 609 |
608 void TestSmiInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | 610 void TestSmiInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
609 // Never emitted outside of the BranchInstr. | 611 // Never emitted outside of the BranchInstr. |
(...skipping 30 matching lines...) Expand all Loading... |
640 | 642 |
641 Label* deopt = CanDeoptimize() ? | 643 Label* deopt = CanDeoptimize() ? |
642 compiler->AddDeoptStub(deopt_id(), ICData::kDeoptTestCids) : NULL; | 644 compiler->AddDeoptStub(deopt_id(), ICData::kDeoptTestCids) : NULL; |
643 | 645 |
644 const intptr_t true_result = (kind() == Token::kIS) ? 1 : 0; | 646 const intptr_t true_result = (kind() == Token::kIS) ? 1 : 0; |
645 const ZoneGrowableArray<intptr_t>& data = cid_results(); | 647 const ZoneGrowableArray<intptr_t>& data = cid_results(); |
646 ASSERT(data[0] == kSmiCid); | 648 ASSERT(data[0] == kSmiCid); |
647 bool result = data[1] == true_result; | 649 bool result = data[1] == true_result; |
648 __ tsti(val_reg, Immediate(kSmiTagMask)); | 650 __ tsti(val_reg, Immediate(kSmiTagMask)); |
649 __ b(result ? labels.true_label : labels.false_label, EQ); | 651 __ b(result ? labels.true_label : labels.false_label, EQ); |
650 __ LoadClassId(cid_reg, val_reg, PP); | 652 __ LoadClassId(cid_reg, val_reg); |
651 | 653 |
652 for (intptr_t i = 2; i < data.length(); i += 2) { | 654 for (intptr_t i = 2; i < data.length(); i += 2) { |
653 const intptr_t test_cid = data[i]; | 655 const intptr_t test_cid = data[i]; |
654 ASSERT(test_cid != kSmiCid); | 656 ASSERT(test_cid != kSmiCid); |
655 result = data[i + 1] == true_result; | 657 result = data[i + 1] == true_result; |
656 __ CompareImmediate(cid_reg, test_cid, PP); | 658 __ CompareImmediate(cid_reg, test_cid); |
657 __ b(result ? labels.true_label : labels.false_label, EQ); | 659 __ b(result ? labels.true_label : labels.false_label, EQ); |
658 } | 660 } |
659 // No match found, deoptimize or false. | 661 // No match found, deoptimize or false. |
660 if (deopt == NULL) { | 662 if (deopt == NULL) { |
661 Label* target = result ? labels.false_label : labels.true_label; | 663 Label* target = result ? labels.false_label : labels.true_label; |
662 if (target != labels.fall_through) { | 664 if (target != labels.fall_through) { |
663 __ b(target); | 665 __ b(target); |
664 } | 666 } |
665 } else { | 667 } else { |
666 __ b(deopt); | 668 __ b(deopt); |
(...skipping 12 matching lines...) Expand all Loading... |
679 | 681 |
680 | 682 |
681 void TestCidsInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | 683 void TestCidsInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
682 const Register result_reg = locs()->out(0).reg(); | 684 const Register result_reg = locs()->out(0).reg(); |
683 Label is_true, is_false, done; | 685 Label is_true, is_false, done; |
684 BranchLabels labels = { &is_true, &is_false, &is_false }; | 686 BranchLabels labels = { &is_true, &is_false, &is_false }; |
685 EmitComparisonCode(compiler, labels); | 687 EmitComparisonCode(compiler, labels); |
686 // TODO(zra): instead of branching, use the csel instruction to get | 688 // TODO(zra): instead of branching, use the csel instruction to get |
687 // True or False into result. | 689 // True or False into result. |
688 __ Bind(&is_false); | 690 __ Bind(&is_false); |
689 __ LoadObject(result_reg, Bool::False(), PP); | 691 __ LoadObject(result_reg, Bool::False()); |
690 __ b(&done); | 692 __ b(&done); |
691 __ Bind(&is_true); | 693 __ Bind(&is_true); |
692 __ LoadObject(result_reg, Bool::True(), PP); | 694 __ LoadObject(result_reg, Bool::True()); |
693 __ Bind(&done); | 695 __ Bind(&done); |
694 } | 696 } |
695 | 697 |
696 | 698 |
697 LocationSummary* RelationalOpInstr::MakeLocationSummary(Zone* zone, | 699 LocationSummary* RelationalOpInstr::MakeLocationSummary(Zone* zone, |
698 bool opt) const { | 700 bool opt) const { |
699 const intptr_t kNumInputs = 2; | 701 const intptr_t kNumInputs = 2; |
700 const intptr_t kNumTemps = 0; | 702 const intptr_t kNumTemps = 0; |
701 if (operation_cid() == kDoubleCid) { | 703 if (operation_cid() == kDoubleCid) { |
702 LocationSummary* summary = new(zone) LocationSummary( | 704 LocationSummary* summary = new(zone) LocationSummary( |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
739 // Special case for NaN comparison. Result is always false unless | 741 // Special case for NaN comparison. Result is always false unless |
740 // relational operator is !=. | 742 // relational operator is !=. |
741 __ b(&is_false, VS); | 743 __ b(&is_false, VS); |
742 } | 744 } |
743 EmitBranchOnCondition(compiler, true_condition, labels); | 745 EmitBranchOnCondition(compiler, true_condition, labels); |
744 // TODO(zra): instead of branching, use the csel instruction to get | 746 // TODO(zra): instead of branching, use the csel instruction to get |
745 // True or False into result. | 747 // True or False into result. |
746 const Register result = locs()->out(0).reg(); | 748 const Register result = locs()->out(0).reg(); |
747 Label done; | 749 Label done; |
748 __ Bind(&is_false); | 750 __ Bind(&is_false); |
749 __ LoadObject(result, Bool::False(), PP); | 751 __ LoadObject(result, Bool::False()); |
750 __ b(&done); | 752 __ b(&done); |
751 __ Bind(&is_true); | 753 __ Bind(&is_true); |
752 __ LoadObject(result, Bool::True(), PP); | 754 __ LoadObject(result, Bool::True()); |
753 __ Bind(&done); | 755 __ Bind(&done); |
754 } | 756 } |
755 | 757 |
756 | 758 |
757 void RelationalOpInstr::EmitBranchCode(FlowGraphCompiler* compiler, | 759 void RelationalOpInstr::EmitBranchCode(FlowGraphCompiler* compiler, |
758 BranchInstr* branch) { | 760 BranchInstr* branch) { |
759 BranchLabels labels = compiler->CreateBranchLabels(branch); | 761 BranchLabels labels = compiler->CreateBranchLabels(branch); |
760 Condition true_condition = EmitComparisonCode(compiler, labels); | 762 Condition true_condition = EmitComparisonCode(compiler, labels); |
761 if ((operation_cid() == kDoubleCid) && (true_condition != NE)) { | 763 if ((operation_cid() == kDoubleCid) && (true_condition != NE)) { |
762 // Special case for NaN comparison. Result is always false unless | 764 // Special case for NaN comparison. Result is always false unless |
763 // relational operator is !=. | 765 // relational operator is !=. |
764 __ b(labels.false_label, VS); | 766 __ b(labels.false_label, VS); |
765 } | 767 } |
766 EmitBranchOnCondition(compiler, true_condition, labels); | 768 EmitBranchOnCondition(compiler, true_condition, labels); |
767 } | 769 } |
768 | 770 |
769 | 771 |
770 LocationSummary* NativeCallInstr::MakeLocationSummary(Zone* zone, | 772 LocationSummary* NativeCallInstr::MakeLocationSummary(Zone* zone, |
771 bool opt) const { | 773 bool opt) const { |
772 return MakeCallSummary(zone); | 774 return MakeCallSummary(zone); |
773 } | 775 } |
774 | 776 |
775 | 777 |
776 void NativeCallInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | 778 void NativeCallInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
777 const Register result = locs()->out(0).reg(); | 779 const Register result = locs()->out(0).reg(); |
778 | 780 |
779 // Push the result place holder initialized to NULL. | 781 // Push the result place holder initialized to NULL. |
780 __ PushObject(Object::null_object(), PP); | 782 __ PushObject(Object::null_object()); |
781 // Pass a pointer to the first argument in R2. | 783 // Pass a pointer to the first argument in R2. |
782 if (!function().HasOptionalParameters()) { | 784 if (!function().HasOptionalParameters()) { |
783 __ AddImmediate(R2, FP, (kParamEndSlotFromFp + | 785 __ AddImmediate(R2, FP, (kParamEndSlotFromFp + |
784 function().NumParameters()) * kWordSize, PP); | 786 function().NumParameters()) * kWordSize); |
785 } else { | 787 } else { |
786 __ AddImmediate(R2, FP, kFirstLocalSlotFromFp * kWordSize, PP); | 788 __ AddImmediate(R2, FP, kFirstLocalSlotFromFp * kWordSize); |
787 } | 789 } |
788 // Compute the effective address. When running under the simulator, | 790 // Compute the effective address. When running under the simulator, |
789 // this is a redirection address that forces the simulator to call | 791 // this is a redirection address that forces the simulator to call |
790 // into the runtime system. | 792 // into the runtime system. |
791 uword entry = reinterpret_cast<uword>(native_c_function()); | 793 uword entry = reinterpret_cast<uword>(native_c_function()); |
792 const intptr_t argc_tag = NativeArguments::ComputeArgcTag(function()); | 794 const intptr_t argc_tag = NativeArguments::ComputeArgcTag(function()); |
793 const bool is_leaf_call = | 795 const bool is_leaf_call = |
794 (argc_tag & NativeArguments::AutoSetupScopeMask()) == 0; | 796 (argc_tag & NativeArguments::AutoSetupScopeMask()) == 0; |
795 const ExternalLabel* stub_entry; | 797 const ExternalLabel* stub_entry; |
796 if (is_bootstrap_native() || is_leaf_call) { | 798 if (is_bootstrap_native() || is_leaf_call) { |
797 stub_entry = &StubCode::CallBootstrapCFunctionLabel(); | 799 stub_entry = &StubCode::CallBootstrapCFunctionLabel(); |
798 #if defined(USING_SIMULATOR) | 800 #if defined(USING_SIMULATOR) |
799 entry = Simulator::RedirectExternalReference( | 801 entry = Simulator::RedirectExternalReference( |
800 entry, Simulator::kBootstrapNativeCall, function().NumParameters()); | 802 entry, Simulator::kBootstrapNativeCall, function().NumParameters()); |
801 #endif | 803 #endif |
802 } else { | 804 } else { |
803 // In the case of non bootstrap native methods the CallNativeCFunction | 805 // In the case of non bootstrap native methods the CallNativeCFunction |
804 // stub generates the redirection address when running under the simulator | 806 // stub generates the redirection address when running under the simulator |
805 // and hence we do not change 'entry' here. | 807 // and hence we do not change 'entry' here. |
806 stub_entry = &StubCode::CallNativeCFunctionLabel(); | 808 stub_entry = &StubCode::CallNativeCFunctionLabel(); |
807 #if defined(USING_SIMULATOR) | 809 #if defined(USING_SIMULATOR) |
808 if (!function().IsNativeAutoSetupScope()) { | 810 if (!function().IsNativeAutoSetupScope()) { |
809 entry = Simulator::RedirectExternalReference( | 811 entry = Simulator::RedirectExternalReference( |
810 entry, Simulator::kBootstrapNativeCall, function().NumParameters()); | 812 entry, Simulator::kBootstrapNativeCall, function().NumParameters()); |
811 } | 813 } |
812 #endif | 814 #endif |
813 } | 815 } |
814 __ LoadImmediate(R5, entry, PP); | 816 __ LoadImmediate(R5, entry); |
815 __ LoadImmediate(R1, argc_tag, PP); | 817 __ LoadImmediate(R1, argc_tag); |
816 compiler->GenerateCall(token_pos(), | 818 compiler->GenerateCall(token_pos(), |
817 stub_entry, | 819 stub_entry, |
818 RawPcDescriptors::kOther, | 820 RawPcDescriptors::kOther, |
819 locs()); | 821 locs()); |
820 __ Pop(result); | 822 __ Pop(result); |
821 } | 823 } |
822 | 824 |
823 | 825 |
824 LocationSummary* StringFromCharCodeInstr::MakeLocationSummary(Zone* zone, | 826 LocationSummary* StringFromCharCodeInstr::MakeLocationSummary(Zone* zone, |
825 bool opt) const { | 827 bool opt) const { |
826 const intptr_t kNumInputs = 1; | 828 const intptr_t kNumInputs = 1; |
827 // TODO(fschneider): Allow immediate operands for the char code. | 829 // TODO(fschneider): Allow immediate operands for the char code. |
828 return LocationSummary::Make(zone, | 830 return LocationSummary::Make(zone, |
829 kNumInputs, | 831 kNumInputs, |
830 Location::RequiresRegister(), | 832 Location::RequiresRegister(), |
831 LocationSummary::kNoCall); | 833 LocationSummary::kNoCall); |
832 } | 834 } |
833 | 835 |
834 | 836 |
835 void StringFromCharCodeInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | 837 void StringFromCharCodeInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
836 ASSERT(compiler->is_optimizing()); | 838 ASSERT(compiler->is_optimizing()); |
837 const Register char_code = locs()->in(0).reg(); | 839 const Register char_code = locs()->in(0).reg(); |
838 const Register result = locs()->out(0).reg(); | 840 const Register result = locs()->out(0).reg(); |
839 __ LoadImmediate( | 841 __ LoadImmediate( |
840 result, reinterpret_cast<uword>(Symbols::PredefinedAddress()), PP); | 842 result, reinterpret_cast<uword>(Symbols::PredefinedAddress())); |
841 __ AddImmediate( | 843 __ AddImmediate( |
842 result, result, Symbols::kNullCharCodeSymbolOffset * kWordSize, PP); | 844 result, result, Symbols::kNullCharCodeSymbolOffset * kWordSize); |
843 __ SmiUntag(TMP, char_code); // Untag to use scaled adress mode. | 845 __ SmiUntag(TMP, char_code); // Untag to use scaled adress mode. |
844 __ ldr(result, Address(result, TMP, UXTX, Address::Scaled)); | 846 __ ldr(result, Address(result, TMP, UXTX, Address::Scaled)); |
845 } | 847 } |
846 | 848 |
847 | 849 |
848 LocationSummary* StringToCharCodeInstr::MakeLocationSummary(Zone* zone, | 850 LocationSummary* StringToCharCodeInstr::MakeLocationSummary(Zone* zone, |
849 bool opt) const { | 851 bool opt) const { |
850 const intptr_t kNumInputs = 1; | 852 const intptr_t kNumInputs = 1; |
851 return LocationSummary::Make(zone, | 853 return LocationSummary::Make(zone, |
852 kNumInputs, | 854 kNumInputs, |
853 Location::RequiresRegister(), | 855 Location::RequiresRegister(), |
854 LocationSummary::kNoCall); | 856 LocationSummary::kNoCall); |
855 } | 857 } |
856 | 858 |
857 | 859 |
858 void StringToCharCodeInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | 860 void StringToCharCodeInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
859 ASSERT(cid_ == kOneByteStringCid); | 861 ASSERT(cid_ == kOneByteStringCid); |
860 const Register str = locs()->in(0).reg(); | 862 const Register str = locs()->in(0).reg(); |
861 const Register result = locs()->out(0).reg(); | 863 const Register result = locs()->out(0).reg(); |
862 __ LoadFieldFromOffset(result, str, String::length_offset(), PP); | 864 __ LoadFieldFromOffset(result, str, String::length_offset()); |
863 __ ldr(TMP, FieldAddress(str, OneByteString::data_offset()), kUnsignedByte); | 865 __ ldr(TMP, FieldAddress(str, OneByteString::data_offset()), kUnsignedByte); |
864 __ CompareImmediate(result, Smi::RawValue(1), PP); | 866 __ CompareImmediate(result, Smi::RawValue(1)); |
865 __ LoadImmediate(result, -1, PP); | 867 __ LoadImmediate(result, -1); |
866 __ csel(result, TMP, result, EQ); | 868 __ csel(result, TMP, result, EQ); |
867 __ SmiTag(result); | 869 __ SmiTag(result); |
868 } | 870 } |
869 | 871 |
870 | 872 |
871 LocationSummary* StringInterpolateInstr::MakeLocationSummary(Zone* zone, | 873 LocationSummary* StringInterpolateInstr::MakeLocationSummary(Zone* zone, |
872 bool opt) const { | 874 bool opt) const { |
873 const intptr_t kNumInputs = 1; | 875 const intptr_t kNumInputs = 1; |
874 const intptr_t kNumTemps = 0; | 876 const intptr_t kNumTemps = 0; |
875 LocationSummary* summary = new(zone) LocationSummary( | 877 LocationSummary* summary = new(zone) LocationSummary( |
(...skipping 27 matching lines...) Expand all Loading... |
903 kNumInputs, | 905 kNumInputs, |
904 Location::RequiresRegister(), | 906 Location::RequiresRegister(), |
905 LocationSummary::kNoCall); | 907 LocationSummary::kNoCall); |
906 } | 908 } |
907 | 909 |
908 | 910 |
909 void LoadUntaggedInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | 911 void LoadUntaggedInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
910 const Register obj = locs()->in(0).reg(); | 912 const Register obj = locs()->in(0).reg(); |
911 const Register result = locs()->out(0).reg(); | 913 const Register result = locs()->out(0).reg(); |
912 if (object()->definition()->representation() == kUntagged) { | 914 if (object()->definition()->representation() == kUntagged) { |
913 __ LoadFromOffset(result, obj, offset(), PP); | 915 __ LoadFromOffset(result, obj, offset()); |
914 } else { | 916 } else { |
915 ASSERT(object()->definition()->representation() == kTagged); | 917 ASSERT(object()->definition()->representation() == kTagged); |
916 __ LoadFieldFromOffset(result, obj, offset(), PP); | 918 __ LoadFieldFromOffset(result, obj, offset()); |
917 } | 919 } |
918 } | 920 } |
919 | 921 |
920 | 922 |
921 LocationSummary* LoadClassIdInstr::MakeLocationSummary(Zone* zone, | 923 LocationSummary* LoadClassIdInstr::MakeLocationSummary(Zone* zone, |
922 bool opt) const { | 924 bool opt) const { |
923 const intptr_t kNumInputs = 1; | 925 const intptr_t kNumInputs = 1; |
924 return LocationSummary::Make(zone, | 926 return LocationSummary::Make(zone, |
925 kNumInputs, | 927 kNumInputs, |
926 Location::RequiresRegister(), | 928 Location::RequiresRegister(), |
927 LocationSummary::kNoCall); | 929 LocationSummary::kNoCall); |
928 } | 930 } |
929 | 931 |
930 | 932 |
931 void LoadClassIdInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | 933 void LoadClassIdInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
932 const Register object = locs()->in(0).reg(); | 934 const Register object = locs()->in(0).reg(); |
933 const Register result = locs()->out(0).reg(); | 935 const Register result = locs()->out(0).reg(); |
934 static const intptr_t kSmiCidSource = | 936 static const intptr_t kSmiCidSource = |
935 static_cast<intptr_t>(kSmiCid) << RawObject::kClassIdTagPos; | 937 static_cast<intptr_t>(kSmiCid) << RawObject::kClassIdTagPos; |
936 | 938 |
937 __ LoadImmediate(TMP, reinterpret_cast<int64_t>(&kSmiCidSource) + 1, PP); | 939 __ LoadImmediate(TMP, reinterpret_cast<int64_t>(&kSmiCidSource) + 1); |
938 __ tsti(object, Immediate(kSmiTagMask)); | 940 __ tsti(object, Immediate(kSmiTagMask)); |
939 __ csel(TMP, TMP, object, EQ); | 941 __ csel(TMP, TMP, object, EQ); |
940 __ LoadClassId(result, TMP, PP); | 942 __ LoadClassId(result, TMP); |
941 __ SmiTag(result); | 943 __ SmiTag(result); |
942 } | 944 } |
943 | 945 |
944 | 946 |
945 CompileType LoadIndexedInstr::ComputeType() const { | 947 CompileType LoadIndexedInstr::ComputeType() const { |
946 switch (class_id_) { | 948 switch (class_id_) { |
947 case kArrayCid: | 949 case kArrayCid: |
948 case kImmutableArrayCid: | 950 case kImmutableArrayCid: |
949 return CompileType::Dynamic(); | 951 return CompileType::Dynamic(); |
950 | 952 |
(...skipping 353 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1304 const Register value = locs()->in(2).reg(); | 1306 const Register value = locs()->in(2).reg(); |
1305 __ StoreIntoObjectNoBarrier(array, element_address, value); | 1307 __ StoreIntoObjectNoBarrier(array, element_address, value); |
1306 } | 1308 } |
1307 break; | 1309 break; |
1308 case kTypedDataInt8ArrayCid: | 1310 case kTypedDataInt8ArrayCid: |
1309 case kTypedDataUint8ArrayCid: | 1311 case kTypedDataUint8ArrayCid: |
1310 case kExternalTypedDataUint8ArrayCid: | 1312 case kExternalTypedDataUint8ArrayCid: |
1311 case kOneByteStringCid: { | 1313 case kOneByteStringCid: { |
1312 if (locs()->in(2).IsConstant()) { | 1314 if (locs()->in(2).IsConstant()) { |
1313 const Smi& constant = Smi::Cast(locs()->in(2).constant()); | 1315 const Smi& constant = Smi::Cast(locs()->in(2).constant()); |
1314 __ LoadImmediate(TMP, static_cast<int8_t>(constant.Value()), PP); | 1316 __ LoadImmediate(TMP, static_cast<int8_t>(constant.Value())); |
1315 __ str(TMP, element_address, kUnsignedByte); | 1317 __ str(TMP, element_address, kUnsignedByte); |
1316 } else { | 1318 } else { |
1317 const Register value = locs()->in(2).reg(); | 1319 const Register value = locs()->in(2).reg(); |
1318 __ SmiUntag(TMP, value); | 1320 __ SmiUntag(TMP, value); |
1319 __ str(TMP, element_address, kUnsignedByte); | 1321 __ str(TMP, element_address, kUnsignedByte); |
1320 } | 1322 } |
1321 break; | 1323 break; |
1322 } | 1324 } |
1323 case kTypedDataUint8ClampedArrayCid: | 1325 case kTypedDataUint8ClampedArrayCid: |
1324 case kExternalTypedDataUint8ClampedArrayCid: { | 1326 case kExternalTypedDataUint8ClampedArrayCid: { |
1325 if (locs()->in(2).IsConstant()) { | 1327 if (locs()->in(2).IsConstant()) { |
1326 const Smi& constant = Smi::Cast(locs()->in(2).constant()); | 1328 const Smi& constant = Smi::Cast(locs()->in(2).constant()); |
1327 intptr_t value = constant.Value(); | 1329 intptr_t value = constant.Value(); |
1328 // Clamp to 0x0 or 0xFF respectively. | 1330 // Clamp to 0x0 or 0xFF respectively. |
1329 if (value > 0xFF) { | 1331 if (value > 0xFF) { |
1330 value = 0xFF; | 1332 value = 0xFF; |
1331 } else if (value < 0) { | 1333 } else if (value < 0) { |
1332 value = 0; | 1334 value = 0; |
1333 } | 1335 } |
1334 __ LoadImmediate(TMP, static_cast<int8_t>(value), PP); | 1336 __ LoadImmediate(TMP, static_cast<int8_t>(value)); |
1335 __ str(TMP, element_address, kUnsignedByte); | 1337 __ str(TMP, element_address, kUnsignedByte); |
1336 } else { | 1338 } else { |
1337 const Register value = locs()->in(2).reg(); | 1339 const Register value = locs()->in(2).reg(); |
1338 __ CompareImmediate(value, 0x1FE, PP); // Smi value and smi 0xFF. | 1340 __ CompareImmediate(value, 0x1FE); // Smi value and smi 0xFF. |
1339 // Clamp to 0x00 or 0xFF respectively. | 1341 // Clamp to 0x00 or 0xFF respectively. |
1340 __ csetm(TMP, GT); // TMP = value > 0x1FE ? -1 : 0. | 1342 __ csetm(TMP, GT); // TMP = value > 0x1FE ? -1 : 0. |
1341 __ csel(TMP, value, TMP, LS); // TMP = value in range ? value : TMP. | 1343 __ csel(TMP, value, TMP, LS); // TMP = value in range ? value : TMP. |
1342 __ SmiUntag(TMP); | 1344 __ SmiUntag(TMP); |
1343 __ str(TMP, element_address, kUnsignedByte); | 1345 __ str(TMP, element_address, kUnsignedByte); |
1344 } | 1346 } |
1345 break; | 1347 break; |
1346 } | 1348 } |
1347 case kTypedDataInt16ArrayCid: | 1349 case kTypedDataInt16ArrayCid: |
1348 case kTypedDataUint16ArrayCid: { | 1350 case kTypedDataUint16ArrayCid: { |
(...skipping 30 matching lines...) Expand all Loading... |
1379 } | 1381 } |
1380 } | 1382 } |
1381 | 1383 |
1382 | 1384 |
1383 static void LoadValueCid(FlowGraphCompiler* compiler, | 1385 static void LoadValueCid(FlowGraphCompiler* compiler, |
1384 Register value_cid_reg, | 1386 Register value_cid_reg, |
1385 Register value_reg, | 1387 Register value_reg, |
1386 Label* value_is_smi = NULL) { | 1388 Label* value_is_smi = NULL) { |
1387 Label done; | 1389 Label done; |
1388 if (value_is_smi == NULL) { | 1390 if (value_is_smi == NULL) { |
1389 __ LoadImmediate(value_cid_reg, kSmiCid, PP); | 1391 __ LoadImmediate(value_cid_reg, kSmiCid); |
1390 } | 1392 } |
1391 __ tsti(value_reg, Immediate(kSmiTagMask)); | 1393 __ tsti(value_reg, Immediate(kSmiTagMask)); |
1392 if (value_is_smi == NULL) { | 1394 if (value_is_smi == NULL) { |
1393 __ b(&done, EQ); | 1395 __ b(&done, EQ); |
1394 } else { | 1396 } else { |
1395 __ b(value_is_smi, EQ); | 1397 __ b(value_is_smi, EQ); |
1396 } | 1398 } |
1397 __ LoadClassId(value_cid_reg, value_reg, PP); | 1399 __ LoadClassId(value_cid_reg, value_reg); |
1398 __ Bind(&done); | 1400 __ Bind(&done); |
1399 } | 1401 } |
1400 | 1402 |
1401 | 1403 |
1402 LocationSummary* GuardFieldClassInstr::MakeLocationSummary(Zone* zone, | 1404 LocationSummary* GuardFieldClassInstr::MakeLocationSummary(Zone* zone, |
1403 bool opt) const { | 1405 bool opt) const { |
1404 const intptr_t kNumInputs = 1; | 1406 const intptr_t kNumInputs = 1; |
1405 | 1407 |
1406 const intptr_t value_cid = value()->Type()->ToCid(); | 1408 const intptr_t value_cid = value()->Type()->ToCid(); |
1407 const intptr_t field_cid = field().guarded_cid(); | 1409 const intptr_t field_cid = field().guarded_cid(); |
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1462 locs()->temp(locs()->temp_count() - 1).reg() : kNoRegister; | 1464 locs()->temp(locs()->temp_count() - 1).reg() : kNoRegister; |
1463 | 1465 |
1464 Label ok, fail_label; | 1466 Label ok, fail_label; |
1465 | 1467 |
1466 Label* deopt = compiler->is_optimizing() ? | 1468 Label* deopt = compiler->is_optimizing() ? |
1467 compiler->AddDeoptStub(deopt_id(), ICData::kDeoptGuardField) : NULL; | 1469 compiler->AddDeoptStub(deopt_id(), ICData::kDeoptGuardField) : NULL; |
1468 | 1470 |
1469 Label* fail = (deopt != NULL) ? deopt : &fail_label; | 1471 Label* fail = (deopt != NULL) ? deopt : &fail_label; |
1470 | 1472 |
1471 if (emit_full_guard) { | 1473 if (emit_full_guard) { |
1472 __ LoadObject(field_reg, Field::ZoneHandle(field().raw()), PP); | 1474 __ LoadObject(field_reg, Field::ZoneHandle(field().raw())); |
1473 | 1475 |
1474 FieldAddress field_cid_operand( | 1476 FieldAddress field_cid_operand( |
1475 field_reg, Field::guarded_cid_offset(), kUnsignedWord); | 1477 field_reg, Field::guarded_cid_offset(), kUnsignedWord); |
1476 FieldAddress field_nullability_operand( | 1478 FieldAddress field_nullability_operand( |
1477 field_reg, Field::is_nullable_offset(), kUnsignedWord); | 1479 field_reg, Field::is_nullable_offset(), kUnsignedWord); |
1478 | 1480 |
1479 if (value_cid == kDynamicCid) { | 1481 if (value_cid == kDynamicCid) { |
1480 LoadValueCid(compiler, value_cid_reg, value_reg); | 1482 LoadValueCid(compiler, value_cid_reg, value_reg); |
1481 Label skip_length_check; | 1483 Label skip_length_check; |
1482 __ ldr(TMP, field_cid_operand, kUnsignedWord); | 1484 __ ldr(TMP, field_cid_operand, kUnsignedWord); |
1483 __ CompareRegisters(value_cid_reg, TMP); | 1485 __ CompareRegisters(value_cid_reg, TMP); |
1484 __ b(&ok, EQ); | 1486 __ b(&ok, EQ); |
1485 __ ldr(TMP, field_nullability_operand, kUnsignedWord); | 1487 __ ldr(TMP, field_nullability_operand, kUnsignedWord); |
1486 __ CompareRegisters(value_cid_reg, TMP); | 1488 __ CompareRegisters(value_cid_reg, TMP); |
1487 } else if (value_cid == kNullCid) { | 1489 } else if (value_cid == kNullCid) { |
1488 __ ldr(value_cid_reg, field_nullability_operand, kUnsignedWord); | 1490 __ ldr(value_cid_reg, field_nullability_operand, kUnsignedWord); |
1489 __ CompareImmediate(value_cid_reg, value_cid, PP); | 1491 __ CompareImmediate(value_cid_reg, value_cid); |
1490 } else { | 1492 } else { |
1491 Label skip_length_check; | 1493 Label skip_length_check; |
1492 __ ldr(value_cid_reg, field_cid_operand, kUnsignedWord); | 1494 __ ldr(value_cid_reg, field_cid_operand, kUnsignedWord); |
1493 __ CompareImmediate(value_cid_reg, value_cid, PP); | 1495 __ CompareImmediate(value_cid_reg, value_cid); |
1494 } | 1496 } |
1495 __ b(&ok, EQ); | 1497 __ b(&ok, EQ); |
1496 | 1498 |
1497 // Check if the tracked state of the guarded field can be initialized | 1499 // Check if the tracked state of the guarded field can be initialized |
1498 // inline. If the field needs length check we fall through to runtime | 1500 // inline. If the field needs length check we fall through to runtime |
1499 // which is responsible for computing offset of the length field | 1501 // which is responsible for computing offset of the length field |
1500 // based on the class id. | 1502 // based on the class id. |
1501 // Length guard will be emitted separately when needed via GuardFieldLength | 1503 // Length guard will be emitted separately when needed via GuardFieldLength |
1502 // instruction after GuardFieldClass. | 1504 // instruction after GuardFieldClass. |
1503 if (!field().needs_length_check()) { | 1505 if (!field().needs_length_check()) { |
1504 // Uninitialized field can be handled inline. Check if the | 1506 // Uninitialized field can be handled inline. Check if the |
1505 // field is still unitialized. | 1507 // field is still unitialized. |
1506 __ ldr(TMP, field_cid_operand, kUnsignedWord); | 1508 __ ldr(TMP, field_cid_operand, kUnsignedWord); |
1507 __ CompareImmediate(TMP, kIllegalCid, PP); | 1509 __ CompareImmediate(TMP, kIllegalCid); |
1508 __ b(fail, NE); | 1510 __ b(fail, NE); |
1509 | 1511 |
1510 if (value_cid == kDynamicCid) { | 1512 if (value_cid == kDynamicCid) { |
1511 __ str(value_cid_reg, field_cid_operand, kUnsignedWord); | 1513 __ str(value_cid_reg, field_cid_operand, kUnsignedWord); |
1512 __ str(value_cid_reg, field_nullability_operand, kUnsignedWord); | 1514 __ str(value_cid_reg, field_nullability_operand, kUnsignedWord); |
1513 } else { | 1515 } else { |
1514 __ LoadImmediate(TMP, value_cid, PP); | 1516 __ LoadImmediate(TMP, value_cid); |
1515 __ str(TMP, field_cid_operand, kUnsignedWord); | 1517 __ str(TMP, field_cid_operand, kUnsignedWord); |
1516 __ str(TMP, field_nullability_operand, kUnsignedWord); | 1518 __ str(TMP, field_nullability_operand, kUnsignedWord); |
1517 } | 1519 } |
1518 | 1520 |
1519 if (deopt == NULL) { | 1521 if (deopt == NULL) { |
1520 ASSERT(!compiler->is_optimizing()); | 1522 ASSERT(!compiler->is_optimizing()); |
1521 __ b(&ok); | 1523 __ b(&ok); |
1522 } | 1524 } |
1523 } | 1525 } |
1524 | 1526 |
1525 if (deopt == NULL) { | 1527 if (deopt == NULL) { |
1526 ASSERT(!compiler->is_optimizing()); | 1528 ASSERT(!compiler->is_optimizing()); |
1527 __ Bind(fail); | 1529 __ Bind(fail); |
1528 | 1530 |
1529 __ LoadFieldFromOffset( | 1531 __ LoadFieldFromOffset( |
1530 TMP, field_reg, Field::guarded_cid_offset(), PP, kUnsignedWord); | 1532 TMP, field_reg, Field::guarded_cid_offset(), kUnsignedWord); |
1531 __ CompareImmediate(TMP, kDynamicCid, PP); | 1533 __ CompareImmediate(TMP, kDynamicCid); |
1532 __ b(&ok, EQ); | 1534 __ b(&ok, EQ); |
1533 | 1535 |
1534 __ Push(field_reg); | 1536 __ Push(field_reg); |
1535 __ Push(value_reg); | 1537 __ Push(value_reg); |
1536 __ CallRuntime(kUpdateFieldCidRuntimeEntry, 2); | 1538 __ CallRuntime(kUpdateFieldCidRuntimeEntry, 2); |
1537 __ Drop(2); // Drop the field and the value. | 1539 __ Drop(2); // Drop the field and the value. |
1538 } | 1540 } |
1539 } else { | 1541 } else { |
1540 ASSERT(compiler->is_optimizing()); | 1542 ASSERT(compiler->is_optimizing()); |
1541 ASSERT(deopt != NULL); | 1543 ASSERT(deopt != NULL); |
1542 | 1544 |
1543 // Field guard class has been initialized and is known. | 1545 // Field guard class has been initialized and is known. |
1544 if (value_cid == kDynamicCid) { | 1546 if (value_cid == kDynamicCid) { |
1545 // Value's class id is not known. | 1547 // Value's class id is not known. |
1546 __ tsti(value_reg, Immediate(kSmiTagMask)); | 1548 __ tsti(value_reg, Immediate(kSmiTagMask)); |
1547 | 1549 |
1548 if (field_cid != kSmiCid) { | 1550 if (field_cid != kSmiCid) { |
1549 __ b(fail, EQ); | 1551 __ b(fail, EQ); |
1550 __ LoadClassId(value_cid_reg, value_reg, PP); | 1552 __ LoadClassId(value_cid_reg, value_reg); |
1551 __ CompareImmediate(value_cid_reg, field_cid, PP); | 1553 __ CompareImmediate(value_cid_reg, field_cid); |
1552 } | 1554 } |
1553 | 1555 |
1554 if (field().is_nullable() && (field_cid != kNullCid)) { | 1556 if (field().is_nullable() && (field_cid != kNullCid)) { |
1555 __ b(&ok, EQ); | 1557 __ b(&ok, EQ); |
1556 __ CompareObject(value_reg, Object::null_object(), PP); | 1558 __ CompareObject(value_reg, Object::null_object()); |
1557 } | 1559 } |
1558 | 1560 |
1559 __ b(fail, NE); | 1561 __ b(fail, NE); |
1560 } else { | 1562 } else { |
1561 // Both value's and field's class id is known. | 1563 // Both value's and field's class id is known. |
1562 ASSERT((value_cid != field_cid) && (value_cid != nullability)); | 1564 ASSERT((value_cid != field_cid) && (value_cid != nullability)); |
1563 __ b(fail); | 1565 __ b(fail); |
1564 } | 1566 } |
1565 } | 1567 } |
1566 __ Bind(&ok); | 1568 __ Bind(&ok); |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1602 const Register value_reg = locs()->in(0).reg(); | 1604 const Register value_reg = locs()->in(0).reg(); |
1603 | 1605 |
1604 if (!compiler->is_optimizing() || | 1606 if (!compiler->is_optimizing() || |
1605 (field().guarded_list_length() == Field::kUnknownFixedLength)) { | 1607 (field().guarded_list_length() == Field::kUnknownFixedLength)) { |
1606 const Register field_reg = locs()->temp(0).reg(); | 1608 const Register field_reg = locs()->temp(0).reg(); |
1607 const Register offset_reg = locs()->temp(1).reg(); | 1609 const Register offset_reg = locs()->temp(1).reg(); |
1608 const Register length_reg = locs()->temp(2).reg(); | 1610 const Register length_reg = locs()->temp(2).reg(); |
1609 | 1611 |
1610 Label ok; | 1612 Label ok; |
1611 | 1613 |
1612 __ LoadObject(field_reg, Field::ZoneHandle(field().raw()), PP); | 1614 __ LoadObject(field_reg, Field::ZoneHandle(field().raw())); |
1613 | 1615 |
1614 __ ldr(offset_reg, | 1616 __ ldr(offset_reg, |
1615 FieldAddress(field_reg, | 1617 FieldAddress(field_reg, |
1616 Field::guarded_list_length_in_object_offset_offset()), | 1618 Field::guarded_list_length_in_object_offset_offset()), |
1617 kByte); | 1619 kByte); |
1618 __ ldr(length_reg, FieldAddress(field_reg, | 1620 __ ldr(length_reg, FieldAddress(field_reg, |
1619 Field::guarded_list_length_offset())); | 1621 Field::guarded_list_length_offset())); |
1620 | 1622 |
1621 __ tst(offset_reg, Operand(offset_reg)); | 1623 __ tst(offset_reg, Operand(offset_reg)); |
1622 __ b(&ok, MI); | 1624 __ b(&ok, MI); |
(...skipping 18 matching lines...) Expand all Loading... |
1641 | 1643 |
1642 __ Bind(&ok); | 1644 __ Bind(&ok); |
1643 } else { | 1645 } else { |
1644 ASSERT(compiler->is_optimizing()); | 1646 ASSERT(compiler->is_optimizing()); |
1645 ASSERT(field().guarded_list_length() >= 0); | 1647 ASSERT(field().guarded_list_length() >= 0); |
1646 ASSERT(field().guarded_list_length_in_object_offset() != | 1648 ASSERT(field().guarded_list_length_in_object_offset() != |
1647 Field::kUnknownLengthOffset); | 1649 Field::kUnknownLengthOffset); |
1648 | 1650 |
1649 __ ldr(TMP, FieldAddress(value_reg, | 1651 __ ldr(TMP, FieldAddress(value_reg, |
1650 field().guarded_list_length_in_object_offset())); | 1652 field().guarded_list_length_in_object_offset())); |
1651 __ CompareImmediate(TMP, Smi::RawValue(field().guarded_list_length()), PP); | 1653 __ CompareImmediate(TMP, Smi::RawValue(field().guarded_list_length())); |
1652 __ b(deopt, NE); | 1654 __ b(deopt, NE); |
1653 } | 1655 } |
1654 } | 1656 } |
1655 | 1657 |
1656 | 1658 |
1657 class BoxAllocationSlowPath : public SlowPathCode { | 1659 class BoxAllocationSlowPath : public SlowPathCode { |
1658 public: | 1660 public: |
1659 BoxAllocationSlowPath(Instruction* instruction, | 1661 BoxAllocationSlowPath(Instruction* instruction, |
1660 const Class& cls, | 1662 const Class& cls, |
1661 Register result) | 1663 Register result) |
(...skipping 27 matching lines...) Expand all Loading... |
1689 compiler->RestoreLiveRegisters(locs); | 1691 compiler->RestoreLiveRegisters(locs); |
1690 __ b(exit_label()); | 1692 __ b(exit_label()); |
1691 } | 1693 } |
1692 | 1694 |
1693 static void Allocate(FlowGraphCompiler* compiler, | 1695 static void Allocate(FlowGraphCompiler* compiler, |
1694 Instruction* instruction, | 1696 Instruction* instruction, |
1695 const Class& cls, | 1697 const Class& cls, |
1696 Register result, | 1698 Register result, |
1697 Register temp) { | 1699 Register temp) { |
1698 if (compiler->intrinsic_mode()) { | 1700 if (compiler->intrinsic_mode()) { |
1699 __ TryAllocate(cls, | 1701 __ TryAllocate(cls, compiler->intrinsic_slow_path_label(), result, temp); |
1700 compiler->intrinsic_slow_path_label(), | |
1701 result, | |
1702 temp, | |
1703 PP); | |
1704 } else { | 1702 } else { |
1705 BoxAllocationSlowPath* slow_path = | 1703 BoxAllocationSlowPath* slow_path = |
1706 new BoxAllocationSlowPath(instruction, cls, result); | 1704 new BoxAllocationSlowPath(instruction, cls, result); |
1707 compiler->AddSlowPathCode(slow_path); | 1705 compiler->AddSlowPathCode(slow_path); |
1708 | 1706 |
1709 __ TryAllocate(cls, | 1707 __ TryAllocate(cls, slow_path->entry_label(), result, temp); |
1710 slow_path->entry_label(), | |
1711 result, | |
1712 temp, | |
1713 PP); | |
1714 __ Bind(slow_path->exit_label()); | 1708 __ Bind(slow_path->exit_label()); |
1715 } | 1709 } |
1716 } | 1710 } |
1717 | 1711 |
1718 private: | 1712 private: |
1719 Instruction* instruction_; | 1713 Instruction* instruction_; |
1720 const Class& cls_; | 1714 const Class& cls_; |
1721 const Register result_; | 1715 const Register result_; |
1722 }; | 1716 }; |
1723 | 1717 |
1724 | 1718 |
1725 static void EnsureMutableBox(FlowGraphCompiler* compiler, | 1719 static void EnsureMutableBox(FlowGraphCompiler* compiler, |
1726 StoreInstanceFieldInstr* instruction, | 1720 StoreInstanceFieldInstr* instruction, |
1727 Register box_reg, | 1721 Register box_reg, |
1728 const Class& cls, | 1722 const Class& cls, |
1729 Register instance_reg, | 1723 Register instance_reg, |
1730 intptr_t offset, | 1724 intptr_t offset, |
1731 Register temp) { | 1725 Register temp) { |
1732 Label done; | 1726 Label done; |
1733 __ LoadFieldFromOffset(box_reg, instance_reg, offset, PP); | 1727 __ LoadFieldFromOffset(box_reg, instance_reg, offset); |
1734 __ CompareObject(box_reg, Object::null_object(), PP); | 1728 __ CompareObject(box_reg, Object::null_object()); |
1735 __ b(&done, NE); | 1729 __ b(&done, NE); |
1736 BoxAllocationSlowPath::Allocate( | 1730 BoxAllocationSlowPath::Allocate( |
1737 compiler, instruction, cls, box_reg, temp); | 1731 compiler, instruction, cls, box_reg, temp); |
1738 __ mov(temp, box_reg); | 1732 __ mov(temp, box_reg); |
1739 __ StoreIntoObjectOffset(instance_reg, offset, temp, PP); | 1733 __ StoreIntoObjectOffset(instance_reg, offset, temp); |
1740 __ Bind(&done); | 1734 __ Bind(&done); |
1741 } | 1735 } |
1742 | 1736 |
1743 | 1737 |
1744 LocationSummary* StoreInstanceFieldInstr::MakeLocationSummary(Zone* zone, | 1738 LocationSummary* StoreInstanceFieldInstr::MakeLocationSummary(Zone* zone, |
1745 bool opt) const { | 1739 bool opt) const { |
1746 const intptr_t kNumInputs = 2; | 1740 const intptr_t kNumInputs = 2; |
1747 const intptr_t kNumTemps = | 1741 const intptr_t kNumTemps = |
1748 (IsUnboxedStore() && opt) ? 2 : | 1742 (IsUnboxedStore() && opt) ? 2 : |
1749 ((IsPotentialUnboxedStore()) ? 2 : 0); | 1743 ((IsPotentialUnboxedStore()) ? 2 : 0); |
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1797 break; | 1791 break; |
1798 case kFloat64x2Cid: | 1792 case kFloat64x2Cid: |
1799 cls = &compiler->float64x2_class(); | 1793 cls = &compiler->float64x2_class(); |
1800 break; | 1794 break; |
1801 default: | 1795 default: |
1802 UNREACHABLE(); | 1796 UNREACHABLE(); |
1803 } | 1797 } |
1804 | 1798 |
1805 BoxAllocationSlowPath::Allocate(compiler, this, *cls, temp, temp2); | 1799 BoxAllocationSlowPath::Allocate(compiler, this, *cls, temp, temp2); |
1806 __ mov(temp2, temp); | 1800 __ mov(temp2, temp); |
1807 __ StoreIntoObjectOffset(instance_reg, offset_in_bytes_, temp2, PP); | 1801 __ StoreIntoObjectOffset(instance_reg, offset_in_bytes_, temp2); |
1808 } else { | 1802 } else { |
1809 __ LoadFieldFromOffset(temp, instance_reg, offset_in_bytes_, PP); | 1803 __ LoadFieldFromOffset(temp, instance_reg, offset_in_bytes_); |
1810 } | 1804 } |
1811 switch (cid) { | 1805 switch (cid) { |
1812 case kDoubleCid: | 1806 case kDoubleCid: |
1813 __ Comment("UnboxedDoubleStoreInstanceFieldInstr"); | 1807 __ Comment("UnboxedDoubleStoreInstanceFieldInstr"); |
1814 __ StoreDFieldToOffset(value, temp, Double::value_offset(), PP); | 1808 __ StoreDFieldToOffset(value, temp, Double::value_offset()); |
1815 break; | 1809 break; |
1816 case kFloat32x4Cid: | 1810 case kFloat32x4Cid: |
1817 __ Comment("UnboxedFloat32x4StoreInstanceFieldInstr"); | 1811 __ Comment("UnboxedFloat32x4StoreInstanceFieldInstr"); |
1818 __ StoreQFieldToOffset(value, temp, Float32x4::value_offset(), PP); | 1812 __ StoreQFieldToOffset(value, temp, Float32x4::value_offset()); |
1819 break; | 1813 break; |
1820 case kFloat64x2Cid: | 1814 case kFloat64x2Cid: |
1821 __ Comment("UnboxedFloat64x2StoreInstanceFieldInstr"); | 1815 __ Comment("UnboxedFloat64x2StoreInstanceFieldInstr"); |
1822 __ StoreQFieldToOffset(value, temp, Float64x2::value_offset(), PP); | 1816 __ StoreQFieldToOffset(value, temp, Float64x2::value_offset()); |
1823 break; | 1817 break; |
1824 default: | 1818 default: |
1825 UNREACHABLE(); | 1819 UNREACHABLE(); |
1826 } | 1820 } |
1827 | 1821 |
1828 return; | 1822 return; |
1829 } | 1823 } |
1830 | 1824 |
1831 if (IsPotentialUnboxedStore()) { | 1825 if (IsPotentialUnboxedStore()) { |
1832 const Register value_reg = locs()->in(1).reg(); | 1826 const Register value_reg = locs()->in(1).reg(); |
1833 const Register temp = locs()->temp(0).reg(); | 1827 const Register temp = locs()->temp(0).reg(); |
1834 const Register temp2 = locs()->temp(1).reg(); | 1828 const Register temp2 = locs()->temp(1).reg(); |
1835 | 1829 |
1836 if (ShouldEmitStoreBarrier()) { | 1830 if (ShouldEmitStoreBarrier()) { |
1837 // Value input is a writable register and should be manually preserved | 1831 // Value input is a writable register and should be manually preserved |
1838 // across allocation slow-path. | 1832 // across allocation slow-path. |
1839 locs()->live_registers()->Add(locs()->in(1), kTagged); | 1833 locs()->live_registers()->Add(locs()->in(1), kTagged); |
1840 } | 1834 } |
1841 | 1835 |
1842 Label store_pointer; | 1836 Label store_pointer; |
1843 Label store_double; | 1837 Label store_double; |
1844 Label store_float32x4; | 1838 Label store_float32x4; |
1845 Label store_float64x2; | 1839 Label store_float64x2; |
1846 | 1840 |
1847 __ LoadObject(temp, Field::ZoneHandle(field().raw()), PP); | 1841 __ LoadObject(temp, Field::ZoneHandle(field().raw())); |
1848 | 1842 |
1849 __ LoadFieldFromOffset(temp2, temp, Field::is_nullable_offset(), PP, | 1843 __ LoadFieldFromOffset(temp2, temp, Field::is_nullable_offset(), |
1850 kUnsignedWord); | 1844 kUnsignedWord); |
1851 __ CompareImmediate(temp2, kNullCid, PP); | 1845 __ CompareImmediate(temp2, kNullCid); |
1852 __ b(&store_pointer, EQ); | 1846 __ b(&store_pointer, EQ); |
1853 | 1847 |
1854 __ LoadFromOffset( | 1848 __ LoadFromOffset( |
1855 temp2, temp, Field::kind_bits_offset() - kHeapObjectTag, | 1849 temp2, temp, Field::kind_bits_offset() - kHeapObjectTag, |
1856 PP, kUnsignedByte); | 1850 kUnsignedByte); |
1857 __ tsti(temp2, Immediate(1 << Field::kUnboxingCandidateBit)); | 1851 __ tsti(temp2, Immediate(1 << Field::kUnboxingCandidateBit)); |
1858 __ b(&store_pointer, EQ); | 1852 __ b(&store_pointer, EQ); |
1859 | 1853 |
1860 __ LoadFieldFromOffset(temp2, temp, Field::guarded_cid_offset(), PP, | 1854 __ LoadFieldFromOffset(temp2, temp, Field::guarded_cid_offset(), |
1861 kUnsignedWord); | 1855 kUnsignedWord); |
1862 __ CompareImmediate(temp2, kDoubleCid, PP); | 1856 __ CompareImmediate(temp2, kDoubleCid); |
1863 __ b(&store_double, EQ); | 1857 __ b(&store_double, EQ); |
1864 | 1858 |
1865 __ LoadFieldFromOffset(temp2, temp, Field::guarded_cid_offset(), PP, | 1859 __ LoadFieldFromOffset(temp2, temp, Field::guarded_cid_offset(), |
1866 kUnsignedWord); | 1860 kUnsignedWord); |
1867 __ CompareImmediate(temp2, kFloat32x4Cid, PP); | 1861 __ CompareImmediate(temp2, kFloat32x4Cid); |
1868 __ b(&store_float32x4, EQ); | 1862 __ b(&store_float32x4, EQ); |
1869 | 1863 |
1870 __ LoadFieldFromOffset(temp2, temp, Field::guarded_cid_offset(), PP, | 1864 __ LoadFieldFromOffset(temp2, temp, Field::guarded_cid_offset(), |
1871 kUnsignedWord); | 1865 kUnsignedWord); |
1872 __ CompareImmediate(temp2, kFloat64x2Cid, PP); | 1866 __ CompareImmediate(temp2, kFloat64x2Cid); |
1873 __ b(&store_float64x2, EQ); | 1867 __ b(&store_float64x2, EQ); |
1874 | 1868 |
1875 // Fall through. | 1869 // Fall through. |
1876 __ b(&store_pointer); | 1870 __ b(&store_pointer); |
1877 | 1871 |
1878 if (!compiler->is_optimizing()) { | 1872 if (!compiler->is_optimizing()) { |
1879 locs()->live_registers()->Add(locs()->in(0)); | 1873 locs()->live_registers()->Add(locs()->in(0)); |
1880 locs()->live_registers()->Add(locs()->in(1)); | 1874 locs()->live_registers()->Add(locs()->in(1)); |
1881 } | 1875 } |
1882 | 1876 |
1883 { | 1877 { |
1884 __ Bind(&store_double); | 1878 __ Bind(&store_double); |
1885 EnsureMutableBox(compiler, | 1879 EnsureMutableBox(compiler, |
1886 this, | 1880 this, |
1887 temp, | 1881 temp, |
1888 compiler->double_class(), | 1882 compiler->double_class(), |
1889 instance_reg, | 1883 instance_reg, |
1890 offset_in_bytes_, | 1884 offset_in_bytes_, |
1891 temp2); | 1885 temp2); |
1892 __ LoadDFieldFromOffset(VTMP, value_reg, Double::value_offset(), PP); | 1886 __ LoadDFieldFromOffset(VTMP, value_reg, Double::value_offset()); |
1893 __ StoreDFieldToOffset(VTMP, temp, Double::value_offset(), PP); | 1887 __ StoreDFieldToOffset(VTMP, temp, Double::value_offset()); |
1894 __ b(&skip_store); | 1888 __ b(&skip_store); |
1895 } | 1889 } |
1896 | 1890 |
1897 { | 1891 { |
1898 __ Bind(&store_float32x4); | 1892 __ Bind(&store_float32x4); |
1899 EnsureMutableBox(compiler, | 1893 EnsureMutableBox(compiler, |
1900 this, | 1894 this, |
1901 temp, | 1895 temp, |
1902 compiler->float32x4_class(), | 1896 compiler->float32x4_class(), |
1903 instance_reg, | 1897 instance_reg, |
1904 offset_in_bytes_, | 1898 offset_in_bytes_, |
1905 temp2); | 1899 temp2); |
1906 __ LoadQFieldFromOffset(VTMP, value_reg, Float32x4::value_offset(), PP); | 1900 __ LoadQFieldFromOffset(VTMP, value_reg, Float32x4::value_offset()); |
1907 __ StoreQFieldToOffset(VTMP, temp, Float32x4::value_offset(), PP); | 1901 __ StoreQFieldToOffset(VTMP, temp, Float32x4::value_offset()); |
1908 __ b(&skip_store); | 1902 __ b(&skip_store); |
1909 } | 1903 } |
1910 | 1904 |
1911 { | 1905 { |
1912 __ Bind(&store_float64x2); | 1906 __ Bind(&store_float64x2); |
1913 EnsureMutableBox(compiler, | 1907 EnsureMutableBox(compiler, |
1914 this, | 1908 this, |
1915 temp, | 1909 temp, |
1916 compiler->float64x2_class(), | 1910 compiler->float64x2_class(), |
1917 instance_reg, | 1911 instance_reg, |
1918 offset_in_bytes_, | 1912 offset_in_bytes_, |
1919 temp2); | 1913 temp2); |
1920 __ LoadQFieldFromOffset(VTMP, value_reg, Float64x2::value_offset(), PP); | 1914 __ LoadQFieldFromOffset(VTMP, value_reg, Float64x2::value_offset()); |
1921 __ StoreQFieldToOffset(VTMP, temp, Float64x2::value_offset(), PP); | 1915 __ StoreQFieldToOffset(VTMP, temp, Float64x2::value_offset()); |
1922 __ b(&skip_store); | 1916 __ b(&skip_store); |
1923 } | 1917 } |
1924 | 1918 |
1925 __ Bind(&store_pointer); | 1919 __ Bind(&store_pointer); |
1926 } | 1920 } |
1927 | 1921 |
1928 if (ShouldEmitStoreBarrier()) { | 1922 if (ShouldEmitStoreBarrier()) { |
1929 const Register value_reg = locs()->in(1).reg(); | 1923 const Register value_reg = locs()->in(1).reg(); |
1930 __ StoreIntoObjectOffset( | 1924 __ StoreIntoObjectOffset( |
1931 instance_reg, offset_in_bytes_, value_reg, PP, CanValueBeSmi()); | 1925 instance_reg, offset_in_bytes_, value_reg, CanValueBeSmi()); |
1932 } else { | 1926 } else { |
1933 if (locs()->in(1).IsConstant()) { | 1927 if (locs()->in(1).IsConstant()) { |
1934 __ StoreIntoObjectOffsetNoBarrier( | 1928 __ StoreIntoObjectOffsetNoBarrier( |
1935 instance_reg, | 1929 instance_reg, offset_in_bytes_, locs()->in(1).constant()); |
1936 offset_in_bytes_, | |
1937 locs()->in(1).constant(), | |
1938 PP); | |
1939 } else { | 1930 } else { |
1940 const Register value_reg = locs()->in(1).reg(); | 1931 const Register value_reg = locs()->in(1).reg(); |
1941 __ StoreIntoObjectOffsetNoBarrier( | 1932 __ StoreIntoObjectOffsetNoBarrier( |
1942 instance_reg, | 1933 instance_reg, offset_in_bytes_, value_reg); |
1943 offset_in_bytes_, | |
1944 value_reg, | |
1945 PP); | |
1946 } | 1934 } |
1947 } | 1935 } |
1948 __ Bind(&skip_store); | 1936 __ Bind(&skip_store); |
1949 } | 1937 } |
1950 | 1938 |
1951 | 1939 |
1952 LocationSummary* LoadStaticFieldInstr::MakeLocationSummary(Zone* zone, | 1940 LocationSummary* LoadStaticFieldInstr::MakeLocationSummary(Zone* zone, |
1953 bool opt) const { | 1941 bool opt) const { |
1954 const intptr_t kNumInputs = 1; | 1942 const intptr_t kNumInputs = 1; |
1955 const intptr_t kNumTemps = 0; | 1943 const intptr_t kNumTemps = 0; |
1956 LocationSummary* summary = new(zone) LocationSummary( | 1944 LocationSummary* summary = new(zone) LocationSummary( |
1957 zone, kNumInputs, kNumTemps, LocationSummary::kNoCall); | 1945 zone, kNumInputs, kNumTemps, LocationSummary::kNoCall); |
1958 summary->set_in(0, Location::RequiresRegister()); | 1946 summary->set_in(0, Location::RequiresRegister()); |
1959 summary->set_out(0, Location::RequiresRegister()); | 1947 summary->set_out(0, Location::RequiresRegister()); |
1960 return summary; | 1948 return summary; |
1961 } | 1949 } |
1962 | 1950 |
1963 | 1951 |
1964 // When the parser is building an implicit static getter for optimization, | 1952 // When the parser is building an implicit static getter for optimization, |
1965 // it can generate a function body where deoptimization ids do not line up | 1953 // it can generate a function body where deoptimization ids do not line up |
1966 // with the unoptimized code. | 1954 // with the unoptimized code. |
1967 // | 1955 // |
1968 // This is safe only so long as LoadStaticFieldInstr cannot deoptimize. | 1956 // This is safe only so long as LoadStaticFieldInstr cannot deoptimize. |
1969 void LoadStaticFieldInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | 1957 void LoadStaticFieldInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
1970 const Register field = locs()->in(0).reg(); | 1958 const Register field = locs()->in(0).reg(); |
1971 const Register result = locs()->out(0).reg(); | 1959 const Register result = locs()->out(0).reg(); |
1972 __ LoadFieldFromOffset(result, field, Field::value_offset(), PP); | 1960 __ LoadFieldFromOffset(result, field, Field::value_offset()); |
1973 } | 1961 } |
1974 | 1962 |
1975 | 1963 |
1976 LocationSummary* StoreStaticFieldInstr::MakeLocationSummary(Zone* zone, | 1964 LocationSummary* StoreStaticFieldInstr::MakeLocationSummary(Zone* zone, |
1977 bool opt) const { | 1965 bool opt) const { |
1978 LocationSummary* locs = new(zone) LocationSummary( | 1966 LocationSummary* locs = new(zone) LocationSummary( |
1979 zone, 1, 1, LocationSummary::kNoCall); | 1967 zone, 1, 1, LocationSummary::kNoCall); |
1980 locs->set_in(0, value()->NeedsStoreBuffer() ? Location::WritableRegister() | 1968 locs->set_in(0, value()->NeedsStoreBuffer() ? Location::WritableRegister() |
1981 : Location::RequiresRegister()); | 1969 : Location::RequiresRegister()); |
1982 locs->set_temp(0, Location::RequiresRegister()); | 1970 locs->set_temp(0, Location::RequiresRegister()); |
1983 return locs; | 1971 return locs; |
1984 } | 1972 } |
1985 | 1973 |
1986 | 1974 |
1987 void StoreStaticFieldInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | 1975 void StoreStaticFieldInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
1988 const Register value = locs()->in(0).reg(); | 1976 const Register value = locs()->in(0).reg(); |
1989 const Register temp = locs()->temp(0).reg(); | 1977 const Register temp = locs()->temp(0).reg(); |
1990 | 1978 |
1991 __ LoadObject(temp, field(), PP); | 1979 __ LoadObject(temp, field()); |
1992 if (this->value()->NeedsStoreBuffer()) { | 1980 if (this->value()->NeedsStoreBuffer()) { |
1993 __ StoreIntoObjectOffset( | 1981 __ StoreIntoObjectOffset( |
1994 temp, Field::value_offset(), value, PP, CanValueBeSmi()); | 1982 temp, Field::value_offset(), value, CanValueBeSmi()); |
1995 } else { | 1983 } else { |
1996 __ StoreIntoObjectOffsetNoBarrier(temp, Field::value_offset(), value, PP); | 1984 __ StoreIntoObjectOffsetNoBarrier(temp, Field::value_offset(), value); |
1997 } | 1985 } |
1998 } | 1986 } |
1999 | 1987 |
2000 | 1988 |
2001 LocationSummary* InstanceOfInstr::MakeLocationSummary(Zone* zone, | 1989 LocationSummary* InstanceOfInstr::MakeLocationSummary(Zone* zone, |
2002 bool opt) const { | 1990 bool opt) const { |
2003 const intptr_t kNumInputs = 3; | 1991 const intptr_t kNumInputs = 3; |
2004 const intptr_t kNumTemps = 0; | 1992 const intptr_t kNumTemps = 0; |
2005 LocationSummary* summary = new(zone) LocationSummary( | 1993 LocationSummary* summary = new(zone) LocationSummary( |
2006 zone, kNumInputs, kNumTemps, LocationSummary::kCall); | 1994 zone, kNumInputs, kNumTemps, LocationSummary::kCall); |
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2069 | 2057 |
2070 // TODO(zra): Use stp once added. | 2058 // TODO(zra): Use stp once added. |
2071 // Initialize all array elements to raw_null. | 2059 // Initialize all array elements to raw_null. |
2072 // R0: new object start as a tagged pointer. | 2060 // R0: new object start as a tagged pointer. |
2073 // R3: new object end address. | 2061 // R3: new object end address. |
2074 // R8: iterator which initially points to the start of the variable | 2062 // R8: iterator which initially points to the start of the variable |
2075 // data area to be initialized. | 2063 // data area to be initialized. |
2076 // R6: null | 2064 // R6: null |
2077 if (num_elements > 0) { | 2065 if (num_elements > 0) { |
2078 const intptr_t array_size = instance_size - sizeof(RawArray); | 2066 const intptr_t array_size = instance_size - sizeof(RawArray); |
2079 __ LoadObject(R6, Object::null_object(), PP); | 2067 __ LoadObject(R6, Object::null_object()); |
2080 __ AddImmediate(R8, R0, sizeof(RawArray) - kHeapObjectTag, PP); | 2068 __ AddImmediate(R8, R0, sizeof(RawArray) - kHeapObjectTag); |
2081 if (array_size < (kInlineArraySize * kWordSize)) { | 2069 if (array_size < (kInlineArraySize * kWordSize)) { |
2082 intptr_t current_offset = 0; | 2070 intptr_t current_offset = 0; |
2083 while (current_offset < array_size) { | 2071 while (current_offset < array_size) { |
2084 __ str(R6, Address(R8, current_offset)); | 2072 __ str(R6, Address(R8, current_offset)); |
2085 current_offset += kWordSize; | 2073 current_offset += kWordSize; |
2086 } | 2074 } |
2087 } else { | 2075 } else { |
2088 Label end_loop, init_loop; | 2076 Label end_loop, init_loop; |
2089 __ Bind(&init_loop); | 2077 __ Bind(&init_loop); |
2090 __ CompareRegisters(R8, R3); | 2078 __ CompareRegisters(R8, R3); |
2091 __ b(&end_loop, CS); | 2079 __ b(&end_loop, CS); |
2092 __ str(R6, Address(R8)); | 2080 __ str(R6, Address(R8)); |
2093 __ AddImmediate(R8, R8, kWordSize, kNoPP); | 2081 __ AddImmediate(R8, R8, kWordSize); |
2094 __ b(&init_loop); | 2082 __ b(&init_loop); |
2095 __ Bind(&end_loop); | 2083 __ Bind(&end_loop); |
2096 } | 2084 } |
2097 } | 2085 } |
2098 __ b(done); | 2086 __ b(done); |
2099 } | 2087 } |
2100 | 2088 |
2101 | 2089 |
2102 void CreateArrayInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | 2090 void CreateArrayInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
2103 const Register kLengthReg = R2; | 2091 const Register kLengthReg = R2; |
2104 const Register kElemTypeReg = R1; | 2092 const Register kElemTypeReg = R1; |
2105 const Register kResultReg = R0; | 2093 const Register kResultReg = R0; |
2106 | 2094 |
2107 ASSERT(locs()->in(kElementTypePos).reg() == kElemTypeReg); | 2095 ASSERT(locs()->in(kElementTypePos).reg() == kElemTypeReg); |
2108 ASSERT(locs()->in(kLengthPos).reg() == kLengthReg); | 2096 ASSERT(locs()->in(kLengthPos).reg() == kLengthReg); |
2109 | 2097 |
2110 if (compiler->is_optimizing() && | 2098 if (compiler->is_optimizing() && |
2111 num_elements()->BindsToConstant() && | 2099 num_elements()->BindsToConstant() && |
2112 num_elements()->BoundConstant().IsSmi()) { | 2100 num_elements()->BoundConstant().IsSmi()) { |
2113 const intptr_t length = Smi::Cast(num_elements()->BoundConstant()).Value(); | 2101 const intptr_t length = Smi::Cast(num_elements()->BoundConstant()).Value(); |
2114 if ((length >= 0) && (length <= Array::kMaxElements)) { | 2102 if ((length >= 0) && (length <= Array::kMaxElements)) { |
2115 Label slow_path, done; | 2103 Label slow_path, done; |
2116 InlineArrayAllocation(compiler, length, &slow_path, &done); | 2104 InlineArrayAllocation(compiler, length, &slow_path, &done); |
2117 __ Bind(&slow_path); | 2105 __ Bind(&slow_path); |
2118 __ PushObject(Object::null_object(), PP); // Make room for the result. | 2106 __ PushObject(Object::null_object()); // Make room for the result. |
2119 __ Push(kLengthReg); // length. | 2107 __ Push(kLengthReg); // length. |
2120 __ Push(kElemTypeReg); | 2108 __ Push(kElemTypeReg); |
2121 compiler->GenerateRuntimeCall(token_pos(), | 2109 compiler->GenerateRuntimeCall(token_pos(), |
2122 deopt_id(), | 2110 deopt_id(), |
2123 kAllocateArrayRuntimeEntry, | 2111 kAllocateArrayRuntimeEntry, |
2124 2, | 2112 2, |
2125 locs()); | 2113 locs()); |
2126 __ Drop(2); | 2114 __ Drop(2); |
2127 __ Pop(kResultReg); | 2115 __ Pop(kResultReg); |
2128 __ Bind(&done); | 2116 __ Bind(&done); |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2161 return locs; | 2149 return locs; |
2162 } | 2150 } |
2163 | 2151 |
2164 | 2152 |
2165 void LoadFieldInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | 2153 void LoadFieldInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
2166 ASSERT(sizeof(classid_t) == kInt32Size); | 2154 ASSERT(sizeof(classid_t) == kInt32Size); |
2167 const Register instance_reg = locs()->in(0).reg(); | 2155 const Register instance_reg = locs()->in(0).reg(); |
2168 if (IsUnboxedLoad() && compiler->is_optimizing()) { | 2156 if (IsUnboxedLoad() && compiler->is_optimizing()) { |
2169 const VRegister result = locs()->out(0).fpu_reg(); | 2157 const VRegister result = locs()->out(0).fpu_reg(); |
2170 const Register temp = locs()->temp(0).reg(); | 2158 const Register temp = locs()->temp(0).reg(); |
2171 __ LoadFieldFromOffset(temp, instance_reg, offset_in_bytes(), PP); | 2159 __ LoadFieldFromOffset(temp, instance_reg, offset_in_bytes()); |
2172 const intptr_t cid = field()->UnboxedFieldCid(); | 2160 const intptr_t cid = field()->UnboxedFieldCid(); |
2173 switch (cid) { | 2161 switch (cid) { |
2174 case kDoubleCid: | 2162 case kDoubleCid: |
2175 __ Comment("UnboxedDoubleLoadFieldInstr"); | 2163 __ Comment("UnboxedDoubleLoadFieldInstr"); |
2176 __ LoadDFieldFromOffset(result, temp, Double::value_offset(), PP); | 2164 __ LoadDFieldFromOffset(result, temp, Double::value_offset()); |
2177 break; | 2165 break; |
2178 case kFloat32x4Cid: | 2166 case kFloat32x4Cid: |
2179 __ LoadQFieldFromOffset(result, temp, Float32x4::value_offset(), PP); | 2167 __ LoadQFieldFromOffset(result, temp, Float32x4::value_offset()); |
2180 break; | 2168 break; |
2181 case kFloat64x2Cid: | 2169 case kFloat64x2Cid: |
2182 __ LoadQFieldFromOffset(result, temp, Float64x2::value_offset(), PP); | 2170 __ LoadQFieldFromOffset(result, temp, Float64x2::value_offset()); |
2183 break; | 2171 break; |
2184 default: | 2172 default: |
2185 UNREACHABLE(); | 2173 UNREACHABLE(); |
2186 } | 2174 } |
2187 return; | 2175 return; |
2188 } | 2176 } |
2189 | 2177 |
2190 Label done; | 2178 Label done; |
2191 const Register result_reg = locs()->out(0).reg(); | 2179 const Register result_reg = locs()->out(0).reg(); |
2192 if (IsPotentialUnboxedLoad()) { | 2180 if (IsPotentialUnboxedLoad()) { |
2193 const Register temp = locs()->temp(0).reg(); | 2181 const Register temp = locs()->temp(0).reg(); |
2194 | 2182 |
2195 Label load_pointer; | 2183 Label load_pointer; |
2196 Label load_double; | 2184 Label load_double; |
2197 Label load_float32x4; | 2185 Label load_float32x4; |
2198 Label load_float64x2; | 2186 Label load_float64x2; |
2199 | 2187 |
2200 __ LoadObject(result_reg, Field::ZoneHandle(field()->raw()), PP); | 2188 __ LoadObject(result_reg, Field::ZoneHandle(field()->raw())); |
2201 | 2189 |
2202 FieldAddress field_cid_operand( | 2190 FieldAddress field_cid_operand( |
2203 result_reg, Field::guarded_cid_offset(), kUnsignedWord); | 2191 result_reg, Field::guarded_cid_offset(), kUnsignedWord); |
2204 FieldAddress field_nullability_operand( | 2192 FieldAddress field_nullability_operand( |
2205 result_reg, Field::is_nullable_offset(), kUnsignedWord); | 2193 result_reg, Field::is_nullable_offset(), kUnsignedWord); |
2206 | 2194 |
2207 __ ldr(temp, field_nullability_operand, kUnsignedWord); | 2195 __ ldr(temp, field_nullability_operand, kUnsignedWord); |
2208 __ CompareImmediate(temp, kNullCid, PP); | 2196 __ CompareImmediate(temp, kNullCid); |
2209 __ b(&load_pointer, EQ); | 2197 __ b(&load_pointer, EQ); |
2210 | 2198 |
2211 __ ldr(temp, field_cid_operand, kUnsignedWord); | 2199 __ ldr(temp, field_cid_operand, kUnsignedWord); |
2212 __ CompareImmediate(temp, kDoubleCid, PP); | 2200 __ CompareImmediate(temp, kDoubleCid); |
2213 __ b(&load_double, EQ); | 2201 __ b(&load_double, EQ); |
2214 | 2202 |
2215 __ ldr(temp, field_cid_operand, kUnsignedWord); | 2203 __ ldr(temp, field_cid_operand, kUnsignedWord); |
2216 __ CompareImmediate(temp, kFloat32x4Cid, PP); | 2204 __ CompareImmediate(temp, kFloat32x4Cid); |
2217 __ b(&load_float32x4, EQ); | 2205 __ b(&load_float32x4, EQ); |
2218 | 2206 |
2219 __ ldr(temp, field_cid_operand, kUnsignedWord); | 2207 __ ldr(temp, field_cid_operand, kUnsignedWord); |
2220 __ CompareImmediate(temp, kFloat64x2Cid, PP); | 2208 __ CompareImmediate(temp, kFloat64x2Cid); |
2221 __ b(&load_float64x2, EQ); | 2209 __ b(&load_float64x2, EQ); |
2222 | 2210 |
2223 // Fall through. | 2211 // Fall through. |
2224 __ b(&load_pointer); | 2212 __ b(&load_pointer); |
2225 | 2213 |
2226 if (!compiler->is_optimizing()) { | 2214 if (!compiler->is_optimizing()) { |
2227 locs()->live_registers()->Add(locs()->in(0)); | 2215 locs()->live_registers()->Add(locs()->in(0)); |
2228 } | 2216 } |
2229 | 2217 |
2230 { | 2218 { |
2231 __ Bind(&load_double); | 2219 __ Bind(&load_double); |
2232 BoxAllocationSlowPath::Allocate(compiler, | 2220 BoxAllocationSlowPath::Allocate(compiler, |
2233 this, | 2221 this, |
2234 compiler->double_class(), | 2222 compiler->double_class(), |
2235 result_reg, | 2223 result_reg, |
2236 temp); | 2224 temp); |
2237 __ LoadFieldFromOffset(temp, instance_reg, offset_in_bytes(), PP); | 2225 __ LoadFieldFromOffset(temp, instance_reg, offset_in_bytes()); |
2238 __ LoadDFieldFromOffset(VTMP, temp, Double::value_offset(), PP); | 2226 __ LoadDFieldFromOffset(VTMP, temp, Double::value_offset()); |
2239 __ StoreDFieldToOffset(VTMP, result_reg, Double::value_offset(), PP); | 2227 __ StoreDFieldToOffset(VTMP, result_reg, Double::value_offset()); |
2240 __ b(&done); | 2228 __ b(&done); |
2241 } | 2229 } |
2242 | 2230 |
2243 { | 2231 { |
2244 __ Bind(&load_float32x4); | 2232 __ Bind(&load_float32x4); |
2245 BoxAllocationSlowPath::Allocate(compiler, | 2233 BoxAllocationSlowPath::Allocate(compiler, |
2246 this, | 2234 this, |
2247 compiler->float32x4_class(), | 2235 compiler->float32x4_class(), |
2248 result_reg, | 2236 result_reg, |
2249 temp); | 2237 temp); |
2250 __ LoadFieldFromOffset(temp, instance_reg, offset_in_bytes(), PP); | 2238 __ LoadFieldFromOffset(temp, instance_reg, offset_in_bytes()); |
2251 __ LoadQFieldFromOffset(VTMP, temp, Float32x4::value_offset(), PP); | 2239 __ LoadQFieldFromOffset(VTMP, temp, Float32x4::value_offset()); |
2252 __ StoreQFieldToOffset(VTMP, result_reg, Float32x4::value_offset(), PP); | 2240 __ StoreQFieldToOffset(VTMP, result_reg, Float32x4::value_offset()); |
2253 __ b(&done); | 2241 __ b(&done); |
2254 } | 2242 } |
2255 | 2243 |
2256 { | 2244 { |
2257 __ Bind(&load_float64x2); | 2245 __ Bind(&load_float64x2); |
2258 BoxAllocationSlowPath::Allocate(compiler, | 2246 BoxAllocationSlowPath::Allocate(compiler, |
2259 this, | 2247 this, |
2260 compiler->float64x2_class(), | 2248 compiler->float64x2_class(), |
2261 result_reg, | 2249 result_reg, |
2262 temp); | 2250 temp); |
2263 __ LoadFieldFromOffset(temp, instance_reg, offset_in_bytes(), PP); | 2251 __ LoadFieldFromOffset(temp, instance_reg, offset_in_bytes()); |
2264 __ LoadQFieldFromOffset(VTMP, temp, Float64x2::value_offset(), PP); | 2252 __ LoadQFieldFromOffset(VTMP, temp, Float64x2::value_offset()); |
2265 __ StoreQFieldToOffset(VTMP, result_reg, Float64x2::value_offset(), PP); | 2253 __ StoreQFieldToOffset(VTMP, result_reg, Float64x2::value_offset()); |
2266 __ b(&done); | 2254 __ b(&done); |
2267 } | 2255 } |
2268 | 2256 |
2269 __ Bind(&load_pointer); | 2257 __ Bind(&load_pointer); |
2270 } | 2258 } |
2271 __ LoadFieldFromOffset(result_reg, instance_reg, offset_in_bytes(), PP); | 2259 __ LoadFieldFromOffset(result_reg, instance_reg, offset_in_bytes()); |
2272 __ Bind(&done); | 2260 __ Bind(&done); |
2273 } | 2261 } |
2274 | 2262 |
2275 | 2263 |
2276 LocationSummary* InstantiateTypeInstr::MakeLocationSummary(Zone* zone, | 2264 LocationSummary* InstantiateTypeInstr::MakeLocationSummary(Zone* zone, |
2277 bool opt) const { | 2265 bool opt) const { |
2278 const intptr_t kNumInputs = 1; | 2266 const intptr_t kNumInputs = 1; |
2279 const intptr_t kNumTemps = 0; | 2267 const intptr_t kNumTemps = 0; |
2280 LocationSummary* locs = new(zone) LocationSummary( | 2268 LocationSummary* locs = new(zone) LocationSummary( |
2281 zone, kNumInputs, kNumTemps, LocationSummary::kCall); | 2269 zone, kNumInputs, kNumTemps, LocationSummary::kCall); |
2282 locs->set_in(0, Location::RegisterLocation(R0)); | 2270 locs->set_in(0, Location::RegisterLocation(R0)); |
2283 locs->set_out(0, Location::RegisterLocation(R0)); | 2271 locs->set_out(0, Location::RegisterLocation(R0)); |
2284 return locs; | 2272 return locs; |
2285 } | 2273 } |
2286 | 2274 |
2287 | 2275 |
2288 void InstantiateTypeInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | 2276 void InstantiateTypeInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
2289 const Register instantiator_reg = locs()->in(0).reg(); | 2277 const Register instantiator_reg = locs()->in(0).reg(); |
2290 const Register result_reg = locs()->out(0).reg(); | 2278 const Register result_reg = locs()->out(0).reg(); |
2291 | 2279 |
2292 // 'instantiator_reg' is the instantiator TypeArguments object (or null). | 2280 // 'instantiator_reg' is the instantiator TypeArguments object (or null). |
2293 // A runtime call to instantiate the type is required. | 2281 // A runtime call to instantiate the type is required. |
2294 __ PushObject(Object::null_object(), PP); // Make room for the result. | 2282 __ PushObject(Object::null_object()); // Make room for the result. |
2295 __ PushObject(type(), PP); | 2283 __ PushObject(type()); |
2296 __ Push(instantiator_reg); // Push instantiator type arguments. | 2284 __ Push(instantiator_reg); // Push instantiator type arguments. |
2297 compiler->GenerateRuntimeCall(token_pos(), | 2285 compiler->GenerateRuntimeCall(token_pos(), |
2298 deopt_id(), | 2286 deopt_id(), |
2299 kInstantiateTypeRuntimeEntry, | 2287 kInstantiateTypeRuntimeEntry, |
2300 2, | 2288 2, |
2301 locs()); | 2289 locs()); |
2302 __ Drop(2); // Drop instantiator and uninstantiated type. | 2290 __ Drop(2); // Drop instantiator and uninstantiated type. |
2303 __ Pop(result_reg); // Pop instantiated type. | 2291 __ Pop(result_reg); // Pop instantiated type. |
2304 ASSERT(instantiator_reg == result_reg); | 2292 ASSERT(instantiator_reg == result_reg); |
2305 } | 2293 } |
(...skipping 21 matching lines...) Expand all Loading... |
2327 // 'instantiator_reg' is the instantiator TypeArguments object (or null). | 2315 // 'instantiator_reg' is the instantiator TypeArguments object (or null). |
2328 ASSERT(!type_arguments().IsUninstantiatedIdentity() && | 2316 ASSERT(!type_arguments().IsUninstantiatedIdentity() && |
2329 !type_arguments().CanShareInstantiatorTypeArguments( | 2317 !type_arguments().CanShareInstantiatorTypeArguments( |
2330 instantiator_class())); | 2318 instantiator_class())); |
2331 // If the instantiator is null and if the type argument vector | 2319 // If the instantiator is null and if the type argument vector |
2332 // instantiated from null becomes a vector of dynamic, then use null as | 2320 // instantiated from null becomes a vector of dynamic, then use null as |
2333 // the type arguments. | 2321 // the type arguments. |
2334 Label type_arguments_instantiated; | 2322 Label type_arguments_instantiated; |
2335 const intptr_t len = type_arguments().Length(); | 2323 const intptr_t len = type_arguments().Length(); |
2336 if (type_arguments().IsRawInstantiatedRaw(len)) { | 2324 if (type_arguments().IsRawInstantiatedRaw(len)) { |
2337 __ CompareObject(instantiator_reg, Object::null_object(), PP); | 2325 __ CompareObject(instantiator_reg, Object::null_object()); |
2338 __ b(&type_arguments_instantiated, EQ); | 2326 __ b(&type_arguments_instantiated, EQ); |
2339 } | 2327 } |
2340 | 2328 |
2341 __ LoadObject(R2, type_arguments(), PP); | 2329 __ LoadObject(R2, type_arguments()); |
2342 __ LoadFieldFromOffset(R2, R2, TypeArguments::instantiations_offset(), PP); | 2330 __ LoadFieldFromOffset(R2, R2, TypeArguments::instantiations_offset()); |
2343 __ AddImmediate(R2, R2, Array::data_offset() - kHeapObjectTag, PP); | 2331 __ AddImmediate(R2, R2, Array::data_offset() - kHeapObjectTag); |
2344 // The instantiations cache is initialized with Object::zero_array() and is | 2332 // The instantiations cache is initialized with Object::zero_array() and is |
2345 // therefore guaranteed to contain kNoInstantiator. No length check needed. | 2333 // therefore guaranteed to contain kNoInstantiator. No length check needed. |
2346 Label loop, found, slow_case; | 2334 Label loop, found, slow_case; |
2347 __ Bind(&loop); | 2335 __ Bind(&loop); |
2348 __ LoadFromOffset(R1, R2, 0 * kWordSize, PP); // Cached instantiator. | 2336 __ LoadFromOffset(R1, R2, 0 * kWordSize); // Cached instantiator. |
2349 __ CompareRegisters(R1, R0); | 2337 __ CompareRegisters(R1, R0); |
2350 __ b(&found, EQ); | 2338 __ b(&found, EQ); |
2351 __ AddImmediate(R2, R2, 2 * kWordSize, PP); | 2339 __ AddImmediate(R2, R2, 2 * kWordSize); |
2352 __ CompareImmediate(R1, Smi::RawValue(StubCode::kNoInstantiator), PP); | 2340 __ CompareImmediate(R1, Smi::RawValue(StubCode::kNoInstantiator)); |
2353 __ b(&loop, NE); | 2341 __ b(&loop, NE); |
2354 __ b(&slow_case); | 2342 __ b(&slow_case); |
2355 __ Bind(&found); | 2343 __ Bind(&found); |
2356 __ LoadFromOffset(R0, R2, 1 * kWordSize, PP); // Cached instantiated args. | 2344 __ LoadFromOffset(R0, R2, 1 * kWordSize); // Cached instantiated args. |
2357 __ b(&type_arguments_instantiated); | 2345 __ b(&type_arguments_instantiated); |
2358 | 2346 |
2359 __ Bind(&slow_case); | 2347 __ Bind(&slow_case); |
2360 // Instantiate non-null type arguments. | 2348 // Instantiate non-null type arguments. |
2361 // A runtime call to instantiate the type arguments is required. | 2349 // A runtime call to instantiate the type arguments is required. |
2362 __ PushObject(Object::null_object(), PP); // Make room for the result. | 2350 __ PushObject(Object::null_object()); // Make room for the result. |
2363 __ PushObject(type_arguments(), PP); | 2351 __ PushObject(type_arguments()); |
2364 __ Push(instantiator_reg); // Push instantiator type arguments. | 2352 __ Push(instantiator_reg); // Push instantiator type arguments. |
2365 compiler->GenerateRuntimeCall(token_pos(), | 2353 compiler->GenerateRuntimeCall(token_pos(), |
2366 deopt_id(), | 2354 deopt_id(), |
2367 kInstantiateTypeArgumentsRuntimeEntry, | 2355 kInstantiateTypeArgumentsRuntimeEntry, |
2368 2, | 2356 2, |
2369 locs()); | 2357 locs()); |
2370 __ Drop(2); // Drop instantiator and uninstantiated type arguments. | 2358 __ Drop(2); // Drop instantiator and uninstantiated type arguments. |
2371 __ Pop(result_reg); // Pop instantiated type arguments. | 2359 __ Pop(result_reg); // Pop instantiated type arguments. |
2372 __ Bind(&type_arguments_instantiated); | 2360 __ Bind(&type_arguments_instantiated); |
2373 } | 2361 } |
(...skipping 23 matching lines...) Expand all Loading... |
2397 | 2385 |
2398 virtual void EmitNativeCode(FlowGraphCompiler* compiler) { | 2386 virtual void EmitNativeCode(FlowGraphCompiler* compiler) { |
2399 __ Comment("AllocateContextSlowPath"); | 2387 __ Comment("AllocateContextSlowPath"); |
2400 __ Bind(entry_label()); | 2388 __ Bind(entry_label()); |
2401 | 2389 |
2402 LocationSummary* locs = instruction_->locs(); | 2390 LocationSummary* locs = instruction_->locs(); |
2403 locs->live_registers()->Remove(locs->out(0)); | 2391 locs->live_registers()->Remove(locs->out(0)); |
2404 | 2392 |
2405 compiler->SaveLiveRegisters(locs); | 2393 compiler->SaveLiveRegisters(locs); |
2406 | 2394 |
2407 __ LoadImmediate(R1, instruction_->num_context_variables(), PP); | 2395 __ LoadImmediate(R1, instruction_->num_context_variables()); |
2408 const ExternalLabel label(StubCode::AllocateContextEntryPoint()); | 2396 const ExternalLabel label(StubCode::AllocateContextEntryPoint()); |
2409 compiler->GenerateCall(instruction_->token_pos(), | 2397 compiler->GenerateCall(instruction_->token_pos(), |
2410 &label, | 2398 &label, |
2411 RawPcDescriptors::kOther, | 2399 RawPcDescriptors::kOther, |
2412 locs); | 2400 locs); |
2413 ASSERT(instruction_->locs()->out(0).reg() == R0); | 2401 ASSERT(instruction_->locs()->out(0).reg() == R0); |
2414 compiler->RestoreLiveRegisters(instruction_->locs()); | 2402 compiler->RestoreLiveRegisters(instruction_->locs()); |
2415 __ b(exit_label()); | 2403 __ b(exit_label()); |
2416 } | 2404 } |
2417 | 2405 |
(...skipping 14 matching lines...) Expand all Loading... |
2432 compiler->AddSlowPathCode(slow_path); | 2420 compiler->AddSlowPathCode(slow_path); |
2433 intptr_t instance_size = Context::InstanceSize(num_context_variables()); | 2421 intptr_t instance_size = Context::InstanceSize(num_context_variables()); |
2434 | 2422 |
2435 __ TryAllocateArray(kContextCid, instance_size, slow_path->entry_label(), | 2423 __ TryAllocateArray(kContextCid, instance_size, slow_path->entry_label(), |
2436 result, // instance | 2424 result, // instance |
2437 temp0, | 2425 temp0, |
2438 temp1, | 2426 temp1, |
2439 temp2); | 2427 temp2); |
2440 | 2428 |
2441 // Setup up number of context variables field. | 2429 // Setup up number of context variables field. |
2442 __ LoadImmediate(temp0, num_context_variables(), PP); | 2430 __ LoadImmediate(temp0, num_context_variables()); |
2443 __ str(temp0, FieldAddress(result, Context::num_variables_offset())); | 2431 __ str(temp0, FieldAddress(result, Context::num_variables_offset())); |
2444 | 2432 |
2445 __ Bind(slow_path->exit_label()); | 2433 __ Bind(slow_path->exit_label()); |
2446 } | 2434 } |
2447 | 2435 |
2448 | 2436 |
2449 LocationSummary* AllocateContextInstr::MakeLocationSummary(Zone* zone, | 2437 LocationSummary* AllocateContextInstr::MakeLocationSummary(Zone* zone, |
2450 bool opt) const { | 2438 bool opt) const { |
2451 const intptr_t kNumInputs = 0; | 2439 const intptr_t kNumInputs = 0; |
2452 const intptr_t kNumTemps = 1; | 2440 const intptr_t kNumTemps = 1; |
2453 LocationSummary* locs = new(zone) LocationSummary( | 2441 LocationSummary* locs = new(zone) LocationSummary( |
2454 zone, kNumInputs, kNumTemps, LocationSummary::kCall); | 2442 zone, kNumInputs, kNumTemps, LocationSummary::kCall); |
2455 locs->set_temp(0, Location::RegisterLocation(R1)); | 2443 locs->set_temp(0, Location::RegisterLocation(R1)); |
2456 locs->set_out(0, Location::RegisterLocation(R0)); | 2444 locs->set_out(0, Location::RegisterLocation(R0)); |
2457 return locs; | 2445 return locs; |
2458 } | 2446 } |
2459 | 2447 |
2460 | 2448 |
2461 void AllocateContextInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | 2449 void AllocateContextInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
2462 ASSERT(locs()->temp(0).reg() == R1); | 2450 ASSERT(locs()->temp(0).reg() == R1); |
2463 ASSERT(locs()->out(0).reg() == R0); | 2451 ASSERT(locs()->out(0).reg() == R0); |
2464 | 2452 |
2465 __ LoadImmediate(R1, num_context_variables(), PP); | 2453 __ LoadImmediate(R1, num_context_variables()); |
2466 const ExternalLabel label(StubCode::AllocateContextEntryPoint()); | 2454 const ExternalLabel label(StubCode::AllocateContextEntryPoint()); |
2467 compiler->GenerateCall(token_pos(), | 2455 compiler->GenerateCall(token_pos(), |
2468 &label, | 2456 &label, |
2469 RawPcDescriptors::kOther, | 2457 RawPcDescriptors::kOther, |
2470 locs()); | 2458 locs()); |
2471 } | 2459 } |
2472 | 2460 |
2473 LocationSummary* InitStaticFieldInstr::MakeLocationSummary(Zone* zone, | 2461 LocationSummary* InitStaticFieldInstr::MakeLocationSummary(Zone* zone, |
2474 bool opt) const { | 2462 bool opt) const { |
2475 const intptr_t kNumInputs = 1; | 2463 const intptr_t kNumInputs = 1; |
2476 const intptr_t kNumTemps = 1; | 2464 const intptr_t kNumTemps = 1; |
2477 LocationSummary* locs = new(zone) LocationSummary( | 2465 LocationSummary* locs = new(zone) LocationSummary( |
2478 zone, kNumInputs, kNumTemps, LocationSummary::kCall); | 2466 zone, kNumInputs, kNumTemps, LocationSummary::kCall); |
2479 locs->set_in(0, Location::RegisterLocation(R0)); | 2467 locs->set_in(0, Location::RegisterLocation(R0)); |
2480 locs->set_temp(0, Location::RegisterLocation(R1)); | 2468 locs->set_temp(0, Location::RegisterLocation(R1)); |
2481 return locs; | 2469 return locs; |
2482 } | 2470 } |
2483 | 2471 |
2484 | 2472 |
2485 void InitStaticFieldInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | 2473 void InitStaticFieldInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
2486 Register field = locs()->in(0).reg(); | 2474 Register field = locs()->in(0).reg(); |
2487 Register temp = locs()->temp(0).reg(); | 2475 Register temp = locs()->temp(0).reg(); |
2488 Label call_runtime, no_call; | 2476 Label call_runtime, no_call; |
2489 | 2477 |
2490 __ ldr(temp, FieldAddress(field, Field::value_offset())); | 2478 __ ldr(temp, FieldAddress(field, Field::value_offset())); |
2491 __ CompareObject(temp, Object::sentinel(), PP); | 2479 __ CompareObject(temp, Object::sentinel()); |
2492 __ b(&call_runtime, EQ); | 2480 __ b(&call_runtime, EQ); |
2493 | 2481 |
2494 __ CompareObject(temp, Object::transition_sentinel(), PP); | 2482 __ CompareObject(temp, Object::transition_sentinel()); |
2495 __ b(&no_call, NE); | 2483 __ b(&no_call, NE); |
2496 | 2484 |
2497 __ Bind(&call_runtime); | 2485 __ Bind(&call_runtime); |
2498 __ PushObject(Object::null_object(), PP); // Make room for (unused) result. | 2486 __ PushObject(Object::null_object()); // Make room for (unused) result. |
2499 __ Push(field); | 2487 __ Push(field); |
2500 compiler->GenerateRuntimeCall(token_pos(), | 2488 compiler->GenerateRuntimeCall(token_pos(), |
2501 deopt_id(), | 2489 deopt_id(), |
2502 kInitStaticFieldRuntimeEntry, | 2490 kInitStaticFieldRuntimeEntry, |
2503 1, | 2491 1, |
2504 locs()); | 2492 locs()); |
2505 __ Drop(2); // Remove argument and result placeholder. | 2493 __ Drop(2); // Remove argument and result placeholder. |
2506 __ Bind(&no_call); | 2494 __ Bind(&no_call); |
2507 } | 2495 } |
2508 | 2496 |
2509 | 2497 |
2510 LocationSummary* CloneContextInstr::MakeLocationSummary(Zone* zone, | 2498 LocationSummary* CloneContextInstr::MakeLocationSummary(Zone* zone, |
2511 bool opt) const { | 2499 bool opt) const { |
2512 const intptr_t kNumInputs = 1; | 2500 const intptr_t kNumInputs = 1; |
2513 const intptr_t kNumTemps = 0; | 2501 const intptr_t kNumTemps = 0; |
2514 LocationSummary* locs = new(zone) LocationSummary( | 2502 LocationSummary* locs = new(zone) LocationSummary( |
2515 zone, kNumInputs, kNumTemps, LocationSummary::kCall); | 2503 zone, kNumInputs, kNumTemps, LocationSummary::kCall); |
2516 locs->set_in(0, Location::RegisterLocation(R0)); | 2504 locs->set_in(0, Location::RegisterLocation(R0)); |
2517 locs->set_out(0, Location::RegisterLocation(R0)); | 2505 locs->set_out(0, Location::RegisterLocation(R0)); |
2518 return locs; | 2506 return locs; |
2519 } | 2507 } |
2520 | 2508 |
2521 | 2509 |
2522 void CloneContextInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | 2510 void CloneContextInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
2523 const Register context_value = locs()->in(0).reg(); | 2511 const Register context_value = locs()->in(0).reg(); |
2524 const Register result = locs()->out(0).reg(); | 2512 const Register result = locs()->out(0).reg(); |
2525 | 2513 |
2526 __ PushObject(Object::null_object(), PP); // Make room for the result. | 2514 __ PushObject(Object::null_object()); // Make room for the result. |
2527 __ Push(context_value); | 2515 __ Push(context_value); |
2528 compiler->GenerateRuntimeCall(token_pos(), | 2516 compiler->GenerateRuntimeCall(token_pos(), |
2529 deopt_id(), | 2517 deopt_id(), |
2530 kCloneContextRuntimeEntry, | 2518 kCloneContextRuntimeEntry, |
2531 1, | 2519 1, |
2532 locs()); | 2520 locs()); |
2533 __ Drop(1); // Remove argument. | 2521 __ Drop(1); // Remove argument. |
2534 __ Pop(result); // Get result (cloned context). | 2522 __ Pop(result); // Get result (cloned context). |
2535 } | 2523 } |
2536 | 2524 |
2537 | 2525 |
2538 LocationSummary* CatchBlockEntryInstr::MakeLocationSummary(Zone* zone, | 2526 LocationSummary* CatchBlockEntryInstr::MakeLocationSummary(Zone* zone, |
2539 bool opt) const { | 2527 bool opt) const { |
2540 UNREACHABLE(); | 2528 UNREACHABLE(); |
2541 return NULL; | 2529 return NULL; |
2542 } | 2530 } |
2543 | 2531 |
2544 | 2532 |
2545 void CatchBlockEntryInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | 2533 void CatchBlockEntryInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
2546 __ Bind(compiler->GetJumpLabel(this)); | 2534 __ Bind(compiler->GetJumpLabel(this)); |
2547 compiler->AddExceptionHandler(catch_try_index(), | 2535 compiler->AddExceptionHandler(catch_try_index(), |
2548 try_index(), | 2536 try_index(), |
2549 compiler->assembler()->CodeSize(), | 2537 compiler->assembler()->CodeSize(), |
2550 catch_handler_types_, | 2538 catch_handler_types_, |
2551 needs_stacktrace()); | 2539 needs_stacktrace()); |
2552 | 2540 |
2553 // Restore the pool pointer. | 2541 // Restore the pool pointer. |
2554 __ LoadPoolPointer(PP); | 2542 __ LoadPoolPointer(); |
2555 | 2543 |
2556 if (HasParallelMove()) { | 2544 if (HasParallelMove()) { |
2557 compiler->parallel_move_resolver()->EmitNativeCode(parallel_move()); | 2545 compiler->parallel_move_resolver()->EmitNativeCode(parallel_move()); |
2558 } | 2546 } |
2559 | 2547 |
2560 // Restore SP from FP as we are coming from a throw and the code for | 2548 // Restore SP from FP as we are coming from a throw and the code for |
2561 // popping arguments has not been run. | 2549 // popping arguments has not been run. |
2562 const intptr_t fp_sp_dist = | 2550 const intptr_t fp_sp_dist = |
2563 (kFirstLocalSlotFromFp + 1 - compiler->StackSize()) * kWordSize; | 2551 (kFirstLocalSlotFromFp + 1 - compiler->StackSize()) * kWordSize; |
2564 ASSERT(fp_sp_dist <= 0); | 2552 ASSERT(fp_sp_dist <= 0); |
2565 __ AddImmediate(SP, FP, fp_sp_dist, PP); | 2553 __ AddImmediate(SP, FP, fp_sp_dist); |
2566 | 2554 |
2567 // Restore stack and initialize the two exception variables: | 2555 // Restore stack and initialize the two exception variables: |
2568 // exception and stack trace variables. | 2556 // exception and stack trace variables. |
2569 __ StoreToOffset(kExceptionObjectReg, | 2557 __ StoreToOffset(kExceptionObjectReg, |
2570 FP, exception_var().index() * kWordSize, PP); | 2558 FP, exception_var().index() * kWordSize); |
2571 __ StoreToOffset(kStackTraceObjectReg, | 2559 __ StoreToOffset(kStackTraceObjectReg, |
2572 FP, stacktrace_var().index() * kWordSize, PP); | 2560 FP, stacktrace_var().index() * kWordSize); |
2573 } | 2561 } |
2574 | 2562 |
2575 | 2563 |
2576 LocationSummary* CheckStackOverflowInstr::MakeLocationSummary(Zone* zone, | 2564 LocationSummary* CheckStackOverflowInstr::MakeLocationSummary(Zone* zone, |
2577 bool opt) const { | 2565 bool opt) const { |
2578 const intptr_t kNumInputs = 0; | 2566 const intptr_t kNumInputs = 0; |
2579 const intptr_t kNumTemps = 1; | 2567 const intptr_t kNumTemps = 1; |
2580 LocationSummary* summary = new(zone) LocationSummary( | 2568 LocationSummary* summary = new(zone) LocationSummary( |
2581 zone, kNumInputs, kNumTemps, LocationSummary::kCallOnSlowPath); | 2569 zone, kNumInputs, kNumTemps, LocationSummary::kCallOnSlowPath); |
2582 summary->set_temp(0, Location::RequiresRegister()); | 2570 summary->set_temp(0, Location::RequiresRegister()); |
2583 return summary; | 2571 return summary; |
2584 } | 2572 } |
2585 | 2573 |
2586 | 2574 |
2587 class CheckStackOverflowSlowPath : public SlowPathCode { | 2575 class CheckStackOverflowSlowPath : public SlowPathCode { |
2588 public: | 2576 public: |
2589 explicit CheckStackOverflowSlowPath(CheckStackOverflowInstr* instruction) | 2577 explicit CheckStackOverflowSlowPath(CheckStackOverflowInstr* instruction) |
2590 : instruction_(instruction) { } | 2578 : instruction_(instruction) { } |
2591 | 2579 |
2592 virtual void EmitNativeCode(FlowGraphCompiler* compiler) { | 2580 virtual void EmitNativeCode(FlowGraphCompiler* compiler) { |
2593 if (FLAG_use_osr && osr_entry_label()->IsLinked()) { | 2581 if (FLAG_use_osr && osr_entry_label()->IsLinked()) { |
2594 uword flags_address = Isolate::Current()->stack_overflow_flags_address(); | 2582 uword flags_address = Isolate::Current()->stack_overflow_flags_address(); |
2595 const Register value = instruction_->locs()->temp(0).reg(); | 2583 const Register value = instruction_->locs()->temp(0).reg(); |
2596 __ Comment("CheckStackOverflowSlowPathOsr"); | 2584 __ Comment("CheckStackOverflowSlowPathOsr"); |
2597 __ Bind(osr_entry_label()); | 2585 __ Bind(osr_entry_label()); |
2598 __ LoadImmediate(TMP, flags_address, PP); | 2586 __ LoadImmediate(TMP, flags_address); |
2599 __ LoadImmediate(value, Isolate::kOsrRequest, PP); | 2587 __ LoadImmediate(value, Isolate::kOsrRequest); |
2600 __ str(value, Address(TMP)); | 2588 __ str(value, Address(TMP)); |
2601 } | 2589 } |
2602 __ Comment("CheckStackOverflowSlowPath"); | 2590 __ Comment("CheckStackOverflowSlowPath"); |
2603 __ Bind(entry_label()); | 2591 __ Bind(entry_label()); |
2604 compiler->SaveLiveRegisters(instruction_->locs()); | 2592 compiler->SaveLiveRegisters(instruction_->locs()); |
2605 // pending_deoptimization_env_ is needed to generate a runtime call that | 2593 // pending_deoptimization_env_ is needed to generate a runtime call that |
2606 // may throw an exception. | 2594 // may throw an exception. |
2607 ASSERT(compiler->pending_deoptimization_env_ == NULL); | 2595 ASSERT(compiler->pending_deoptimization_env_ == NULL); |
2608 Environment* env = compiler->SlowPathEnvironmentFor(instruction_); | 2596 Environment* env = compiler->SlowPathEnvironmentFor(instruction_); |
2609 compiler->pending_deoptimization_env_ = env; | 2597 compiler->pending_deoptimization_env_ = env; |
(...skipping 23 matching lines...) Expand all Loading... |
2633 CheckStackOverflowInstr* instruction_; | 2621 CheckStackOverflowInstr* instruction_; |
2634 Label osr_entry_label_; | 2622 Label osr_entry_label_; |
2635 }; | 2623 }; |
2636 | 2624 |
2637 | 2625 |
2638 void CheckStackOverflowInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | 2626 void CheckStackOverflowInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
2639 CheckStackOverflowSlowPath* slow_path = new CheckStackOverflowSlowPath(this); | 2627 CheckStackOverflowSlowPath* slow_path = new CheckStackOverflowSlowPath(this); |
2640 compiler->AddSlowPathCode(slow_path); | 2628 compiler->AddSlowPathCode(slow_path); |
2641 | 2629 |
2642 if (compiler->is_optimizing()) { | 2630 if (compiler->is_optimizing()) { |
2643 __ LoadImmediate(TMP, Isolate::Current()->stack_limit_address(), PP); | 2631 __ LoadImmediate(TMP, Isolate::Current()->stack_limit_address()); |
2644 __ ldr(TMP, Address(TMP)); | 2632 __ ldr(TMP, Address(TMP)); |
2645 } else { | 2633 } else { |
2646 __ LoadIsolate(TMP); | 2634 __ LoadIsolate(TMP); |
2647 __ ldr(TMP, Address(TMP, Isolate::stack_limit_offset())); | 2635 __ ldr(TMP, Address(TMP, Isolate::stack_limit_offset())); |
2648 } | 2636 } |
2649 __ CompareRegisters(SP, TMP); | 2637 __ CompareRegisters(SP, TMP); |
2650 __ b(slow_path->entry_label(), LS); | 2638 __ b(slow_path->entry_label(), LS); |
2651 if (compiler->CanOSRFunction() && in_loop()) { | 2639 if (compiler->CanOSRFunction() && in_loop()) { |
2652 const Register temp = locs()->temp(0).reg(); | 2640 const Register temp = locs()->temp(0).reg(); |
2653 // In unoptimized code check the usage counter to trigger OSR at loop | 2641 // In unoptimized code check the usage counter to trigger OSR at loop |
2654 // stack checks. Use progressively higher thresholds for more deeply | 2642 // stack checks. Use progressively higher thresholds for more deeply |
2655 // nested loops to attempt to hit outer loops with OSR when possible. | 2643 // nested loops to attempt to hit outer loops with OSR when possible. |
2656 __ LoadObject(temp, compiler->parsed_function().function(), PP); | 2644 __ LoadObject(temp, compiler->parsed_function().function()); |
2657 intptr_t threshold = | 2645 intptr_t threshold = |
2658 FLAG_optimization_counter_threshold * (loop_depth() + 1); | 2646 FLAG_optimization_counter_threshold * (loop_depth() + 1); |
2659 __ LoadFieldFromOffset( | 2647 __ LoadFieldFromOffset( |
2660 temp, temp, Function::usage_counter_offset(), PP, kWord); | 2648 temp, temp, Function::usage_counter_offset(), kWord); |
2661 __ CompareImmediate(temp, threshold, PP); | 2649 __ CompareImmediate(temp, threshold); |
2662 __ b(slow_path->osr_entry_label(), GE); | 2650 __ b(slow_path->osr_entry_label(), GE); |
2663 } | 2651 } |
2664 if (compiler->ForceSlowPathForStackOverflow()) { | 2652 if (compiler->ForceSlowPathForStackOverflow()) { |
2665 __ b(slow_path->entry_label()); | 2653 __ b(slow_path->entry_label()); |
2666 } | 2654 } |
2667 __ Bind(slow_path->exit_label()); | 2655 __ Bind(slow_path->exit_label()); |
2668 } | 2656 } |
2669 | 2657 |
2670 | 2658 |
2671 static void EmitJavascriptOverflowCheck(FlowGraphCompiler* compiler, | 2659 static void EmitJavascriptOverflowCheck(FlowGraphCompiler* compiler, |
2672 Range* range, | 2660 Range* range, |
2673 Label* overflow, | 2661 Label* overflow, |
2674 Register result) { | 2662 Register result) { |
2675 if (!RangeUtils::IsWithin(range, -0x20000000000000LL, 0x20000000000000LL)) { | 2663 if (!RangeUtils::IsWithin(range, -0x20000000000000LL, 0x20000000000000LL)) { |
2676 ASSERT(overflow != NULL); | 2664 ASSERT(overflow != NULL); |
2677 __ LoadImmediate(TMP, 0x20000000000000LL, PP); | 2665 __ LoadImmediate(TMP, 0x20000000000000LL); |
2678 __ add(TMP2, result, Operand(TMP)); | 2666 __ add(TMP2, result, Operand(TMP)); |
2679 __ cmp(TMP2, Operand(TMP, LSL, 1)); | 2667 __ cmp(TMP2, Operand(TMP, LSL, 1)); |
2680 __ b(overflow, HI); | 2668 __ b(overflow, HI); |
2681 } | 2669 } |
2682 } | 2670 } |
2683 | 2671 |
2684 | 2672 |
2685 static void EmitSmiShiftLeft(FlowGraphCompiler* compiler, | 2673 static void EmitSmiShiftLeft(FlowGraphCompiler* compiler, |
2686 BinarySmiOpInstr* shift_left) { | 2674 BinarySmiOpInstr* shift_left) { |
2687 const LocationSummary& locs = *shift_left->locs(); | 2675 const LocationSummary& locs = *shift_left->locs(); |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2724 __ CompareRegisters(right, ZR); | 2712 __ CompareRegisters(right, ZR); |
2725 __ b(deopt, MI); | 2713 __ b(deopt, MI); |
2726 __ mov(result, ZR); | 2714 __ mov(result, ZR); |
2727 return; | 2715 return; |
2728 } | 2716 } |
2729 const intptr_t max_right = kSmiBits - Utils::HighestBit(left_int); | 2717 const intptr_t max_right = kSmiBits - Utils::HighestBit(left_int); |
2730 const bool right_needs_check = | 2718 const bool right_needs_check = |
2731 !RangeUtils::IsWithin(right_range, 0, max_right - 1); | 2719 !RangeUtils::IsWithin(right_range, 0, max_right - 1); |
2732 if (right_needs_check) { | 2720 if (right_needs_check) { |
2733 __ CompareImmediate(right, | 2721 __ CompareImmediate(right, |
2734 reinterpret_cast<int64_t>(Smi::New(max_right)), PP); | 2722 reinterpret_cast<int64_t>(Smi::New(max_right))); |
2735 __ b(deopt, CS); | 2723 __ b(deopt, CS); |
2736 } | 2724 } |
2737 __ SmiUntag(TMP, right); | 2725 __ SmiUntag(TMP, right); |
2738 __ lslv(result, left, TMP); | 2726 __ lslv(result, left, TMP); |
2739 } | 2727 } |
2740 if (FLAG_throw_on_javascript_int_overflow) { | 2728 if (FLAG_throw_on_javascript_int_overflow) { |
2741 EmitJavascriptOverflowCheck(compiler, shift_left->range(), deopt, result); | 2729 EmitJavascriptOverflowCheck(compiler, shift_left->range(), deopt, result); |
2742 } | 2730 } |
2743 return; | 2731 return; |
2744 } | 2732 } |
2745 | 2733 |
2746 const bool right_needs_check = | 2734 const bool right_needs_check = |
2747 !RangeUtils::IsWithin(right_range, 0, (Smi::kBits - 1)); | 2735 !RangeUtils::IsWithin(right_range, 0, (Smi::kBits - 1)); |
2748 if (!shift_left->can_overflow()) { | 2736 if (!shift_left->can_overflow()) { |
2749 if (right_needs_check) { | 2737 if (right_needs_check) { |
2750 const bool right_may_be_negative = | 2738 const bool right_may_be_negative = |
2751 (right_range == NULL) || !right_range->IsPositive(); | 2739 (right_range == NULL) || !right_range->IsPositive(); |
2752 if (right_may_be_negative) { | 2740 if (right_may_be_negative) { |
2753 ASSERT(shift_left->CanDeoptimize()); | 2741 ASSERT(shift_left->CanDeoptimize()); |
2754 __ CompareRegisters(right, ZR); | 2742 __ CompareRegisters(right, ZR); |
2755 __ b(deopt, MI); | 2743 __ b(deopt, MI); |
2756 } | 2744 } |
2757 | 2745 |
2758 __ CompareImmediate( | 2746 __ CompareImmediate( |
2759 right, reinterpret_cast<int64_t>(Smi::New(Smi::kBits)), PP); | 2747 right, reinterpret_cast<int64_t>(Smi::New(Smi::kBits))); |
2760 __ csel(result, ZR, result, CS); | 2748 __ csel(result, ZR, result, CS); |
2761 __ SmiUntag(TMP, right); | 2749 __ SmiUntag(TMP, right); |
2762 __ lslv(TMP, left, TMP); | 2750 __ lslv(TMP, left, TMP); |
2763 __ csel(result, TMP, result, CC); | 2751 __ csel(result, TMP, result, CC); |
2764 } else { | 2752 } else { |
2765 __ SmiUntag(TMP, right); | 2753 __ SmiUntag(TMP, right); |
2766 __ lslv(result, left, TMP); | 2754 __ lslv(result, left, TMP); |
2767 } | 2755 } |
2768 } else { | 2756 } else { |
2769 if (right_needs_check) { | 2757 if (right_needs_check) { |
2770 ASSERT(shift_left->CanDeoptimize()); | 2758 ASSERT(shift_left->CanDeoptimize()); |
2771 __ CompareImmediate( | 2759 __ CompareImmediate( |
2772 right, reinterpret_cast<int64_t>(Smi::New(Smi::kBits)), PP); | 2760 right, reinterpret_cast<int64_t>(Smi::New(Smi::kBits))); |
2773 __ b(deopt, CS); | 2761 __ b(deopt, CS); |
2774 } | 2762 } |
2775 // Left is not a constant. | 2763 // Left is not a constant. |
2776 // Check if count too large for handling it inlined. | 2764 // Check if count too large for handling it inlined. |
2777 __ SmiUntag(TMP, right); | 2765 __ SmiUntag(TMP, right); |
2778 // Overflow test (preserve left, right, and TMP); | 2766 // Overflow test (preserve left, right, and TMP); |
2779 const Register temp = locs.temp(0).reg(); | 2767 const Register temp = locs.temp(0).reg(); |
2780 __ lslv(temp, left, TMP); | 2768 __ lslv(temp, left, TMP); |
2781 __ asrv(TMP2, temp, TMP); | 2769 __ asrv(TMP2, temp, TMP); |
2782 __ CompareRegisters(left, TMP2); | 2770 __ CompareRegisters(left, TMP2); |
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2841 deopt = compiler->AddDeoptStub(deopt_id(), ICData::kDeoptBinarySmiOp); | 2829 deopt = compiler->AddDeoptStub(deopt_id(), ICData::kDeoptBinarySmiOp); |
2842 } | 2830 } |
2843 | 2831 |
2844 if (locs()->in(1).IsConstant()) { | 2832 if (locs()->in(1).IsConstant()) { |
2845 const Object& constant = locs()->in(1).constant(); | 2833 const Object& constant = locs()->in(1).constant(); |
2846 ASSERT(constant.IsSmi()); | 2834 ASSERT(constant.IsSmi()); |
2847 const int64_t imm = reinterpret_cast<int64_t>(constant.raw()); | 2835 const int64_t imm = reinterpret_cast<int64_t>(constant.raw()); |
2848 switch (op_kind()) { | 2836 switch (op_kind()) { |
2849 case Token::kADD: { | 2837 case Token::kADD: { |
2850 if (deopt == NULL) { | 2838 if (deopt == NULL) { |
2851 __ AddImmediate(result, left, imm, PP); | 2839 __ AddImmediate(result, left, imm); |
2852 } else { | 2840 } else { |
2853 __ AddImmediateSetFlags(result, left, imm, PP); | 2841 __ AddImmediateSetFlags(result, left, imm); |
2854 __ b(deopt, VS); | 2842 __ b(deopt, VS); |
2855 } | 2843 } |
2856 break; | 2844 break; |
2857 } | 2845 } |
2858 case Token::kSUB: { | 2846 case Token::kSUB: { |
2859 if (deopt == NULL) { | 2847 if (deopt == NULL) { |
2860 __ AddImmediate(result, left, -imm, PP); | 2848 __ AddImmediate(result, left, -imm); |
2861 } else { | 2849 } else { |
2862 // Negating imm and using AddImmediateSetFlags would not detect the | 2850 // Negating imm and using AddImmediateSetFlags would not detect the |
2863 // overflow when imm == kMinInt64. | 2851 // overflow when imm == kMinInt64. |
2864 __ SubImmediateSetFlags(result, left, imm, PP); | 2852 __ SubImmediateSetFlags(result, left, imm); |
2865 __ b(deopt, VS); | 2853 __ b(deopt, VS); |
2866 } | 2854 } |
2867 break; | 2855 break; |
2868 } | 2856 } |
2869 case Token::kMUL: { | 2857 case Token::kMUL: { |
2870 // Keep left value tagged and untag right value. | 2858 // Keep left value tagged and untag right value. |
2871 const intptr_t value = Smi::Cast(constant).Value(); | 2859 const intptr_t value = Smi::Cast(constant).Value(); |
2872 __ LoadImmediate(TMP, value, PP); | 2860 __ LoadImmediate(TMP, value); |
2873 __ mul(result, left, TMP); | 2861 __ mul(result, left, TMP); |
2874 if (deopt != NULL) { | 2862 if (deopt != NULL) { |
2875 __ smulh(TMP, left, TMP); | 2863 __ smulh(TMP, left, TMP); |
2876 // TMP: result bits 64..127. | 2864 // TMP: result bits 64..127. |
2877 __ cmp(TMP, Operand(result, ASR, 63)); | 2865 __ cmp(TMP, Operand(result, ASR, 63)); |
2878 __ b(deopt, NE); | 2866 __ b(deopt, NE); |
2879 } | 2867 } |
2880 break; | 2868 break; |
2881 } | 2869 } |
2882 case Token::kTRUNCDIV: { | 2870 case Token::kTRUNCDIV: { |
2883 const intptr_t value = Smi::Cast(constant).Value(); | 2871 const intptr_t value = Smi::Cast(constant).Value(); |
2884 ASSERT(Utils::IsPowerOfTwo(Utils::Abs(value))); | 2872 ASSERT(Utils::IsPowerOfTwo(Utils::Abs(value))); |
2885 const intptr_t shift_count = | 2873 const intptr_t shift_count = |
2886 Utils::ShiftForPowerOfTwo(Utils::Abs(value)) + kSmiTagSize; | 2874 Utils::ShiftForPowerOfTwo(Utils::Abs(value)) + kSmiTagSize; |
2887 ASSERT(kSmiTagSize == 1); | 2875 ASSERT(kSmiTagSize == 1); |
2888 __ AsrImmediate(TMP, left, 63); | 2876 __ AsrImmediate(TMP, left, 63); |
2889 ASSERT(shift_count > 1); // 1, -1 case handled above. | 2877 ASSERT(shift_count > 1); // 1, -1 case handled above. |
2890 const Register temp = TMP2; | 2878 const Register temp = TMP2; |
2891 __ add(temp, left, Operand(TMP, LSR, 64 - shift_count)); | 2879 __ add(temp, left, Operand(TMP, LSR, 64 - shift_count)); |
2892 ASSERT(shift_count > 0); | 2880 ASSERT(shift_count > 0); |
2893 __ AsrImmediate(result, temp, shift_count); | 2881 __ AsrImmediate(result, temp, shift_count); |
2894 if (value < 0) { | 2882 if (value < 0) { |
2895 __ sub(result, ZR, Operand(result)); | 2883 __ sub(result, ZR, Operand(result)); |
2896 } | 2884 } |
2897 __ SmiTag(result); | 2885 __ SmiTag(result); |
2898 break; | 2886 break; |
2899 } | 2887 } |
2900 case Token::kBIT_AND: | 2888 case Token::kBIT_AND: |
2901 // No overflow check. | 2889 // No overflow check. |
2902 __ AndImmediate(result, left, imm, PP); | 2890 __ AndImmediate(result, left, imm); |
2903 break; | 2891 break; |
2904 case Token::kBIT_OR: | 2892 case Token::kBIT_OR: |
2905 // No overflow check. | 2893 // No overflow check. |
2906 __ OrImmediate(result, left, imm, PP); | 2894 __ OrImmediate(result, left, imm); |
2907 break; | 2895 break; |
2908 case Token::kBIT_XOR: | 2896 case Token::kBIT_XOR: |
2909 // No overflow check. | 2897 // No overflow check. |
2910 __ XorImmediate(result, left, imm, PP); | 2898 __ XorImmediate(result, left, imm); |
2911 break; | 2899 break; |
2912 case Token::kSHR: { | 2900 case Token::kSHR: { |
2913 // Asr operation masks the count to 6 bits. | 2901 // Asr operation masks the count to 6 bits. |
2914 const intptr_t kCountLimit = 0x3F; | 2902 const intptr_t kCountLimit = 0x3F; |
2915 intptr_t value = Smi::Cast(constant).Value(); | 2903 intptr_t value = Smi::Cast(constant).Value(); |
2916 __ AsrImmediate( | 2904 __ AsrImmediate( |
2917 result, left, Utils::Minimum(value + kSmiTagSize, kCountLimit)); | 2905 result, left, Utils::Minimum(value + kSmiTagSize, kCountLimit)); |
2918 __ SmiTag(result); | 2906 __ SmiTag(result); |
2919 break; | 2907 break; |
2920 } | 2908 } |
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2984 __ b(deopt, EQ); | 2972 __ b(deopt, EQ); |
2985 } | 2973 } |
2986 const Register temp = TMP2; | 2974 const Register temp = TMP2; |
2987 __ SmiUntag(temp, left); | 2975 __ SmiUntag(temp, left); |
2988 __ SmiUntag(TMP, right); | 2976 __ SmiUntag(TMP, right); |
2989 | 2977 |
2990 __ sdiv(result, temp, TMP); | 2978 __ sdiv(result, temp, TMP); |
2991 | 2979 |
2992 // Check the corner case of dividing the 'MIN_SMI' with -1, in which | 2980 // Check the corner case of dividing the 'MIN_SMI' with -1, in which |
2993 // case we cannot tag the result. | 2981 // case we cannot tag the result. |
2994 __ CompareImmediate(result, 0x4000000000000000LL, kNoPP); | 2982 __ CompareImmediate(result, 0x4000000000000000LL); |
2995 __ b(deopt, EQ); | 2983 __ b(deopt, EQ); |
2996 __ SmiTag(result); | 2984 __ SmiTag(result); |
2997 break; | 2985 break; |
2998 } | 2986 } |
2999 case Token::kMOD: { | 2987 case Token::kMOD: { |
3000 if ((right_range == NULL) || right_range->Overlaps(0, 0)) { | 2988 if ((right_range == NULL) || right_range->Overlaps(0, 0)) { |
3001 // Handle divide by zero in runtime. | 2989 // Handle divide by zero in runtime. |
3002 __ CompareRegisters(right, ZR); | 2990 __ CompareRegisters(right, ZR); |
3003 __ b(deopt, EQ); | 2991 __ b(deopt, EQ); |
3004 } | 2992 } |
(...skipping 28 matching lines...) Expand all Loading... |
3033 case Token::kSHR: { | 3021 case Token::kSHR: { |
3034 if (CanDeoptimize()) { | 3022 if (CanDeoptimize()) { |
3035 __ CompareRegisters(right, ZR); | 3023 __ CompareRegisters(right, ZR); |
3036 __ b(deopt, LT); | 3024 __ b(deopt, LT); |
3037 } | 3025 } |
3038 __ SmiUntag(TMP, right); | 3026 __ SmiUntag(TMP, right); |
3039 // sarl operation masks the count to 6 bits. | 3027 // sarl operation masks the count to 6 bits. |
3040 const intptr_t kCountLimit = 0x3F; | 3028 const intptr_t kCountLimit = 0x3F; |
3041 if ((right_range == NULL) || | 3029 if ((right_range == NULL) || |
3042 !right_range->OnlyLessThanOrEqualTo(kCountLimit)) { | 3030 !right_range->OnlyLessThanOrEqualTo(kCountLimit)) { |
3043 __ LoadImmediate(TMP2, kCountLimit, PP); | 3031 __ LoadImmediate(TMP2, kCountLimit); |
3044 __ CompareRegisters(TMP, TMP2); | 3032 __ CompareRegisters(TMP, TMP2); |
3045 __ csel(TMP, TMP2, TMP, GT); | 3033 __ csel(TMP, TMP2, TMP, GT); |
3046 } | 3034 } |
3047 const Register temp = locs()->temp(0).reg(); | 3035 const Register temp = locs()->temp(0).reg(); |
3048 __ SmiUntag(temp, left); | 3036 __ SmiUntag(temp, left); |
3049 __ asrv(result, temp, TMP); | 3037 __ asrv(result, temp, TMP); |
3050 __ SmiTag(result); | 3038 __ SmiTag(result); |
3051 break; | 3039 break; |
3052 } | 3040 } |
3053 case Token::kDIV: { | 3041 case Token::kDIV: { |
(...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3128 | 3116 |
3129 BoxAllocationSlowPath::Allocate( | 3117 BoxAllocationSlowPath::Allocate( |
3130 compiler, | 3118 compiler, |
3131 this, | 3119 this, |
3132 compiler->BoxClassFor(from_representation()), | 3120 compiler->BoxClassFor(from_representation()), |
3133 out_reg, | 3121 out_reg, |
3134 temp_reg); | 3122 temp_reg); |
3135 | 3123 |
3136 switch (from_representation()) { | 3124 switch (from_representation()) { |
3137 case kUnboxedDouble: | 3125 case kUnboxedDouble: |
3138 __ StoreDFieldToOffset(value, out_reg, ValueOffset(), PP); | 3126 __ StoreDFieldToOffset(value, out_reg, ValueOffset()); |
3139 break; | 3127 break; |
3140 case kUnboxedFloat32x4: | 3128 case kUnboxedFloat32x4: |
3141 case kUnboxedFloat64x2: | 3129 case kUnboxedFloat64x2: |
3142 case kUnboxedInt32x4: | 3130 case kUnboxedInt32x4: |
3143 __ StoreQFieldToOffset(value, out_reg, ValueOffset(), PP); | 3131 __ StoreQFieldToOffset(value, out_reg, ValueOffset()); |
3144 break; | 3132 break; |
3145 default: | 3133 default: |
3146 UNREACHABLE(); | 3134 UNREACHABLE(); |
3147 break; | 3135 break; |
3148 } | 3136 } |
3149 } | 3137 } |
3150 | 3138 |
3151 | 3139 |
3152 LocationSummary* UnboxInstr::MakeLocationSummary(Zone* zone, | 3140 LocationSummary* UnboxInstr::MakeLocationSummary(Zone* zone, |
3153 bool opt) const { | 3141 bool opt) const { |
(...skipping 11 matching lines...) Expand all Loading... |
3165 const Register box = locs()->in(0).reg(); | 3153 const Register box = locs()->in(0).reg(); |
3166 | 3154 |
3167 switch (representation()) { | 3155 switch (representation()) { |
3168 case kUnboxedMint: { | 3156 case kUnboxedMint: { |
3169 UNIMPLEMENTED(); | 3157 UNIMPLEMENTED(); |
3170 break; | 3158 break; |
3171 } | 3159 } |
3172 | 3160 |
3173 case kUnboxedDouble: { | 3161 case kUnboxedDouble: { |
3174 const VRegister result = locs()->out(0).fpu_reg(); | 3162 const VRegister result = locs()->out(0).fpu_reg(); |
3175 __ LoadDFieldFromOffset(result, box, ValueOffset(), PP); | 3163 __ LoadDFieldFromOffset(result, box, ValueOffset()); |
3176 break; | 3164 break; |
3177 } | 3165 } |
3178 | 3166 |
3179 case kUnboxedFloat32x4: | 3167 case kUnboxedFloat32x4: |
3180 case kUnboxedFloat64x2: | 3168 case kUnboxedFloat64x2: |
3181 case kUnboxedInt32x4: { | 3169 case kUnboxedInt32x4: { |
3182 const VRegister result = locs()->out(0).fpu_reg(); | 3170 const VRegister result = locs()->out(0).fpu_reg(); |
3183 __ LoadQFieldFromOffset(result, box, ValueOffset(), PP); | 3171 __ LoadQFieldFromOffset(result, box, ValueOffset()); |
3184 break; | 3172 break; |
3185 } | 3173 } |
3186 | 3174 |
3187 default: | 3175 default: |
3188 UNREACHABLE(); | 3176 UNREACHABLE(); |
3189 break; | 3177 break; |
3190 } | 3178 } |
3191 } | 3179 } |
3192 | 3180 |
3193 | 3181 |
(...skipping 29 matching lines...) Expand all Loading... |
3223 } else if (CanConvertSmi() && (value_cid == kSmiCid)) { | 3211 } else if (CanConvertSmi() && (value_cid == kSmiCid)) { |
3224 EmitSmiConversion(compiler); | 3212 EmitSmiConversion(compiler); |
3225 } else { | 3213 } else { |
3226 const Register box = locs()->in(0).reg(); | 3214 const Register box = locs()->in(0).reg(); |
3227 Label* deopt = compiler->AddDeoptStub(GetDeoptId(), | 3215 Label* deopt = compiler->AddDeoptStub(GetDeoptId(), |
3228 ICData::kDeoptCheckClass); | 3216 ICData::kDeoptCheckClass); |
3229 Label is_smi; | 3217 Label is_smi; |
3230 | 3218 |
3231 if ((value()->Type()->ToNullableCid() == box_cid) && | 3219 if ((value()->Type()->ToNullableCid() == box_cid) && |
3232 value()->Type()->is_nullable()) { | 3220 value()->Type()->is_nullable()) { |
3233 __ CompareObject(box, Object::null_object(), PP); | 3221 __ CompareObject(box, Object::null_object()); |
3234 __ b(deopt, EQ); | 3222 __ b(deopt, EQ); |
3235 } else { | 3223 } else { |
3236 __ tsti(box, Immediate(kSmiTagMask)); | 3224 __ tsti(box, Immediate(kSmiTagMask)); |
3237 __ b(CanConvertSmi() ? &is_smi : deopt, EQ); | 3225 __ b(CanConvertSmi() ? &is_smi : deopt, EQ); |
3238 __ CompareClassId(box, box_cid, PP); | 3226 __ CompareClassId(box, box_cid); |
3239 __ b(deopt, NE); | 3227 __ b(deopt, NE); |
3240 } | 3228 } |
3241 | 3229 |
3242 EmitLoadFromBox(compiler); | 3230 EmitLoadFromBox(compiler); |
3243 | 3231 |
3244 if (is_smi.IsLinked()) { | 3232 if (is_smi.IsLinked()) { |
3245 Label done; | 3233 Label done; |
3246 __ b(&done); | 3234 __ b(&done); |
3247 __ Bind(&is_smi); | 3235 __ Bind(&is_smi); |
3248 EmitSmiConversion(compiler); | 3236 EmitSmiConversion(compiler); |
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3304 void UnboxInteger32Instr::EmitNativeCode(FlowGraphCompiler* compiler) { | 3292 void UnboxInteger32Instr::EmitNativeCode(FlowGraphCompiler* compiler) { |
3305 const intptr_t value_cid = value()->Type()->ToCid(); | 3293 const intptr_t value_cid = value()->Type()->ToCid(); |
3306 const Register out = locs()->out(0).reg(); | 3294 const Register out = locs()->out(0).reg(); |
3307 const Register value = locs()->in(0).reg(); | 3295 const Register value = locs()->in(0).reg(); |
3308 Label* deopt = CanDeoptimize() ? | 3296 Label* deopt = CanDeoptimize() ? |
3309 compiler->AddDeoptStub(GetDeoptId(), ICData::kDeoptUnboxInteger) : NULL; | 3297 compiler->AddDeoptStub(GetDeoptId(), ICData::kDeoptUnboxInteger) : NULL; |
3310 | 3298 |
3311 if (value_cid == kSmiCid) { | 3299 if (value_cid == kSmiCid) { |
3312 __ SmiUntag(out, value); | 3300 __ SmiUntag(out, value); |
3313 } else if (value_cid == kMintCid) { | 3301 } else if (value_cid == kMintCid) { |
3314 __ LoadFieldFromOffset(out, value, Mint::value_offset(), PP); | 3302 __ LoadFieldFromOffset(out, value, Mint::value_offset()); |
3315 } else if (!CanDeoptimize()) { | 3303 } else if (!CanDeoptimize()) { |
3316 // Type information is not conclusive, but range analysis found | 3304 // Type information is not conclusive, but range analysis found |
3317 // the value to be in int64 range. Therefore it must be a smi | 3305 // the value to be in int64 range. Therefore it must be a smi |
3318 // or mint value. | 3306 // or mint value. |
3319 ASSERT(is_truncating()); | 3307 ASSERT(is_truncating()); |
3320 Label done; | 3308 Label done; |
3321 __ SmiUntag(out, value); | 3309 __ SmiUntag(out, value); |
3322 __ TestImmediate(value, kSmiTagMask, PP); | 3310 __ TestImmediate(value, kSmiTagMask); |
3323 __ b(&done, EQ); | 3311 __ b(&done, EQ); |
3324 __ LoadFieldFromOffset(out, value, Mint::value_offset(), PP); | 3312 __ LoadFieldFromOffset(out, value, Mint::value_offset()); |
3325 __ Bind(&done); | 3313 __ Bind(&done); |
3326 } else { | 3314 } else { |
3327 Label done; | 3315 Label done; |
3328 __ SmiUntag(out, value); | 3316 __ SmiUntag(out, value); |
3329 __ TestImmediate(value, kSmiTagMask, PP); | 3317 __ TestImmediate(value, kSmiTagMask); |
3330 __ b(&done, EQ); | 3318 __ b(&done, EQ); |
3331 __ CompareClassId(value, kMintCid, PP); | 3319 __ CompareClassId(value, kMintCid); |
3332 __ b(deopt, NE); | 3320 __ b(deopt, NE); |
3333 __ LoadFieldFromOffset(out, value, Mint::value_offset(), PP); | 3321 __ LoadFieldFromOffset(out, value, Mint::value_offset()); |
3334 __ Bind(&done); | 3322 __ Bind(&done); |
3335 } | 3323 } |
3336 | 3324 |
3337 // TODO(vegorov): as it is implemented right now truncating unboxing would | 3325 // TODO(vegorov): as it is implemented right now truncating unboxing would |
3338 // leave "garbage" in the higher word. | 3326 // leave "garbage" in the higher word. |
3339 if (!is_truncating() && (deopt != NULL)) { | 3327 if (!is_truncating() && (deopt != NULL)) { |
3340 ASSERT(representation() == kUnboxedInt32); | 3328 ASSERT(representation() == kUnboxedInt32); |
3341 __ cmp(out, Operand(out, SXTW, 0)); | 3329 __ cmp(out, Operand(out, SXTW, 0)); |
3342 __ b(deopt, NE); | 3330 __ b(deopt, NE); |
3343 } | 3331 } |
(...skipping 815 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4159 | 4147 |
4160 void Int32x4BoolConstructorInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | 4148 void Int32x4BoolConstructorInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
4161 const Register v0 = locs()->in(0).reg(); | 4149 const Register v0 = locs()->in(0).reg(); |
4162 const Register v1 = locs()->in(1).reg(); | 4150 const Register v1 = locs()->in(1).reg(); |
4163 const Register v2 = locs()->in(2).reg(); | 4151 const Register v2 = locs()->in(2).reg(); |
4164 const Register v3 = locs()->in(3).reg(); | 4152 const Register v3 = locs()->in(3).reg(); |
4165 const Register temp = locs()->temp(0).reg(); | 4153 const Register temp = locs()->temp(0).reg(); |
4166 const VRegister result = locs()->out(0).fpu_reg(); | 4154 const VRegister result = locs()->out(0).fpu_reg(); |
4167 | 4155 |
4168 __ veor(result, result, result); | 4156 __ veor(result, result, result); |
4169 __ LoadImmediate(temp, 0xffffffff, PP); | 4157 __ LoadImmediate(temp, 0xffffffff); |
4170 __ LoadObject(TMP2, Bool::True(), PP); | 4158 __ LoadObject(TMP2, Bool::True()); |
4171 | 4159 |
4172 // __ CompareObject(v0, Bool::True(), PP); | 4160 // __ CompareObject(v0, Bool::True()); |
4173 __ CompareRegisters(v0, TMP2); | 4161 __ CompareRegisters(v0, TMP2); |
4174 __ csel(TMP, temp, ZR, EQ); | 4162 __ csel(TMP, temp, ZR, EQ); |
4175 __ vinsw(result, 0, TMP); | 4163 __ vinsw(result, 0, TMP); |
4176 | 4164 |
4177 // __ CompareObject(v1, Bool::True(), PP); | 4165 // __ CompareObject(v1, Bool::True()); |
4178 __ CompareRegisters(v1, TMP2); | 4166 __ CompareRegisters(v1, TMP2); |
4179 __ csel(TMP, temp, ZR, EQ); | 4167 __ csel(TMP, temp, ZR, EQ); |
4180 __ vinsw(result, 1, TMP); | 4168 __ vinsw(result, 1, TMP); |
4181 | 4169 |
4182 // __ CompareObject(v2, Bool::True(), PP); | 4170 // __ CompareObject(v2, Bool::True()); |
4183 __ CompareRegisters(v2, TMP2); | 4171 __ CompareRegisters(v2, TMP2); |
4184 __ csel(TMP, temp, ZR, EQ); | 4172 __ csel(TMP, temp, ZR, EQ); |
4185 __ vinsw(result, 2, TMP); | 4173 __ vinsw(result, 2, TMP); |
4186 | 4174 |
4187 // __ CompareObject(v3, Bool::True(), PP); | 4175 // __ CompareObject(v3, Bool::True()); |
4188 __ CompareRegisters(v3, TMP2); | 4176 __ CompareRegisters(v3, TMP2); |
4189 __ csel(TMP, temp, ZR, EQ); | 4177 __ csel(TMP, temp, ZR, EQ); |
4190 __ vinsw(result, 3, TMP); | 4178 __ vinsw(result, 3, TMP); |
4191 } | 4179 } |
4192 | 4180 |
4193 | 4181 |
4194 LocationSummary* Int32x4GetFlagInstr::MakeLocationSummary(Zone* zone, | 4182 LocationSummary* Int32x4GetFlagInstr::MakeLocationSummary(Zone* zone, |
4195 bool opt) const { | 4183 bool opt) const { |
4196 const intptr_t kNumInputs = 1; | 4184 const intptr_t kNumInputs = 1; |
4197 const intptr_t kNumTemps = 0; | 4185 const intptr_t kNumTemps = 0; |
(...skipping 19 matching lines...) Expand all Loading... |
4217 case MethodRecognizer::kInt32x4GetFlagZ: | 4205 case MethodRecognizer::kInt32x4GetFlagZ: |
4218 __ vmovrs(result, value, 2); | 4206 __ vmovrs(result, value, 2); |
4219 break; | 4207 break; |
4220 case MethodRecognizer::kInt32x4GetFlagW: | 4208 case MethodRecognizer::kInt32x4GetFlagW: |
4221 __ vmovrs(result, value, 3); | 4209 __ vmovrs(result, value, 3); |
4222 break; | 4210 break; |
4223 default: UNREACHABLE(); | 4211 default: UNREACHABLE(); |
4224 } | 4212 } |
4225 | 4213 |
4226 __ tst(result, Operand(result)); | 4214 __ tst(result, Operand(result)); |
4227 __ LoadObject(result, Bool::True(), PP); | 4215 __ LoadObject(result, Bool::True()); |
4228 __ LoadObject(TMP, Bool::False(), PP); | 4216 __ LoadObject(TMP, Bool::False()); |
4229 __ csel(result, TMP, result, EQ); | 4217 __ csel(result, TMP, result, EQ); |
4230 } | 4218 } |
4231 | 4219 |
4232 | 4220 |
4233 LocationSummary* Int32x4SelectInstr::MakeLocationSummary(Zone* zone, | 4221 LocationSummary* Int32x4SelectInstr::MakeLocationSummary(Zone* zone, |
4234 bool opt) const { | 4222 bool opt) const { |
4235 const intptr_t kNumInputs = 3; | 4223 const intptr_t kNumInputs = 3; |
4236 const intptr_t kNumTemps = 1; | 4224 const intptr_t kNumTemps = 1; |
4237 LocationSummary* summary = new LocationSummary( | 4225 LocationSummary* summary = new LocationSummary( |
4238 zone, kNumInputs, kNumTemps, LocationSummary::kNoCall); | 4226 zone, kNumInputs, kNumTemps, LocationSummary::kNoCall); |
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4280 | 4268 |
4281 void Int32x4SetFlagInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | 4269 void Int32x4SetFlagInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
4282 const VRegister mask = locs()->in(0).fpu_reg(); | 4270 const VRegister mask = locs()->in(0).fpu_reg(); |
4283 const Register flag = locs()->in(1).reg(); | 4271 const Register flag = locs()->in(1).reg(); |
4284 const VRegister result = locs()->out(0).fpu_reg(); | 4272 const VRegister result = locs()->out(0).fpu_reg(); |
4285 | 4273 |
4286 if (result != mask) { | 4274 if (result != mask) { |
4287 __ vmov(result, mask); | 4275 __ vmov(result, mask); |
4288 } | 4276 } |
4289 | 4277 |
4290 __ CompareObject(flag, Bool::True(), PP); | 4278 __ CompareObject(flag, Bool::True()); |
4291 __ LoadImmediate(TMP, 0xffffffff, PP); | 4279 __ LoadImmediate(TMP, 0xffffffff); |
4292 __ csel(TMP, TMP, ZR, EQ); | 4280 __ csel(TMP, TMP, ZR, EQ); |
4293 switch (op_kind()) { | 4281 switch (op_kind()) { |
4294 case MethodRecognizer::kInt32x4WithFlagX: | 4282 case MethodRecognizer::kInt32x4WithFlagX: |
4295 __ vinsw(result, 0, TMP); | 4283 __ vinsw(result, 0, TMP); |
4296 break; | 4284 break; |
4297 case MethodRecognizer::kInt32x4WithFlagY: | 4285 case MethodRecognizer::kInt32x4WithFlagY: |
4298 __ vinsw(result, 1, TMP); | 4286 __ vinsw(result, 1, TMP); |
4299 break; | 4287 break; |
4300 case MethodRecognizer::kInt32x4WithFlagZ: | 4288 case MethodRecognizer::kInt32x4WithFlagZ: |
4301 __ vinsw(result, 2, TMP); | 4289 __ vinsw(result, 2, TMP); |
(...skipping 158 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4460 __ b(&are_equal, EQ); | 4448 __ b(&are_equal, EQ); |
4461 const Condition double_condition = | 4449 const Condition double_condition = |
4462 is_min ? TokenKindToDoubleCondition(Token::kLTE) | 4450 is_min ? TokenKindToDoubleCondition(Token::kLTE) |
4463 : TokenKindToDoubleCondition(Token::kGTE); | 4451 : TokenKindToDoubleCondition(Token::kGTE); |
4464 ASSERT(left == result); | 4452 ASSERT(left == result); |
4465 __ b(&done, double_condition); | 4453 __ b(&done, double_condition); |
4466 __ fmovdd(result, right); | 4454 __ fmovdd(result, right); |
4467 __ b(&done); | 4455 __ b(&done); |
4468 | 4456 |
4469 __ Bind(&returns_nan); | 4457 __ Bind(&returns_nan); |
4470 __ LoadDImmediate(result, NAN, PP); | 4458 __ LoadDImmediate(result, NAN); |
4471 __ b(&done); | 4459 __ b(&done); |
4472 | 4460 |
4473 __ Bind(&are_equal); | 4461 __ Bind(&are_equal); |
4474 // Check for negative zero: -0.0 is equal 0.0 but min or max must return | 4462 // Check for negative zero: -0.0 is equal 0.0 but min or max must return |
4475 // -0.0 or 0.0 respectively. | 4463 // -0.0 or 0.0 respectively. |
4476 // Check for negative left value (get the sign bit): | 4464 // Check for negative left value (get the sign bit): |
4477 // - min -> left is negative ? left : right. | 4465 // - min -> left is negative ? left : right. |
4478 // - max -> left is negative ? right : left | 4466 // - max -> left is negative ? right : left |
4479 // Check the sign bit. | 4467 // Check the sign bit. |
4480 __ fmovrd(TMP, left); // Sign bit is in bit 63 of TMP. | 4468 __ fmovrd(TMP, left); // Sign bit is in bit 63 of TMP. |
4481 __ CompareImmediate(TMP, 0, PP); | 4469 __ CompareImmediate(TMP, 0); |
4482 if (is_min) { | 4470 if (is_min) { |
4483 ASSERT(left == result); | 4471 ASSERT(left == result); |
4484 __ b(&done, LT); | 4472 __ b(&done, LT); |
4485 __ fmovdd(result, right); | 4473 __ fmovdd(result, right); |
4486 } else { | 4474 } else { |
4487 __ b(&done, GE); | 4475 __ b(&done, GE); |
4488 __ fmovdd(result, right); | 4476 __ fmovdd(result, right); |
4489 ASSERT(left == result); | 4477 ASSERT(left == result); |
4490 } | 4478 } |
4491 __ Bind(&done); | 4479 __ Bind(&done); |
(...skipping 132 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4624 result->set_out(0, Location::RegisterLocation(R0)); | 4612 result->set_out(0, Location::RegisterLocation(R0)); |
4625 return result; | 4613 return result; |
4626 } | 4614 } |
4627 | 4615 |
4628 | 4616 |
4629 void DoubleToIntegerInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | 4617 void DoubleToIntegerInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
4630 const Register result = locs()->out(0).reg(); | 4618 const Register result = locs()->out(0).reg(); |
4631 const Register value_obj = locs()->in(0).reg(); | 4619 const Register value_obj = locs()->in(0).reg(); |
4632 ASSERT(result == R0); | 4620 ASSERT(result == R0); |
4633 ASSERT(result != value_obj); | 4621 ASSERT(result != value_obj); |
4634 __ LoadDFieldFromOffset(VTMP, value_obj, Double::value_offset(), PP); | 4622 __ LoadDFieldFromOffset(VTMP, value_obj, Double::value_offset()); |
4635 | 4623 |
4636 Label do_call, done; | 4624 Label do_call, done; |
4637 // First check for NaN. Checking for minint after the conversion doesn't work | 4625 // First check for NaN. Checking for minint after the conversion doesn't work |
4638 // on ARM64 because fcvtzds gives 0 for NaN. | 4626 // on ARM64 because fcvtzds gives 0 for NaN. |
4639 __ fcmpd(VTMP, VTMP); | 4627 __ fcmpd(VTMP, VTMP); |
4640 __ b(&do_call, VS); | 4628 __ b(&do_call, VS); |
4641 | 4629 |
4642 __ fcvtzds(result, VTMP); | 4630 __ fcvtzds(result, VTMP); |
4643 // Overflow is signaled with minint. | 4631 // Overflow is signaled with minint. |
4644 | 4632 |
4645 // Check for overflow and that it fits into Smi. | 4633 // Check for overflow and that it fits into Smi. |
4646 __ CompareImmediate(result, 0xC000000000000000, PP); | 4634 __ CompareImmediate(result, 0xC000000000000000); |
4647 __ b(&do_call, MI); | 4635 __ b(&do_call, MI); |
4648 __ SmiTag(result); | 4636 __ SmiTag(result); |
4649 if (FLAG_throw_on_javascript_int_overflow) { | 4637 if (FLAG_throw_on_javascript_int_overflow) { |
4650 EmitJavascriptOverflowCheck(compiler, range(), &do_call, result); | 4638 EmitJavascriptOverflowCheck(compiler, range(), &do_call, result); |
4651 } | 4639 } |
4652 __ b(&done); | 4640 __ b(&done); |
4653 __ Bind(&do_call); | 4641 __ Bind(&do_call); |
4654 __ Push(value_obj); | 4642 __ Push(value_obj); |
4655 ASSERT(instance_call()->HasICData()); | 4643 ASSERT(instance_call()->HasICData()); |
4656 const ICData& ic_data = *instance_call()->ic_data(); | 4644 const ICData& ic_data = *instance_call()->ic_data(); |
(...skipping 29 matching lines...) Expand all Loading... |
4686 const Register result = locs()->out(0).reg(); | 4674 const Register result = locs()->out(0).reg(); |
4687 const VRegister value = locs()->in(0).fpu_reg(); | 4675 const VRegister value = locs()->in(0).fpu_reg(); |
4688 // First check for NaN. Checking for minint after the conversion doesn't work | 4676 // First check for NaN. Checking for minint after the conversion doesn't work |
4689 // on ARM64 because fcvtzds gives 0 for NaN. | 4677 // on ARM64 because fcvtzds gives 0 for NaN. |
4690 // TODO(zra): Check spec that this is true. | 4678 // TODO(zra): Check spec that this is true. |
4691 __ fcmpd(value, value); | 4679 __ fcmpd(value, value); |
4692 __ b(deopt, VS); | 4680 __ b(deopt, VS); |
4693 | 4681 |
4694 __ fcvtzds(result, value); | 4682 __ fcvtzds(result, value); |
4695 // Check for overflow and that it fits into Smi. | 4683 // Check for overflow and that it fits into Smi. |
4696 __ CompareImmediate(result, 0xC000000000000000, PP); | 4684 __ CompareImmediate(result, 0xC000000000000000); |
4697 __ b(deopt, MI); | 4685 __ b(deopt, MI); |
4698 __ SmiTag(result); | 4686 __ SmiTag(result); |
4699 if (FLAG_throw_on_javascript_int_overflow) { | 4687 if (FLAG_throw_on_javascript_int_overflow) { |
4700 EmitJavascriptOverflowCheck(compiler, range(), deopt, result); | 4688 EmitJavascriptOverflowCheck(compiler, range(), deopt, result); |
4701 } | 4689 } |
4702 } | 4690 } |
4703 | 4691 |
4704 | 4692 |
4705 LocationSummary* DoubleToDoubleInstr::MakeLocationSummary(Zone* zone, | 4693 LocationSummary* DoubleToDoubleInstr::MakeLocationSummary(Zone* zone, |
4706 bool opt) const { | 4694 bool opt) const { |
(...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4794 LocationSummary* locs = instr->locs(); | 4782 LocationSummary* locs = instr->locs(); |
4795 | 4783 |
4796 const VRegister base = locs->in(0).fpu_reg(); | 4784 const VRegister base = locs->in(0).fpu_reg(); |
4797 const VRegister exp = locs->in(1).fpu_reg(); | 4785 const VRegister exp = locs->in(1).fpu_reg(); |
4798 const VRegister result = locs->out(0).fpu_reg(); | 4786 const VRegister result = locs->out(0).fpu_reg(); |
4799 const VRegister saved_base = locs->temp(0).fpu_reg(); | 4787 const VRegister saved_base = locs->temp(0).fpu_reg(); |
4800 ASSERT((base == result) && (result != saved_base)); | 4788 ASSERT((base == result) && (result != saved_base)); |
4801 | 4789 |
4802 Label skip_call, try_sqrt, check_base, return_nan, do_pow; | 4790 Label skip_call, try_sqrt, check_base, return_nan, do_pow; |
4803 __ fmovdd(saved_base, base); | 4791 __ fmovdd(saved_base, base); |
4804 __ LoadDImmediate(result, 1.0, PP); | 4792 __ LoadDImmediate(result, 1.0); |
4805 // exponent == 0.0 -> return 1.0; | 4793 // exponent == 0.0 -> return 1.0; |
4806 __ fcmpdz(exp); | 4794 __ fcmpdz(exp); |
4807 __ b(&check_base, VS); // NaN -> check base. | 4795 __ b(&check_base, VS); // NaN -> check base. |
4808 __ b(&skip_call, EQ); // exp is 0.0, result is 1.0. | 4796 __ b(&skip_call, EQ); // exp is 0.0, result is 1.0. |
4809 | 4797 |
4810 // exponent == 1.0 ? | 4798 // exponent == 1.0 ? |
4811 __ fcmpd(exp, result); | 4799 __ fcmpd(exp, result); |
4812 Label return_base; | 4800 Label return_base; |
4813 __ b(&return_base, EQ); | 4801 __ b(&return_base, EQ); |
4814 | 4802 |
4815 // exponent == 2.0 ? | 4803 // exponent == 2.0 ? |
4816 __ LoadDImmediate(VTMP, 2.0, PP); | 4804 __ LoadDImmediate(VTMP, 2.0); |
4817 __ fcmpd(exp, VTMP); | 4805 __ fcmpd(exp, VTMP); |
4818 Label return_base_times_2; | 4806 Label return_base_times_2; |
4819 __ b(&return_base_times_2, EQ); | 4807 __ b(&return_base_times_2, EQ); |
4820 | 4808 |
4821 // exponent == 3.0 ? | 4809 // exponent == 3.0 ? |
4822 __ LoadDImmediate(VTMP, 3.0, PP); | 4810 __ LoadDImmediate(VTMP, 3.0); |
4823 __ fcmpd(exp, VTMP); | 4811 __ fcmpd(exp, VTMP); |
4824 __ b(&check_base, NE); | 4812 __ b(&check_base, NE); |
4825 | 4813 |
4826 // base_times_3. | 4814 // base_times_3. |
4827 __ fmuld(result, saved_base, saved_base); | 4815 __ fmuld(result, saved_base, saved_base); |
4828 __ fmuld(result, result, saved_base); | 4816 __ fmuld(result, result, saved_base); |
4829 __ b(&skip_call); | 4817 __ b(&skip_call); |
4830 | 4818 |
4831 __ Bind(&return_base); | 4819 __ Bind(&return_base); |
4832 __ fmovdd(result, saved_base); | 4820 __ fmovdd(result, saved_base); |
4833 __ b(&skip_call); | 4821 __ b(&skip_call); |
4834 | 4822 |
4835 __ Bind(&return_base_times_2); | 4823 __ Bind(&return_base_times_2); |
4836 __ fmuld(result, saved_base, saved_base); | 4824 __ fmuld(result, saved_base, saved_base); |
4837 __ b(&skip_call); | 4825 __ b(&skip_call); |
4838 | 4826 |
4839 __ Bind(&check_base); | 4827 __ Bind(&check_base); |
4840 // Note: 'exp' could be NaN. | 4828 // Note: 'exp' could be NaN. |
4841 // base == 1.0 -> return 1.0; | 4829 // base == 1.0 -> return 1.0; |
4842 __ fcmpd(saved_base, result); | 4830 __ fcmpd(saved_base, result); |
4843 __ b(&return_nan, VS); | 4831 __ b(&return_nan, VS); |
4844 __ b(&skip_call, EQ); // base is 1.0, result is 1.0. | 4832 __ b(&skip_call, EQ); // base is 1.0, result is 1.0. |
4845 | 4833 |
4846 __ fcmpd(saved_base, exp); | 4834 __ fcmpd(saved_base, exp); |
4847 __ b(&try_sqrt, VC); // // Neither 'exp' nor 'base' is NaN. | 4835 __ b(&try_sqrt, VC); // // Neither 'exp' nor 'base' is NaN. |
4848 | 4836 |
4849 __ Bind(&return_nan); | 4837 __ Bind(&return_nan); |
4850 __ LoadDImmediate(result, NAN, PP); | 4838 __ LoadDImmediate(result, NAN); |
4851 __ b(&skip_call); | 4839 __ b(&skip_call); |
4852 | 4840 |
4853 Label return_zero; | 4841 Label return_zero; |
4854 __ Bind(&try_sqrt); | 4842 __ Bind(&try_sqrt); |
4855 | 4843 |
4856 // Before calling pow, check if we could use sqrt instead of pow. | 4844 // Before calling pow, check if we could use sqrt instead of pow. |
4857 __ LoadDImmediate(result, kNegInfinity, PP); | 4845 __ LoadDImmediate(result, kNegInfinity); |
4858 | 4846 |
4859 // base == -Infinity -> call pow; | 4847 // base == -Infinity -> call pow; |
4860 __ fcmpd(saved_base, result); | 4848 __ fcmpd(saved_base, result); |
4861 __ b(&do_pow, EQ); | 4849 __ b(&do_pow, EQ); |
4862 | 4850 |
4863 // exponent == 0.5 ? | 4851 // exponent == 0.5 ? |
4864 __ LoadDImmediate(result, 0.5, PP); | 4852 __ LoadDImmediate(result, 0.5); |
4865 __ fcmpd(exp, result); | 4853 __ fcmpd(exp, result); |
4866 __ b(&do_pow, NE); | 4854 __ b(&do_pow, NE); |
4867 | 4855 |
4868 // base == 0 -> return 0; | 4856 // base == 0 -> return 0; |
4869 __ fcmpdz(saved_base); | 4857 __ fcmpdz(saved_base); |
4870 __ b(&return_zero, EQ); | 4858 __ b(&return_zero, EQ); |
4871 | 4859 |
4872 __ fsqrtd(result, saved_base); | 4860 __ fsqrtd(result, saved_base); |
4873 __ b(&skip_call); | 4861 __ b(&skip_call); |
4874 | 4862 |
4875 __ Bind(&return_zero); | 4863 __ Bind(&return_zero); |
4876 __ LoadDImmediate(result, 0.0, PP); | 4864 __ LoadDImmediate(result, 0.0); |
4877 __ b(&skip_call); | 4865 __ b(&skip_call); |
4878 | 4866 |
4879 __ Bind(&do_pow); | 4867 __ Bind(&do_pow); |
4880 __ fmovdd(base, saved_base); // Restore base. | 4868 __ fmovdd(base, saved_base); // Restore base. |
4881 | 4869 |
4882 __ CallRuntime(instr->TargetFunction(), kInputCount); | 4870 __ CallRuntime(instr->TargetFunction(), kInputCount); |
4883 __ Bind(&skip_call); | 4871 __ Bind(&skip_call); |
4884 } | 4872 } |
4885 | 4873 |
4886 | 4874 |
(...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4981 __ b(deopt, EQ); | 4969 __ b(deopt, EQ); |
4982 } | 4970 } |
4983 | 4971 |
4984 __ SmiUntag(result_mod, left); | 4972 __ SmiUntag(result_mod, left); |
4985 __ SmiUntag(TMP, right); | 4973 __ SmiUntag(TMP, right); |
4986 | 4974 |
4987 __ sdiv(result_div, result_mod, TMP); | 4975 __ sdiv(result_div, result_mod, TMP); |
4988 | 4976 |
4989 // Check the corner case of dividing the 'MIN_SMI' with -1, in which | 4977 // Check the corner case of dividing the 'MIN_SMI' with -1, in which |
4990 // case we cannot tag the result. | 4978 // case we cannot tag the result. |
4991 __ CompareImmediate(result_div, 0x4000000000000000, PP); | 4979 __ CompareImmediate(result_div, 0x4000000000000000); |
4992 __ b(deopt, EQ); | 4980 __ b(deopt, EQ); |
4993 // result_mod <- left - right * result_div. | 4981 // result_mod <- left - right * result_div. |
4994 __ msub(result_mod, TMP, result_div, result_mod); | 4982 __ msub(result_mod, TMP, result_div, result_mod); |
4995 __ SmiTag(result_div); | 4983 __ SmiTag(result_div); |
4996 __ SmiTag(result_mod); | 4984 __ SmiTag(result_mod); |
4997 // Correct MOD result: | 4985 // Correct MOD result: |
4998 // res = left % right; | 4986 // res = left % right; |
4999 // if (res < 0) { | 4987 // if (res < 0) { |
5000 // if (right < 0) { | 4988 // if (right < 0) { |
5001 // res = res - right; | 4989 // res = res - right; |
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5060 } | 5048 } |
5061 return summary; | 5049 return summary; |
5062 } | 5050 } |
5063 | 5051 |
5064 | 5052 |
5065 void CheckClassInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | 5053 void CheckClassInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
5066 Label* deopt = compiler->AddDeoptStub(deopt_id(), | 5054 Label* deopt = compiler->AddDeoptStub(deopt_id(), |
5067 ICData::kDeoptCheckClass, | 5055 ICData::kDeoptCheckClass, |
5068 licm_hoisted_ ? ICData::kHoisted : 0); | 5056 licm_hoisted_ ? ICData::kHoisted : 0); |
5069 if (IsNullCheck()) { | 5057 if (IsNullCheck()) { |
5070 __ CompareObject(locs()->in(0).reg(), Object::null_object(), PP); | 5058 __ CompareObject(locs()->in(0).reg(), Object::null_object()); |
5071 ASSERT(DeoptIfNull() || DeoptIfNotNull()); | 5059 ASSERT(DeoptIfNull() || DeoptIfNotNull()); |
5072 Condition cond = DeoptIfNull() ? EQ : NE; | 5060 Condition cond = DeoptIfNull() ? EQ : NE; |
5073 __ b(deopt, cond); | 5061 __ b(deopt, cond); |
5074 return; | 5062 return; |
5075 } | 5063 } |
5076 | 5064 |
5077 ASSERT((unary_checks().GetReceiverClassIdAt(0) != kSmiCid) || | 5065 ASSERT((unary_checks().GetReceiverClassIdAt(0) != kSmiCid) || |
5078 (unary_checks().NumberOfChecks() > 1)); | 5066 (unary_checks().NumberOfChecks() > 1)); |
5079 const Register value = locs()->in(0).reg(); | 5067 const Register value = locs()->in(0).reg(); |
5080 const Register temp = locs()->temp(0).reg(); | 5068 const Register temp = locs()->temp(0).reg(); |
5081 Label is_ok; | 5069 Label is_ok; |
5082 if (unary_checks().GetReceiverClassIdAt(0) == kSmiCid) { | 5070 if (unary_checks().GetReceiverClassIdAt(0) == kSmiCid) { |
5083 __ tsti(value, Immediate(kSmiTagMask)); | 5071 __ tsti(value, Immediate(kSmiTagMask)); |
5084 __ b(&is_ok, EQ); | 5072 __ b(&is_ok, EQ); |
5085 } else { | 5073 } else { |
5086 __ tsti(value, Immediate(kSmiTagMask)); | 5074 __ tsti(value, Immediate(kSmiTagMask)); |
5087 __ b(deopt, EQ); | 5075 __ b(deopt, EQ); |
5088 } | 5076 } |
5089 __ LoadClassId(temp, value, PP); | 5077 __ LoadClassId(temp, value); |
5090 | 5078 |
5091 if (IsDenseSwitch()) { | 5079 if (IsDenseSwitch()) { |
5092 ASSERT(cids_[0] < cids_[cids_.length() - 1]); | 5080 ASSERT(cids_[0] < cids_[cids_.length() - 1]); |
5093 __ AddImmediate(temp, temp, -cids_[0], PP); | 5081 __ AddImmediate(temp, temp, -cids_[0]); |
5094 __ CompareImmediate(temp, cids_[cids_.length() - 1] - cids_[0], PP); | 5082 __ CompareImmediate(temp, cids_[cids_.length() - 1] - cids_[0]); |
5095 __ b(deopt, HI); | 5083 __ b(deopt, HI); |
5096 | 5084 |
5097 intptr_t mask = ComputeCidMask(); | 5085 intptr_t mask = ComputeCidMask(); |
5098 if (!IsDenseMask(mask)) { | 5086 if (!IsDenseMask(mask)) { |
5099 // Only need mask if there are missing numbers in the range. | 5087 // Only need mask if there are missing numbers in the range. |
5100 ASSERT(cids_.length() > 2); | 5088 ASSERT(cids_.length() > 2); |
5101 Register mask_reg = locs()->temp(1).reg(); | 5089 Register mask_reg = locs()->temp(1).reg(); |
5102 __ LoadImmediate(mask_reg, 1, PP); | 5090 __ LoadImmediate(mask_reg, 1); |
5103 __ lslv(mask_reg, mask_reg, temp); | 5091 __ lslv(mask_reg, mask_reg, temp); |
5104 __ TestImmediate(mask_reg, mask, PP); | 5092 __ TestImmediate(mask_reg, mask); |
5105 __ b(deopt, EQ); | 5093 __ b(deopt, EQ); |
5106 } | 5094 } |
5107 | 5095 |
5108 } else { | 5096 } else { |
5109 GrowableArray<CidTarget> sorted_ic_data; | 5097 GrowableArray<CidTarget> sorted_ic_data; |
5110 FlowGraphCompiler::SortICDataByCount(unary_checks(), | 5098 FlowGraphCompiler::SortICDataByCount(unary_checks(), |
5111 &sorted_ic_data, | 5099 &sorted_ic_data, |
5112 /* drop_smi = */ true); | 5100 /* drop_smi = */ true); |
5113 const intptr_t num_checks = sorted_ic_data.length(); | 5101 const intptr_t num_checks = sorted_ic_data.length(); |
5114 for (intptr_t i = 0; i < num_checks; i++) { | 5102 for (intptr_t i = 0; i < num_checks; i++) { |
5115 const intptr_t cid = sorted_ic_data[i].cid; | 5103 const intptr_t cid = sorted_ic_data[i].cid; |
5116 ASSERT(cid != kSmiCid); | 5104 ASSERT(cid != kSmiCid); |
5117 __ CompareImmediate(temp, cid, PP); | 5105 __ CompareImmediate(temp, cid); |
5118 if (i == (num_checks - 1)) { | 5106 if (i == (num_checks - 1)) { |
5119 __ b(deopt, NE); | 5107 __ b(deopt, NE); |
5120 } else { | 5108 } else { |
5121 __ b(&is_ok, EQ); | 5109 __ b(&is_ok, EQ); |
5122 } | 5110 } |
5123 } | 5111 } |
5124 } | 5112 } |
5125 __ Bind(&is_ok); | 5113 __ Bind(&is_ok); |
5126 } | 5114 } |
5127 | 5115 |
5128 | 5116 |
5129 LocationSummary* CheckClassIdInstr::MakeLocationSummary(Zone* zone, | 5117 LocationSummary* CheckClassIdInstr::MakeLocationSummary(Zone* zone, |
5130 bool opt) const { | 5118 bool opt) const { |
5131 const intptr_t kNumInputs = 1; | 5119 const intptr_t kNumInputs = 1; |
5132 const intptr_t kNumTemps = 0; | 5120 const intptr_t kNumTemps = 0; |
5133 LocationSummary* summary = new(zone) LocationSummary( | 5121 LocationSummary* summary = new(zone) LocationSummary( |
5134 zone, kNumInputs, kNumTemps, LocationSummary::kNoCall); | 5122 zone, kNumInputs, kNumTemps, LocationSummary::kNoCall); |
5135 summary->set_in(0, Location::RequiresRegister()); | 5123 summary->set_in(0, Location::RequiresRegister()); |
5136 return summary; | 5124 return summary; |
5137 } | 5125 } |
5138 | 5126 |
5139 | 5127 |
5140 void CheckClassIdInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | 5128 void CheckClassIdInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
5141 Register value = locs()->in(0).reg(); | 5129 Register value = locs()->in(0).reg(); |
5142 Label* deopt = compiler->AddDeoptStub(deopt_id(), ICData::kDeoptCheckClass); | 5130 Label* deopt = compiler->AddDeoptStub(deopt_id(), ICData::kDeoptCheckClass); |
5143 __ CompareImmediate(value, Smi::RawValue(cid_), PP); | 5131 __ CompareImmediate(value, Smi::RawValue(cid_)); |
5144 __ b(deopt, NE); | 5132 __ b(deopt, NE); |
5145 } | 5133 } |
5146 | 5134 |
5147 | 5135 |
5148 LocationSummary* CheckSmiInstr::MakeLocationSummary(Zone* zone, | 5136 LocationSummary* CheckSmiInstr::MakeLocationSummary(Zone* zone, |
5149 bool opt) const { | 5137 bool opt) const { |
5150 const intptr_t kNumInputs = 1; | 5138 const intptr_t kNumInputs = 1; |
5151 const intptr_t kNumTemps = 0; | 5139 const intptr_t kNumTemps = 0; |
5152 LocationSummary* summary = new(zone) LocationSummary( | 5140 LocationSummary* summary = new(zone) LocationSummary( |
5153 zone, kNumInputs, kNumTemps, LocationSummary::kNoCall); | 5141 zone, kNumInputs, kNumTemps, LocationSummary::kNoCall); |
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5202 (Smi::Cast(index_loc.constant()).Value() < 0)); | 5190 (Smi::Cast(index_loc.constant()).Value() < 0)); |
5203 // Unconditionally deoptimize for constant bounds checks because they | 5191 // Unconditionally deoptimize for constant bounds checks because they |
5204 // only occur only when index is out-of-bounds. | 5192 // only occur only when index is out-of-bounds. |
5205 __ b(deopt); | 5193 __ b(deopt); |
5206 return; | 5194 return; |
5207 } | 5195 } |
5208 | 5196 |
5209 if (index_loc.IsConstant()) { | 5197 if (index_loc.IsConstant()) { |
5210 const Register length = length_loc.reg(); | 5198 const Register length = length_loc.reg(); |
5211 const Smi& index = Smi::Cast(index_loc.constant()); | 5199 const Smi& index = Smi::Cast(index_loc.constant()); |
5212 __ CompareImmediate(length, reinterpret_cast<int64_t>(index.raw()), PP); | 5200 __ CompareImmediate(length, reinterpret_cast<int64_t>(index.raw())); |
5213 __ b(deopt, LS); | 5201 __ b(deopt, LS); |
5214 } else if (length_loc.IsConstant()) { | 5202 } else if (length_loc.IsConstant()) { |
5215 const Smi& length = Smi::Cast(length_loc.constant()); | 5203 const Smi& length = Smi::Cast(length_loc.constant()); |
5216 const Register index = index_loc.reg(); | 5204 const Register index = index_loc.reg(); |
5217 if (length.Value() == Smi::kMaxValue) { | 5205 if (length.Value() == Smi::kMaxValue) { |
5218 __ tst(index, Operand(index)); | 5206 __ tst(index, Operand(index)); |
5219 __ b(deopt, MI); | 5207 __ b(deopt, MI); |
5220 } else { | 5208 } else { |
5221 __ CompareImmediate(index, reinterpret_cast<int64_t>(length.raw()), PP); | 5209 __ CompareImmediate(index, reinterpret_cast<int64_t>(length.raw())); |
5222 __ b(deopt, CS); | 5210 __ b(deopt, CS); |
5223 } | 5211 } |
5224 } else { | 5212 } else { |
5225 const Register length = length_loc.reg(); | 5213 const Register length = length_loc.reg(); |
5226 const Register index = index_loc.reg(); | 5214 const Register index = index_loc.reg(); |
5227 __ CompareRegisters(index, length); | 5215 __ CompareRegisters(index, length); |
5228 __ b(deopt, CS); | 5216 __ b(deopt, CS); |
5229 } | 5217 } |
5230 } | 5218 } |
5231 | 5219 |
(...skipping 295 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5527 ASSERT(kind() == Token::kEQ_STRICT || kind() == Token::kNE_STRICT); | 5515 ASSERT(kind() == Token::kEQ_STRICT || kind() == Token::kNE_STRICT); |
5528 | 5516 |
5529 Label is_true, is_false; | 5517 Label is_true, is_false; |
5530 BranchLabels labels = { &is_true, &is_false, &is_false }; | 5518 BranchLabels labels = { &is_true, &is_false, &is_false }; |
5531 Condition true_condition = EmitComparisonCode(compiler, labels); | 5519 Condition true_condition = EmitComparisonCode(compiler, labels); |
5532 EmitBranchOnCondition(compiler, true_condition, labels); | 5520 EmitBranchOnCondition(compiler, true_condition, labels); |
5533 | 5521 |
5534 const Register result = locs()->out(0).reg(); | 5522 const Register result = locs()->out(0).reg(); |
5535 Label done; | 5523 Label done; |
5536 __ Bind(&is_false); | 5524 __ Bind(&is_false); |
5537 __ LoadObject(result, Bool::False(), PP); | 5525 __ LoadObject(result, Bool::False()); |
5538 __ b(&done); | 5526 __ b(&done); |
5539 __ Bind(&is_true); | 5527 __ Bind(&is_true); |
5540 __ LoadObject(result, Bool::True(), PP); | 5528 __ LoadObject(result, Bool::True()); |
5541 __ Bind(&done); | 5529 __ Bind(&done); |
5542 } | 5530 } |
5543 | 5531 |
5544 | 5532 |
5545 void StrictCompareInstr::EmitBranchCode(FlowGraphCompiler* compiler, | 5533 void StrictCompareInstr::EmitBranchCode(FlowGraphCompiler* compiler, |
5546 BranchInstr* branch) { | 5534 BranchInstr* branch) { |
5547 ASSERT(kind() == Token::kEQ_STRICT || kind() == Token::kNE_STRICT); | 5535 ASSERT(kind() == Token::kEQ_STRICT || kind() == Token::kNE_STRICT); |
5548 | 5536 |
5549 BranchLabels labels = compiler->CreateBranchLabels(branch); | 5537 BranchLabels labels = compiler->CreateBranchLabels(branch); |
5550 Condition true_condition = EmitComparisonCode(compiler, labels); | 5538 Condition true_condition = EmitComparisonCode(compiler, labels); |
5551 EmitBranchOnCondition(compiler, true_condition, labels); | 5539 EmitBranchOnCondition(compiler, true_condition, labels); |
5552 } | 5540 } |
5553 | 5541 |
5554 | 5542 |
5555 LocationSummary* BooleanNegateInstr::MakeLocationSummary(Zone* zone, | 5543 LocationSummary* BooleanNegateInstr::MakeLocationSummary(Zone* zone, |
5556 bool opt) const { | 5544 bool opt) const { |
5557 return LocationSummary::Make(zone, | 5545 return LocationSummary::Make(zone, |
5558 1, | 5546 1, |
5559 Location::RequiresRegister(), | 5547 Location::RequiresRegister(), |
5560 LocationSummary::kNoCall); | 5548 LocationSummary::kNoCall); |
5561 } | 5549 } |
5562 | 5550 |
5563 | 5551 |
5564 void BooleanNegateInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | 5552 void BooleanNegateInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
5565 const Register value = locs()->in(0).reg(); | 5553 const Register value = locs()->in(0).reg(); |
5566 const Register result = locs()->out(0).reg(); | 5554 const Register result = locs()->out(0).reg(); |
5567 | 5555 |
5568 __ LoadObject(result, Bool::True(), PP); | 5556 __ LoadObject(result, Bool::True()); |
5569 __ LoadObject(TMP, Bool::False(), PP); | 5557 __ LoadObject(TMP, Bool::False()); |
5570 __ CompareRegisters(result, value); | 5558 __ CompareRegisters(result, value); |
5571 __ csel(result, TMP, result, EQ); | 5559 __ csel(result, TMP, result, EQ); |
5572 } | 5560 } |
5573 | 5561 |
5574 | 5562 |
5575 LocationSummary* AllocateObjectInstr::MakeLocationSummary(Zone* zone, | 5563 LocationSummary* AllocateObjectInstr::MakeLocationSummary(Zone* zone, |
5576 bool opt) const { | 5564 bool opt) const { |
5577 return MakeCallSummary(zone); | 5565 return MakeCallSummary(zone); |
5578 } | 5566 } |
5579 | 5567 |
(...skipping 27 matching lines...) Expand all Loading... |
5607 zone, kNumInputs, kNumTemps, LocationSummary::kCall); | 5595 zone, kNumInputs, kNumTemps, LocationSummary::kCall); |
5608 locs->set_in(0, Location::RegisterLocation(R0)); | 5596 locs->set_in(0, Location::RegisterLocation(R0)); |
5609 locs->set_out(0, Location::RegisterLocation(R0)); | 5597 locs->set_out(0, Location::RegisterLocation(R0)); |
5610 return locs; | 5598 return locs; |
5611 } | 5599 } |
5612 | 5600 |
5613 | 5601 |
5614 void GrowRegExpStackInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | 5602 void GrowRegExpStackInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
5615 const Register typed_data = locs()->in(0).reg(); | 5603 const Register typed_data = locs()->in(0).reg(); |
5616 const Register result = locs()->out(0).reg(); | 5604 const Register result = locs()->out(0).reg(); |
5617 __ PushObject(Object::null_object(), PP); | 5605 __ PushObject(Object::null_object()); |
5618 __ Push(typed_data); | 5606 __ Push(typed_data); |
5619 compiler->GenerateRuntimeCall(Scanner::kNoSourcePos, // No token position. | 5607 compiler->GenerateRuntimeCall(Scanner::kNoSourcePos, // No token position. |
5620 deopt_id(), | 5608 deopt_id(), |
5621 kGrowRegExpStackRuntimeEntry, | 5609 kGrowRegExpStackRuntimeEntry, |
5622 1, | 5610 1, |
5623 locs()); | 5611 locs()); |
5624 __ Drop(1); | 5612 __ Drop(1); |
5625 __ Pop(result); | 5613 __ Pop(result); |
5626 } | 5614 } |
5627 | 5615 |
5628 | 5616 |
5629 } // namespace dart | 5617 } // namespace dart |
5630 | 5618 |
5631 #endif // defined TARGET_ARCH_ARM64 | 5619 #endif // defined TARGET_ARCH_ARM64 |
OLD | NEW |