OLD | NEW |
1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, 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_ARM. | 5 #include "vm/globals.h" // Needed here to get TARGET_ARCH_ARM. |
6 #if defined(TARGET_ARCH_ARM) | 6 #if defined(TARGET_ARCH_ARM) |
7 | 7 |
8 #include "vm/flow_graph_compiler.h" | 8 #include "vm/flow_graph_compiler.h" |
9 | 9 |
10 #include "vm/ast_printer.h" | 10 #include "vm/ast_printer.h" |
(...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
111 builder->AddCallerFp(slot_ix++); | 111 builder->AddCallerFp(slot_ix++); |
112 builder->AddReturnAddress(current->function(), deopt_id(), slot_ix++); | 112 builder->AddReturnAddress(current->function(), deopt_id(), slot_ix++); |
113 | 113 |
114 // Emit all values that are needed for materialization as a part of the | 114 // Emit all values that are needed for materialization as a part of the |
115 // expression stack for the bottom-most frame. This guarantees that GC | 115 // expression stack for the bottom-most frame. This guarantees that GC |
116 // will be able to find them during materialization. | 116 // will be able to find them during materialization. |
117 slot_ix = builder->EmitMaterializationArguments(slot_ix); | 117 slot_ix = builder->EmitMaterializationArguments(slot_ix); |
118 | 118 |
119 // For the innermost environment, set outgoing arguments and the locals. | 119 // For the innermost environment, set outgoing arguments and the locals. |
120 for (intptr_t i = current->Length() - 1; | 120 for (intptr_t i = current->Length() - 1; |
121 i >= current->fixed_parameter_count(); | 121 i >= current->fixed_parameter_count(); i--) { |
122 i--) { | |
123 builder->AddCopy(current->ValueAt(i), current->LocationAt(i), slot_ix++); | 122 builder->AddCopy(current->ValueAt(i), current->LocationAt(i), slot_ix++); |
124 } | 123 } |
125 | 124 |
126 Environment* previous = current; | 125 Environment* previous = current; |
127 current = current->outer(); | 126 current = current->outer(); |
128 while (current != NULL) { | 127 while (current != NULL) { |
129 builder->AddPp(current->function(), slot_ix++); | 128 builder->AddPp(current->function(), slot_ix++); |
130 builder->AddPcMarker(previous->function(), slot_ix++); | 129 builder->AddPcMarker(previous->function(), slot_ix++); |
131 builder->AddCallerFp(slot_ix++); | 130 builder->AddCallerFp(slot_ix++); |
132 | 131 |
133 // For any outer environment the deopt id is that of the call instruction | 132 // For any outer environment the deopt id is that of the call instruction |
134 // which is recorded in the outer environment. | 133 // which is recorded in the outer environment. |
135 builder->AddReturnAddress( | 134 builder->AddReturnAddress(current->function(), |
136 current->function(), | 135 Thread::ToDeoptAfter(current->deopt_id()), |
137 Thread::ToDeoptAfter(current->deopt_id()), | 136 slot_ix++); |
138 slot_ix++); | |
139 | 137 |
140 // The values of outgoing arguments can be changed from the inlined call so | 138 // The values of outgoing arguments can be changed from the inlined call so |
141 // we must read them from the previous environment. | 139 // we must read them from the previous environment. |
142 for (intptr_t i = previous->fixed_parameter_count() - 1; i >= 0; i--) { | 140 for (intptr_t i = previous->fixed_parameter_count() - 1; i >= 0; i--) { |
143 builder->AddCopy(previous->ValueAt(i), | 141 builder->AddCopy(previous->ValueAt(i), previous->LocationAt(i), |
144 previous->LocationAt(i), | |
145 slot_ix++); | 142 slot_ix++); |
146 } | 143 } |
147 | 144 |
148 // Set the locals, note that outgoing arguments are not in the environment. | 145 // Set the locals, note that outgoing arguments are not in the environment. |
149 for (intptr_t i = current->Length() - 1; | 146 for (intptr_t i = current->Length() - 1; |
150 i >= current->fixed_parameter_count(); | 147 i >= current->fixed_parameter_count(); i--) { |
151 i--) { | 148 builder->AddCopy(current->ValueAt(i), current->LocationAt(i), slot_ix++); |
152 builder->AddCopy(current->ValueAt(i), | |
153 current->LocationAt(i), | |
154 slot_ix++); | |
155 } | 149 } |
156 | 150 |
157 // Iterate on the outer environment. | 151 // Iterate on the outer environment. |
158 previous = current; | 152 previous = current; |
159 current = current->outer(); | 153 current = current->outer(); |
160 } | 154 } |
161 // The previous pointer is now the outermost environment. | 155 // The previous pointer is now the outermost environment. |
162 ASSERT(previous != NULL); | 156 ASSERT(previous != NULL); |
163 | 157 |
164 // Set slots for the outermost environment. | 158 // Set slots for the outermost environment. |
(...skipping 116 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
281 __ b(is_not_instance_lbl, EQ); | 275 __ b(is_not_instance_lbl, EQ); |
282 } | 276 } |
283 // A function type test requires checking the function signature. | 277 // A function type test requires checking the function signature. |
284 if (!type.IsFunctionType()) { | 278 if (!type.IsFunctionType()) { |
285 const intptr_t num_type_args = type_class.NumTypeArguments(); | 279 const intptr_t num_type_args = type_class.NumTypeArguments(); |
286 const intptr_t num_type_params = type_class.NumTypeParameters(); | 280 const intptr_t num_type_params = type_class.NumTypeParameters(); |
287 const intptr_t from_index = num_type_args - num_type_params; | 281 const intptr_t from_index = num_type_args - num_type_params; |
288 const TypeArguments& type_arguments = | 282 const TypeArguments& type_arguments = |
289 TypeArguments::ZoneHandle(zone(), type.arguments()); | 283 TypeArguments::ZoneHandle(zone(), type.arguments()); |
290 const bool is_raw_type = type_arguments.IsNull() || | 284 const bool is_raw_type = type_arguments.IsNull() || |
291 type_arguments.IsRaw(from_index, num_type_params); | 285 type_arguments.IsRaw(from_index, num_type_params); |
292 if (is_raw_type) { | 286 if (is_raw_type) { |
293 const Register kClassIdReg = R2; | 287 const Register kClassIdReg = R2; |
294 // dynamic type argument, check only classes. | 288 // dynamic type argument, check only classes. |
295 __ LoadClassId(kClassIdReg, kInstanceReg); | 289 __ LoadClassId(kClassIdReg, kInstanceReg); |
296 __ CompareImmediate(kClassIdReg, type_class.id()); | 290 __ CompareImmediate(kClassIdReg, type_class.id()); |
297 __ b(is_instance_lbl, EQ); | 291 __ b(is_instance_lbl, EQ); |
298 // List is a very common case. | 292 // List is a very common case. |
299 if (IsListClass(type_class)) { | 293 if (IsListClass(type_class)) { |
300 GenerateListTypeCheck(kClassIdReg, is_instance_lbl); | 294 GenerateListTypeCheck(kClassIdReg, is_instance_lbl); |
301 } | 295 } |
302 return GenerateSubtype1TestCacheLookup( | 296 return GenerateSubtype1TestCacheLookup( |
303 token_pos, type_class, is_instance_lbl, is_not_instance_lbl); | 297 token_pos, type_class, is_instance_lbl, is_not_instance_lbl); |
304 } | 298 } |
305 // If one type argument only, check if type argument is Object or dynamic. | 299 // If one type argument only, check if type argument is Object or dynamic. |
306 if (type_arguments.Length() == 1) { | 300 if (type_arguments.Length() == 1) { |
307 const AbstractType& tp_argument = AbstractType::ZoneHandle( | 301 const AbstractType& tp_argument = |
308 zone(), type_arguments.TypeAt(0)); | 302 AbstractType::ZoneHandle(zone(), type_arguments.TypeAt(0)); |
309 ASSERT(!tp_argument.IsMalformed()); | 303 ASSERT(!tp_argument.IsMalformed()); |
310 if (tp_argument.IsType()) { | 304 if (tp_argument.IsType()) { |
311 ASSERT(tp_argument.HasResolvedTypeClass()); | 305 ASSERT(tp_argument.HasResolvedTypeClass()); |
312 // Check if type argument is dynamic or Object. | 306 // Check if type argument is dynamic or Object. |
313 const Type& object_type = Type::Handle(zone(), Type::ObjectType()); | 307 const Type& object_type = Type::Handle(zone(), Type::ObjectType()); |
314 if (object_type.IsSubtypeOf(tp_argument, NULL, NULL, Heap::kOld)) { | 308 if (object_type.IsSubtypeOf(tp_argument, NULL, NULL, Heap::kOld)) { |
315 // Instance class test only necessary. | 309 // Instance class test only necessary. |
316 return GenerateSubtype1TestCacheLookup( | 310 return GenerateSubtype1TestCacheLookup( |
317 token_pos, type_class, is_instance_lbl, is_not_instance_lbl); | 311 token_pos, type_class, is_instance_lbl, is_not_instance_lbl); |
318 } | 312 } |
319 } | 313 } |
320 } | 314 } |
321 } | 315 } |
322 // Regular subtype test cache involving instance's type arguments. | 316 // Regular subtype test cache involving instance's type arguments. |
323 const Register kTypeArgumentsReg = kNoRegister; | 317 const Register kTypeArgumentsReg = kNoRegister; |
324 const Register kTempReg = kNoRegister; | 318 const Register kTempReg = kNoRegister; |
325 // R0: instance (must be preserved). | 319 // R0: instance (must be preserved). |
326 return GenerateCallSubtypeTestStub(kTestTypeTwoArgs, | 320 return GenerateCallSubtypeTestStub(kTestTypeTwoArgs, kInstanceReg, |
327 kInstanceReg, | 321 kTypeArgumentsReg, kTempReg, |
328 kTypeArgumentsReg, | 322 is_instance_lbl, is_not_instance_lbl); |
329 kTempReg, | |
330 is_instance_lbl, | |
331 is_not_instance_lbl); | |
332 } | 323 } |
333 | 324 |
334 | 325 |
335 void FlowGraphCompiler::CheckClassIds(Register class_id_reg, | 326 void FlowGraphCompiler::CheckClassIds(Register class_id_reg, |
336 const GrowableArray<intptr_t>& class_ids, | 327 const GrowableArray<intptr_t>& class_ids, |
337 Label* is_equal_lbl, | 328 Label* is_equal_lbl, |
338 Label* is_not_equal_lbl) { | 329 Label* is_not_equal_lbl) { |
339 for (intptr_t i = 0; i < class_ids.length(); i++) { | 330 for (intptr_t i = 0; i < class_ids.length(); i++) { |
340 __ CompareImmediate(class_id_reg, class_ids[i]); | 331 __ CompareImmediate(class_id_reg, class_ids[i]); |
341 __ b(is_equal_lbl, EQ); | 332 __ b(is_equal_lbl, EQ); |
(...skipping 18 matching lines...) Expand all Loading... |
360 // Fallthrough. | 351 // Fallthrough. |
361 return true; | 352 return true; |
362 } | 353 } |
363 const Class& type_class = Class::Handle(zone(), type.type_class()); | 354 const Class& type_class = Class::Handle(zone(), type.type_class()); |
364 ASSERT(type_class.NumTypeArguments() == 0); | 355 ASSERT(type_class.NumTypeArguments() == 0); |
365 | 356 |
366 const Register kInstanceReg = R0; | 357 const Register kInstanceReg = R0; |
367 __ tst(kInstanceReg, Operand(kSmiTagMask)); | 358 __ tst(kInstanceReg, Operand(kSmiTagMask)); |
368 // If instance is Smi, check directly. | 359 // If instance is Smi, check directly. |
369 const Class& smi_class = Class::Handle(zone(), Smi::Class()); | 360 const Class& smi_class = Class::Handle(zone(), Smi::Class()); |
370 if (smi_class.IsSubtypeOf(TypeArguments::Handle(zone()), | 361 if (smi_class.IsSubtypeOf(TypeArguments::Handle(zone()), type_class, |
371 type_class, | 362 TypeArguments::Handle(zone()), NULL, NULL, |
372 TypeArguments::Handle(zone()), | |
373 NULL, | |
374 NULL, | |
375 Heap::kOld)) { | 363 Heap::kOld)) { |
376 __ b(is_instance_lbl, EQ); | 364 __ b(is_instance_lbl, EQ); |
377 } else { | 365 } else { |
378 __ b(is_not_instance_lbl, EQ); | 366 __ b(is_not_instance_lbl, EQ); |
379 } | 367 } |
380 const Register kClassIdReg = R2; | 368 const Register kClassIdReg = R2; |
381 __ LoadClassId(kClassIdReg, kInstanceReg); | 369 __ LoadClassId(kClassIdReg, kInstanceReg); |
382 // See ClassFinalizer::ResolveSuperTypeAndInterfaces for list of restricted | 370 // See ClassFinalizer::ResolveSuperTypeAndInterfaces for list of restricted |
383 // interfaces. | 371 // interfaces. |
384 // Bool interface can be implemented only by core class Bool. | 372 // Bool interface can be implemented only by core class Bool. |
385 if (type.IsBoolType()) { | 373 if (type.IsBoolType()) { |
386 __ CompareImmediate(kClassIdReg, kBoolCid); | 374 __ CompareImmediate(kClassIdReg, kBoolCid); |
387 __ b(is_instance_lbl, EQ); | 375 __ b(is_instance_lbl, EQ); |
388 __ b(is_not_instance_lbl); | 376 __ b(is_not_instance_lbl); |
389 return false; | 377 return false; |
390 } | 378 } |
391 // Custom checking for numbers (Smi, Mint, Bigint and Double). | 379 // Custom checking for numbers (Smi, Mint, Bigint and Double). |
392 // Note that instance is not Smi (checked above). | 380 // Note that instance is not Smi (checked above). |
393 if (type.IsNumberType() || type.IsIntType() || type.IsDoubleType()) { | 381 if (type.IsNumberType() || type.IsIntType() || type.IsDoubleType()) { |
394 GenerateNumberTypeCheck( | 382 GenerateNumberTypeCheck(kClassIdReg, type, is_instance_lbl, |
395 kClassIdReg, type, is_instance_lbl, is_not_instance_lbl); | 383 is_not_instance_lbl); |
396 return false; | 384 return false; |
397 } | 385 } |
398 if (type.IsStringType()) { | 386 if (type.IsStringType()) { |
399 GenerateStringTypeCheck(kClassIdReg, is_instance_lbl, is_not_instance_lbl); | 387 GenerateStringTypeCheck(kClassIdReg, is_instance_lbl, is_not_instance_lbl); |
400 return false; | 388 return false; |
401 } | 389 } |
402 if (type.IsDartFunctionType()) { | 390 if (type.IsDartFunctionType()) { |
403 // Check if instance is a closure. | 391 // Check if instance is a closure. |
404 __ CompareImmediate(kClassIdReg, kClosureCid); | 392 __ CompareImmediate(kClassIdReg, kClosureCid); |
405 __ b(is_instance_lbl, EQ); | 393 __ b(is_instance_lbl, EQ); |
(...skipping 26 matching lines...) Expand all Loading... |
432 __ LoadClass(R1, kInstanceReg, R2); | 420 __ LoadClass(R1, kInstanceReg, R2); |
433 // R1: instance class. | 421 // R1: instance class. |
434 // Check immediate superclass equality. | 422 // Check immediate superclass equality. |
435 __ ldr(R2, FieldAddress(R1, Class::super_type_offset())); | 423 __ ldr(R2, FieldAddress(R1, Class::super_type_offset())); |
436 __ ldr(R2, FieldAddress(R2, Type::type_class_id_offset())); | 424 __ ldr(R2, FieldAddress(R2, Type::type_class_id_offset())); |
437 __ CompareImmediate(R2, Smi::RawValue(type_class.id())); | 425 __ CompareImmediate(R2, Smi::RawValue(type_class.id())); |
438 __ b(is_instance_lbl, EQ); | 426 __ b(is_instance_lbl, EQ); |
439 | 427 |
440 const Register kTypeArgumentsReg = kNoRegister; | 428 const Register kTypeArgumentsReg = kNoRegister; |
441 const Register kTempReg = kNoRegister; | 429 const Register kTempReg = kNoRegister; |
442 return GenerateCallSubtypeTestStub(kTestTypeOneArg, | 430 return GenerateCallSubtypeTestStub(kTestTypeOneArg, kInstanceReg, |
443 kInstanceReg, | 431 kTypeArgumentsReg, kTempReg, |
444 kTypeArgumentsReg, | 432 is_instance_lbl, is_not_instance_lbl); |
445 kTempReg, | |
446 is_instance_lbl, | |
447 is_not_instance_lbl); | |
448 } | 433 } |
449 | 434 |
450 | 435 |
451 // Generates inlined check if 'type' is a type parameter or type itself | 436 // Generates inlined check if 'type' is a type parameter or type itself |
452 // R0: instance (preserved). | 437 // R0: instance (preserved). |
453 RawSubtypeTestCache* FlowGraphCompiler::GenerateUninstantiatedTypeTest( | 438 RawSubtypeTestCache* FlowGraphCompiler::GenerateUninstantiatedTypeTest( |
454 TokenPosition token_pos, | 439 TokenPosition token_pos, |
455 const AbstractType& type, | 440 const AbstractType& type, |
456 Label* is_instance_lbl, | 441 Label* is_instance_lbl, |
457 Label* is_not_instance_lbl) { | 442 Label* is_not_instance_lbl) { |
458 __ Comment("UninstantiatedTypeTest"); | 443 __ Comment("UninstantiatedTypeTest"); |
459 ASSERT(!type.IsInstantiated()); | 444 ASSERT(!type.IsInstantiated()); |
460 // Skip check if destination is a dynamic type. | 445 // Skip check if destination is a dynamic type. |
461 if (type.IsTypeParameter()) { | 446 if (type.IsTypeParameter()) { |
462 const TypeParameter& type_param = TypeParameter::Cast(type); | 447 const TypeParameter& type_param = TypeParameter::Cast(type); |
463 // Load instantiator type arguments on stack. | 448 // Load instantiator type arguments on stack. |
464 __ ldr(R1, Address(SP, 0)); // Get instantiator type arguments. | 449 __ ldr(R1, Address(SP, 0)); // Get instantiator type arguments. |
465 // R1: instantiator type arguments. | 450 // R1: instantiator type arguments. |
466 // Check if type arguments are null, i.e. equivalent to vector of dynamic. | 451 // Check if type arguments are null, i.e. equivalent to vector of dynamic. |
467 __ CompareObject(R1, Object::null_object()); | 452 __ CompareObject(R1, Object::null_object()); |
468 __ b(is_instance_lbl, EQ); | 453 __ b(is_instance_lbl, EQ); |
469 __ ldr(R2, | 454 __ ldr(R2, |
470 FieldAddress(R1, TypeArguments::type_at_offset(type_param.index()))); | 455 FieldAddress(R1, TypeArguments::type_at_offset(type_param.index()))); |
471 // R2: concrete type of type. | 456 // R2: concrete type of type. |
472 // Check if type argument is dynamic. | 457 // Check if type argument is dynamic. |
473 __ CompareObject(R2, Object::dynamic_type()); | 458 __ CompareObject(R2, Object::dynamic_type()); |
474 __ b(is_instance_lbl, EQ); | 459 __ b(is_instance_lbl, EQ); |
475 __ CompareObject(R2, Type::ZoneHandle(zone(), Type::ObjectType())); | 460 __ CompareObject(R2, Type::ZoneHandle(zone(), Type::ObjectType())); |
476 __ b(is_instance_lbl, EQ); | 461 __ b(is_instance_lbl, EQ); |
477 | 462 |
478 // For Smi check quickly against int and num interfaces. | 463 // For Smi check quickly against int and num interfaces. |
479 Label not_smi; | 464 Label not_smi; |
480 __ tst(R0, Operand(kSmiTagMask)); // Value is Smi? | 465 __ tst(R0, Operand(kSmiTagMask)); // Value is Smi? |
481 __ b(¬_smi, NE); | 466 __ b(¬_smi, NE); |
482 __ CompareObject(R2, Type::ZoneHandle(zone(), Type::IntType())); | 467 __ CompareObject(R2, Type::ZoneHandle(zone(), Type::IntType())); |
483 __ b(is_instance_lbl, EQ); | 468 __ b(is_instance_lbl, EQ); |
484 __ CompareObject(R2, Type::ZoneHandle(zone(), Type::Number())); | 469 __ CompareObject(R2, Type::ZoneHandle(zone(), Type::Number())); |
485 __ b(is_instance_lbl, EQ); | 470 __ b(is_instance_lbl, EQ); |
486 // Smi must be handled in runtime. | 471 // Smi must be handled in runtime. |
487 Label fall_through; | 472 Label fall_through; |
488 __ b(&fall_through); | 473 __ b(&fall_through); |
489 | 474 |
490 __ Bind(¬_smi); | 475 __ Bind(¬_smi); |
491 // R1: instantiator type arguments. | 476 // R1: instantiator type arguments. |
492 // R0: instance. | 477 // R0: instance. |
493 const Register kInstanceReg = R0; | 478 const Register kInstanceReg = R0; |
494 const Register kTypeArgumentsReg = R1; | 479 const Register kTypeArgumentsReg = R1; |
495 const Register kTempReg = kNoRegister; | 480 const Register kTempReg = kNoRegister; |
496 const SubtypeTestCache& type_test_cache = | 481 const SubtypeTestCache& type_test_cache = SubtypeTestCache::ZoneHandle( |
497 SubtypeTestCache::ZoneHandle(zone(), | 482 zone(), GenerateCallSubtypeTestStub( |
498 GenerateCallSubtypeTestStub(kTestTypeThreeArgs, | 483 kTestTypeThreeArgs, kInstanceReg, kTypeArgumentsReg, |
499 kInstanceReg, | 484 kTempReg, is_instance_lbl, is_not_instance_lbl)); |
500 kTypeArgumentsReg, | |
501 kTempReg, | |
502 is_instance_lbl, | |
503 is_not_instance_lbl)); | |
504 __ Bind(&fall_through); | 485 __ Bind(&fall_through); |
505 return type_test_cache.raw(); | 486 return type_test_cache.raw(); |
506 } | 487 } |
507 if (type.IsType()) { | 488 if (type.IsType()) { |
508 const Register kInstanceReg = R0; | 489 const Register kInstanceReg = R0; |
509 const Register kTypeArgumentsReg = R1; | 490 const Register kTypeArgumentsReg = R1; |
510 __ tst(kInstanceReg, Operand(kSmiTagMask)); // Is instance Smi? | 491 __ tst(kInstanceReg, Operand(kSmiTagMask)); // Is instance Smi? |
511 __ b(is_not_instance_lbl, EQ); | 492 __ b(is_not_instance_lbl, EQ); |
512 __ ldr(kTypeArgumentsReg, Address(SP, 0)); // Instantiator type args. | 493 __ ldr(kTypeArgumentsReg, Address(SP, 0)); // Instantiator type args. |
513 // Uninstantiated type class is known at compile time, but the type | 494 // Uninstantiated type class is known at compile time, but the type |
514 // arguments are determined at runtime by the instantiator. | 495 // arguments are determined at runtime by the instantiator. |
515 const Register kTempReg = kNoRegister; | 496 const Register kTempReg = kNoRegister; |
516 return GenerateCallSubtypeTestStub(kTestTypeThreeArgs, | 497 return GenerateCallSubtypeTestStub(kTestTypeThreeArgs, kInstanceReg, |
517 kInstanceReg, | 498 kTypeArgumentsReg, kTempReg, |
518 kTypeArgumentsReg, | 499 is_instance_lbl, is_not_instance_lbl); |
519 kTempReg, | |
520 is_instance_lbl, | |
521 is_not_instance_lbl); | |
522 } | 500 } |
523 return SubtypeTestCache::null(); | 501 return SubtypeTestCache::null(); |
524 } | 502 } |
525 | 503 |
526 | 504 |
527 // Inputs: | 505 // Inputs: |
528 // - R0: instance being type checked (preserved). | 506 // - R0: instance being type checked (preserved). |
529 // - R1: optional instantiator type arguments (preserved). | 507 // - R1: optional instantiator type arguments (preserved). |
530 // Clobbers R2, R3. | 508 // Clobbers R2, R3. |
531 // Returns: | 509 // Returns: |
(...skipping 11 matching lines...) Expand all Loading... |
543 // A non-null value is returned from a void function, which will result in a | 521 // A non-null value is returned from a void function, which will result in a |
544 // type error. A null value is handled prior to executing this inline code. | 522 // type error. A null value is handled prior to executing this inline code. |
545 return SubtypeTestCache::null(); | 523 return SubtypeTestCache::null(); |
546 } | 524 } |
547 if (type.IsInstantiated()) { | 525 if (type.IsInstantiated()) { |
548 const Class& type_class = Class::ZoneHandle(zone(), type.type_class()); | 526 const Class& type_class = Class::ZoneHandle(zone(), type.type_class()); |
549 // A class equality check is only applicable with a dst type (not a | 527 // A class equality check is only applicable with a dst type (not a |
550 // function type) of a non-parameterized class or with a raw dst type of | 528 // function type) of a non-parameterized class or with a raw dst type of |
551 // a parameterized class. | 529 // a parameterized class. |
552 if (type.IsFunctionType() || (type_class.NumTypeArguments() > 0)) { | 530 if (type.IsFunctionType() || (type_class.NumTypeArguments() > 0)) { |
553 return GenerateInstantiatedTypeWithArgumentsTest(token_pos, | 531 return GenerateInstantiatedTypeWithArgumentsTest( |
554 type, | 532 token_pos, type, is_instance_lbl, is_not_instance_lbl); |
555 is_instance_lbl, | |
556 is_not_instance_lbl); | |
557 // Fall through to runtime call. | 533 // Fall through to runtime call. |
558 } | 534 } |
559 const bool has_fall_through = | 535 const bool has_fall_through = GenerateInstantiatedTypeNoArgumentsTest( |
560 GenerateInstantiatedTypeNoArgumentsTest(token_pos, | 536 token_pos, type, is_instance_lbl, is_not_instance_lbl); |
561 type, | |
562 is_instance_lbl, | |
563 is_not_instance_lbl); | |
564 if (has_fall_through) { | 537 if (has_fall_through) { |
565 // If test non-conclusive so far, try the inlined type-test cache. | 538 // If test non-conclusive so far, try the inlined type-test cache. |
566 // 'type' is known at compile time. | 539 // 'type' is known at compile time. |
567 return GenerateSubtype1TestCacheLookup( | 540 return GenerateSubtype1TestCacheLookup( |
568 token_pos, type_class, is_instance_lbl, is_not_instance_lbl); | 541 token_pos, type_class, is_instance_lbl, is_not_instance_lbl); |
569 } else { | 542 } else { |
570 return SubtypeTestCache::null(); | 543 return SubtypeTestCache::null(); |
571 } | 544 } |
572 } | 545 } |
573 return GenerateUninstantiatedTypeTest(token_pos, | 546 return GenerateUninstantiatedTypeTest(token_pos, type, is_instance_lbl, |
574 type, | |
575 is_instance_lbl, | |
576 is_not_instance_lbl); | 547 is_not_instance_lbl); |
577 } | 548 } |
578 | 549 |
579 | 550 |
580 // If instanceof type test cannot be performed successfully at compile time and | 551 // If instanceof type test cannot be performed successfully at compile time and |
581 // therefore eliminated, optimize it by adding inlined tests for: | 552 // therefore eliminated, optimize it by adding inlined tests for: |
582 // - NULL -> return false. | 553 // - NULL -> return false. |
583 // - Smi -> compile time subtype check (only if dst class is not parameterized). | 554 // - Smi -> compile time subtype check (only if dst class is not parameterized). |
584 // - Class equality (only if class is not parameterized). | 555 // - Class equality (only if class is not parameterized). |
585 // Inputs: | 556 // Inputs: |
(...skipping 21 matching lines...) Expand all Loading... |
607 // instantiated). | 578 // instantiated). |
608 // We can only inline this null check if the type is instantiated at compile | 579 // We can only inline this null check if the type is instantiated at compile |
609 // time, since an uninstantiated type at compile time could be Object or | 580 // time, since an uninstantiated type at compile time could be Object or |
610 // dynamic at run time. | 581 // dynamic at run time. |
611 __ CompareObject(R0, Object::null_object()); | 582 __ CompareObject(R0, Object::null_object()); |
612 __ b(type.IsNullType() ? &is_instance : &is_not_instance, EQ); | 583 __ b(type.IsNullType() ? &is_instance : &is_not_instance, EQ); |
613 } | 584 } |
614 | 585 |
615 // Generate inline instanceof test. | 586 // Generate inline instanceof test. |
616 SubtypeTestCache& test_cache = SubtypeTestCache::ZoneHandle(zone()); | 587 SubtypeTestCache& test_cache = SubtypeTestCache::ZoneHandle(zone()); |
617 test_cache = GenerateInlineInstanceof(token_pos, type, | 588 test_cache = |
618 &is_instance, &is_not_instance); | 589 GenerateInlineInstanceof(token_pos, type, &is_instance, &is_not_instance); |
619 | 590 |
620 // test_cache is null if there is no fall-through. | 591 // test_cache is null if there is no fall-through. |
621 Label done; | 592 Label done; |
622 if (!test_cache.IsNull()) { | 593 if (!test_cache.IsNull()) { |
623 // Generate runtime call. | 594 // Generate runtime call. |
624 // Load instantiator type arguments (R1). | 595 // Load instantiator type arguments (R1). |
625 __ ldr(R1, Address(SP, 0 * kWordSize)); | 596 __ ldr(R1, Address(SP, 0 * kWordSize)); |
626 __ PushObject(Object::null_object()); // Make room for the result. | 597 __ PushObject(Object::null_object()); // Make room for the result. |
627 __ Push(R0); // Push the instance. | 598 __ Push(R0); // Push the instance. |
628 __ PushObject(type); // Push the type. | 599 __ PushObject(type); // Push the type. |
629 __ Push(R1); // Push instantiator type arguments (R1). | 600 __ Push(R1); // Push instantiator type arguments (R1). |
630 __ LoadUniqueObject(R0, test_cache); | 601 __ LoadUniqueObject(R0, test_cache); |
631 __ Push(R0); | 602 __ Push(R0); |
632 GenerateRuntimeCall(token_pos, deopt_id, kInstanceofRuntimeEntry, 4, locs); | 603 GenerateRuntimeCall(token_pos, deopt_id, kInstanceofRuntimeEntry, 4, locs); |
633 // Pop the parameters supplied to the runtime entry. The result of the | 604 // Pop the parameters supplied to the runtime entry. The result of the |
634 // instanceof runtime call will be left as the result of the operation. | 605 // instanceof runtime call will be left as the result of the operation. |
635 __ Drop(4); | 606 __ Drop(4); |
636 if (negate_result) { | 607 if (negate_result) { |
637 __ Pop(R1); | 608 __ Pop(R1); |
638 __ LoadObject(R0, Bool::True()); | 609 __ LoadObject(R0, Bool::True()); |
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
681 // Preserve instantiator type arguments (R1). | 652 // Preserve instantiator type arguments (R1). |
682 __ Push(R1); | 653 __ Push(R1); |
683 // A null object is always assignable and is returned as result. | 654 // A null object is always assignable and is returned as result. |
684 Label is_assignable, runtime_call; | 655 Label is_assignable, runtime_call; |
685 __ CompareObject(R0, Object::null_object()); | 656 __ CompareObject(R0, Object::null_object()); |
686 __ b(&is_assignable, EQ); | 657 __ b(&is_assignable, EQ); |
687 | 658 |
688 // Generate throw new TypeError() if the type is malformed or malbounded. | 659 // Generate throw new TypeError() if the type is malformed or malbounded. |
689 if (dst_type.IsMalformedOrMalbounded()) { | 660 if (dst_type.IsMalformedOrMalbounded()) { |
690 __ PushObject(Object::null_object()); // Make room for the result. | 661 __ PushObject(Object::null_object()); // Make room for the result. |
691 __ Push(R0); // Push the source object. | 662 __ Push(R0); // Push the source object. |
692 __ PushObject(dst_name); // Push the name of the destination. | 663 __ PushObject(dst_name); // Push the name of the destination. |
693 __ PushObject(dst_type); // Push the type of the destination. | 664 __ PushObject(dst_type); // Push the type of the destination. |
694 GenerateRuntimeCall(token_pos, | 665 GenerateRuntimeCall(token_pos, deopt_id, kBadTypeErrorRuntimeEntry, 3, |
695 deopt_id, | |
696 kBadTypeErrorRuntimeEntry, | |
697 3, | |
698 locs); | 666 locs); |
699 // We should never return here. | 667 // We should never return here. |
700 __ bkpt(0); | 668 __ bkpt(0); |
701 | 669 |
702 __ Bind(&is_assignable); // For a null object. | 670 __ Bind(&is_assignable); // For a null object. |
703 // Restore instantiator type arguments (R1). | 671 // Restore instantiator type arguments (R1). |
704 __ Pop(R1); | 672 __ Pop(R1); |
705 return; | 673 return; |
706 } | 674 } |
707 | 675 |
708 // Generate inline type check, linking to runtime call if not assignable. | 676 // Generate inline type check, linking to runtime call if not assignable. |
709 SubtypeTestCache& test_cache = SubtypeTestCache::ZoneHandle(zone()); | 677 SubtypeTestCache& test_cache = SubtypeTestCache::ZoneHandle(zone()); |
710 test_cache = GenerateInlineInstanceof(token_pos, dst_type, | 678 test_cache = GenerateInlineInstanceof(token_pos, dst_type, &is_assignable, |
711 &is_assignable, &runtime_call); | 679 &runtime_call); |
712 | 680 |
713 __ Bind(&runtime_call); | 681 __ Bind(&runtime_call); |
714 // Load instantiator type arguments (R1). | 682 // Load instantiator type arguments (R1). |
715 __ ldr(R1, Address(SP, 0 * kWordSize)); | 683 __ ldr(R1, Address(SP, 0 * kWordSize)); |
716 __ PushObject(Object::null_object()); // Make room for the result. | 684 __ PushObject(Object::null_object()); // Make room for the result. |
717 __ Push(R0); // Push the source object. | 685 __ Push(R0); // Push the source object. |
718 __ PushObject(dst_type); // Push the type of the destination. | 686 __ PushObject(dst_type); // Push the type of the destination. |
719 __ Push(R1); // Push instantiator type arguments (R1). | 687 __ Push(R1); // Push instantiator type arguments (R1). |
720 __ PushObject(dst_name); // Push the name of the destination. | 688 __ PushObject(dst_name); // Push the name of the destination. |
721 __ LoadUniqueObject(R0, test_cache); | 689 __ LoadUniqueObject(R0, test_cache); |
722 __ Push(R0); | 690 __ Push(R0); |
723 GenerateRuntimeCall(token_pos, deopt_id, kTypeCheckRuntimeEntry, 5, locs); | 691 GenerateRuntimeCall(token_pos, deopt_id, kTypeCheckRuntimeEntry, 5, locs); |
724 // Pop the parameters supplied to the runtime entry. The result of the | 692 // Pop the parameters supplied to the runtime entry. The result of the |
725 // type check runtime call is the checked value. | 693 // type check runtime call is the checked value. |
726 __ Drop(5); | 694 __ Drop(5); |
727 __ Pop(R0); | 695 __ Pop(R0); |
728 | 696 |
729 __ Bind(&is_assignable); | 697 __ Bind(&is_assignable); |
(...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
798 __ Bind(&loop); | 766 __ Bind(&loop); |
799 __ ldr(IP, argument_addr); | 767 __ ldr(IP, argument_addr); |
800 __ str(IP, copy_addr); | 768 __ str(IP, copy_addr); |
801 __ Bind(&loop_condition); | 769 __ Bind(&loop_condition); |
802 __ subs(R6, R6, Operand(1)); | 770 __ subs(R6, R6, Operand(1)); |
803 __ b(&loop, PL); | 771 __ b(&loop, PL); |
804 | 772 |
805 // Copy or initialize optional named arguments. | 773 // Copy or initialize optional named arguments. |
806 Label all_arguments_processed; | 774 Label all_arguments_processed; |
807 #ifdef DEBUG | 775 #ifdef DEBUG |
808 const bool check_correct_named_args = true; | 776 const bool check_correct_named_args = true; |
809 #else | 777 #else |
810 const bool check_correct_named_args = function.IsClosureFunction(); | 778 const bool check_correct_named_args = function.IsClosureFunction(); |
811 #endif | 779 #endif |
812 if (num_opt_named_params > 0) { | 780 if (num_opt_named_params > 0) { |
813 // Start by alphabetically sorting the names of the optional parameters. | 781 // Start by alphabetically sorting the names of the optional parameters. |
814 LocalVariable** opt_param = new LocalVariable*[num_opt_named_params]; | 782 LocalVariable** opt_param = new LocalVariable*[num_opt_named_params]; |
815 int* opt_param_position = new int[num_opt_named_params]; | 783 int* opt_param_position = new int[num_opt_named_params]; |
816 for (int pos = num_fixed_params; pos < num_params; pos++) { | 784 for (int pos = num_fixed_params; pos < num_params; pos++) { |
817 LocalVariable* parameter = scope->VariableAt(pos); | 785 LocalVariable* parameter = scope->VariableAt(pos); |
818 const String& opt_param_name = parameter->name(); | 786 const String& opt_param_name = parameter->name(); |
819 int i = pos - num_fixed_params; | 787 int i = pos - num_fixed_params; |
820 while (--i >= 0) { | 788 while (--i >= 0) { |
(...skipping 10 matching lines...) Expand all Loading... |
831 // Generate code handling each optional parameter in alphabetical order. | 799 // Generate code handling each optional parameter in alphabetical order. |
832 __ ldr(NOTFP, FieldAddress(R4, ArgumentsDescriptor::count_offset())); | 800 __ ldr(NOTFP, FieldAddress(R4, ArgumentsDescriptor::count_offset())); |
833 __ ldr(R6, | 801 __ ldr(R6, |
834 FieldAddress(R4, ArgumentsDescriptor::positional_count_offset())); | 802 FieldAddress(R4, ArgumentsDescriptor::positional_count_offset())); |
835 __ SmiUntag(R6); | 803 __ SmiUntag(R6); |
836 // Let NOTFP point to the first passed argument, i.e. to | 804 // Let NOTFP point to the first passed argument, i.e. to |
837 // fp[kParamEndSlotFromFp + num_args - 0]; num_args (NOTFP) is Smi. | 805 // fp[kParamEndSlotFromFp + num_args - 0]; num_args (NOTFP) is Smi. |
838 __ add(NOTFP, FP, Operand(NOTFP, LSL, 1)); | 806 __ add(NOTFP, FP, Operand(NOTFP, LSL, 1)); |
839 __ AddImmediate(NOTFP, NOTFP, kParamEndSlotFromFp * kWordSize); | 807 __ AddImmediate(NOTFP, NOTFP, kParamEndSlotFromFp * kWordSize); |
840 // Let R8 point to the entry of the first named argument. | 808 // Let R8 point to the entry of the first named argument. |
841 __ add(R8, R4, Operand( | 809 __ add(R8, R4, Operand(ArgumentsDescriptor::first_named_entry_offset() - |
842 ArgumentsDescriptor::first_named_entry_offset() - kHeapObjectTag)); | 810 kHeapObjectTag)); |
843 for (int i = 0; i < num_opt_named_params; i++) { | 811 for (int i = 0; i < num_opt_named_params; i++) { |
844 Label load_default_value, assign_optional_parameter; | 812 Label load_default_value, assign_optional_parameter; |
845 const int param_pos = opt_param_position[i]; | 813 const int param_pos = opt_param_position[i]; |
846 // Check if this named parameter was passed in. | 814 // Check if this named parameter was passed in. |
847 // Load R9 with the name of the argument. | 815 // Load R9 with the name of the argument. |
848 __ ldr(R9, Address(R8, ArgumentsDescriptor::name_offset())); | 816 __ ldr(R9, Address(R8, ArgumentsDescriptor::name_offset())); |
849 ASSERT(opt_param[i]->name().IsSymbol()); | 817 ASSERT(opt_param[i]->name().IsSymbol()); |
850 __ CompareObject(R9, opt_param[i]->name()); | 818 __ CompareObject(R9, opt_param[i]->name()); |
851 __ b(&load_default_value, NE); | 819 __ b(&load_default_value, NE); |
852 // Load R9 with passed-in argument at provided arg_pos, i.e. at | 820 // Load R9 with passed-in argument at provided arg_pos, i.e. at |
(...skipping 118 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
971 __ LoadObject(R0, Object::null_object()); | 939 __ LoadObject(R0, Object::null_object()); |
972 __ Ret(); | 940 __ Ret(); |
973 } | 941 } |
974 | 942 |
975 | 943 |
976 static const Register new_pp = NOTFP; | 944 static const Register new_pp = NOTFP; |
977 | 945 |
978 | 946 |
979 void FlowGraphCompiler::EmitFrameEntry() { | 947 void FlowGraphCompiler::EmitFrameEntry() { |
980 const Function& function = parsed_function().function(); | 948 const Function& function = parsed_function().function(); |
981 if (CanOptimizeFunction() && | 949 if (CanOptimizeFunction() && function.IsOptimizable() && |
982 function.IsOptimizable() && | |
983 (!is_optimizing() || may_reoptimize())) { | 950 (!is_optimizing() || may_reoptimize())) { |
984 __ Comment("Invocation Count Check"); | 951 __ Comment("Invocation Count Check"); |
985 const Register function_reg = R8; | 952 const Register function_reg = R8; |
986 // The pool pointer is not setup before entering the Dart frame. | 953 // The pool pointer is not setup before entering the Dart frame. |
987 // Temporarily setup pool pointer for this dart function. | 954 // Temporarily setup pool pointer for this dart function. |
988 __ LoadPoolPointer(new_pp); | 955 __ LoadPoolPointer(new_pp); |
989 // Load function object from object pool. | 956 // Load function object from object pool. |
990 __ LoadFunctionFromCalleePool(function_reg, function, new_pp); | 957 __ LoadFunctionFromCalleePool(function_reg, function, new_pp); |
991 | 958 |
992 __ ldr(R3, FieldAddress(function_reg, | 959 __ ldr(R3, FieldAddress(function_reg, Function::usage_counter_offset())); |
993 Function::usage_counter_offset())); | |
994 // Reoptimization of an optimized function is triggered by counting in | 960 // Reoptimization of an optimized function is triggered by counting in |
995 // IC stubs, but not at the entry of the function. | 961 // IC stubs, but not at the entry of the function. |
996 if (!is_optimizing()) { | 962 if (!is_optimizing()) { |
997 __ add(R3, R3, Operand(1)); | 963 __ add(R3, R3, Operand(1)); |
998 __ str(R3, FieldAddress(function_reg, | 964 __ str(R3, FieldAddress(function_reg, Function::usage_counter_offset())); |
999 Function::usage_counter_offset())); | |
1000 } | 965 } |
1001 __ CompareImmediate(R3, GetOptimizationThreshold()); | 966 __ CompareImmediate(R3, GetOptimizationThreshold()); |
1002 ASSERT(function_reg == R8); | 967 ASSERT(function_reg == R8); |
1003 __ Branch(*StubCode::OptimizeFunction_entry(), kNotPatchable, new_pp, GE); | 968 __ Branch(*StubCode::OptimizeFunction_entry(), kNotPatchable, new_pp, GE); |
1004 } | 969 } |
1005 __ Comment("Enter frame"); | 970 __ Comment("Enter frame"); |
1006 if (flow_graph().IsCompiledForOsr()) { | 971 if (flow_graph().IsCompiledForOsr()) { |
1007 intptr_t extra_slots = StackSize() | 972 intptr_t extra_slots = StackSize() - flow_graph().num_stack_locals() - |
1008 - flow_graph().num_stack_locals() | 973 flow_graph().num_copied_params(); |
1009 - flow_graph().num_copied_params(); | |
1010 ASSERT(extra_slots >= 0); | 974 ASSERT(extra_slots >= 0); |
1011 __ EnterOsrFrame(extra_slots * kWordSize); | 975 __ EnterOsrFrame(extra_slots * kWordSize); |
1012 } else { | 976 } else { |
1013 ASSERT(StackSize() >= 0); | 977 ASSERT(StackSize() >= 0); |
1014 __ EnterDartFrame(StackSize() * kWordSize); | 978 __ EnterDartFrame(StackSize() * kWordSize); |
1015 } | 979 } |
1016 } | 980 } |
1017 | 981 |
1018 | 982 |
1019 // Input parameters: | 983 // Input parameters: |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1052 if (num_copied_params == 0) { | 1016 if (num_copied_params == 0) { |
1053 const bool check_arguments = | 1017 const bool check_arguments = |
1054 function.IsClosureFunction() && !flow_graph().IsCompiledForOsr(); | 1018 function.IsClosureFunction() && !flow_graph().IsCompiledForOsr(); |
1055 if (check_arguments) { | 1019 if (check_arguments) { |
1056 __ Comment("Check argument count"); | 1020 __ Comment("Check argument count"); |
1057 // Check that exactly num_fixed arguments are passed in. | 1021 // Check that exactly num_fixed arguments are passed in. |
1058 Label correct_num_arguments, wrong_num_arguments; | 1022 Label correct_num_arguments, wrong_num_arguments; |
1059 __ ldr(R0, FieldAddress(R4, ArgumentsDescriptor::count_offset())); | 1023 __ ldr(R0, FieldAddress(R4, ArgumentsDescriptor::count_offset())); |
1060 __ CompareImmediate(R0, Smi::RawValue(num_fixed_params)); | 1024 __ CompareImmediate(R0, Smi::RawValue(num_fixed_params)); |
1061 __ b(&wrong_num_arguments, NE); | 1025 __ b(&wrong_num_arguments, NE); |
1062 __ ldr(R1, FieldAddress(R4, | 1026 __ ldr(R1, |
1063 ArgumentsDescriptor::positional_count_offset())); | 1027 FieldAddress(R4, ArgumentsDescriptor::positional_count_offset())); |
1064 __ cmp(R0, Operand(R1)); | 1028 __ cmp(R0, Operand(R1)); |
1065 __ b(&correct_num_arguments, EQ); | 1029 __ b(&correct_num_arguments, EQ); |
1066 __ Bind(&wrong_num_arguments); | 1030 __ Bind(&wrong_num_arguments); |
1067 ASSERT(assembler()->constant_pool_allowed()); | 1031 ASSERT(assembler()->constant_pool_allowed()); |
1068 __ LeaveDartFrame(kKeepCalleePP); // Arguments are still on the stack. | 1032 __ LeaveDartFrame(kKeepCalleePP); // Arguments are still on the stack. |
1069 __ Branch(*StubCode::CallClosureNoSuchMethod_entry()); | 1033 __ Branch(*StubCode::CallClosureNoSuchMethod_entry()); |
1070 // The noSuchMethod call may return to the caller, but not here. | 1034 // The noSuchMethod call may return to the caller, but not here. |
1071 __ Bind(&correct_num_arguments); | 1035 __ Bind(&correct_num_arguments); |
1072 } | 1036 } |
1073 } else if (!flow_graph().IsCompiledForOsr()) { | 1037 } else if (!flow_graph().IsCompiledForOsr()) { |
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1139 AddCurrentDescriptor(kind, deopt_id, token_pos); | 1103 AddCurrentDescriptor(kind, deopt_id, token_pos); |
1140 RecordSafepoint(locs); | 1104 RecordSafepoint(locs); |
1141 // Marks either the continuation point in unoptimized code or the | 1105 // Marks either the continuation point in unoptimized code or the |
1142 // deoptimization point in optimized code, after call. | 1106 // deoptimization point in optimized code, after call. |
1143 const intptr_t deopt_id_after = Thread::ToDeoptAfter(deopt_id); | 1107 const intptr_t deopt_id_after = Thread::ToDeoptAfter(deopt_id); |
1144 if (is_optimizing()) { | 1108 if (is_optimizing()) { |
1145 AddDeoptIndexAtCall(deopt_id_after); | 1109 AddDeoptIndexAtCall(deopt_id_after); |
1146 } else { | 1110 } else { |
1147 // Add deoptimization continuation point after the call and before the | 1111 // Add deoptimization continuation point after the call and before the |
1148 // arguments are removed. | 1112 // arguments are removed. |
1149 AddCurrentDescriptor(RawPcDescriptors::kDeopt, | 1113 AddCurrentDescriptor(RawPcDescriptors::kDeopt, deopt_id_after, token_pos); |
1150 deopt_id_after, token_pos); | |
1151 } | 1114 } |
1152 } | 1115 } |
1153 | 1116 |
1154 | 1117 |
1155 void FlowGraphCompiler::GenerateStaticDartCall(intptr_t deopt_id, | 1118 void FlowGraphCompiler::GenerateStaticDartCall(intptr_t deopt_id, |
1156 TokenPosition token_pos, | 1119 TokenPosition token_pos, |
1157 const StubEntry& stub_entry, | 1120 const StubEntry& stub_entry, |
1158 RawPcDescriptors::Kind kind, | 1121 RawPcDescriptors::Kind kind, |
1159 LocationSummary* locs, | 1122 LocationSummary* locs, |
1160 const Function& target) { | 1123 const Function& target) { |
1161 // Call sites to the same target can share object pool entries. These | 1124 // Call sites to the same target can share object pool entries. These |
1162 // call sites are never patched for breakpoints: the function is deoptimized | 1125 // call sites are never patched for breakpoints: the function is deoptimized |
1163 // and the unoptimized code with IC calls for static calls is patched instead. | 1126 // and the unoptimized code with IC calls for static calls is patched instead. |
1164 ASSERT(is_optimizing()); | 1127 ASSERT(is_optimizing()); |
1165 __ BranchLinkWithEquivalence(stub_entry, target); | 1128 __ BranchLinkWithEquivalence(stub_entry, target); |
1166 | 1129 |
1167 AddCurrentDescriptor(kind, deopt_id, token_pos); | 1130 AddCurrentDescriptor(kind, deopt_id, token_pos); |
1168 RecordSafepoint(locs); | 1131 RecordSafepoint(locs); |
1169 // Marks either the continuation point in unoptimized code or the | 1132 // Marks either the continuation point in unoptimized code or the |
1170 // deoptimization point in optimized code, after call. | 1133 // deoptimization point in optimized code, after call. |
1171 const intptr_t deopt_id_after = Thread::ToDeoptAfter(deopt_id); | 1134 const intptr_t deopt_id_after = Thread::ToDeoptAfter(deopt_id); |
1172 if (is_optimizing()) { | 1135 if (is_optimizing()) { |
1173 AddDeoptIndexAtCall(deopt_id_after); | 1136 AddDeoptIndexAtCall(deopt_id_after); |
1174 } else { | 1137 } else { |
1175 // Add deoptimization continuation point after the call and before the | 1138 // Add deoptimization continuation point after the call and before the |
1176 // arguments are removed. | 1139 // arguments are removed. |
1177 AddCurrentDescriptor(RawPcDescriptors::kDeopt, | 1140 AddCurrentDescriptor(RawPcDescriptors::kDeopt, deopt_id_after, token_pos); |
1178 deopt_id_after, token_pos); | |
1179 } | 1141 } |
1180 AddStaticCallTarget(target); | 1142 AddStaticCallTarget(target); |
1181 } | 1143 } |
1182 | 1144 |
1183 | 1145 |
1184 void FlowGraphCompiler::GenerateRuntimeCall(TokenPosition token_pos, | 1146 void FlowGraphCompiler::GenerateRuntimeCall(TokenPosition token_pos, |
1185 intptr_t deopt_id, | 1147 intptr_t deopt_id, |
1186 const RuntimeEntry& entry, | 1148 const RuntimeEntry& entry, |
1187 intptr_t argument_count, | 1149 intptr_t argument_count, |
1188 LocationSummary* locs) { | 1150 LocationSummary* locs) { |
1189 __ CallRuntime(entry, argument_count); | 1151 __ CallRuntime(entry, argument_count); |
1190 AddCurrentDescriptor(RawPcDescriptors::kOther, deopt_id, token_pos); | 1152 AddCurrentDescriptor(RawPcDescriptors::kOther, deopt_id, token_pos); |
1191 RecordSafepoint(locs); | 1153 RecordSafepoint(locs); |
1192 if (deopt_id != Thread::kNoDeoptId) { | 1154 if (deopt_id != Thread::kNoDeoptId) { |
1193 // Marks either the continuation point in unoptimized code or the | 1155 // Marks either the continuation point in unoptimized code or the |
1194 // deoptimization point in optimized code, after call. | 1156 // deoptimization point in optimized code, after call. |
1195 const intptr_t deopt_id_after = Thread::ToDeoptAfter(deopt_id); | 1157 const intptr_t deopt_id_after = Thread::ToDeoptAfter(deopt_id); |
1196 if (is_optimizing()) { | 1158 if (is_optimizing()) { |
1197 AddDeoptIndexAtCall(deopt_id_after); | 1159 AddDeoptIndexAtCall(deopt_id_after); |
1198 } else { | 1160 } else { |
1199 // Add deoptimization continuation point after the call and before the | 1161 // Add deoptimization continuation point after the call and before the |
1200 // arguments are removed. | 1162 // arguments are removed. |
1201 AddCurrentDescriptor(RawPcDescriptors::kDeopt, | 1163 AddCurrentDescriptor(RawPcDescriptors::kDeopt, deopt_id_after, token_pos); |
1202 deopt_id_after, | |
1203 token_pos); | |
1204 } | 1164 } |
1205 } | 1165 } |
1206 } | 1166 } |
1207 | 1167 |
1208 | 1168 |
1209 void FlowGraphCompiler::EmitEdgeCounter(intptr_t edge_id) { | 1169 void FlowGraphCompiler::EmitEdgeCounter(intptr_t edge_id) { |
1210 // We do not check for overflow when incrementing the edge counter. The | 1170 // We do not check for overflow when incrementing the edge counter. The |
1211 // function should normally be optimized long before the counter can | 1171 // function should normally be optimized long before the counter can |
1212 // overflow; and though we do not reset the counters when we optimize or | 1172 // overflow; and though we do not reset the counters when we optimize or |
1213 // deoptimize, there is a bound on the number of | 1173 // deoptimize, there is a bound on the number of |
1214 // optimization/deoptimization cycles we will attempt. | 1174 // optimization/deoptimization cycles we will attempt. |
1215 ASSERT(!edge_counters_array_.IsNull()); | 1175 ASSERT(!edge_counters_array_.IsNull()); |
1216 ASSERT(assembler_->constant_pool_allowed()); | 1176 ASSERT(assembler_->constant_pool_allowed()); |
1217 __ Comment("Edge counter"); | 1177 __ Comment("Edge counter"); |
1218 __ LoadObject(R0, edge_counters_array_); | 1178 __ LoadObject(R0, edge_counters_array_); |
1219 #if defined(DEBUG) | 1179 #if defined(DEBUG) |
1220 bool old_use_far_branches = assembler_->use_far_branches(); | 1180 bool old_use_far_branches = assembler_->use_far_branches(); |
1221 assembler_->set_use_far_branches(true); | 1181 assembler_->set_use_far_branches(true); |
1222 #endif // DEBUG | 1182 #endif // DEBUG |
1223 __ LoadFieldFromOffset(kWord, R1, R0, Array::element_offset(edge_id)); | 1183 __ LoadFieldFromOffset(kWord, R1, R0, Array::element_offset(edge_id)); |
1224 __ add(R1, R1, Operand(Smi::RawValue(1))); | 1184 __ add(R1, R1, Operand(Smi::RawValue(1))); |
1225 __ StoreIntoObjectNoBarrierOffset(R0, Array::element_offset(edge_id), R1); | 1185 __ StoreIntoObjectNoBarrierOffset(R0, Array::element_offset(edge_id), R1); |
1226 #if defined(DEBUG) | 1186 #if defined(DEBUG) |
1227 assembler_->set_use_far_branches(old_use_far_branches); | 1187 assembler_->set_use_far_branches(old_use_far_branches); |
1228 #endif // DEBUG | 1188 #endif // DEBUG |
1229 } | 1189 } |
1230 | 1190 |
1231 | 1191 |
1232 void FlowGraphCompiler::EmitOptimizedInstanceCall( | 1192 void FlowGraphCompiler::EmitOptimizedInstanceCall(const StubEntry& stub_entry, |
1233 const StubEntry& stub_entry, | 1193 const ICData& ic_data, |
1234 const ICData& ic_data, | 1194 intptr_t argument_count, |
1235 intptr_t argument_count, | 1195 intptr_t deopt_id, |
1236 intptr_t deopt_id, | 1196 TokenPosition token_pos, |
1237 TokenPosition token_pos, | 1197 LocationSummary* locs) { |
1238 LocationSummary* locs) { | |
1239 ASSERT(Array::Handle(zone(), ic_data.arguments_descriptor()).Length() > 0); | 1198 ASSERT(Array::Handle(zone(), ic_data.arguments_descriptor()).Length() > 0); |
1240 // Each ICData propagated from unoptimized to optimized code contains the | 1199 // Each ICData propagated from unoptimized to optimized code contains the |
1241 // function that corresponds to the Dart function of that IC call. Due | 1200 // function that corresponds to the Dart function of that IC call. Due |
1242 // to inlining in optimized code, that function may not correspond to the | 1201 // to inlining in optimized code, that function may not correspond to the |
1243 // top-level function (parsed_function().function()) which could be | 1202 // top-level function (parsed_function().function()) which could be |
1244 // reoptimized and which counter needs to be incremented. | 1203 // reoptimized and which counter needs to be incremented. |
1245 // Pass the function explicitly, it is used in IC stub. | 1204 // Pass the function explicitly, it is used in IC stub. |
1246 | 1205 |
1247 __ LoadObject(R8, parsed_function().function()); | 1206 __ LoadObject(R8, parsed_function().function()); |
1248 __ LoadUniqueObject(R9, ic_data); | 1207 __ LoadUniqueObject(R9, ic_data); |
1249 GenerateDartCall(deopt_id, | 1208 GenerateDartCall(deopt_id, token_pos, stub_entry, RawPcDescriptors::kIcCall, |
1250 token_pos, | |
1251 stub_entry, | |
1252 RawPcDescriptors::kIcCall, | |
1253 locs); | 1209 locs); |
1254 __ Drop(argument_count); | 1210 __ Drop(argument_count); |
1255 } | 1211 } |
1256 | 1212 |
1257 | 1213 |
1258 void FlowGraphCompiler::EmitInstanceCall(const StubEntry& stub_entry, | 1214 void FlowGraphCompiler::EmitInstanceCall(const StubEntry& stub_entry, |
1259 const ICData& ic_data, | 1215 const ICData& ic_data, |
1260 intptr_t argument_count, | 1216 intptr_t argument_count, |
1261 intptr_t deopt_id, | 1217 intptr_t deopt_id, |
1262 TokenPosition token_pos, | 1218 TokenPosition token_pos, |
1263 LocationSummary* locs) { | 1219 LocationSummary* locs) { |
1264 ASSERT(Array::Handle(zone(), ic_data.arguments_descriptor()).Length() > 0); | 1220 ASSERT(Array::Handle(zone(), ic_data.arguments_descriptor()).Length() > 0); |
1265 __ LoadUniqueObject(R9, ic_data); | 1221 __ LoadUniqueObject(R9, ic_data); |
1266 GenerateDartCall(deopt_id, | 1222 GenerateDartCall(deopt_id, token_pos, stub_entry, RawPcDescriptors::kIcCall, |
1267 token_pos, | |
1268 stub_entry, | |
1269 RawPcDescriptors::kIcCall, | |
1270 locs); | 1223 locs); |
1271 __ Drop(argument_count); | 1224 __ Drop(argument_count); |
1272 } | 1225 } |
1273 | 1226 |
1274 | 1227 |
1275 void FlowGraphCompiler::EmitMegamorphicInstanceCall( | 1228 void FlowGraphCompiler::EmitMegamorphicInstanceCall( |
1276 const ICData& ic_data, | 1229 const ICData& ic_data, |
1277 intptr_t argument_count, | 1230 intptr_t argument_count, |
1278 intptr_t deopt_id, | 1231 intptr_t deopt_id, |
1279 TokenPosition token_pos, | 1232 TokenPosition token_pos, |
1280 LocationSummary* locs, | 1233 LocationSummary* locs, |
1281 intptr_t try_index, | 1234 intptr_t try_index, |
1282 intptr_t slow_path_argument_count) { | 1235 intptr_t slow_path_argument_count) { |
1283 const String& name = String::Handle(zone(), ic_data.target_name()); | 1236 const String& name = String::Handle(zone(), ic_data.target_name()); |
1284 const Array& arguments_descriptor = | 1237 const Array& arguments_descriptor = |
1285 Array::ZoneHandle(zone(), ic_data.arguments_descriptor()); | 1238 Array::ZoneHandle(zone(), ic_data.arguments_descriptor()); |
1286 ASSERT(!arguments_descriptor.IsNull() && (arguments_descriptor.Length() > 0)); | 1239 ASSERT(!arguments_descriptor.IsNull() && (arguments_descriptor.Length() > 0)); |
1287 const MegamorphicCache& cache = MegamorphicCache::ZoneHandle(zone(), | 1240 const MegamorphicCache& cache = MegamorphicCache::ZoneHandle( |
| 1241 zone(), |
1288 MegamorphicCacheTable::Lookup(isolate(), name, arguments_descriptor)); | 1242 MegamorphicCacheTable::Lookup(isolate(), name, arguments_descriptor)); |
1289 | 1243 |
1290 __ Comment("MegamorphicCall"); | 1244 __ Comment("MegamorphicCall"); |
1291 // Load receiver into R0. | 1245 // Load receiver into R0. |
1292 __ LoadFromOffset(kWord, R0, SP, (argument_count - 1) * kWordSize); | 1246 __ LoadFromOffset(kWord, R0, SP, (argument_count - 1) * kWordSize); |
1293 Label done; | 1247 Label done; |
1294 if (ShouldInlineSmiStringHashCode(ic_data)) { | 1248 if (ShouldInlineSmiStringHashCode(ic_data)) { |
1295 Label megamorphic_call; | 1249 Label megamorphic_call; |
1296 __ Comment("Inlined get:hashCode for Smi and OneByteString"); | 1250 __ Comment("Inlined get:hashCode for Smi and OneByteString"); |
1297 __ tst(R0, Operand(kSmiTagMask)); | 1251 __ tst(R0, Operand(kSmiTagMask)); |
1298 __ b(&done, EQ); // Is Smi (result is receiver). | 1252 __ b(&done, EQ); // Is Smi (result is receiver). |
1299 | 1253 |
1300 // Use R9 (cache for megamorphic call) as scratch. | 1254 // Use R9 (cache for megamorphic call) as scratch. |
1301 __ CompareClassId(R0, kOneByteStringCid, R9); | 1255 __ CompareClassId(R0, kOneByteStringCid, R9); |
1302 __ b(&megamorphic_call, NE); | 1256 __ b(&megamorphic_call, NE); |
1303 | 1257 |
1304 __ mov(R9, Operand(R0)); // Preserve receiver in R9. | 1258 __ mov(R9, Operand(R0)); // Preserve receiver in R9. |
1305 __ ldr(R0, FieldAddress(R0, String::hash_offset())); | 1259 __ ldr(R0, FieldAddress(R0, String::hash_offset())); |
1306 ASSERT(Smi::New(0) == 0); | 1260 ASSERT(Smi::New(0) == 0); |
1307 __ cmp(R0, Operand(0)); | 1261 __ cmp(R0, Operand(0)); |
1308 | 1262 |
1309 __ b(&done, NE); // Return if already computed. | 1263 __ b(&done, NE); // Return if already computed. |
1310 __ mov(R0, Operand(R9)); // Restore receiver in R0. | 1264 __ mov(R0, Operand(R9)); // Restore receiver in R0. |
1311 | 1265 |
1312 __ Bind(&megamorphic_call); | 1266 __ Bind(&megamorphic_call); |
1313 __ Comment("Slow case: megamorphic call"); | 1267 __ Comment("Slow case: megamorphic call"); |
1314 } | 1268 } |
1315 __ LoadObject(R9, cache); | 1269 __ LoadObject(R9, cache); |
1316 __ ldr(LR, Address(THR, Thread::megamorphic_call_checked_entry_offset())); | 1270 __ ldr(LR, Address(THR, Thread::megamorphic_call_checked_entry_offset())); |
1317 __ blx(LR); | 1271 __ blx(LR); |
1318 | 1272 |
1319 __ Bind(&done); | 1273 __ Bind(&done); |
1320 RecordSafepoint(locs, slow_path_argument_count); | 1274 RecordSafepoint(locs, slow_path_argument_count); |
1321 const intptr_t deopt_id_after = Thread::ToDeoptAfter(deopt_id); | 1275 const intptr_t deopt_id_after = Thread::ToDeoptAfter(deopt_id); |
1322 if (FLAG_precompiled_mode) { | 1276 if (FLAG_precompiled_mode) { |
1323 // Megamorphic calls may occur in slow path stubs. | 1277 // Megamorphic calls may occur in slow path stubs. |
1324 // If valid use try_index argument. | 1278 // If valid use try_index argument. |
1325 if (try_index == CatchClauseNode::kInvalidTryIndex) { | 1279 if (try_index == CatchClauseNode::kInvalidTryIndex) { |
1326 try_index = CurrentTryIndex(); | 1280 try_index = CurrentTryIndex(); |
1327 } | 1281 } |
1328 pc_descriptors_list()->AddDescriptor(RawPcDescriptors::kOther, | 1282 pc_descriptors_list()->AddDescriptor( |
1329 assembler()->CodeSize(), | 1283 RawPcDescriptors::kOther, assembler()->CodeSize(), Thread::kNoDeoptId, |
1330 Thread::kNoDeoptId, | 1284 token_pos, try_index); |
1331 token_pos, | |
1332 try_index); | |
1333 } else if (is_optimizing()) { | 1285 } else if (is_optimizing()) { |
1334 AddCurrentDescriptor(RawPcDescriptors::kOther, | 1286 AddCurrentDescriptor(RawPcDescriptors::kOther, Thread::kNoDeoptId, |
1335 Thread::kNoDeoptId, token_pos); | 1287 token_pos); |
1336 AddDeoptIndexAtCall(deopt_id_after); | 1288 AddDeoptIndexAtCall(deopt_id_after); |
1337 } else { | 1289 } else { |
1338 AddCurrentDescriptor(RawPcDescriptors::kOther, | 1290 AddCurrentDescriptor(RawPcDescriptors::kOther, Thread::kNoDeoptId, |
1339 Thread::kNoDeoptId, token_pos); | 1291 token_pos); |
1340 // Add deoptimization continuation point after the call and before the | 1292 // Add deoptimization continuation point after the call and before the |
1341 // arguments are removed. | 1293 // arguments are removed. |
1342 AddCurrentDescriptor(RawPcDescriptors::kDeopt, | 1294 AddCurrentDescriptor(RawPcDescriptors::kDeopt, deopt_id_after, token_pos); |
1343 deopt_id_after, token_pos); | |
1344 } | 1295 } |
1345 __ Drop(argument_count); | 1296 __ Drop(argument_count); |
1346 } | 1297 } |
1347 | 1298 |
1348 | 1299 |
1349 void FlowGraphCompiler::EmitSwitchableInstanceCall( | 1300 void FlowGraphCompiler::EmitSwitchableInstanceCall(const ICData& ic_data, |
1350 const ICData& ic_data, | 1301 intptr_t argument_count, |
1351 intptr_t argument_count, | 1302 intptr_t deopt_id, |
1352 intptr_t deopt_id, | 1303 TokenPosition token_pos, |
1353 TokenPosition token_pos, | 1304 LocationSummary* locs) { |
1354 LocationSummary* locs) { | |
1355 ASSERT(ic_data.NumArgsTested() == 1); | 1305 ASSERT(ic_data.NumArgsTested() == 1); |
1356 const Code& initial_stub = Code::ZoneHandle( | 1306 const Code& initial_stub = |
1357 StubCode::ICCallThroughFunction_entry()->code()); | 1307 Code::ZoneHandle(StubCode::ICCallThroughFunction_entry()->code()); |
1358 | 1308 |
1359 __ Comment("SwitchableCall"); | 1309 __ Comment("SwitchableCall"); |
1360 | 1310 |
1361 __ LoadFromOffset(kWord, R0, SP, (argument_count - 1) * kWordSize); | 1311 __ LoadFromOffset(kWord, R0, SP, (argument_count - 1) * kWordSize); |
1362 __ LoadUniqueObject(CODE_REG, initial_stub); | 1312 __ LoadUniqueObject(CODE_REG, initial_stub); |
1363 __ ldr(LR, FieldAddress(CODE_REG, Code::checked_entry_point_offset())); | 1313 __ ldr(LR, FieldAddress(CODE_REG, Code::checked_entry_point_offset())); |
1364 __ LoadUniqueObject(R9, ic_data); | 1314 __ LoadUniqueObject(R9, ic_data); |
1365 __ blx(LR); | 1315 __ blx(LR); |
1366 | 1316 |
1367 AddCurrentDescriptor(RawPcDescriptors::kOther, Thread::kNoDeoptId, token_pos); | 1317 AddCurrentDescriptor(RawPcDescriptors::kOther, Thread::kNoDeoptId, token_pos); |
1368 RecordSafepoint(locs); | 1318 RecordSafepoint(locs); |
1369 const intptr_t deopt_id_after = Thread::ToDeoptAfter(deopt_id); | 1319 const intptr_t deopt_id_after = Thread::ToDeoptAfter(deopt_id); |
1370 if (is_optimizing()) { | 1320 if (is_optimizing()) { |
1371 AddDeoptIndexAtCall(deopt_id_after); | 1321 AddDeoptIndexAtCall(deopt_id_after); |
1372 } else { | 1322 } else { |
1373 // Add deoptimization continuation point after the call and before the | 1323 // Add deoptimization continuation point after the call and before the |
1374 // arguments are removed. | 1324 // arguments are removed. |
1375 AddCurrentDescriptor(RawPcDescriptors::kDeopt, | 1325 AddCurrentDescriptor(RawPcDescriptors::kDeopt, deopt_id_after, token_pos); |
1376 deopt_id_after, token_pos); | |
1377 } | 1326 } |
1378 __ Drop(argument_count); | 1327 __ Drop(argument_count); |
1379 } | 1328 } |
1380 | 1329 |
1381 | 1330 |
1382 void FlowGraphCompiler::EmitUnoptimizedStaticCall( | 1331 void FlowGraphCompiler::EmitUnoptimizedStaticCall(intptr_t argument_count, |
1383 intptr_t argument_count, | 1332 intptr_t deopt_id, |
1384 intptr_t deopt_id, | 1333 TokenPosition token_pos, |
1385 TokenPosition token_pos, | 1334 LocationSummary* locs, |
1386 LocationSummary* locs, | 1335 const ICData& ic_data) { |
1387 const ICData& ic_data) { | |
1388 const StubEntry* stub_entry = | 1336 const StubEntry* stub_entry = |
1389 StubCode::UnoptimizedStaticCallEntry(ic_data.NumArgsTested()); | 1337 StubCode::UnoptimizedStaticCallEntry(ic_data.NumArgsTested()); |
1390 __ LoadObject(R9, ic_data); | 1338 __ LoadObject(R9, ic_data); |
1391 GenerateDartCall(deopt_id, | 1339 GenerateDartCall(deopt_id, token_pos, *stub_entry, |
1392 token_pos, | 1340 RawPcDescriptors::kUnoptStaticCall, locs); |
1393 *stub_entry, | |
1394 RawPcDescriptors::kUnoptStaticCall, | |
1395 locs); | |
1396 __ Drop(argument_count); | 1341 __ Drop(argument_count); |
1397 } | 1342 } |
1398 | 1343 |
1399 | 1344 |
1400 void FlowGraphCompiler::EmitOptimizedStaticCall( | 1345 void FlowGraphCompiler::EmitOptimizedStaticCall( |
1401 const Function& function, | 1346 const Function& function, |
1402 const Array& arguments_descriptor, | 1347 const Array& arguments_descriptor, |
1403 intptr_t argument_count, | 1348 intptr_t argument_count, |
1404 intptr_t deopt_id, | 1349 intptr_t deopt_id, |
1405 TokenPosition token_pos, | 1350 TokenPosition token_pos, |
1406 LocationSummary* locs) { | 1351 LocationSummary* locs) { |
1407 ASSERT(!function.IsClosureFunction()); | 1352 ASSERT(!function.IsClosureFunction()); |
1408 if (function.HasOptionalParameters()) { | 1353 if (function.HasOptionalParameters()) { |
1409 __ LoadObject(R4, arguments_descriptor); | 1354 __ LoadObject(R4, arguments_descriptor); |
1410 } else { | 1355 } else { |
1411 __ LoadImmediate(R4, 0); // GC safe smi zero because of stub. | 1356 __ LoadImmediate(R4, 0); // GC safe smi zero because of stub. |
1412 } | 1357 } |
1413 // Do not use the code from the function, but let the code be patched so that | 1358 // Do not use the code from the function, but let the code be patched so that |
1414 // we can record the outgoing edges to other code. | 1359 // we can record the outgoing edges to other code. |
1415 GenerateStaticDartCall(deopt_id, | 1360 GenerateStaticDartCall(deopt_id, token_pos, |
1416 token_pos, | |
1417 *StubCode::CallStaticFunction_entry(), | 1361 *StubCode::CallStaticFunction_entry(), |
1418 RawPcDescriptors::kOther, | 1362 RawPcDescriptors::kOther, locs, function); |
1419 locs, | |
1420 function); | |
1421 __ Drop(argument_count); | 1363 __ Drop(argument_count); |
1422 } | 1364 } |
1423 | 1365 |
1424 | 1366 |
1425 Condition FlowGraphCompiler::EmitEqualityRegConstCompare( | 1367 Condition FlowGraphCompiler::EmitEqualityRegConstCompare( |
1426 Register reg, | 1368 Register reg, |
1427 const Object& obj, | 1369 const Object& obj, |
1428 bool needs_number_check, | 1370 bool needs_number_check, |
1429 TokenPosition token_pos) { | 1371 TokenPosition token_pos) { |
1430 if (needs_number_check) { | 1372 if (needs_number_check) { |
1431 ASSERT(!obj.IsMint() && !obj.IsDouble() && !obj.IsBigint()); | 1373 ASSERT(!obj.IsMint() && !obj.IsDouble() && !obj.IsBigint()); |
1432 __ Push(reg); | 1374 __ Push(reg); |
1433 __ PushObject(obj); | 1375 __ PushObject(obj); |
1434 if (is_optimizing()) { | 1376 if (is_optimizing()) { |
1435 __ BranchLinkPatchable( | 1377 __ BranchLinkPatchable( |
1436 *StubCode::OptimizedIdenticalWithNumberCheck_entry()); | 1378 *StubCode::OptimizedIdenticalWithNumberCheck_entry()); |
1437 } else { | 1379 } else { |
1438 __ BranchLinkPatchable( | 1380 __ BranchLinkPatchable( |
1439 *StubCode::UnoptimizedIdenticalWithNumberCheck_entry()); | 1381 *StubCode::UnoptimizedIdenticalWithNumberCheck_entry()); |
1440 } | 1382 } |
1441 if (token_pos.IsReal()) { | 1383 if (token_pos.IsReal()) { |
1442 AddCurrentDescriptor(RawPcDescriptors::kRuntimeCall, | 1384 AddCurrentDescriptor(RawPcDescriptors::kRuntimeCall, Thread::kNoDeoptId, |
1443 Thread::kNoDeoptId, | |
1444 token_pos); | 1385 token_pos); |
1445 } | 1386 } |
1446 // Stub returns result in flags (result of a cmp, we need Z computed). | 1387 // Stub returns result in flags (result of a cmp, we need Z computed). |
1447 __ Drop(1); // Discard constant. | 1388 __ Drop(1); // Discard constant. |
1448 __ Pop(reg); // Restore 'reg'. | 1389 __ Pop(reg); // Restore 'reg'. |
1449 } else { | 1390 } else { |
1450 __ CompareObject(reg, obj); | 1391 __ CompareObject(reg, obj); |
1451 } | 1392 } |
1452 return EQ; | 1393 return EQ; |
1453 } | 1394 } |
1454 | 1395 |
1455 | 1396 |
1456 Condition FlowGraphCompiler::EmitEqualityRegRegCompare( | 1397 Condition FlowGraphCompiler::EmitEqualityRegRegCompare( |
1457 Register left, | 1398 Register left, |
1458 Register right, | 1399 Register right, |
1459 bool needs_number_check, | 1400 bool needs_number_check, |
1460 TokenPosition token_pos) { | 1401 TokenPosition token_pos) { |
1461 if (needs_number_check) { | 1402 if (needs_number_check) { |
1462 __ Push(left); | 1403 __ Push(left); |
1463 __ Push(right); | 1404 __ Push(right); |
1464 if (is_optimizing()) { | 1405 if (is_optimizing()) { |
1465 __ BranchLinkPatchable( | 1406 __ BranchLinkPatchable( |
1466 *StubCode::OptimizedIdenticalWithNumberCheck_entry()); | 1407 *StubCode::OptimizedIdenticalWithNumberCheck_entry()); |
1467 } else { | 1408 } else { |
1468 __ BranchLinkPatchable( | 1409 __ BranchLinkPatchable( |
1469 *StubCode::UnoptimizedIdenticalWithNumberCheck_entry()); | 1410 *StubCode::UnoptimizedIdenticalWithNumberCheck_entry()); |
1470 } | 1411 } |
1471 if (token_pos.IsReal()) { | 1412 if (token_pos.IsReal()) { |
1472 AddCurrentDescriptor(RawPcDescriptors::kRuntimeCall, | 1413 AddCurrentDescriptor(RawPcDescriptors::kRuntimeCall, Thread::kNoDeoptId, |
1473 Thread::kNoDeoptId, | |
1474 token_pos); | 1414 token_pos); |
1475 } | 1415 } |
1476 // Stub returns result in flags (result of a cmp, we need Z computed). | 1416 // Stub returns result in flags (result of a cmp, we need Z computed). |
1477 __ Pop(right); | 1417 __ Pop(right); |
1478 __ Pop(left); | 1418 __ Pop(left); |
1479 } else { | 1419 } else { |
1480 __ cmp(left, Operand(right)); | 1420 __ cmp(left, Operand(right)); |
1481 } | 1421 } |
1482 return EQ; | 1422 return EQ; |
1483 } | 1423 } |
(...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1580 intptr_t argument_count, | 1520 intptr_t argument_count, |
1581 const Array& argument_names, | 1521 const Array& argument_names, |
1582 Label* failed, | 1522 Label* failed, |
1583 Label* match_found, | 1523 Label* match_found, |
1584 intptr_t deopt_id, | 1524 intptr_t deopt_id, |
1585 TokenPosition token_index, | 1525 TokenPosition token_index, |
1586 LocationSummary* locs, | 1526 LocationSummary* locs, |
1587 bool complete) { | 1527 bool complete) { |
1588 ASSERT(is_optimizing()); | 1528 ASSERT(is_optimizing()); |
1589 __ Comment("EmitTestAndCall"); | 1529 __ Comment("EmitTestAndCall"); |
1590 const Array& arguments_descriptor = | 1530 const Array& arguments_descriptor = Array::ZoneHandle( |
1591 Array::ZoneHandle(zone(), ArgumentsDescriptor::New(argument_count, | 1531 zone(), ArgumentsDescriptor::New(argument_count, argument_names)); |
1592 argument_names)); | |
1593 | 1532 |
1594 // Load receiver into R0. | 1533 // Load receiver into R0. |
1595 __ LoadFromOffset(kWord, R0, SP, (argument_count - 1) * kWordSize); | 1534 __ LoadFromOffset(kWord, R0, SP, (argument_count - 1) * kWordSize); |
1596 __ LoadObject(R4, arguments_descriptor); | 1535 __ LoadObject(R4, arguments_descriptor); |
1597 | 1536 |
1598 const bool kFirstCheckIsSmi = ic_data.GetReceiverClassIdAt(0) == kSmiCid; | 1537 const bool kFirstCheckIsSmi = ic_data.GetReceiverClassIdAt(0) == kSmiCid; |
1599 const intptr_t kNumChecks = ic_data.NumberOfChecks(); | 1538 const intptr_t kNumChecks = ic_data.NumberOfChecks(); |
1600 | 1539 |
1601 ASSERT(!ic_data.IsNull() && (kNumChecks > 0)); | 1540 ASSERT(!ic_data.IsNull() && (kNumChecks > 0)); |
1602 | 1541 |
1603 Label after_smi_test; | 1542 Label after_smi_test; |
1604 if (kFirstCheckIsSmi) { | 1543 if (kFirstCheckIsSmi) { |
1605 __ tst(R0, Operand(kSmiTagMask)); | 1544 __ tst(R0, Operand(kSmiTagMask)); |
1606 // Jump if receiver is not Smi. | 1545 // Jump if receiver is not Smi. |
1607 if (kNumChecks == 1) { | 1546 if (kNumChecks == 1) { |
1608 __ b(failed, NE); | 1547 __ b(failed, NE); |
1609 } else { | 1548 } else { |
1610 __ b(&after_smi_test, NE); | 1549 __ b(&after_smi_test, NE); |
1611 } | 1550 } |
1612 // Do not use the code from the function, but let the code be patched so | 1551 // Do not use the code from the function, but let the code be patched so |
1613 // that we can record the outgoing edges to other code. | 1552 // that we can record the outgoing edges to other code. |
1614 const Function& function = Function::ZoneHandle( | 1553 const Function& function = |
1615 zone(), ic_data.GetTargetAt(0)); | 1554 Function::ZoneHandle(zone(), ic_data.GetTargetAt(0)); |
1616 GenerateStaticDartCall(deopt_id, | 1555 GenerateStaticDartCall(deopt_id, token_index, |
1617 token_index, | |
1618 *StubCode::CallStaticFunction_entry(), | 1556 *StubCode::CallStaticFunction_entry(), |
1619 RawPcDescriptors::kOther, | 1557 RawPcDescriptors::kOther, locs, function); |
1620 locs, | |
1621 function); | |
1622 __ Drop(argument_count); | 1558 __ Drop(argument_count); |
1623 if (kNumChecks > 1) { | 1559 if (kNumChecks > 1) { |
1624 __ b(match_found); | 1560 __ b(match_found); |
1625 } | 1561 } |
1626 } else { | 1562 } else { |
1627 // Receiver is Smi, but Smi is not a valid class therefore fail. | 1563 // Receiver is Smi, but Smi is not a valid class therefore fail. |
1628 // (Smi class must be first in the list). | 1564 // (Smi class must be first in the list). |
1629 if (!complete) { | 1565 if (!complete) { |
1630 __ tst(R0, Operand(kSmiTagMask)); | 1566 __ tst(R0, Operand(kSmiTagMask)); |
1631 __ b(failed, EQ); | 1567 __ b(failed, EQ); |
(...skipping 25 matching lines...) Expand all Loading... |
1657 } | 1593 } |
1658 } else { | 1594 } else { |
1659 if (!kIsLastCheck) { | 1595 if (!kIsLastCheck) { |
1660 __ CompareImmediate(R2, sorted[i].cid); | 1596 __ CompareImmediate(R2, sorted[i].cid); |
1661 __ b(&next_test, NE); | 1597 __ b(&next_test, NE); |
1662 } | 1598 } |
1663 } | 1599 } |
1664 // Do not use the code from the function, but let the code be patched so | 1600 // Do not use the code from the function, but let the code be patched so |
1665 // that we can record the outgoing edges to other code. | 1601 // that we can record the outgoing edges to other code. |
1666 const Function& function = *sorted[i].target; | 1602 const Function& function = *sorted[i].target; |
1667 GenerateStaticDartCall(deopt_id, | 1603 GenerateStaticDartCall(deopt_id, token_index, |
1668 token_index, | |
1669 *StubCode::CallStaticFunction_entry(), | 1604 *StubCode::CallStaticFunction_entry(), |
1670 RawPcDescriptors::kOther, | 1605 RawPcDescriptors::kOther, locs, function); |
1671 locs, | |
1672 function); | |
1673 __ Drop(argument_count); | 1606 __ Drop(argument_count); |
1674 if (!kIsLastCheck) { | 1607 if (!kIsLastCheck) { |
1675 __ b(match_found); | 1608 __ b(match_found); |
1676 } | 1609 } |
1677 __ Bind(&next_test); | 1610 __ Bind(&next_test); |
1678 } | 1611 } |
1679 } | 1612 } |
1680 | 1613 |
1681 | 1614 |
1682 #undef __ | 1615 #undef __ |
1683 #define __ compiler_->assembler()-> | 1616 #define __ compiler_->assembler()-> |
1684 | 1617 |
1685 | 1618 |
1686 void ParallelMoveResolver::EmitMove(int index) { | 1619 void ParallelMoveResolver::EmitMove(int index) { |
1687 MoveOperands* move = moves_[index]; | 1620 MoveOperands* move = moves_[index]; |
1688 const Location source = move->src(); | 1621 const Location source = move->src(); |
1689 const Location destination = move->dest(); | 1622 const Location destination = move->dest(); |
1690 | 1623 |
1691 if (source.IsRegister()) { | 1624 if (source.IsRegister()) { |
1692 if (destination.IsRegister()) { | 1625 if (destination.IsRegister()) { |
1693 __ mov(destination.reg(), Operand(source.reg())); | 1626 __ mov(destination.reg(), Operand(source.reg())); |
1694 } else { | 1627 } else { |
1695 ASSERT(destination.IsStackSlot()); | 1628 ASSERT(destination.IsStackSlot()); |
1696 const intptr_t dest_offset = destination.ToStackSlotOffset(); | 1629 const intptr_t dest_offset = destination.ToStackSlotOffset(); |
1697 __ StoreToOffset( | 1630 __ StoreToOffset(kWord, source.reg(), destination.base_reg(), |
1698 kWord, source.reg(), destination.base_reg(), dest_offset); | 1631 dest_offset); |
1699 } | 1632 } |
1700 } else if (source.IsStackSlot()) { | 1633 } else if (source.IsStackSlot()) { |
1701 if (destination.IsRegister()) { | 1634 if (destination.IsRegister()) { |
1702 const intptr_t source_offset = source.ToStackSlotOffset(); | 1635 const intptr_t source_offset = source.ToStackSlotOffset(); |
1703 __ LoadFromOffset( | 1636 __ LoadFromOffset(kWord, destination.reg(), source.base_reg(), |
1704 kWord, destination.reg(), source.base_reg(), source_offset); | 1637 source_offset); |
1705 } else { | 1638 } else { |
1706 ASSERT(destination.IsStackSlot()); | 1639 ASSERT(destination.IsStackSlot()); |
1707 const intptr_t source_offset = source.ToStackSlotOffset(); | 1640 const intptr_t source_offset = source.ToStackSlotOffset(); |
1708 const intptr_t dest_offset = destination.ToStackSlotOffset(); | 1641 const intptr_t dest_offset = destination.ToStackSlotOffset(); |
1709 __ LoadFromOffset(kWord, TMP, source.base_reg(), source_offset); | 1642 __ LoadFromOffset(kWord, TMP, source.base_reg(), source_offset); |
1710 __ StoreToOffset(kWord, TMP, destination.base_reg(), dest_offset); | 1643 __ StoreToOffset(kWord, TMP, destination.base_reg(), dest_offset); |
1711 } | 1644 } |
1712 } else if (source.IsFpuRegister()) { | 1645 } else if (source.IsFpuRegister()) { |
1713 if (destination.IsFpuRegister()) { | 1646 if (destination.IsFpuRegister()) { |
1714 if (TargetCPUFeatures::neon_supported()) { | 1647 if (TargetCPUFeatures::neon_supported()) { |
1715 __ vmovq(destination.fpu_reg(), source.fpu_reg()); | 1648 __ vmovq(destination.fpu_reg(), source.fpu_reg()); |
1716 } else { | 1649 } else { |
1717 // If we're not inlining simd values, then only the even numbered D | 1650 // If we're not inlining simd values, then only the even numbered D |
1718 // register will have anything in them. | 1651 // register will have anything in them. |
1719 __ vmovd(EvenDRegisterOf(destination.fpu_reg()), | 1652 __ vmovd(EvenDRegisterOf(destination.fpu_reg()), |
1720 EvenDRegisterOf(source.fpu_reg())); | 1653 EvenDRegisterOf(source.fpu_reg())); |
1721 } | 1654 } |
1722 } else { | 1655 } else { |
1723 if (destination.IsDoubleStackSlot()) { | 1656 if (destination.IsDoubleStackSlot()) { |
1724 const intptr_t dest_offset = destination.ToStackSlotOffset(); | 1657 const intptr_t dest_offset = destination.ToStackSlotOffset(); |
1725 DRegister src = EvenDRegisterOf(source.fpu_reg()); | 1658 DRegister src = EvenDRegisterOf(source.fpu_reg()); |
1726 __ StoreDToOffset(src, destination.base_reg(), dest_offset); | 1659 __ StoreDToOffset(src, destination.base_reg(), dest_offset); |
1727 } else { | 1660 } else { |
1728 ASSERT(destination.IsQuadStackSlot()); | 1661 ASSERT(destination.IsQuadStackSlot()); |
1729 const intptr_t dest_offset = destination.ToStackSlotOffset(); | 1662 const intptr_t dest_offset = destination.ToStackSlotOffset(); |
1730 const DRegister dsrc0 = EvenDRegisterOf(source.fpu_reg()); | 1663 const DRegister dsrc0 = EvenDRegisterOf(source.fpu_reg()); |
1731 __ StoreMultipleDToOffset( | 1664 __ StoreMultipleDToOffset(dsrc0, 2, destination.base_reg(), |
1732 dsrc0, 2, destination.base_reg(), dest_offset); | 1665 dest_offset); |
1733 } | 1666 } |
1734 } | 1667 } |
1735 } else if (source.IsDoubleStackSlot()) { | 1668 } else if (source.IsDoubleStackSlot()) { |
1736 if (destination.IsFpuRegister()) { | 1669 if (destination.IsFpuRegister()) { |
1737 const intptr_t source_offset = source.ToStackSlotOffset(); | 1670 const intptr_t source_offset = source.ToStackSlotOffset(); |
1738 const DRegister dst = EvenDRegisterOf(destination.fpu_reg()); | 1671 const DRegister dst = EvenDRegisterOf(destination.fpu_reg()); |
1739 __ LoadDFromOffset(dst, source.base_reg(), source_offset); | 1672 __ LoadDFromOffset(dst, source.base_reg(), source_offset); |
1740 } else { | 1673 } else { |
1741 ASSERT(destination.IsDoubleStackSlot()); | 1674 ASSERT(destination.IsDoubleStackSlot()); |
1742 const intptr_t source_offset = source.ToStackSlotOffset(); | 1675 const intptr_t source_offset = source.ToStackSlotOffset(); |
(...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1809 const Location source = move->src(); | 1742 const Location source = move->src(); |
1810 const Location destination = move->dest(); | 1743 const Location destination = move->dest(); |
1811 | 1744 |
1812 if (source.IsRegister() && destination.IsRegister()) { | 1745 if (source.IsRegister() && destination.IsRegister()) { |
1813 ASSERT(source.reg() != IP); | 1746 ASSERT(source.reg() != IP); |
1814 ASSERT(destination.reg() != IP); | 1747 ASSERT(destination.reg() != IP); |
1815 __ mov(IP, Operand(source.reg())); | 1748 __ mov(IP, Operand(source.reg())); |
1816 __ mov(source.reg(), Operand(destination.reg())); | 1749 __ mov(source.reg(), Operand(destination.reg())); |
1817 __ mov(destination.reg(), Operand(IP)); | 1750 __ mov(destination.reg(), Operand(IP)); |
1818 } else if (source.IsRegister() && destination.IsStackSlot()) { | 1751 } else if (source.IsRegister() && destination.IsStackSlot()) { |
1819 Exchange(source.reg(), | 1752 Exchange(source.reg(), destination.base_reg(), |
1820 destination.base_reg(), destination.ToStackSlotOffset()); | 1753 destination.ToStackSlotOffset()); |
1821 } else if (source.IsStackSlot() && destination.IsRegister()) { | 1754 } else if (source.IsStackSlot() && destination.IsRegister()) { |
1822 Exchange(destination.reg(), | 1755 Exchange(destination.reg(), source.base_reg(), source.ToStackSlotOffset()); |
1823 source.base_reg(), source.ToStackSlotOffset()); | |
1824 } else if (source.IsStackSlot() && destination.IsStackSlot()) { | 1756 } else if (source.IsStackSlot() && destination.IsStackSlot()) { |
1825 Exchange(source.base_reg(), source.ToStackSlotOffset(), | 1757 Exchange(source.base_reg(), source.ToStackSlotOffset(), |
1826 destination.base_reg(), destination.ToStackSlotOffset()); | 1758 destination.base_reg(), destination.ToStackSlotOffset()); |
1827 } else if (source.IsFpuRegister() && destination.IsFpuRegister()) { | 1759 } else if (source.IsFpuRegister() && destination.IsFpuRegister()) { |
1828 if (TargetCPUFeatures::neon_supported()) { | 1760 if (TargetCPUFeatures::neon_supported()) { |
1829 const QRegister dst = destination.fpu_reg(); | 1761 const QRegister dst = destination.fpu_reg(); |
1830 const QRegister src = source.fpu_reg(); | 1762 const QRegister src = source.fpu_reg(); |
1831 __ vmovq(QTMP, src); | 1763 __ vmovq(QTMP, src); |
1832 __ vmovq(src, dst); | 1764 __ vmovq(src, dst); |
1833 __ vmovq(dst, QTMP); | 1765 __ vmovq(dst, QTMP); |
1834 } else { | 1766 } else { |
1835 const DRegister dst = EvenDRegisterOf(destination.fpu_reg()); | 1767 const DRegister dst = EvenDRegisterOf(destination.fpu_reg()); |
1836 const DRegister src = EvenDRegisterOf(source.fpu_reg()); | 1768 const DRegister src = EvenDRegisterOf(source.fpu_reg()); |
1837 __ vmovd(DTMP, src); | 1769 __ vmovd(DTMP, src); |
1838 __ vmovd(src, dst); | 1770 __ vmovd(src, dst); |
1839 __ vmovd(dst, DTMP); | 1771 __ vmovd(dst, DTMP); |
1840 } | 1772 } |
1841 } else if (source.IsFpuRegister() || destination.IsFpuRegister()) { | 1773 } else if (source.IsFpuRegister() || destination.IsFpuRegister()) { |
1842 ASSERT(destination.IsDoubleStackSlot() || | 1774 ASSERT(destination.IsDoubleStackSlot() || destination.IsQuadStackSlot() || |
1843 destination.IsQuadStackSlot() || | 1775 source.IsDoubleStackSlot() || source.IsQuadStackSlot()); |
1844 source.IsDoubleStackSlot() || | 1776 bool double_width = |
1845 source.IsQuadStackSlot()); | 1777 destination.IsDoubleStackSlot() || source.IsDoubleStackSlot(); |
1846 bool double_width = destination.IsDoubleStackSlot() || | 1778 QRegister qreg = |
1847 source.IsDoubleStackSlot(); | 1779 source.IsFpuRegister() ? source.fpu_reg() : destination.fpu_reg(); |
1848 QRegister qreg = source.IsFpuRegister() ? source.fpu_reg() | |
1849 : destination.fpu_reg(); | |
1850 DRegister reg = EvenDRegisterOf(qreg); | 1780 DRegister reg = EvenDRegisterOf(qreg); |
1851 Register base_reg = source.IsFpuRegister() | 1781 Register base_reg = |
1852 ? destination.base_reg() | 1782 source.IsFpuRegister() ? destination.base_reg() : source.base_reg(); |
1853 : source.base_reg(); | |
1854 const intptr_t slot_offset = source.IsFpuRegister() | 1783 const intptr_t slot_offset = source.IsFpuRegister() |
1855 ? destination.ToStackSlotOffset() | 1784 ? destination.ToStackSlotOffset() |
1856 : source.ToStackSlotOffset(); | 1785 : source.ToStackSlotOffset(); |
1857 | 1786 |
1858 if (double_width) { | 1787 if (double_width) { |
1859 __ LoadDFromOffset(DTMP, base_reg, slot_offset); | 1788 __ LoadDFromOffset(DTMP, base_reg, slot_offset); |
1860 __ StoreDToOffset(reg, base_reg, slot_offset); | 1789 __ StoreDToOffset(reg, base_reg, slot_offset); |
1861 __ vmovd(reg, DTMP); | 1790 __ vmovd(reg, DTMP); |
1862 } else { | 1791 } else { |
1863 __ LoadMultipleDFromOffset(DTMP, 2, base_reg, slot_offset); | 1792 __ LoadMultipleDFromOffset(DTMP, 2, base_reg, slot_offset); |
1864 __ StoreMultipleDToOffset(reg, 2, base_reg, slot_offset); | 1793 __ StoreMultipleDToOffset(reg, 2, base_reg, slot_offset); |
1865 __ vmovq(qreg, QTMP); | 1794 __ vmovq(qreg, QTMP); |
1866 } | 1795 } |
1867 } else if (source.IsDoubleStackSlot() && destination.IsDoubleStackSlot()) { | 1796 } else if (source.IsDoubleStackSlot() && destination.IsDoubleStackSlot()) { |
1868 const intptr_t source_offset = source.ToStackSlotOffset(); | 1797 const intptr_t source_offset = source.ToStackSlotOffset(); |
1869 const intptr_t dest_offset = destination.ToStackSlotOffset(); | 1798 const intptr_t dest_offset = destination.ToStackSlotOffset(); |
1870 | 1799 |
1871 ScratchFpuRegisterScope ensure_scratch(this, kNoQRegister); | 1800 ScratchFpuRegisterScope ensure_scratch(this, kNoQRegister); |
1872 DRegister scratch = EvenDRegisterOf(ensure_scratch.reg()); | 1801 DRegister scratch = EvenDRegisterOf(ensure_scratch.reg()); |
1873 __ LoadDFromOffset(DTMP, source.base_reg(), source_offset); | 1802 __ LoadDFromOffset(DTMP, source.base_reg(), source_offset); |
1874 __ LoadDFromOffset(scratch, destination.base_reg(), dest_offset); | 1803 __ LoadDFromOffset(scratch, destination.base_reg(), dest_offset); |
1875 __ StoreDToOffset(DTMP, destination.base_reg(), dest_offset); | 1804 __ StoreDToOffset(DTMP, destination.base_reg(), dest_offset); |
1876 __ StoreDToOffset(scratch, destination.base_reg(), source_offset); | 1805 __ StoreDToOffset(scratch, destination.base_reg(), source_offset); |
1877 } else if (source.IsQuadStackSlot() && destination.IsQuadStackSlot()) { | 1806 } else if (source.IsQuadStackSlot() && destination.IsQuadStackSlot()) { |
1878 const intptr_t source_offset = source.ToStackSlotOffset(); | 1807 const intptr_t source_offset = source.ToStackSlotOffset(); |
1879 const intptr_t dest_offset = destination.ToStackSlotOffset(); | 1808 const intptr_t dest_offset = destination.ToStackSlotOffset(); |
1880 | 1809 |
1881 ScratchFpuRegisterScope ensure_scratch(this, kNoQRegister); | 1810 ScratchFpuRegisterScope ensure_scratch(this, kNoQRegister); |
1882 DRegister scratch = EvenDRegisterOf(ensure_scratch.reg()); | 1811 DRegister scratch = EvenDRegisterOf(ensure_scratch.reg()); |
1883 __ LoadMultipleDFromOffset(DTMP, 2, source.base_reg(), source_offset); | 1812 __ LoadMultipleDFromOffset(DTMP, 2, source.base_reg(), source_offset); |
1884 __ LoadMultipleDFromOffset(scratch, 2, destination.base_reg(), dest_offset); | 1813 __ LoadMultipleDFromOffset(scratch, 2, destination.base_reg(), dest_offset); |
1885 __ StoreMultipleDToOffset(DTMP, 2, destination.base_reg(), dest_offset); | 1814 __ StoreMultipleDToOffset(DTMP, 2, destination.base_reg(), dest_offset); |
1886 __ StoreMultipleDToOffset( | 1815 __ StoreMultipleDToOffset(scratch, 2, destination.base_reg(), |
1887 scratch, 2, destination.base_reg(), source_offset); | 1816 source_offset); |
1888 } else { | 1817 } else { |
1889 UNREACHABLE(); | 1818 UNREACHABLE(); |
1890 } | 1819 } |
1891 | 1820 |
1892 // The swap of source and destination has executed a move from source to | 1821 // The swap of source and destination has executed a move from source to |
1893 // destination. | 1822 // destination. |
1894 move->Eliminate(); | 1823 move->Eliminate(); |
1895 | 1824 |
1896 // Any unperformed (including pending) move with a source of either | 1825 // Any unperformed (including pending) move with a source of either |
1897 // this move's source or destination needs to have their source | 1826 // this move's source or destination needs to have their source |
(...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1975 DRegister dreg = EvenDRegisterOf(reg); | 1904 DRegister dreg = EvenDRegisterOf(reg); |
1976 __ vldrd(dreg, Address(SP, kDoubleSize, Address::PostIndex)); | 1905 __ vldrd(dreg, Address(SP, kDoubleSize, Address::PostIndex)); |
1977 } | 1906 } |
1978 | 1907 |
1979 | 1908 |
1980 #undef __ | 1909 #undef __ |
1981 | 1910 |
1982 } // namespace dart | 1911 } // namespace dart |
1983 | 1912 |
1984 #endif // defined TARGET_ARCH_ARM | 1913 #endif // defined TARGET_ARCH_ARM |
OLD | NEW |