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/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 98 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
109 builder->AddCallerFp(slot_ix++); | 109 builder->AddCallerFp(slot_ix++); |
110 builder->AddReturnAddress(current->function(), deopt_id(), slot_ix++); | 110 builder->AddReturnAddress(current->function(), deopt_id(), slot_ix++); |
111 | 111 |
112 // Emit all values that are needed for materialization as a part of the | 112 // Emit all values that are needed for materialization as a part of the |
113 // expression stack for the bottom-most frame. This guarantees that GC | 113 // expression stack for the bottom-most frame. This guarantees that GC |
114 // will be able to find them during materialization. | 114 // will be able to find them during materialization. |
115 slot_ix = builder->EmitMaterializationArguments(slot_ix); | 115 slot_ix = builder->EmitMaterializationArguments(slot_ix); |
116 | 116 |
117 // For the innermost environment, set outgoing arguments and the locals. | 117 // For the innermost environment, set outgoing arguments and the locals. |
118 for (intptr_t i = current->Length() - 1; | 118 for (intptr_t i = current->Length() - 1; |
119 i >= current->fixed_parameter_count(); | 119 i >= current->fixed_parameter_count(); i--) { |
120 i--) { | |
121 builder->AddCopy(current->ValueAt(i), current->LocationAt(i), slot_ix++); | 120 builder->AddCopy(current->ValueAt(i), current->LocationAt(i), slot_ix++); |
122 } | 121 } |
123 | 122 |
124 Environment* previous = current; | 123 Environment* previous = current; |
125 current = current->outer(); | 124 current = current->outer(); |
126 while (current != NULL) { | 125 while (current != NULL) { |
127 builder->AddPp(current->function(), slot_ix++); | 126 builder->AddPp(current->function(), slot_ix++); |
128 builder->AddPcMarker(previous->function(), slot_ix++); | 127 builder->AddPcMarker(previous->function(), slot_ix++); |
129 builder->AddCallerFp(slot_ix++); | 128 builder->AddCallerFp(slot_ix++); |
130 | 129 |
131 // For any outer environment the deopt id is that of the call instruction | 130 // For any outer environment the deopt id is that of the call instruction |
132 // which is recorded in the outer environment. | 131 // which is recorded in the outer environment. |
133 builder->AddReturnAddress( | 132 builder->AddReturnAddress(current->function(), |
134 current->function(), | 133 Thread::ToDeoptAfter(current->deopt_id()), |
135 Thread::ToDeoptAfter(current->deopt_id()), | 134 slot_ix++); |
136 slot_ix++); | |
137 | 135 |
138 // The values of outgoing arguments can be changed from the inlined call so | 136 // The values of outgoing arguments can be changed from the inlined call so |
139 // we must read them from the previous environment. | 137 // we must read them from the previous environment. |
140 for (intptr_t i = previous->fixed_parameter_count() - 1; i >= 0; i--) { | 138 for (intptr_t i = previous->fixed_parameter_count() - 1; i >= 0; i--) { |
141 builder->AddCopy(previous->ValueAt(i), | 139 builder->AddCopy(previous->ValueAt(i), previous->LocationAt(i), |
142 previous->LocationAt(i), | |
143 slot_ix++); | 140 slot_ix++); |
144 } | 141 } |
145 | 142 |
146 // Set the locals, note that outgoing arguments are not in the environment. | 143 // Set the locals, note that outgoing arguments are not in the environment. |
147 for (intptr_t i = current->Length() - 1; | 144 for (intptr_t i = current->Length() - 1; |
148 i >= current->fixed_parameter_count(); | 145 i >= current->fixed_parameter_count(); i--) { |
149 i--) { | 146 builder->AddCopy(current->ValueAt(i), current->LocationAt(i), slot_ix++); |
150 builder->AddCopy(current->ValueAt(i), | |
151 current->LocationAt(i), | |
152 slot_ix++); | |
153 } | 147 } |
154 | 148 |
155 // Iterate on the outer environment. | 149 // Iterate on the outer environment. |
156 previous = current; | 150 previous = current; |
157 current = current->outer(); | 151 current = current->outer(); |
158 } | 152 } |
159 // The previous pointer is now the outermost environment. | 153 // The previous pointer is now the outermost environment. |
160 ASSERT(previous != NULL); | 154 ASSERT(previous != NULL); |
161 | 155 |
162 // Add slots for the outermost environment. | 156 // Add slots for the outermost environment. |
(...skipping 111 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
274 __ b(is_not_instance_lbl, EQ); | 268 __ b(is_not_instance_lbl, EQ); |
275 } | 269 } |
276 // A function type test requires checking the function signature. | 270 // A function type test requires checking the function signature. |
277 if (!type.IsFunctionType()) { | 271 if (!type.IsFunctionType()) { |
278 const intptr_t num_type_args = type_class.NumTypeArguments(); | 272 const intptr_t num_type_args = type_class.NumTypeArguments(); |
279 const intptr_t num_type_params = type_class.NumTypeParameters(); | 273 const intptr_t num_type_params = type_class.NumTypeParameters(); |
280 const intptr_t from_index = num_type_args - num_type_params; | 274 const intptr_t from_index = num_type_args - num_type_params; |
281 const TypeArguments& type_arguments = | 275 const TypeArguments& type_arguments = |
282 TypeArguments::ZoneHandle(zone(), type.arguments()); | 276 TypeArguments::ZoneHandle(zone(), type.arguments()); |
283 const bool is_raw_type = type_arguments.IsNull() || | 277 const bool is_raw_type = type_arguments.IsNull() || |
284 type_arguments.IsRaw(from_index, num_type_params); | 278 type_arguments.IsRaw(from_index, num_type_params); |
285 if (is_raw_type) { | 279 if (is_raw_type) { |
286 const Register kClassIdReg = R2; | 280 const Register kClassIdReg = R2; |
287 // dynamic type argument, check only classes. | 281 // dynamic type argument, check only classes. |
288 __ LoadClassId(kClassIdReg, kInstanceReg); | 282 __ LoadClassId(kClassIdReg, kInstanceReg); |
289 __ CompareImmediate(kClassIdReg, type_class.id()); | 283 __ CompareImmediate(kClassIdReg, type_class.id()); |
290 __ b(is_instance_lbl, EQ); | 284 __ b(is_instance_lbl, EQ); |
291 // List is a very common case. | 285 // List is a very common case. |
292 if (IsListClass(type_class)) { | 286 if (IsListClass(type_class)) { |
293 GenerateListTypeCheck(kClassIdReg, is_instance_lbl); | 287 GenerateListTypeCheck(kClassIdReg, is_instance_lbl); |
294 } | 288 } |
295 return GenerateSubtype1TestCacheLookup( | 289 return GenerateSubtype1TestCacheLookup( |
296 token_pos, type_class, is_instance_lbl, is_not_instance_lbl); | 290 token_pos, type_class, is_instance_lbl, is_not_instance_lbl); |
297 } | 291 } |
298 // If one type argument only, check if type argument is Object or dynamic. | 292 // If one type argument only, check if type argument is Object or dynamic. |
299 if (type_arguments.Length() == 1) { | 293 if (type_arguments.Length() == 1) { |
300 const AbstractType& tp_argument = AbstractType::ZoneHandle( | 294 const AbstractType& tp_argument = |
301 zone(), type_arguments.TypeAt(0)); | 295 AbstractType::ZoneHandle(zone(), type_arguments.TypeAt(0)); |
302 ASSERT(!tp_argument.IsMalformed()); | 296 ASSERT(!tp_argument.IsMalformed()); |
303 if (tp_argument.IsType()) { | 297 if (tp_argument.IsType()) { |
304 ASSERT(tp_argument.HasResolvedTypeClass()); | 298 ASSERT(tp_argument.HasResolvedTypeClass()); |
305 // Check if type argument is dynamic or Object. | 299 // Check if type argument is dynamic or Object. |
306 const Type& object_type = Type::Handle(zone(), Type::ObjectType()); | 300 const Type& object_type = Type::Handle(zone(), Type::ObjectType()); |
307 if (object_type.IsSubtypeOf(tp_argument, NULL, NULL, Heap::kOld)) { | 301 if (object_type.IsSubtypeOf(tp_argument, NULL, NULL, Heap::kOld)) { |
308 // Instance class test only necessary. | 302 // Instance class test only necessary. |
309 return GenerateSubtype1TestCacheLookup( | 303 return GenerateSubtype1TestCacheLookup( |
310 token_pos, type_class, is_instance_lbl, is_not_instance_lbl); | 304 token_pos, type_class, is_instance_lbl, is_not_instance_lbl); |
311 } | 305 } |
312 } | 306 } |
313 } | 307 } |
314 } | 308 } |
315 // Regular subtype test cache involving instance's type arguments. | 309 // Regular subtype test cache involving instance's type arguments. |
316 const Register kTypeArgumentsReg = kNoRegister; | 310 const Register kTypeArgumentsReg = kNoRegister; |
317 const Register kTempReg = kNoRegister; | 311 const Register kTempReg = kNoRegister; |
318 // R0: instance (must be preserved). | 312 // R0: instance (must be preserved). |
319 return GenerateCallSubtypeTestStub(kTestTypeTwoArgs, | 313 return GenerateCallSubtypeTestStub(kTestTypeTwoArgs, kInstanceReg, |
320 kInstanceReg, | 314 kTypeArgumentsReg, kTempReg, |
321 kTypeArgumentsReg, | 315 is_instance_lbl, is_not_instance_lbl); |
322 kTempReg, | |
323 is_instance_lbl, | |
324 is_not_instance_lbl); | |
325 } | 316 } |
326 | 317 |
327 | 318 |
328 void FlowGraphCompiler::CheckClassIds(Register class_id_reg, | 319 void FlowGraphCompiler::CheckClassIds(Register class_id_reg, |
329 const GrowableArray<intptr_t>& class_ids, | 320 const GrowableArray<intptr_t>& class_ids, |
330 Label* is_equal_lbl, | 321 Label* is_equal_lbl, |
331 Label* is_not_equal_lbl) { | 322 Label* is_not_equal_lbl) { |
332 for (intptr_t i = 0; i < class_ids.length(); i++) { | 323 for (intptr_t i = 0; i < class_ids.length(); i++) { |
333 __ CompareImmediate(class_id_reg, class_ids[i]); | 324 __ CompareImmediate(class_id_reg, class_ids[i]); |
334 __ b(is_equal_lbl, EQ); | 325 __ b(is_equal_lbl, EQ); |
(...skipping 18 matching lines...) Expand all Loading... |
353 // Fallthrough. | 344 // Fallthrough. |
354 return true; | 345 return true; |
355 } | 346 } |
356 const Class& type_class = Class::Handle(zone(), type.type_class()); | 347 const Class& type_class = Class::Handle(zone(), type.type_class()); |
357 ASSERT(type_class.NumTypeArguments() == 0); | 348 ASSERT(type_class.NumTypeArguments() == 0); |
358 | 349 |
359 const Register kInstanceReg = R0; | 350 const Register kInstanceReg = R0; |
360 __ tsti(kInstanceReg, Immediate(kSmiTagMask)); | 351 __ tsti(kInstanceReg, Immediate(kSmiTagMask)); |
361 // If instance is Smi, check directly. | 352 // If instance is Smi, check directly. |
362 const Class& smi_class = Class::Handle(zone(), Smi::Class()); | 353 const Class& smi_class = Class::Handle(zone(), Smi::Class()); |
363 if (smi_class.IsSubtypeOf(TypeArguments::Handle(zone()), | 354 if (smi_class.IsSubtypeOf(TypeArguments::Handle(zone()), type_class, |
364 type_class, | 355 TypeArguments::Handle(zone()), NULL, NULL, |
365 TypeArguments::Handle(zone()), | |
366 NULL, | |
367 NULL, | |
368 Heap::kOld)) { | 356 Heap::kOld)) { |
369 __ b(is_instance_lbl, EQ); | 357 __ b(is_instance_lbl, EQ); |
370 } else { | 358 } else { |
371 __ b(is_not_instance_lbl, EQ); | 359 __ b(is_not_instance_lbl, EQ); |
372 } | 360 } |
373 const Register kClassIdReg = R2; | 361 const Register kClassIdReg = R2; |
374 __ LoadClassId(kClassIdReg, kInstanceReg); | 362 __ LoadClassId(kClassIdReg, kInstanceReg); |
375 // See ClassFinalizer::ResolveSuperTypeAndInterfaces for list of restricted | 363 // See ClassFinalizer::ResolveSuperTypeAndInterfaces for list of restricted |
376 // interfaces. | 364 // interfaces. |
377 // Bool interface can be implemented only by core class Bool. | 365 // Bool interface can be implemented only by core class Bool. |
378 if (type.IsBoolType()) { | 366 if (type.IsBoolType()) { |
379 __ CompareImmediate(kClassIdReg, kBoolCid); | 367 __ CompareImmediate(kClassIdReg, kBoolCid); |
380 __ b(is_instance_lbl, EQ); | 368 __ b(is_instance_lbl, EQ); |
381 __ b(is_not_instance_lbl); | 369 __ b(is_not_instance_lbl); |
382 return false; | 370 return false; |
383 } | 371 } |
384 // Custom checking for numbers (Smi, Mint, Bigint and Double). | 372 // Custom checking for numbers (Smi, Mint, Bigint and Double). |
385 // Note that instance is not Smi (checked above). | 373 // Note that instance is not Smi (checked above). |
386 if (type.IsNumberType() || type.IsIntType() || type.IsDoubleType()) { | 374 if (type.IsNumberType() || type.IsIntType() || type.IsDoubleType()) { |
387 GenerateNumberTypeCheck( | 375 GenerateNumberTypeCheck(kClassIdReg, type, is_instance_lbl, |
388 kClassIdReg, type, is_instance_lbl, is_not_instance_lbl); | 376 is_not_instance_lbl); |
389 return false; | 377 return false; |
390 } | 378 } |
391 if (type.IsStringType()) { | 379 if (type.IsStringType()) { |
392 GenerateStringTypeCheck(kClassIdReg, is_instance_lbl, is_not_instance_lbl); | 380 GenerateStringTypeCheck(kClassIdReg, is_instance_lbl, is_not_instance_lbl); |
393 return false; | 381 return false; |
394 } | 382 } |
395 if (type.IsDartFunctionType()) { | 383 if (type.IsDartFunctionType()) { |
396 // Check if instance is a closure. | 384 // Check if instance is a closure. |
397 __ CompareImmediate(kClassIdReg, kClosureCid); | 385 __ CompareImmediate(kClassIdReg, kClosureCid); |
398 __ b(is_instance_lbl, EQ); | 386 __ b(is_instance_lbl, EQ); |
(...skipping 26 matching lines...) Expand all Loading... |
425 __ LoadClass(R1, kInstanceReg); | 413 __ LoadClass(R1, kInstanceReg); |
426 // R1: instance class. | 414 // R1: instance class. |
427 // Check immediate superclass equality. | 415 // Check immediate superclass equality. |
428 __ LoadFieldFromOffset(R2, R1, Class::super_type_offset()); | 416 __ LoadFieldFromOffset(R2, R1, Class::super_type_offset()); |
429 __ LoadFieldFromOffset(R2, R2, Type::type_class_id_offset()); | 417 __ LoadFieldFromOffset(R2, R2, Type::type_class_id_offset()); |
430 __ CompareImmediate(R2, Smi::RawValue(type_class.id())); | 418 __ CompareImmediate(R2, Smi::RawValue(type_class.id())); |
431 __ b(is_instance_lbl, EQ); | 419 __ b(is_instance_lbl, EQ); |
432 | 420 |
433 const Register kTypeArgumentsReg = kNoRegister; | 421 const Register kTypeArgumentsReg = kNoRegister; |
434 const Register kTempReg = kNoRegister; | 422 const Register kTempReg = kNoRegister; |
435 return GenerateCallSubtypeTestStub(kTestTypeOneArg, | 423 return GenerateCallSubtypeTestStub(kTestTypeOneArg, kInstanceReg, |
436 kInstanceReg, | 424 kTypeArgumentsReg, kTempReg, |
437 kTypeArgumentsReg, | 425 is_instance_lbl, is_not_instance_lbl); |
438 kTempReg, | |
439 is_instance_lbl, | |
440 is_not_instance_lbl); | |
441 } | 426 } |
442 | 427 |
443 | 428 |
444 // Generates inlined check if 'type' is a type parameter or type itself | 429 // Generates inlined check if 'type' is a type parameter or type itself |
445 // R0: instance (preserved). | 430 // R0: instance (preserved). |
446 RawSubtypeTestCache* FlowGraphCompiler::GenerateUninstantiatedTypeTest( | 431 RawSubtypeTestCache* FlowGraphCompiler::GenerateUninstantiatedTypeTest( |
447 TokenPosition token_pos, | 432 TokenPosition token_pos, |
448 const AbstractType& type, | 433 const AbstractType& type, |
449 Label* is_instance_lbl, | 434 Label* is_instance_lbl, |
450 Label* is_not_instance_lbl) { | 435 Label* is_not_instance_lbl) { |
451 __ Comment("UninstantiatedTypeTest"); | 436 __ Comment("UninstantiatedTypeTest"); |
452 ASSERT(!type.IsInstantiated()); | 437 ASSERT(!type.IsInstantiated()); |
453 // Skip check if destination is a dynamic type. | 438 // Skip check if destination is a dynamic type. |
454 if (type.IsTypeParameter()) { | 439 if (type.IsTypeParameter()) { |
455 const TypeParameter& type_param = TypeParameter::Cast(type); | 440 const TypeParameter& type_param = TypeParameter::Cast(type); |
456 // Load instantiator type arguments on stack. | 441 // Load instantiator type arguments on stack. |
457 __ ldr(R1, Address(SP)); // Get instantiator type arguments. | 442 __ ldr(R1, Address(SP)); // Get instantiator type arguments. |
458 // R1: instantiator type arguments. | 443 // R1: instantiator type arguments. |
459 // Check if type arguments are null, i.e. equivalent to vector of dynamic. | 444 // Check if type arguments are null, i.e. equivalent to vector of dynamic. |
460 __ CompareObject(R1, Object::null_object()); | 445 __ CompareObject(R1, Object::null_object()); |
461 __ b(is_instance_lbl, EQ); | 446 __ b(is_instance_lbl, EQ); |
462 __ LoadFieldFromOffset( | 447 __ LoadFieldFromOffset(R2, R1, |
463 R2, R1, TypeArguments::type_at_offset(type_param.index())); | 448 TypeArguments::type_at_offset(type_param.index())); |
464 // R2: concrete type of type. | 449 // R2: concrete type of type. |
465 // Check if type argument is dynamic. | 450 // Check if type argument is dynamic. |
466 __ CompareObject(R2, Object::dynamic_type()); | 451 __ CompareObject(R2, Object::dynamic_type()); |
467 __ b(is_instance_lbl, EQ); | 452 __ b(is_instance_lbl, EQ); |
468 __ CompareObject(R2, Type::ZoneHandle(zone(), Type::ObjectType())); | 453 __ CompareObject(R2, Type::ZoneHandle(zone(), Type::ObjectType())); |
469 __ b(is_instance_lbl, EQ); | 454 __ b(is_instance_lbl, EQ); |
470 | 455 |
471 // For Smi check quickly against int and num interfaces. | 456 // For Smi check quickly against int and num interfaces. |
472 Label not_smi; | 457 Label not_smi; |
473 __ tsti(R0, Immediate(kSmiTagMask)); // Value is Smi? | 458 __ tsti(R0, Immediate(kSmiTagMask)); // Value is Smi? |
474 __ b(¬_smi, NE); | 459 __ b(¬_smi, NE); |
475 __ CompareObject(R2, Type::ZoneHandle(zone(), Type::IntType())); | 460 __ CompareObject(R2, Type::ZoneHandle(zone(), Type::IntType())); |
476 __ b(is_instance_lbl, EQ); | 461 __ b(is_instance_lbl, EQ); |
477 __ CompareObject(R2, Type::ZoneHandle(zone(), Type::Number())); | 462 __ CompareObject(R2, Type::ZoneHandle(zone(), Type::Number())); |
478 __ b(is_instance_lbl, EQ); | 463 __ b(is_instance_lbl, EQ); |
479 // Smi must be handled in runtime. | 464 // Smi must be handled in runtime. |
480 Label fall_through; | 465 Label fall_through; |
481 __ b(&fall_through); | 466 __ b(&fall_through); |
482 | 467 |
483 __ Bind(¬_smi); | 468 __ Bind(¬_smi); |
484 // R1: instantiator type arguments. | 469 // R1: instantiator type arguments. |
485 // R0: instance. | 470 // R0: instance. |
486 const Register kInstanceReg = R0; | 471 const Register kInstanceReg = R0; |
487 const Register kTypeArgumentsReg = R1; | 472 const Register kTypeArgumentsReg = R1; |
488 const Register kTempReg = kNoRegister; | 473 const Register kTempReg = kNoRegister; |
489 const SubtypeTestCache& type_test_cache = | 474 const SubtypeTestCache& type_test_cache = SubtypeTestCache::ZoneHandle( |
490 SubtypeTestCache::ZoneHandle(zone(), | 475 zone(), GenerateCallSubtypeTestStub( |
491 GenerateCallSubtypeTestStub(kTestTypeThreeArgs, | 476 kTestTypeThreeArgs, kInstanceReg, kTypeArgumentsReg, |
492 kInstanceReg, | 477 kTempReg, is_instance_lbl, is_not_instance_lbl)); |
493 kTypeArgumentsReg, | |
494 kTempReg, | |
495 is_instance_lbl, | |
496 is_not_instance_lbl)); | |
497 __ Bind(&fall_through); | 478 __ Bind(&fall_through); |
498 return type_test_cache.raw(); | 479 return type_test_cache.raw(); |
499 } | 480 } |
500 if (type.IsType()) { | 481 if (type.IsType()) { |
501 const Register kInstanceReg = R0; | 482 const Register kInstanceReg = R0; |
502 const Register kTypeArgumentsReg = R1; | 483 const Register kTypeArgumentsReg = R1; |
503 __ tsti(kInstanceReg, Immediate(kSmiTagMask)); // Is instance Smi? | 484 __ tsti(kInstanceReg, Immediate(kSmiTagMask)); // Is instance Smi? |
504 __ b(is_not_instance_lbl, EQ); | 485 __ b(is_not_instance_lbl, EQ); |
505 __ ldr(kTypeArgumentsReg, Address(SP)); // Instantiator type args. | 486 __ ldr(kTypeArgumentsReg, Address(SP)); // Instantiator type args. |
506 // Uninstantiated type class is known at compile time, but the type | 487 // Uninstantiated type class is known at compile time, but the type |
507 // arguments are determined at runtime by the instantiator. | 488 // arguments are determined at runtime by the instantiator. |
508 const Register kTempReg = kNoRegister; | 489 const Register kTempReg = kNoRegister; |
509 return GenerateCallSubtypeTestStub(kTestTypeThreeArgs, | 490 return GenerateCallSubtypeTestStub(kTestTypeThreeArgs, kInstanceReg, |
510 kInstanceReg, | 491 kTypeArgumentsReg, kTempReg, |
511 kTypeArgumentsReg, | 492 is_instance_lbl, is_not_instance_lbl); |
512 kTempReg, | |
513 is_instance_lbl, | |
514 is_not_instance_lbl); | |
515 } | 493 } |
516 return SubtypeTestCache::null(); | 494 return SubtypeTestCache::null(); |
517 } | 495 } |
518 | 496 |
519 | 497 |
520 // Inputs: | 498 // Inputs: |
521 // - R0: instance being type checked (preserved). | 499 // - R0: instance being type checked (preserved). |
522 // - R1: optional instantiator type arguments (preserved). | 500 // - R1: optional instantiator type arguments (preserved). |
523 // Clobbers R2, R3. | 501 // Clobbers R2, R3. |
524 // Returns: | 502 // Returns: |
(...skipping 11 matching lines...) Expand all Loading... |
536 // A non-null value is returned from a void function, which will result in a | 514 // A non-null value is returned from a void function, which will result in a |
537 // type error. A null value is handled prior to executing this inline code. | 515 // type error. A null value is handled prior to executing this inline code. |
538 return SubtypeTestCache::null(); | 516 return SubtypeTestCache::null(); |
539 } | 517 } |
540 if (type.IsInstantiated()) { | 518 if (type.IsInstantiated()) { |
541 const Class& type_class = Class::ZoneHandle(zone(), type.type_class()); | 519 const Class& type_class = Class::ZoneHandle(zone(), type.type_class()); |
542 // A class equality check is only applicable with a dst type (not a | 520 // A class equality check is only applicable with a dst type (not a |
543 // function type) of a non-parameterized class or with a raw dst type of | 521 // function type) of a non-parameterized class or with a raw dst type of |
544 // a parameterized class. | 522 // a parameterized class. |
545 if (type.IsFunctionType() || (type_class.NumTypeArguments() > 0)) { | 523 if (type.IsFunctionType() || (type_class.NumTypeArguments() > 0)) { |
546 return GenerateInstantiatedTypeWithArgumentsTest(token_pos, | 524 return GenerateInstantiatedTypeWithArgumentsTest( |
547 type, | 525 token_pos, type, is_instance_lbl, is_not_instance_lbl); |
548 is_instance_lbl, | |
549 is_not_instance_lbl); | |
550 // Fall through to runtime call. | 526 // Fall through to runtime call. |
551 } | 527 } |
552 const bool has_fall_through = | 528 const bool has_fall_through = GenerateInstantiatedTypeNoArgumentsTest( |
553 GenerateInstantiatedTypeNoArgumentsTest(token_pos, | 529 token_pos, type, is_instance_lbl, is_not_instance_lbl); |
554 type, | |
555 is_instance_lbl, | |
556 is_not_instance_lbl); | |
557 if (has_fall_through) { | 530 if (has_fall_through) { |
558 // If test non-conclusive so far, try the inlined type-test cache. | 531 // If test non-conclusive so far, try the inlined type-test cache. |
559 // 'type' is known at compile time. | 532 // 'type' is known at compile time. |
560 return GenerateSubtype1TestCacheLookup( | 533 return GenerateSubtype1TestCacheLookup( |
561 token_pos, type_class, is_instance_lbl, is_not_instance_lbl); | 534 token_pos, type_class, is_instance_lbl, is_not_instance_lbl); |
562 } else { | 535 } else { |
563 return SubtypeTestCache::null(); | 536 return SubtypeTestCache::null(); |
564 } | 537 } |
565 } | 538 } |
566 return GenerateUninstantiatedTypeTest(token_pos, | 539 return GenerateUninstantiatedTypeTest(token_pos, type, is_instance_lbl, |
567 type, | |
568 is_instance_lbl, | |
569 is_not_instance_lbl); | 540 is_not_instance_lbl); |
570 } | 541 } |
571 | 542 |
572 | 543 |
573 // If instanceof type test cannot be performed successfully at compile time and | 544 // If instanceof type test cannot be performed successfully at compile time and |
574 // therefore eliminated, optimize it by adding inlined tests for: | 545 // therefore eliminated, optimize it by adding inlined tests for: |
575 // - NULL -> return false. | 546 // - NULL -> return false. |
576 // - Smi -> compile time subtype check (only if dst class is not parameterized). | 547 // - Smi -> compile time subtype check (only if dst class is not parameterized). |
577 // - Class equality (only if class is not parameterized). | 548 // - Class equality (only if class is not parameterized). |
578 // Inputs: | 549 // Inputs: |
(...skipping 21 matching lines...) Expand all Loading... |
600 // instantiated). | 571 // instantiated). |
601 // We can only inline this null check if the type is instantiated at compile | 572 // We can only inline this null check if the type is instantiated at compile |
602 // time, since an uninstantiated type at compile time could be Object or | 573 // time, since an uninstantiated type at compile time could be Object or |
603 // dynamic at run time. | 574 // dynamic at run time. |
604 __ CompareObject(R0, Object::null_object()); | 575 __ CompareObject(R0, Object::null_object()); |
605 __ b(type.IsNullType() ? &is_instance : &is_not_instance, EQ); | 576 __ b(type.IsNullType() ? &is_instance : &is_not_instance, EQ); |
606 } | 577 } |
607 | 578 |
608 // Generate inline instanceof test. | 579 // Generate inline instanceof test. |
609 SubtypeTestCache& test_cache = SubtypeTestCache::ZoneHandle(zone()); | 580 SubtypeTestCache& test_cache = SubtypeTestCache::ZoneHandle(zone()); |
610 test_cache = GenerateInlineInstanceof(token_pos, type, | 581 test_cache = |
611 &is_instance, &is_not_instance); | 582 GenerateInlineInstanceof(token_pos, type, &is_instance, &is_not_instance); |
612 | 583 |
613 // test_cache is null if there is no fall-through. | 584 // test_cache is null if there is no fall-through. |
614 Label done; | 585 Label done; |
615 if (!test_cache.IsNull()) { | 586 if (!test_cache.IsNull()) { |
616 // Generate runtime call. | 587 // Generate runtime call. |
617 // Load instantiator (R2) and its type arguments (R1). | 588 // Load instantiator (R2) and its type arguments (R1). |
618 __ ldr(R1, Address(SP, 0 * kWordSize)); | 589 __ ldr(R1, Address(SP, 0 * kWordSize)); |
619 __ PushObject(Object::null_object()); // Make room for the result. | 590 __ PushObject(Object::null_object()); // Make room for the result. |
620 __ Push(R0); // Push the instance. | 591 __ Push(R0); // Push the instance. |
621 __ PushObject(type); // Push the type. | 592 __ PushObject(type); // Push the type. |
622 __ Push(R1); // Push instantiator type arguments (R1). | 593 __ Push(R1); // Push instantiator type arguments (R1). |
623 __ LoadUniqueObject(R0, test_cache); | 594 __ LoadUniqueObject(R0, test_cache); |
624 __ Push(R0); | 595 __ Push(R0); |
625 GenerateRuntimeCall(token_pos, deopt_id, kInstanceofRuntimeEntry, 4, locs); | 596 GenerateRuntimeCall(token_pos, deopt_id, kInstanceofRuntimeEntry, 4, locs); |
626 // Pop the parameters supplied to the runtime entry. The result of the | 597 // Pop the parameters supplied to the runtime entry. The result of the |
627 // instanceof runtime call will be left as the result of the operation. | 598 // instanceof runtime call will be left as the result of the operation. |
628 __ Drop(4); | 599 __ Drop(4); |
629 if (negate_result) { | 600 if (negate_result) { |
630 __ Pop(R1); | 601 __ Pop(R1); |
631 __ LoadObject(R0, Bool::True()); | 602 __ LoadObject(R0, Bool::True()); |
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
674 // Preserve instantiator type arguments (R1). | 645 // Preserve instantiator type arguments (R1). |
675 __ Push(R1); | 646 __ Push(R1); |
676 // A null object is always assignable and is returned as result. | 647 // A null object is always assignable and is returned as result. |
677 Label is_assignable, runtime_call; | 648 Label is_assignable, runtime_call; |
678 __ CompareObject(R0, Object::null_object()); | 649 __ CompareObject(R0, Object::null_object()); |
679 __ b(&is_assignable, EQ); | 650 __ b(&is_assignable, EQ); |
680 | 651 |
681 // Generate throw new TypeError() if the type is malformed or malbounded. | 652 // Generate throw new TypeError() if the type is malformed or malbounded. |
682 if (dst_type.IsMalformedOrMalbounded()) { | 653 if (dst_type.IsMalformedOrMalbounded()) { |
683 __ PushObject(Object::null_object()); // Make room for the result. | 654 __ PushObject(Object::null_object()); // Make room for the result. |
684 __ Push(R0); // Push the source object. | 655 __ Push(R0); // Push the source object. |
685 __ PushObject(dst_name); // Push the name of the destination. | 656 __ PushObject(dst_name); // Push the name of the destination. |
686 __ PushObject(dst_type); // Push the type of the destination. | 657 __ PushObject(dst_type); // Push the type of the destination. |
687 GenerateRuntimeCall(token_pos, | 658 GenerateRuntimeCall(token_pos, deopt_id, kBadTypeErrorRuntimeEntry, 3, |
688 deopt_id, | |
689 kBadTypeErrorRuntimeEntry, | |
690 3, | |
691 locs); | 659 locs); |
692 // We should never return here. | 660 // We should never return here. |
693 __ brk(0); | 661 __ brk(0); |
694 | 662 |
695 __ Bind(&is_assignable); // For a null object. | 663 __ Bind(&is_assignable); // For a null object. |
696 // Restore instantiator type arguments (R1). | 664 // Restore instantiator type arguments (R1). |
697 __ Pop(R1); | 665 __ Pop(R1); |
698 return; | 666 return; |
699 } | 667 } |
700 | 668 |
701 // Generate inline type check, linking to runtime call if not assignable. | 669 // Generate inline type check, linking to runtime call if not assignable. |
702 SubtypeTestCache& test_cache = SubtypeTestCache::ZoneHandle(zone()); | 670 SubtypeTestCache& test_cache = SubtypeTestCache::ZoneHandle(zone()); |
703 test_cache = GenerateInlineInstanceof(token_pos, dst_type, | 671 test_cache = GenerateInlineInstanceof(token_pos, dst_type, &is_assignable, |
704 &is_assignable, &runtime_call); | 672 &runtime_call); |
705 | 673 |
706 __ Bind(&runtime_call); | 674 __ Bind(&runtime_call); |
707 __ ldr(R1, Address(SP)); // Load instantiator type arguments (R1). | 675 __ ldr(R1, Address(SP)); // Load instantiator type arguments (R1). |
708 __ PushObject(Object::null_object()); // Make room for the result. | 676 __ PushObject(Object::null_object()); // Make room for the result. |
709 __ Push(R0); // Push the source object. | 677 __ Push(R0); // Push the source object. |
710 __ PushObject(dst_type); // Push the type of the destination. | 678 __ PushObject(dst_type); // Push the type of the destination. |
711 __ Push(R1); // Push instantiator type arguments (R1). | 679 __ Push(R1); // Push instantiator type arguments (R1). |
712 __ PushObject(dst_name); // Push the name of the destination. | 680 __ PushObject(dst_name); // Push the name of the destination. |
713 __ LoadUniqueObject(R0, test_cache); | 681 __ LoadUniqueObject(R0, test_cache); |
714 __ Push(R0); | 682 __ Push(R0); |
715 GenerateRuntimeCall(token_pos, deopt_id, kTypeCheckRuntimeEntry, 5, locs); | 683 GenerateRuntimeCall(token_pos, deopt_id, kTypeCheckRuntimeEntry, 5, locs); |
716 // Pop the parameters supplied to the runtime entry. The result of the | 684 // Pop the parameters supplied to the runtime entry. The result of the |
717 // type check runtime call is the checked value. | 685 // type check runtime call is the checked value. |
718 __ Drop(5); | 686 __ Drop(5); |
719 __ Pop(R0); | 687 __ Pop(R0); |
720 | 688 |
721 __ Bind(&is_assignable); | 689 __ Bind(&is_assignable); |
(...skipping 25 matching lines...) Expand all Loading... |
747 const int num_params = | 715 const int num_params = |
748 num_fixed_params + num_opt_pos_params + num_opt_named_params; | 716 num_fixed_params + num_opt_pos_params + num_opt_named_params; |
749 ASSERT(function.NumParameters() == num_params); | 717 ASSERT(function.NumParameters() == num_params); |
750 ASSERT(parsed_function().first_parameter_index() == kFirstLocalSlotFromFp); | 718 ASSERT(parsed_function().first_parameter_index() == kFirstLocalSlotFromFp); |
751 | 719 |
752 // Check that min_num_pos_args <= num_pos_args <= max_num_pos_args, | 720 // Check that min_num_pos_args <= num_pos_args <= max_num_pos_args, |
753 // where num_pos_args is the number of positional arguments passed in. | 721 // where num_pos_args is the number of positional arguments passed in. |
754 const int min_num_pos_args = num_fixed_params; | 722 const int min_num_pos_args = num_fixed_params; |
755 const int max_num_pos_args = num_fixed_params + num_opt_pos_params; | 723 const int max_num_pos_args = num_fixed_params + num_opt_pos_params; |
756 | 724 |
757 __ LoadFieldFromOffset( | 725 __ LoadFieldFromOffset(R8, R4, |
758 R8, R4, ArgumentsDescriptor::positional_count_offset()); | 726 ArgumentsDescriptor::positional_count_offset()); |
759 // Check that min_num_pos_args <= num_pos_args. | 727 // Check that min_num_pos_args <= num_pos_args. |
760 Label wrong_num_arguments; | 728 Label wrong_num_arguments; |
761 __ CompareImmediate(R8, Smi::RawValue(min_num_pos_args)); | 729 __ CompareImmediate(R8, Smi::RawValue(min_num_pos_args)); |
762 __ b(&wrong_num_arguments, LT); | 730 __ b(&wrong_num_arguments, LT); |
763 // Check that num_pos_args <= max_num_pos_args. | 731 // Check that num_pos_args <= max_num_pos_args. |
764 __ CompareImmediate(R8, Smi::RawValue(max_num_pos_args)); | 732 __ CompareImmediate(R8, Smi::RawValue(max_num_pos_args)); |
765 __ b(&wrong_num_arguments, GT); | 733 __ b(&wrong_num_arguments, GT); |
766 | 734 |
767 // Copy positional arguments. | 735 // Copy positional arguments. |
768 // Argument i passed at fp[kParamEndSlotFromFp + num_args - i] is copied | 736 // Argument i passed at fp[kParamEndSlotFromFp + num_args - i] is copied |
(...skipping 22 matching lines...) Expand all Loading... |
791 __ Bind(&loop); | 759 __ Bind(&loop); |
792 __ ldr(TMP, argument_addr); | 760 __ ldr(TMP, argument_addr); |
793 __ str(TMP, copy_addr); | 761 __ str(TMP, copy_addr); |
794 __ Bind(&loop_condition); | 762 __ Bind(&loop_condition); |
795 __ subs(R8, R8, Operand(1)); | 763 __ subs(R8, R8, Operand(1)); |
796 __ b(&loop, PL); | 764 __ b(&loop, PL); |
797 | 765 |
798 // Copy or initialize optional named arguments. | 766 // Copy or initialize optional named arguments. |
799 Label all_arguments_processed; | 767 Label all_arguments_processed; |
800 #ifdef DEBUG | 768 #ifdef DEBUG |
801 const bool check_correct_named_args = true; | 769 const bool check_correct_named_args = true; |
802 #else | 770 #else |
803 const bool check_correct_named_args = function.IsClosureFunction(); | 771 const bool check_correct_named_args = function.IsClosureFunction(); |
804 #endif | 772 #endif |
805 if (num_opt_named_params > 0) { | 773 if (num_opt_named_params > 0) { |
806 // Start by alphabetically sorting the names of the optional parameters. | 774 // Start by alphabetically sorting the names of the optional parameters. |
807 LocalVariable** opt_param = new LocalVariable*[num_opt_named_params]; | 775 LocalVariable** opt_param = new LocalVariable*[num_opt_named_params]; |
808 int* opt_param_position = new int[num_opt_named_params]; | 776 int* opt_param_position = new int[num_opt_named_params]; |
809 for (int pos = num_fixed_params; pos < num_params; pos++) { | 777 for (int pos = num_fixed_params; pos < num_params; pos++) { |
810 LocalVariable* parameter = scope->VariableAt(pos); | 778 LocalVariable* parameter = scope->VariableAt(pos); |
811 const String& opt_param_name = parameter->name(); | 779 const String& opt_param_name = parameter->name(); |
812 int i = pos - num_fixed_params; | 780 int i = pos - num_fixed_params; |
813 while (--i >= 0) { | 781 while (--i >= 0) { |
814 LocalVariable* param_i = opt_param[i]; | 782 LocalVariable* param_i = opt_param[i]; |
815 const intptr_t result = opt_param_name.CompareTo(param_i->name()); | 783 const intptr_t result = opt_param_name.CompareTo(param_i->name()); |
816 ASSERT(result != 0); | 784 ASSERT(result != 0); |
817 if (result > 0) break; | 785 if (result > 0) break; |
818 opt_param[i + 1] = opt_param[i]; | 786 opt_param[i + 1] = opt_param[i]; |
819 opt_param_position[i + 1] = opt_param_position[i]; | 787 opt_param_position[i + 1] = opt_param_position[i]; |
820 } | 788 } |
821 opt_param[i + 1] = parameter; | 789 opt_param[i + 1] = parameter; |
822 opt_param_position[i + 1] = pos; | 790 opt_param_position[i + 1] = pos; |
823 } | 791 } |
824 // Generate code handling each optional parameter in alphabetical order. | 792 // Generate code handling each optional parameter in alphabetical order. |
825 __ LoadFieldFromOffset(R7, R4, ArgumentsDescriptor::count_offset()); | 793 __ LoadFieldFromOffset(R7, R4, ArgumentsDescriptor::count_offset()); |
826 __ LoadFieldFromOffset( | 794 __ LoadFieldFromOffset(R8, R4, |
827 R8, R4, ArgumentsDescriptor::positional_count_offset()); | 795 ArgumentsDescriptor::positional_count_offset()); |
828 __ SmiUntag(R8); | 796 __ SmiUntag(R8); |
829 // Let R7 point to the first passed argument, i.e. to | 797 // Let R7 point to the first passed argument, i.e. to |
830 // fp[kParamEndSlotFromFp + num_args - 0]; num_args (R7) is Smi. | 798 // fp[kParamEndSlotFromFp + num_args - 0]; num_args (R7) is Smi. |
831 __ add(R7, FP, Operand(R7, LSL, 2)); | 799 __ add(R7, FP, Operand(R7, LSL, 2)); |
832 __ AddImmediate(R7, R7, kParamEndSlotFromFp * kWordSize); | 800 __ AddImmediate(R7, R7, kParamEndSlotFromFp * kWordSize); |
833 // Let R6 point to the entry of the first named argument. | 801 // Let R6 point to the entry of the first named argument. |
834 __ add(R6, R4, Operand( | 802 __ add(R6, R4, Operand(ArgumentsDescriptor::first_named_entry_offset() - |
835 ArgumentsDescriptor::first_named_entry_offset() - kHeapObjectTag)); | 803 kHeapObjectTag)); |
836 for (int i = 0; i < num_opt_named_params; i++) { | 804 for (int i = 0; i < num_opt_named_params; i++) { |
837 Label load_default_value, assign_optional_parameter; | 805 Label load_default_value, assign_optional_parameter; |
838 const int param_pos = opt_param_position[i]; | 806 const int param_pos = opt_param_position[i]; |
839 // Check if this named parameter was passed in. | 807 // Check if this named parameter was passed in. |
840 // Load R5 with the name of the argument. | 808 // Load R5 with the name of the argument. |
841 __ LoadFromOffset(R5, R6, ArgumentsDescriptor::name_offset()); | 809 __ LoadFromOffset(R5, R6, ArgumentsDescriptor::name_offset()); |
842 ASSERT(opt_param[i]->name().IsSymbol()); | 810 ASSERT(opt_param[i]->name().IsSymbol()); |
843 __ CompareObject(R5, opt_param[i]->name()); | 811 __ CompareObject(R5, opt_param[i]->name()); |
844 __ b(&load_default_value, NE); | 812 __ b(&load_default_value, NE); |
845 // Load R5 with passed-in argument at provided arg_pos, i.e. at | 813 // Load R5 with passed-in argument at provided arg_pos, i.e. at |
(...skipping 24 matching lines...) Expand all Loading... |
870 delete[] opt_param_position; | 838 delete[] opt_param_position; |
871 if (check_correct_named_args) { | 839 if (check_correct_named_args) { |
872 // Check that R6 now points to the null terminator in the arguments | 840 // Check that R6 now points to the null terminator in the arguments |
873 // descriptor. | 841 // descriptor. |
874 __ ldr(R5, Address(R6)); | 842 __ ldr(R5, Address(R6)); |
875 __ CompareObject(R5, Object::null_object()); | 843 __ CompareObject(R5, Object::null_object()); |
876 __ b(&all_arguments_processed, EQ); | 844 __ b(&all_arguments_processed, EQ); |
877 } | 845 } |
878 } else { | 846 } else { |
879 ASSERT(num_opt_pos_params > 0); | 847 ASSERT(num_opt_pos_params > 0); |
880 __ LoadFieldFromOffset( | 848 __ LoadFieldFromOffset(R8, R4, |
881 R8, R4, ArgumentsDescriptor::positional_count_offset()); | 849 ArgumentsDescriptor::positional_count_offset()); |
882 __ SmiUntag(R8); | 850 __ SmiUntag(R8); |
883 for (int i = 0; i < num_opt_pos_params; i++) { | 851 for (int i = 0; i < num_opt_pos_params; i++) { |
884 Label next_parameter; | 852 Label next_parameter; |
885 // Handle this optional positional parameter only if k or fewer positional | 853 // Handle this optional positional parameter only if k or fewer positional |
886 // arguments have been passed, where k is param_pos, the position of this | 854 // arguments have been passed, where k is param_pos, the position of this |
887 // optional parameter in the formal parameter list. | 855 // optional parameter in the formal parameter list. |
888 const int param_pos = num_fixed_params + i; | 856 const int param_pos = num_fixed_params + i; |
889 __ CompareImmediate(R8, param_pos); | 857 __ CompareImmediate(R8, param_pos); |
890 __ b(&next_parameter, GT); | 858 __ b(&next_parameter, GT); |
891 // Load R5 with default argument. | 859 // Load R5 with default argument. |
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
961 __ LoadFromOffset(R1, SP, 0 * kWordSize); // Value. | 929 __ LoadFromOffset(R1, SP, 0 * kWordSize); // Value. |
962 __ StoreIntoObjectOffset(R0, offset, R1); | 930 __ StoreIntoObjectOffset(R0, offset, R1); |
963 __ LoadObject(R0, Object::null_object()); | 931 __ LoadObject(R0, Object::null_object()); |
964 __ ret(); | 932 __ ret(); |
965 } | 933 } |
966 | 934 |
967 | 935 |
968 void FlowGraphCompiler::EmitFrameEntry() { | 936 void FlowGraphCompiler::EmitFrameEntry() { |
969 const Function& function = parsed_function().function(); | 937 const Function& function = parsed_function().function(); |
970 Register new_pp = kNoRegister; | 938 Register new_pp = kNoRegister; |
971 if (CanOptimizeFunction() && | 939 if (CanOptimizeFunction() && function.IsOptimizable() && |
972 function.IsOptimizable() && | |
973 (!is_optimizing() || may_reoptimize())) { | 940 (!is_optimizing() || may_reoptimize())) { |
974 __ Comment("Invocation Count Check"); | 941 __ Comment("Invocation Count Check"); |
975 const Register function_reg = R6; | 942 const Register function_reg = R6; |
976 new_pp = R13; | 943 new_pp = R13; |
977 // The pool pointer is not setup before entering the Dart frame. | 944 // The pool pointer is not setup before entering the Dart frame. |
978 // Temporarily setup pool pointer for this dart function. | 945 // Temporarily setup pool pointer for this dart function. |
979 __ LoadPoolPointer(new_pp); | 946 __ LoadPoolPointer(new_pp); |
980 | 947 |
981 // Load function object using the callee's pool pointer. | 948 // Load function object using the callee's pool pointer. |
982 __ LoadFunctionFromCalleePool(function_reg, function, new_pp); | 949 __ LoadFunctionFromCalleePool(function_reg, function, new_pp); |
983 | 950 |
984 __ LoadFieldFromOffset( | 951 __ LoadFieldFromOffset(R7, function_reg, Function::usage_counter_offset(), |
985 R7, function_reg, Function::usage_counter_offset(), kWord); | 952 kWord); |
986 // Reoptimization of an optimized function is triggered by counting in | 953 // Reoptimization of an optimized function is triggered by counting in |
987 // IC stubs, but not at the entry of the function. | 954 // IC stubs, but not at the entry of the function. |
988 if (!is_optimizing()) { | 955 if (!is_optimizing()) { |
989 __ add(R7, R7, Operand(1)); | 956 __ add(R7, R7, Operand(1)); |
990 __ StoreFieldToOffset( | 957 __ StoreFieldToOffset(R7, function_reg, Function::usage_counter_offset(), |
991 R7, function_reg, Function::usage_counter_offset(), kWord); | 958 kWord); |
992 } | 959 } |
993 __ CompareImmediate(R7, GetOptimizationThreshold()); | 960 __ CompareImmediate(R7, GetOptimizationThreshold()); |
994 ASSERT(function_reg == R6); | 961 ASSERT(function_reg == R6); |
995 Label dont_optimize; | 962 Label dont_optimize; |
996 __ b(&dont_optimize, LT); | 963 __ b(&dont_optimize, LT); |
997 __ Branch(*StubCode::OptimizeFunction_entry(), new_pp); | 964 __ Branch(*StubCode::OptimizeFunction_entry(), new_pp); |
998 __ Bind(&dont_optimize); | 965 __ Bind(&dont_optimize); |
999 } | 966 } |
1000 __ Comment("Enter frame"); | 967 __ Comment("Enter frame"); |
1001 if (flow_graph().IsCompiledForOsr()) { | 968 if (flow_graph().IsCompiledForOsr()) { |
1002 intptr_t extra_slots = StackSize() | 969 intptr_t extra_slots = StackSize() - flow_graph().num_stack_locals() - |
1003 - flow_graph().num_stack_locals() | 970 flow_graph().num_copied_params(); |
1004 - flow_graph().num_copied_params(); | |
1005 ASSERT(extra_slots >= 0); | 971 ASSERT(extra_slots >= 0); |
1006 __ EnterOsrFrame(extra_slots * kWordSize, new_pp); | 972 __ EnterOsrFrame(extra_slots * kWordSize, new_pp); |
1007 } else { | 973 } else { |
1008 ASSERT(StackSize() >= 0); | 974 ASSERT(StackSize() >= 0); |
1009 __ EnterDartFrame(StackSize() * kWordSize, new_pp); | 975 __ EnterDartFrame(StackSize() * kWordSize, new_pp); |
1010 } | 976 } |
1011 } | 977 } |
1012 | 978 |
1013 | 979 |
1014 // Input parameters: | 980 // Input parameters: |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1048 const bool check_arguments = | 1014 const bool check_arguments = |
1049 function.IsClosureFunction() && !flow_graph().IsCompiledForOsr(); | 1015 function.IsClosureFunction() && !flow_graph().IsCompiledForOsr(); |
1050 if (check_arguments) { | 1016 if (check_arguments) { |
1051 __ Comment("Check argument count"); | 1017 __ Comment("Check argument count"); |
1052 // Check that exactly num_fixed arguments are passed in. | 1018 // Check that exactly num_fixed arguments are passed in. |
1053 Label correct_num_arguments, wrong_num_arguments; | 1019 Label correct_num_arguments, wrong_num_arguments; |
1054 __ LoadFieldFromOffset(R0, R4, ArgumentsDescriptor::count_offset()); | 1020 __ LoadFieldFromOffset(R0, R4, ArgumentsDescriptor::count_offset()); |
1055 __ CompareImmediate(R0, Smi::RawValue(num_fixed_params)); | 1021 __ CompareImmediate(R0, Smi::RawValue(num_fixed_params)); |
1056 __ b(&wrong_num_arguments, NE); | 1022 __ b(&wrong_num_arguments, NE); |
1057 __ LoadFieldFromOffset(R1, R4, | 1023 __ LoadFieldFromOffset(R1, R4, |
1058 ArgumentsDescriptor::positional_count_offset()); | 1024 ArgumentsDescriptor::positional_count_offset()); |
1059 __ CompareRegisters(R0, R1); | 1025 __ CompareRegisters(R0, R1); |
1060 __ b(&correct_num_arguments, EQ); | 1026 __ b(&correct_num_arguments, EQ); |
1061 __ Bind(&wrong_num_arguments); | 1027 __ Bind(&wrong_num_arguments); |
1062 __ LeaveDartFrame(kKeepCalleePP); // Arguments are still on the stack. | 1028 __ LeaveDartFrame(kKeepCalleePP); // Arguments are still on the stack. |
1063 __ BranchPatchable(*StubCode::CallClosureNoSuchMethod_entry()); | 1029 __ BranchPatchable(*StubCode::CallClosureNoSuchMethod_entry()); |
1064 // The noSuchMethod call may return to the caller, but not here. | 1030 // The noSuchMethod call may return to the caller, but not here. |
1065 __ Bind(&correct_num_arguments); | 1031 __ Bind(&correct_num_arguments); |
1066 } | 1032 } |
1067 } else if (!flow_graph().IsCompiledForOsr()) { | 1033 } else if (!flow_graph().IsCompiledForOsr()) { |
1068 CopyParameters(); | 1034 CopyParameters(); |
(...skipping 136 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1205 ASSERT(!edge_counters_array_.IsNull()); | 1171 ASSERT(!edge_counters_array_.IsNull()); |
1206 ASSERT(assembler_->constant_pool_allowed()); | 1172 ASSERT(assembler_->constant_pool_allowed()); |
1207 __ Comment("Edge counter"); | 1173 __ Comment("Edge counter"); |
1208 __ LoadObject(R0, edge_counters_array_); | 1174 __ LoadObject(R0, edge_counters_array_); |
1209 __ LoadFieldFromOffset(TMP, R0, Array::element_offset(edge_id)); | 1175 __ LoadFieldFromOffset(TMP, R0, Array::element_offset(edge_id)); |
1210 __ add(TMP, TMP, Operand(Smi::RawValue(1))); | 1176 __ add(TMP, TMP, Operand(Smi::RawValue(1))); |
1211 __ StoreFieldToOffset(TMP, R0, Array::element_offset(edge_id)); | 1177 __ StoreFieldToOffset(TMP, R0, Array::element_offset(edge_id)); |
1212 } | 1178 } |
1213 | 1179 |
1214 | 1180 |
1215 void FlowGraphCompiler::EmitOptimizedInstanceCall( | 1181 void FlowGraphCompiler::EmitOptimizedInstanceCall(const StubEntry& stub_entry, |
1216 const StubEntry& stub_entry, | 1182 const ICData& ic_data, |
1217 const ICData& ic_data, | 1183 intptr_t argument_count, |
1218 intptr_t argument_count, | 1184 intptr_t deopt_id, |
1219 intptr_t deopt_id, | 1185 TokenPosition token_pos, |
1220 TokenPosition token_pos, | 1186 LocationSummary* locs) { |
1221 LocationSummary* locs) { | |
1222 ASSERT(Array::Handle(zone(), ic_data.arguments_descriptor()).Length() > 0); | 1187 ASSERT(Array::Handle(zone(), ic_data.arguments_descriptor()).Length() > 0); |
1223 // Each ICData propagated from unoptimized to optimized code contains the | 1188 // Each ICData propagated from unoptimized to optimized code contains the |
1224 // function that corresponds to the Dart function of that IC call. Due | 1189 // function that corresponds to the Dart function of that IC call. Due |
1225 // to inlining in optimized code, that function may not correspond to the | 1190 // to inlining in optimized code, that function may not correspond to the |
1226 // top-level function (parsed_function().function()) which could be | 1191 // top-level function (parsed_function().function()) which could be |
1227 // reoptimized and which counter needs to be incremented. | 1192 // reoptimized and which counter needs to be incremented. |
1228 // Pass the function explicitly, it is used in IC stub. | 1193 // Pass the function explicitly, it is used in IC stub. |
1229 | 1194 |
1230 __ LoadObject(R6, parsed_function().function()); | 1195 __ LoadObject(R6, parsed_function().function()); |
1231 __ LoadUniqueObject(R5, ic_data); | 1196 __ LoadUniqueObject(R5, ic_data); |
1232 GenerateDartCall(deopt_id, | 1197 GenerateDartCall(deopt_id, token_pos, stub_entry, RawPcDescriptors::kIcCall, |
1233 token_pos, | |
1234 stub_entry, | |
1235 RawPcDescriptors::kIcCall, | |
1236 locs); | 1198 locs); |
1237 __ Drop(argument_count); | 1199 __ Drop(argument_count); |
1238 } | 1200 } |
1239 | 1201 |
1240 | 1202 |
1241 void FlowGraphCompiler::EmitInstanceCall(const StubEntry& stub_entry, | 1203 void FlowGraphCompiler::EmitInstanceCall(const StubEntry& stub_entry, |
1242 const ICData& ic_data, | 1204 const ICData& ic_data, |
1243 intptr_t argument_count, | 1205 intptr_t argument_count, |
1244 intptr_t deopt_id, | 1206 intptr_t deopt_id, |
1245 TokenPosition token_pos, | 1207 TokenPosition token_pos, |
1246 LocationSummary* locs) { | 1208 LocationSummary* locs) { |
1247 ASSERT(Array::Handle(zone(), ic_data.arguments_descriptor()).Length() > 0); | 1209 ASSERT(Array::Handle(zone(), ic_data.arguments_descriptor()).Length() > 0); |
1248 __ LoadUniqueObject(R5, ic_data); | 1210 __ LoadUniqueObject(R5, ic_data); |
1249 GenerateDartCall(deopt_id, | 1211 GenerateDartCall(deopt_id, token_pos, stub_entry, RawPcDescriptors::kIcCall, |
1250 token_pos, | |
1251 stub_entry, | |
1252 RawPcDescriptors::kIcCall, | |
1253 locs); | 1212 locs); |
1254 __ Drop(argument_count); | 1213 __ Drop(argument_count); |
1255 } | 1214 } |
1256 | 1215 |
1257 | 1216 |
1258 void FlowGraphCompiler::EmitMegamorphicInstanceCall( | 1217 void FlowGraphCompiler::EmitMegamorphicInstanceCall( |
1259 const ICData& ic_data, | 1218 const ICData& ic_data, |
1260 intptr_t argument_count, | 1219 intptr_t argument_count, |
1261 intptr_t deopt_id, | 1220 intptr_t deopt_id, |
1262 TokenPosition token_pos, | 1221 TokenPosition token_pos, |
1263 LocationSummary* locs, | 1222 LocationSummary* locs, |
1264 intptr_t try_index, | 1223 intptr_t try_index, |
1265 intptr_t slow_path_argument_count) { | 1224 intptr_t slow_path_argument_count) { |
1266 const String& name = String::Handle(zone(), ic_data.target_name()); | 1225 const String& name = String::Handle(zone(), ic_data.target_name()); |
1267 const Array& arguments_descriptor = | 1226 const Array& arguments_descriptor = |
1268 Array::ZoneHandle(zone(), ic_data.arguments_descriptor()); | 1227 Array::ZoneHandle(zone(), ic_data.arguments_descriptor()); |
1269 ASSERT(!arguments_descriptor.IsNull() && (arguments_descriptor.Length() > 0)); | 1228 ASSERT(!arguments_descriptor.IsNull() && (arguments_descriptor.Length() > 0)); |
1270 const MegamorphicCache& cache = MegamorphicCache::ZoneHandle(zone(), | 1229 const MegamorphicCache& cache = MegamorphicCache::ZoneHandle( |
| 1230 zone(), |
1271 MegamorphicCacheTable::Lookup(isolate(), name, arguments_descriptor)); | 1231 MegamorphicCacheTable::Lookup(isolate(), name, arguments_descriptor)); |
1272 | 1232 |
1273 __ Comment("MegamorphicCall"); | 1233 __ Comment("MegamorphicCall"); |
1274 // Load receiver into R0. | 1234 // Load receiver into R0. |
1275 __ LoadFromOffset(R0, SP, (argument_count - 1) * kWordSize); | 1235 __ LoadFromOffset(R0, SP, (argument_count - 1) * kWordSize); |
1276 Label done; | 1236 Label done; |
1277 if (ShouldInlineSmiStringHashCode(ic_data)) { | 1237 if (ShouldInlineSmiStringHashCode(ic_data)) { |
1278 Label megamorphic_call; | 1238 Label megamorphic_call; |
1279 __ Comment("Inlined get:hashCode for Smi and OneByteString"); | 1239 __ Comment("Inlined get:hashCode for Smi and OneByteString"); |
1280 __ tsti(R0, Immediate(kSmiTagMask)); | 1240 __ tsti(R0, Immediate(kSmiTagMask)); |
(...skipping 19 matching lines...) Expand all Loading... |
1300 | 1260 |
1301 __ Bind(&done); | 1261 __ Bind(&done); |
1302 RecordSafepoint(locs, slow_path_argument_count); | 1262 RecordSafepoint(locs, slow_path_argument_count); |
1303 const intptr_t deopt_id_after = Thread::ToDeoptAfter(deopt_id); | 1263 const intptr_t deopt_id_after = Thread::ToDeoptAfter(deopt_id); |
1304 if (FLAG_precompiled_mode) { | 1264 if (FLAG_precompiled_mode) { |
1305 // Megamorphic calls may occur in slow path stubs. | 1265 // Megamorphic calls may occur in slow path stubs. |
1306 // If valid use try_index argument. | 1266 // If valid use try_index argument. |
1307 if (try_index == CatchClauseNode::kInvalidTryIndex) { | 1267 if (try_index == CatchClauseNode::kInvalidTryIndex) { |
1308 try_index = CurrentTryIndex(); | 1268 try_index = CurrentTryIndex(); |
1309 } | 1269 } |
1310 pc_descriptors_list()->AddDescriptor(RawPcDescriptors::kOther, | 1270 pc_descriptors_list()->AddDescriptor( |
1311 assembler()->CodeSize(), | 1271 RawPcDescriptors::kOther, assembler()->CodeSize(), Thread::kNoDeoptId, |
1312 Thread::kNoDeoptId, | 1272 token_pos, try_index); |
1313 token_pos, | |
1314 try_index); | |
1315 } else if (is_optimizing()) { | 1273 } else if (is_optimizing()) { |
1316 AddCurrentDescriptor(RawPcDescriptors::kOther, | 1274 AddCurrentDescriptor(RawPcDescriptors::kOther, Thread::kNoDeoptId, |
1317 Thread::kNoDeoptId, token_pos); | 1275 token_pos); |
1318 AddDeoptIndexAtCall(deopt_id_after); | 1276 AddDeoptIndexAtCall(deopt_id_after); |
1319 } else { | 1277 } else { |
1320 AddCurrentDescriptor(RawPcDescriptors::kOther, | 1278 AddCurrentDescriptor(RawPcDescriptors::kOther, Thread::kNoDeoptId, |
1321 Thread::kNoDeoptId, token_pos); | 1279 token_pos); |
1322 // Add deoptimization continuation point after the call and before the | 1280 // Add deoptimization continuation point after the call and before the |
1323 // arguments are removed. | 1281 // arguments are removed. |
1324 AddCurrentDescriptor(RawPcDescriptors::kDeopt, deopt_id_after, token_pos); | 1282 AddCurrentDescriptor(RawPcDescriptors::kDeopt, deopt_id_after, token_pos); |
1325 } | 1283 } |
1326 __ Drop(argument_count); | 1284 __ Drop(argument_count); |
1327 } | 1285 } |
1328 | 1286 |
1329 | 1287 |
1330 void FlowGraphCompiler::EmitSwitchableInstanceCall( | 1288 void FlowGraphCompiler::EmitSwitchableInstanceCall(const ICData& ic_data, |
1331 const ICData& ic_data, | 1289 intptr_t argument_count, |
1332 intptr_t argument_count, | 1290 intptr_t deopt_id, |
1333 intptr_t deopt_id, | 1291 TokenPosition token_pos, |
1334 TokenPosition token_pos, | 1292 LocationSummary* locs) { |
1335 LocationSummary* locs) { | |
1336 ASSERT(ic_data.NumArgsTested() == 1); | 1293 ASSERT(ic_data.NumArgsTested() == 1); |
1337 const Code& initial_stub = Code::ZoneHandle( | 1294 const Code& initial_stub = |
1338 StubCode::ICCallThroughFunction_entry()->code()); | 1295 Code::ZoneHandle(StubCode::ICCallThroughFunction_entry()->code()); |
1339 __ Comment("SwitchableCall"); | 1296 __ Comment("SwitchableCall"); |
1340 | 1297 |
1341 __ LoadFromOffset(R0, SP, (argument_count - 1) * kWordSize); | 1298 __ LoadFromOffset(R0, SP, (argument_count - 1) * kWordSize); |
1342 __ LoadUniqueObject(CODE_REG, initial_stub); | 1299 __ LoadUniqueObject(CODE_REG, initial_stub); |
1343 __ ldr(TMP, FieldAddress(CODE_REG, Code::checked_entry_point_offset())); | 1300 __ ldr(TMP, FieldAddress(CODE_REG, Code::checked_entry_point_offset())); |
1344 __ LoadUniqueObject(R5, ic_data); | 1301 __ LoadUniqueObject(R5, ic_data); |
1345 __ blr(TMP); | 1302 __ blr(TMP); |
1346 | 1303 |
1347 AddCurrentDescriptor(RawPcDescriptors::kOther, | 1304 AddCurrentDescriptor(RawPcDescriptors::kOther, Thread::kNoDeoptId, token_pos); |
1348 Thread::kNoDeoptId, token_pos); | |
1349 RecordSafepoint(locs); | 1305 RecordSafepoint(locs); |
1350 const intptr_t deopt_id_after = Thread::ToDeoptAfter(deopt_id); | 1306 const intptr_t deopt_id_after = Thread::ToDeoptAfter(deopt_id); |
1351 if (is_optimizing()) { | 1307 if (is_optimizing()) { |
1352 AddDeoptIndexAtCall(deopt_id_after); | 1308 AddDeoptIndexAtCall(deopt_id_after); |
1353 } else { | 1309 } else { |
1354 // Add deoptimization continuation point after the call and before the | 1310 // Add deoptimization continuation point after the call and before the |
1355 // arguments are removed. | 1311 // arguments are removed. |
1356 AddCurrentDescriptor(RawPcDescriptors::kDeopt, deopt_id_after, token_pos); | 1312 AddCurrentDescriptor(RawPcDescriptors::kDeopt, deopt_id_after, token_pos); |
1357 } | 1313 } |
1358 __ Drop(argument_count); | 1314 __ Drop(argument_count); |
1359 } | 1315 } |
1360 | 1316 |
1361 | 1317 |
1362 void FlowGraphCompiler::EmitUnoptimizedStaticCall( | 1318 void FlowGraphCompiler::EmitUnoptimizedStaticCall(intptr_t argument_count, |
1363 intptr_t argument_count, | 1319 intptr_t deopt_id, |
1364 intptr_t deopt_id, | 1320 TokenPosition token_pos, |
1365 TokenPosition token_pos, | 1321 LocationSummary* locs, |
1366 LocationSummary* locs, | 1322 const ICData& ic_data) { |
1367 const ICData& ic_data) { | |
1368 const StubEntry* stub_entry = | 1323 const StubEntry* stub_entry = |
1369 StubCode::UnoptimizedStaticCallEntry(ic_data.NumArgsTested()); | 1324 StubCode::UnoptimizedStaticCallEntry(ic_data.NumArgsTested()); |
1370 __ LoadObject(R5, ic_data); | 1325 __ LoadObject(R5, ic_data); |
1371 GenerateDartCall(deopt_id, | 1326 GenerateDartCall(deopt_id, token_pos, *stub_entry, |
1372 token_pos, | 1327 RawPcDescriptors::kUnoptStaticCall, locs); |
1373 *stub_entry, | |
1374 RawPcDescriptors::kUnoptStaticCall, | |
1375 locs); | |
1376 __ Drop(argument_count); | 1328 __ Drop(argument_count); |
1377 } | 1329 } |
1378 | 1330 |
1379 | 1331 |
1380 void FlowGraphCompiler::EmitOptimizedStaticCall( | 1332 void FlowGraphCompiler::EmitOptimizedStaticCall( |
1381 const Function& function, | 1333 const Function& function, |
1382 const Array& arguments_descriptor, | 1334 const Array& arguments_descriptor, |
1383 intptr_t argument_count, | 1335 intptr_t argument_count, |
1384 intptr_t deopt_id, | 1336 intptr_t deopt_id, |
1385 TokenPosition token_pos, | 1337 TokenPosition token_pos, |
1386 LocationSummary* locs) { | 1338 LocationSummary* locs) { |
1387 ASSERT(!function.IsClosureFunction()); | 1339 ASSERT(!function.IsClosureFunction()); |
1388 if (function.HasOptionalParameters()) { | 1340 if (function.HasOptionalParameters()) { |
1389 __ LoadObject(R4, arguments_descriptor); | 1341 __ LoadObject(R4, arguments_descriptor); |
1390 } else { | 1342 } else { |
1391 __ LoadImmediate(R4, 0); // GC safe smi zero because of stub. | 1343 __ LoadImmediate(R4, 0); // GC safe smi zero because of stub. |
1392 } | 1344 } |
1393 // Do not use the code from the function, but let the code be patched so that | 1345 // Do not use the code from the function, but let the code be patched so that |
1394 // we can record the outgoing edges to other code. | 1346 // we can record the outgoing edges to other code. |
1395 GenerateStaticDartCall(deopt_id, | 1347 GenerateStaticDartCall(deopt_id, token_pos, |
1396 token_pos, | |
1397 *StubCode::CallStaticFunction_entry(), | 1348 *StubCode::CallStaticFunction_entry(), |
1398 RawPcDescriptors::kOther, | 1349 RawPcDescriptors::kOther, locs, function); |
1399 locs, | |
1400 function); | |
1401 __ Drop(argument_count); | 1350 __ Drop(argument_count); |
1402 } | 1351 } |
1403 | 1352 |
1404 | 1353 |
1405 Condition FlowGraphCompiler::EmitEqualityRegConstCompare( | 1354 Condition FlowGraphCompiler::EmitEqualityRegConstCompare( |
1406 Register reg, | 1355 Register reg, |
1407 const Object& obj, | 1356 const Object& obj, |
1408 bool needs_number_check, | 1357 bool needs_number_check, |
1409 TokenPosition token_pos) { | 1358 TokenPosition token_pos) { |
1410 if (needs_number_check) { | 1359 if (needs_number_check) { |
1411 ASSERT(!obj.IsMint() && !obj.IsDouble() && !obj.IsBigint()); | 1360 ASSERT(!obj.IsMint() && !obj.IsDouble() && !obj.IsBigint()); |
1412 __ Push(reg); | 1361 __ Push(reg); |
1413 __ PushObject(obj); | 1362 __ PushObject(obj); |
1414 if (is_optimizing()) { | 1363 if (is_optimizing()) { |
1415 __ BranchLinkPatchable( | 1364 __ BranchLinkPatchable( |
1416 *StubCode::OptimizedIdenticalWithNumberCheck_entry()); | 1365 *StubCode::OptimizedIdenticalWithNumberCheck_entry()); |
1417 } else { | 1366 } else { |
1418 __ BranchLinkPatchable( | 1367 __ BranchLinkPatchable( |
1419 *StubCode::UnoptimizedIdenticalWithNumberCheck_entry()); | 1368 *StubCode::UnoptimizedIdenticalWithNumberCheck_entry()); |
1420 } | 1369 } |
1421 if (token_pos.IsReal()) { | 1370 if (token_pos.IsReal()) { |
1422 AddCurrentDescriptor(RawPcDescriptors::kRuntimeCall, | 1371 AddCurrentDescriptor(RawPcDescriptors::kRuntimeCall, Thread::kNoDeoptId, |
1423 Thread::kNoDeoptId, | |
1424 token_pos); | 1372 token_pos); |
1425 } | 1373 } |
1426 // Stub returns result in flags (result of a cmp, we need Z computed). | 1374 // Stub returns result in flags (result of a cmp, we need Z computed). |
1427 __ Drop(1); // Discard constant. | 1375 __ Drop(1); // Discard constant. |
1428 __ Pop(reg); // Restore 'reg'. | 1376 __ Pop(reg); // Restore 'reg'. |
1429 } else { | 1377 } else { |
1430 __ CompareObject(reg, obj); | 1378 __ CompareObject(reg, obj); |
1431 } | 1379 } |
1432 return EQ; | 1380 return EQ; |
1433 } | 1381 } |
1434 | 1382 |
1435 | 1383 |
1436 Condition FlowGraphCompiler::EmitEqualityRegRegCompare( | 1384 Condition FlowGraphCompiler::EmitEqualityRegRegCompare( |
1437 Register left, | 1385 Register left, |
1438 Register right, | 1386 Register right, |
1439 bool needs_number_check, | 1387 bool needs_number_check, |
1440 TokenPosition token_pos) { | 1388 TokenPosition token_pos) { |
1441 if (needs_number_check) { | 1389 if (needs_number_check) { |
1442 __ Push(left); | 1390 __ Push(left); |
1443 __ Push(right); | 1391 __ Push(right); |
1444 if (is_optimizing()) { | 1392 if (is_optimizing()) { |
1445 __ BranchLinkPatchable( | 1393 __ BranchLinkPatchable( |
1446 *StubCode::OptimizedIdenticalWithNumberCheck_entry()); | 1394 *StubCode::OptimizedIdenticalWithNumberCheck_entry()); |
1447 } else { | 1395 } else { |
1448 __ BranchLinkPatchable( | 1396 __ BranchLinkPatchable( |
1449 *StubCode::UnoptimizedIdenticalWithNumberCheck_entry()); | 1397 *StubCode::UnoptimizedIdenticalWithNumberCheck_entry()); |
1450 } | 1398 } |
1451 if (token_pos.IsReal()) { | 1399 if (token_pos.IsReal()) { |
1452 AddCurrentDescriptor(RawPcDescriptors::kRuntimeCall, | 1400 AddCurrentDescriptor(RawPcDescriptors::kRuntimeCall, Thread::kNoDeoptId, |
1453 Thread::kNoDeoptId, | |
1454 token_pos); | 1401 token_pos); |
1455 } | 1402 } |
1456 // Stub returns result in flags (result of a cmp, we need Z computed). | 1403 // Stub returns result in flags (result of a cmp, we need Z computed). |
1457 __ Pop(right); | 1404 __ Pop(right); |
1458 __ Pop(left); | 1405 __ Pop(left); |
1459 } else { | 1406 } else { |
1460 __ CompareRegisters(left, right); | 1407 __ CompareRegisters(left, right); |
1461 } | 1408 } |
1462 return EQ; | 1409 return EQ; |
1463 } | 1410 } |
(...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1536 const Array& argument_names, | 1483 const Array& argument_names, |
1537 Label* failed, | 1484 Label* failed, |
1538 Label* match_found, | 1485 Label* match_found, |
1539 intptr_t deopt_id, | 1486 intptr_t deopt_id, |
1540 TokenPosition token_index, | 1487 TokenPosition token_index, |
1541 LocationSummary* locs, | 1488 LocationSummary* locs, |
1542 bool complete) { | 1489 bool complete) { |
1543 ASSERT(is_optimizing()); | 1490 ASSERT(is_optimizing()); |
1544 | 1491 |
1545 __ Comment("EmitTestAndCall"); | 1492 __ Comment("EmitTestAndCall"); |
1546 const Array& arguments_descriptor = | 1493 const Array& arguments_descriptor = Array::ZoneHandle( |
1547 Array::ZoneHandle(zone(), ArgumentsDescriptor::New(argument_count, | 1494 zone(), ArgumentsDescriptor::New(argument_count, argument_names)); |
1548 argument_names)); | |
1549 | 1495 |
1550 // Load receiver into R0. | 1496 // Load receiver into R0. |
1551 __ LoadFromOffset(R0, SP, (argument_count - 1) * kWordSize); | 1497 __ LoadFromOffset(R0, SP, (argument_count - 1) * kWordSize); |
1552 __ LoadObject(R4, arguments_descriptor); | 1498 __ LoadObject(R4, arguments_descriptor); |
1553 | 1499 |
1554 const bool kFirstCheckIsSmi = ic_data.GetReceiverClassIdAt(0) == kSmiCid; | 1500 const bool kFirstCheckIsSmi = ic_data.GetReceiverClassIdAt(0) == kSmiCid; |
1555 const intptr_t kNumChecks = ic_data.NumberOfChecks(); | 1501 const intptr_t kNumChecks = ic_data.NumberOfChecks(); |
1556 | 1502 |
1557 ASSERT(!ic_data.IsNull() && (kNumChecks > 0)); | 1503 ASSERT(!ic_data.IsNull() && (kNumChecks > 0)); |
1558 | 1504 |
1559 Label after_smi_test; | 1505 Label after_smi_test; |
1560 if (kFirstCheckIsSmi) { | 1506 if (kFirstCheckIsSmi) { |
1561 __ tsti(R0, Immediate(kSmiTagMask)); | 1507 __ tsti(R0, Immediate(kSmiTagMask)); |
1562 // Jump if receiver is not Smi. | 1508 // Jump if receiver is not Smi. |
1563 if (kNumChecks == 1) { | 1509 if (kNumChecks == 1) { |
1564 __ b(failed, NE); | 1510 __ b(failed, NE); |
1565 } else { | 1511 } else { |
1566 __ b(&after_smi_test, NE); | 1512 __ b(&after_smi_test, NE); |
1567 } | 1513 } |
1568 // Do not use the code from the function, but let the code be patched so | 1514 // Do not use the code from the function, but let the code be patched so |
1569 // that we can record the outgoing edges to other code. | 1515 // that we can record the outgoing edges to other code. |
1570 const Function& function = Function::ZoneHandle( | 1516 const Function& function = |
1571 zone(), ic_data.GetTargetAt(0)); | 1517 Function::ZoneHandle(zone(), ic_data.GetTargetAt(0)); |
1572 GenerateStaticDartCall(deopt_id, | 1518 GenerateStaticDartCall(deopt_id, token_index, |
1573 token_index, | |
1574 *StubCode::CallStaticFunction_entry(), | 1519 *StubCode::CallStaticFunction_entry(), |
1575 RawPcDescriptors::kOther, | 1520 RawPcDescriptors::kOther, locs, function); |
1576 locs, | |
1577 function); | |
1578 __ Drop(argument_count); | 1521 __ Drop(argument_count); |
1579 if (kNumChecks > 1) { | 1522 if (kNumChecks > 1) { |
1580 __ b(match_found); | 1523 __ b(match_found); |
1581 } | 1524 } |
1582 } else { | 1525 } else { |
1583 // Receiver is Smi, but Smi is not a valid class therefore fail. | 1526 // Receiver is Smi, but Smi is not a valid class therefore fail. |
1584 // (Smi class must be first in the list). | 1527 // (Smi class must be first in the list). |
1585 if (!complete) { | 1528 if (!complete) { |
1586 __ tsti(R0, Immediate(kSmiTagMask)); | 1529 __ tsti(R0, Immediate(kSmiTagMask)); |
1587 __ b(failed, EQ); | 1530 __ b(failed, EQ); |
(...skipping 25 matching lines...) Expand all Loading... |
1613 } | 1556 } |
1614 } else { | 1557 } else { |
1615 if (!kIsLastCheck) { | 1558 if (!kIsLastCheck) { |
1616 __ CompareImmediate(R2, sorted[i].cid); | 1559 __ CompareImmediate(R2, sorted[i].cid); |
1617 __ b(&next_test, NE); | 1560 __ b(&next_test, NE); |
1618 } | 1561 } |
1619 } | 1562 } |
1620 // Do not use the code from the function, but let the code be patched so | 1563 // Do not use the code from the function, but let the code be patched so |
1621 // that we can record the outgoing edges to other code. | 1564 // that we can record the outgoing edges to other code. |
1622 const Function& function = *sorted[i].target; | 1565 const Function& function = *sorted[i].target; |
1623 GenerateStaticDartCall(deopt_id, | 1566 GenerateStaticDartCall(deopt_id, token_index, |
1624 token_index, | |
1625 *StubCode::CallStaticFunction_entry(), | 1567 *StubCode::CallStaticFunction_entry(), |
1626 RawPcDescriptors::kOther, | 1568 RawPcDescriptors::kOther, locs, function); |
1627 locs, | |
1628 function); | |
1629 __ Drop(argument_count); | 1569 __ Drop(argument_count); |
1630 if (!kIsLastCheck) { | 1570 if (!kIsLastCheck) { |
1631 __ b(match_found); | 1571 __ b(match_found); |
1632 } | 1572 } |
1633 __ Bind(&next_test); | 1573 __ Bind(&next_test); |
1634 } | 1574 } |
1635 } | 1575 } |
1636 | 1576 |
1637 | 1577 |
1638 #undef __ | 1578 #undef __ |
1639 #define __ compiler_->assembler()-> | 1579 #define __ compiler_->assembler()-> |
1640 | 1580 |
1641 | 1581 |
1642 void ParallelMoveResolver::EmitMove(int index) { | 1582 void ParallelMoveResolver::EmitMove(int index) { |
1643 MoveOperands* move = moves_[index]; | 1583 MoveOperands* move = moves_[index]; |
1644 const Location source = move->src(); | 1584 const Location source = move->src(); |
1645 const Location destination = move->dest(); | 1585 const Location destination = move->dest(); |
1646 | 1586 |
1647 if (source.IsRegister()) { | 1587 if (source.IsRegister()) { |
1648 if (destination.IsRegister()) { | 1588 if (destination.IsRegister()) { |
1649 __ mov(destination.reg(), source.reg()); | 1589 __ mov(destination.reg(), source.reg()); |
1650 } else { | 1590 } else { |
1651 ASSERT(destination.IsStackSlot()); | 1591 ASSERT(destination.IsStackSlot()); |
1652 const intptr_t dest_offset = destination.ToStackSlotOffset(); | 1592 const intptr_t dest_offset = destination.ToStackSlotOffset(); |
1653 __ StoreToOffset(source.reg(), destination.base_reg(), dest_offset); | 1593 __ StoreToOffset(source.reg(), destination.base_reg(), dest_offset); |
1654 } | 1594 } |
1655 } else if (source.IsStackSlot()) { | 1595 } else if (source.IsStackSlot()) { |
1656 if (destination.IsRegister()) { | 1596 if (destination.IsRegister()) { |
1657 const intptr_t source_offset = source.ToStackSlotOffset(); | 1597 const intptr_t source_offset = source.ToStackSlotOffset(); |
1658 __ LoadFromOffset( | 1598 __ LoadFromOffset(destination.reg(), source.base_reg(), source_offset); |
1659 destination.reg(), source.base_reg(), source_offset); | |
1660 } else { | 1599 } else { |
1661 ASSERT(destination.IsStackSlot()); | 1600 ASSERT(destination.IsStackSlot()); |
1662 const intptr_t source_offset = source.ToStackSlotOffset(); | 1601 const intptr_t source_offset = source.ToStackSlotOffset(); |
1663 const intptr_t dest_offset = destination.ToStackSlotOffset(); | 1602 const intptr_t dest_offset = destination.ToStackSlotOffset(); |
1664 ScratchRegisterScope tmp(this, kNoRegister); | 1603 ScratchRegisterScope tmp(this, kNoRegister); |
1665 __ LoadFromOffset(tmp.reg(), source.base_reg(), source_offset); | 1604 __ LoadFromOffset(tmp.reg(), source.base_reg(), source_offset); |
1666 __ StoreToOffset(tmp.reg(), destination.base_reg(), dest_offset); | 1605 __ StoreToOffset(tmp.reg(), destination.base_reg(), dest_offset); |
1667 } | 1606 } |
1668 } else if (source.IsFpuRegister()) { | 1607 } else if (source.IsFpuRegister()) { |
1669 if (destination.IsFpuRegister()) { | 1608 if (destination.IsFpuRegister()) { |
1670 __ vmov(destination.fpu_reg(), source.fpu_reg()); | 1609 __ vmov(destination.fpu_reg(), source.fpu_reg()); |
1671 } else { | 1610 } else { |
1672 if (destination.IsDoubleStackSlot()) { | 1611 if (destination.IsDoubleStackSlot()) { |
1673 const intptr_t dest_offset = destination.ToStackSlotOffset(); | 1612 const intptr_t dest_offset = destination.ToStackSlotOffset(); |
1674 VRegister src = source.fpu_reg(); | 1613 VRegister src = source.fpu_reg(); |
1675 __ StoreDToOffset(src, destination.base_reg(), dest_offset); | 1614 __ StoreDToOffset(src, destination.base_reg(), dest_offset); |
1676 } else { | 1615 } else { |
1677 ASSERT(destination.IsQuadStackSlot()); | 1616 ASSERT(destination.IsQuadStackSlot()); |
1678 const intptr_t dest_offset = destination.ToStackSlotOffset(); | 1617 const intptr_t dest_offset = destination.ToStackSlotOffset(); |
1679 __ StoreQToOffset( | 1618 __ StoreQToOffset(source.fpu_reg(), destination.base_reg(), |
1680 source.fpu_reg(), destination.base_reg(), dest_offset); | 1619 dest_offset); |
1681 } | 1620 } |
1682 } | 1621 } |
1683 } else if (source.IsDoubleStackSlot()) { | 1622 } else if (source.IsDoubleStackSlot()) { |
1684 if (destination.IsFpuRegister()) { | 1623 if (destination.IsFpuRegister()) { |
1685 const intptr_t source_offset = source.ToStackSlotOffset(); | 1624 const intptr_t source_offset = source.ToStackSlotOffset(); |
1686 const VRegister dst = destination.fpu_reg(); | 1625 const VRegister dst = destination.fpu_reg(); |
1687 __ LoadDFromOffset(dst, source.base_reg(), source_offset); | 1626 __ LoadDFromOffset(dst, source.base_reg(), source_offset); |
1688 } else { | 1627 } else { |
1689 ASSERT(destination.IsDoubleStackSlot()); | 1628 ASSERT(destination.IsDoubleStackSlot()); |
1690 const intptr_t source_offset = source.ToStackSlotOffset(); | 1629 const intptr_t source_offset = source.ToStackSlotOffset(); |
1691 const intptr_t dest_offset = destination.ToStackSlotOffset(); | 1630 const intptr_t dest_offset = destination.ToStackSlotOffset(); |
1692 __ LoadDFromOffset(VTMP, source.base_reg(), source_offset); | 1631 __ LoadDFromOffset(VTMP, source.base_reg(), source_offset); |
1693 __ StoreDToOffset(VTMP, destination.base_reg(), dest_offset); | 1632 __ StoreDToOffset(VTMP, destination.base_reg(), dest_offset); |
1694 } | 1633 } |
1695 } else if (source.IsQuadStackSlot()) { | 1634 } else if (source.IsQuadStackSlot()) { |
1696 if (destination.IsFpuRegister()) { | 1635 if (destination.IsFpuRegister()) { |
1697 const intptr_t source_offset = source.ToStackSlotOffset(); | 1636 const intptr_t source_offset = source.ToStackSlotOffset(); |
1698 __ LoadQFromOffset( | 1637 __ LoadQFromOffset(destination.fpu_reg(), source.base_reg(), |
1699 destination.fpu_reg(), source.base_reg(), source_offset); | 1638 source_offset); |
1700 } else { | 1639 } else { |
1701 ASSERT(destination.IsQuadStackSlot()); | 1640 ASSERT(destination.IsQuadStackSlot()); |
1702 const intptr_t source_offset = source.ToStackSlotOffset(); | 1641 const intptr_t source_offset = source.ToStackSlotOffset(); |
1703 const intptr_t dest_offset = destination.ToStackSlotOffset(); | 1642 const intptr_t dest_offset = destination.ToStackSlotOffset(); |
1704 __ LoadQFromOffset(VTMP, source.base_reg(), source_offset); | 1643 __ LoadQFromOffset(VTMP, source.base_reg(), source_offset); |
1705 __ StoreQToOffset(VTMP, destination.base_reg(), dest_offset); | 1644 __ StoreQToOffset(VTMP, destination.base_reg(), dest_offset); |
1706 } | 1645 } |
1707 } else { | 1646 } else { |
1708 ASSERT(source.IsConstant()); | 1647 ASSERT(source.IsConstant()); |
1709 const Object& constant = source.constant(); | 1648 const Object& constant = source.constant(); |
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1758 const Location source = move->src(); | 1697 const Location source = move->src(); |
1759 const Location destination = move->dest(); | 1698 const Location destination = move->dest(); |
1760 | 1699 |
1761 if (source.IsRegister() && destination.IsRegister()) { | 1700 if (source.IsRegister() && destination.IsRegister()) { |
1762 ASSERT(source.reg() != TMP); | 1701 ASSERT(source.reg() != TMP); |
1763 ASSERT(destination.reg() != TMP); | 1702 ASSERT(destination.reg() != TMP); |
1764 __ mov(TMP, source.reg()); | 1703 __ mov(TMP, source.reg()); |
1765 __ mov(source.reg(), destination.reg()); | 1704 __ mov(source.reg(), destination.reg()); |
1766 __ mov(destination.reg(), TMP); | 1705 __ mov(destination.reg(), TMP); |
1767 } else if (source.IsRegister() && destination.IsStackSlot()) { | 1706 } else if (source.IsRegister() && destination.IsStackSlot()) { |
1768 Exchange(source.reg(), | 1707 Exchange(source.reg(), destination.base_reg(), |
1769 destination.base_reg(), destination.ToStackSlotOffset()); | 1708 destination.ToStackSlotOffset()); |
1770 } else if (source.IsStackSlot() && destination.IsRegister()) { | 1709 } else if (source.IsStackSlot() && destination.IsRegister()) { |
1771 Exchange(destination.reg(), | 1710 Exchange(destination.reg(), source.base_reg(), source.ToStackSlotOffset()); |
1772 source.base_reg(), source.ToStackSlotOffset()); | |
1773 } else if (source.IsStackSlot() && destination.IsStackSlot()) { | 1711 } else if (source.IsStackSlot() && destination.IsStackSlot()) { |
1774 Exchange(source.base_reg(), source.ToStackSlotOffset(), | 1712 Exchange(source.base_reg(), source.ToStackSlotOffset(), |
1775 destination.base_reg(), destination.ToStackSlotOffset()); | 1713 destination.base_reg(), destination.ToStackSlotOffset()); |
1776 } else if (source.IsFpuRegister() && destination.IsFpuRegister()) { | 1714 } else if (source.IsFpuRegister() && destination.IsFpuRegister()) { |
1777 const VRegister dst = destination.fpu_reg(); | 1715 const VRegister dst = destination.fpu_reg(); |
1778 const VRegister src = source.fpu_reg(); | 1716 const VRegister src = source.fpu_reg(); |
1779 __ vmov(VTMP, src); | 1717 __ vmov(VTMP, src); |
1780 __ vmov(src, dst); | 1718 __ vmov(src, dst); |
1781 __ vmov(dst, VTMP); | 1719 __ vmov(dst, VTMP); |
1782 } else if (source.IsFpuRegister() || destination.IsFpuRegister()) { | 1720 } else if (source.IsFpuRegister() || destination.IsFpuRegister()) { |
1783 ASSERT(destination.IsDoubleStackSlot() || | 1721 ASSERT(destination.IsDoubleStackSlot() || destination.IsQuadStackSlot() || |
1784 destination.IsQuadStackSlot() || | 1722 source.IsDoubleStackSlot() || source.IsQuadStackSlot()); |
1785 source.IsDoubleStackSlot() || | 1723 bool double_width = |
1786 source.IsQuadStackSlot()); | 1724 destination.IsDoubleStackSlot() || source.IsDoubleStackSlot(); |
1787 bool double_width = destination.IsDoubleStackSlot() || | 1725 VRegister reg = |
1788 source.IsDoubleStackSlot(); | 1726 source.IsFpuRegister() ? source.fpu_reg() : destination.fpu_reg(); |
1789 VRegister reg = source.IsFpuRegister() ? source.fpu_reg() | 1727 Register base_reg = |
1790 : destination.fpu_reg(); | 1728 source.IsFpuRegister() ? destination.base_reg() : source.base_reg(); |
1791 Register base_reg = source.IsFpuRegister() | |
1792 ? destination.base_reg() | |
1793 : source.base_reg(); | |
1794 const intptr_t slot_offset = source.IsFpuRegister() | 1729 const intptr_t slot_offset = source.IsFpuRegister() |
1795 ? destination.ToStackSlotOffset() | 1730 ? destination.ToStackSlotOffset() |
1796 : source.ToStackSlotOffset(); | 1731 : source.ToStackSlotOffset(); |
1797 | 1732 |
1798 if (double_width) { | 1733 if (double_width) { |
1799 __ LoadDFromOffset(VTMP, base_reg, slot_offset); | 1734 __ LoadDFromOffset(VTMP, base_reg, slot_offset); |
1800 __ StoreDToOffset(reg, base_reg, slot_offset); | 1735 __ StoreDToOffset(reg, base_reg, slot_offset); |
1801 __ fmovdd(reg, VTMP); | 1736 __ fmovdd(reg, VTMP); |
1802 } else { | 1737 } else { |
1803 __ LoadQFromOffset(VTMP, base_reg, slot_offset); | 1738 __ LoadQFromOffset(VTMP, base_reg, slot_offset); |
1804 __ StoreQToOffset(reg, base_reg, slot_offset); | 1739 __ StoreQToOffset(reg, base_reg, slot_offset); |
1805 __ vmov(reg, VTMP); | 1740 __ vmov(reg, VTMP); |
1806 } | 1741 } |
(...skipping 105 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1912 void ParallelMoveResolver::RestoreFpuScratch(FpuRegister reg) { | 1847 void ParallelMoveResolver::RestoreFpuScratch(FpuRegister reg) { |
1913 __ PopDouble(reg); | 1848 __ PopDouble(reg); |
1914 } | 1849 } |
1915 | 1850 |
1916 | 1851 |
1917 #undef __ | 1852 #undef __ |
1918 | 1853 |
1919 } // namespace dart | 1854 } // namespace dart |
1920 | 1855 |
1921 #endif // defined TARGET_ARCH_ARM64 | 1856 #endif // defined TARGET_ARCH_ARM64 |
OLD | NEW |