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_MIPS. | 5 #include "vm/globals.h" // Needed here to get TARGET_ARCH_MIPS. |
6 #if defined(TARGET_ARCH_MIPS) | 6 #if defined(TARGET_ARCH_MIPS) |
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 183 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
194 Label fall_through; | 194 Label fall_through; |
195 __ BranchEqual(bool_register, Object::null_object(), &fall_through); | 195 __ BranchEqual(bool_register, Object::null_object(), &fall_through); |
196 __ BranchEqual(bool_register, Bool::True(), is_true); | 196 __ BranchEqual(bool_register, Bool::True(), is_true); |
197 __ b(is_false); | 197 __ b(is_false); |
198 __ Bind(&fall_through); | 198 __ Bind(&fall_through); |
199 } | 199 } |
200 | 200 |
201 | 201 |
202 // A0: instance (must be preserved). | 202 // A0: instance (must be preserved). |
203 // A1: instantiator type arguments (if used). | 203 // A1: instantiator type arguments (if used). |
| 204 // A2: function type arguments (if used). |
| 205 // Clobbers A3. |
204 RawSubtypeTestCache* FlowGraphCompiler::GenerateCallSubtypeTestStub( | 206 RawSubtypeTestCache* FlowGraphCompiler::GenerateCallSubtypeTestStub( |
205 TypeTestStubKind test_kind, | 207 TypeTestStubKind test_kind, |
206 Register instance_reg, | 208 Register instance_reg, |
207 Register type_arguments_reg, | 209 Register instantiator_type_arguments_reg, |
| 210 Register function_type_arguments_reg, |
208 Register temp_reg, | 211 Register temp_reg, |
209 Label* is_instance_lbl, | 212 Label* is_instance_lbl, |
210 Label* is_not_instance_lbl) { | 213 Label* is_not_instance_lbl) { |
211 __ Comment("CallSubtypeTestStub"); | 214 __ Comment("CallSubtypeTestStub"); |
212 ASSERT(instance_reg == A0); | 215 ASSERT(instance_reg == A0); |
213 ASSERT(temp_reg == kNoRegister); // Unused on MIPS. | 216 ASSERT(temp_reg == kNoRegister); // Unused on MIPS. |
214 const SubtypeTestCache& type_test_cache = | 217 const SubtypeTestCache& type_test_cache = |
215 SubtypeTestCache::ZoneHandle(zone(), SubtypeTestCache::New()); | 218 SubtypeTestCache::ZoneHandle(zone(), SubtypeTestCache::New()); |
216 __ LoadUniqueObject(A2, type_test_cache); | 219 __ LoadUniqueObject(A3, type_test_cache); |
217 if (test_kind == kTestTypeOneArg) { | 220 if (test_kind == kTestTypeOneArg) { |
218 ASSERT(type_arguments_reg == kNoRegister); | 221 ASSERT(instantiator_type_arguments_reg == kNoRegister); |
219 __ LoadObject(A1, Object::null_object()); | 222 ASSERT(function_type_arguments_reg == kNoRegister); |
220 __ BranchLink(*StubCode::Subtype1TestCache_entry()); | 223 __ BranchLink(*StubCode::Subtype1TestCache_entry()); |
221 } else if (test_kind == kTestTypeTwoArgs) { | 224 } else if (test_kind == kTestTypeTwoArgs) { |
222 ASSERT(type_arguments_reg == kNoRegister); | 225 ASSERT(instantiator_type_arguments_reg == kNoRegister); |
223 __ LoadObject(A1, Object::null_object()); | 226 ASSERT(function_type_arguments_reg == kNoRegister); |
224 __ BranchLink(*StubCode::Subtype2TestCache_entry()); | 227 __ BranchLink(*StubCode::Subtype2TestCache_entry()); |
225 } else if (test_kind == kTestTypeThreeArgs) { | 228 } else if (test_kind == kTestTypeFourArgs) { |
226 ASSERT(type_arguments_reg == A1); | 229 ASSERT(instantiator_type_arguments_reg == A1); |
227 __ BranchLink(*StubCode::Subtype3TestCache_entry()); | 230 ASSERT(function_type_arguments_reg == A2); |
| 231 __ BranchLink(*StubCode::Subtype4TestCache_entry()); |
228 } else { | 232 } else { |
229 UNREACHABLE(); | 233 UNREACHABLE(); |
230 } | 234 } |
231 // Result is in V0: null -> not found, otherwise Bool::True or Bool::False. | 235 // Result is in V0: null -> not found, otherwise Bool::True or Bool::False. |
232 GenerateBoolToJump(V0, is_instance_lbl, is_not_instance_lbl); | 236 GenerateBoolToJump(V0, is_instance_lbl, is_not_instance_lbl); |
233 return type_test_cache.raw(); | 237 return type_test_cache.raw(); |
234 } | 238 } |
235 | 239 |
236 | 240 |
237 // Jumps to labels 'is_instance' or 'is_not_instance' respectively, if | 241 // Jumps to labels 'is_instance' or 'is_not_instance' respectively, if |
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
294 const Type& object_type = Type::Handle(zone(), Type::ObjectType()); | 298 const Type& object_type = Type::Handle(zone(), Type::ObjectType()); |
295 if (object_type.IsSubtypeOf(tp_argument, NULL, NULL, Heap::kOld)) { | 299 if (object_type.IsSubtypeOf(tp_argument, NULL, NULL, Heap::kOld)) { |
296 // Instance class test only necessary. | 300 // Instance class test only necessary. |
297 return GenerateSubtype1TestCacheLookup( | 301 return GenerateSubtype1TestCacheLookup( |
298 token_pos, type_class, is_instance_lbl, is_not_instance_lbl); | 302 token_pos, type_class, is_instance_lbl, is_not_instance_lbl); |
299 } | 303 } |
300 } | 304 } |
301 } | 305 } |
302 } | 306 } |
303 // Regular subtype test cache involving instance's type arguments. | 307 // Regular subtype test cache involving instance's type arguments. |
304 const Register kTypeArgumentsReg = kNoRegister; | 308 const Register kInstantiatorTypeArgumentsReg = kNoRegister; |
| 309 const Register kFunctionTypeArgumentsReg = kNoRegister; |
305 const Register kTempReg = kNoRegister; | 310 const Register kTempReg = kNoRegister; |
306 // A0: instance (must be preserved). | 311 // A0: instance (must be preserved). |
307 return GenerateCallSubtypeTestStub(kTestTypeTwoArgs, kInstanceReg, | 312 return GenerateCallSubtypeTestStub(kTestTypeTwoArgs, kInstanceReg, |
308 kTypeArgumentsReg, kTempReg, | 313 kInstantiatorTypeArgumentsReg, |
| 314 kFunctionTypeArgumentsReg, kTempReg, |
309 is_instance_lbl, is_not_instance_lbl); | 315 is_instance_lbl, is_not_instance_lbl); |
310 } | 316 } |
311 | 317 |
312 | 318 |
313 void FlowGraphCompiler::CheckClassIds(Register class_id_reg, | 319 void FlowGraphCompiler::CheckClassIds(Register class_id_reg, |
314 const GrowableArray<intptr_t>& class_ids, | 320 const GrowableArray<intptr_t>& class_ids, |
315 Label* is_equal_lbl, | 321 Label* is_equal_lbl, |
316 Label* is_not_equal_lbl) { | 322 Label* is_not_equal_lbl) { |
317 __ Comment("CheckClassIds"); | 323 __ Comment("CheckClassIds"); |
318 for (intptr_t i = 0; i < class_ids.length(); i++) { | 324 for (intptr_t i = 0; i < class_ids.length(); i++) { |
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
382 if (!type_class.is_abstract()) { | 388 if (!type_class.is_abstract()) { |
383 __ BranchEqual(kClassIdReg, Immediate(type_class.id()), is_instance_lbl); | 389 __ BranchEqual(kClassIdReg, Immediate(type_class.id()), is_instance_lbl); |
384 } | 390 } |
385 // Otherwise fallthrough. | 391 // Otherwise fallthrough. |
386 return true; | 392 return true; |
387 } | 393 } |
388 | 394 |
389 | 395 |
390 // Uses SubtypeTestCache to store instance class and result. | 396 // Uses SubtypeTestCache to store instance class and result. |
391 // A0: instance to test. | 397 // A0: instance to test. |
392 // Clobbers A1, A2, T0-T3. | 398 // Clobbers A1-A3, T0-T3. |
393 // Immediate class test already done. | 399 // Immediate class test already done. |
394 // TODO(srdjan): Implement a quicker subtype check, as type test | 400 // TODO(srdjan): Implement a quicker subtype check, as type test |
395 // arrays can grow too high, but they may be useful when optimizing | 401 // arrays can grow too high, but they may be useful when optimizing |
396 // code (type-feedback). | 402 // code (type-feedback). |
397 RawSubtypeTestCache* FlowGraphCompiler::GenerateSubtype1TestCacheLookup( | 403 RawSubtypeTestCache* FlowGraphCompiler::GenerateSubtype1TestCacheLookup( |
398 TokenPosition token_pos, | 404 TokenPosition token_pos, |
399 const Class& type_class, | 405 const Class& type_class, |
400 Label* is_instance_lbl, | 406 Label* is_instance_lbl, |
401 Label* is_not_instance_lbl) { | 407 Label* is_not_instance_lbl) { |
402 __ Comment("Subtype1TestCacheLookup"); | 408 __ Comment("Subtype1TestCacheLookup"); |
403 const Register kInstanceReg = A0; | 409 const Register kInstanceReg = A0; |
404 __ LoadClass(T0, kInstanceReg); | 410 __ LoadClass(T0, kInstanceReg); |
405 // T0: instance class. | 411 // T0: instance class. |
406 // Check immediate superclass equality. | 412 // Check immediate superclass equality. |
407 __ lw(T0, FieldAddress(T0, Class::super_type_offset())); | 413 __ lw(T0, FieldAddress(T0, Class::super_type_offset())); |
408 __ lw(T0, FieldAddress(T0, Type::type_class_id_offset())); | 414 __ lw(T0, FieldAddress(T0, Type::type_class_id_offset())); |
409 __ BranchEqual(T0, Immediate(Smi::RawValue(type_class.id())), | 415 __ BranchEqual(T0, Immediate(Smi::RawValue(type_class.id())), |
410 is_instance_lbl); | 416 is_instance_lbl); |
411 | 417 |
412 const Register kTypeArgumentsReg = kNoRegister; | 418 const Register kInstantiatorTypeArgumentsReg = kNoRegister; |
| 419 const Register kFunctionTypeArgumentsReg = kNoRegister; |
413 const Register kTempReg = kNoRegister; | 420 const Register kTempReg = kNoRegister; |
414 return GenerateCallSubtypeTestStub(kTestTypeOneArg, kInstanceReg, | 421 return GenerateCallSubtypeTestStub(kTestTypeOneArg, kInstanceReg, |
415 kTypeArgumentsReg, kTempReg, | 422 kInstantiatorTypeArgumentsReg, |
| 423 kFunctionTypeArgumentsReg, kTempReg, |
416 is_instance_lbl, is_not_instance_lbl); | 424 is_instance_lbl, is_not_instance_lbl); |
417 } | 425 } |
418 | 426 |
419 | 427 |
420 // Generates inlined check if 'type' is a type parameter or type itself | 428 // Generates inlined check if 'type' is a type parameter or type itself |
421 // A0: instance (preserved). | 429 // A0: instance (preserved). |
422 RawSubtypeTestCache* FlowGraphCompiler::GenerateUninstantiatedTypeTest( | 430 RawSubtypeTestCache* FlowGraphCompiler::GenerateUninstantiatedTypeTest( |
423 TokenPosition token_pos, | 431 TokenPosition token_pos, |
424 const AbstractType& type, | 432 const AbstractType& type, |
425 Label* is_instance_lbl, | 433 Label* is_instance_lbl, |
426 Label* is_not_instance_lbl) { | 434 Label* is_not_instance_lbl) { |
427 __ Comment("UninstantiatedTypeTest"); | 435 __ Comment("UninstantiatedTypeTest"); |
428 ASSERT(!type.IsInstantiated()); | 436 ASSERT(!type.IsInstantiated()); |
429 // Skip check if destination is a dynamic type. | 437 // Skip check if destination is a dynamic type. |
430 if (type.IsTypeParameter()) { | 438 if (type.IsTypeParameter()) { |
431 const TypeParameter& type_param = TypeParameter::Cast(type); | 439 const TypeParameter& type_param = TypeParameter::Cast(type); |
432 // Load instantiator type arguments on stack. | 440 __ lw(A1, Address(SP, 1 * kWordSize)); // Get instantiator type args. |
433 __ lw(A1, Address(SP, 0)); // Get instantiator type arguments. | 441 __ lw(A2, Address(SP, 0 * kWordSize)); // Get function type args. |
434 // A1: instantiator type arguments. | 442 // A1: instantiator type arguments. |
| 443 // A2: function type arguments. |
| 444 const Register kTypeArgumentsReg = |
| 445 type_param.IsClassTypeParameter() ? A1 : A2; |
435 // Check if type arguments are null, i.e. equivalent to vector of dynamic. | 446 // Check if type arguments are null, i.e. equivalent to vector of dynamic. |
436 __ LoadObject(T7, Object::null_object()); | 447 __ LoadObject(T7, Object::null_object()); |
437 __ beq(A1, T7, is_instance_lbl); | 448 __ beq(kTypeArgumentsReg, T7, is_instance_lbl); |
438 __ lw(T2, | 449 __ lw(T2, FieldAddress(kTypeArgumentsReg, |
439 FieldAddress(A1, TypeArguments::type_at_offset(type_param.index()))); | 450 TypeArguments::type_at_offset(type_param.index()))); |
440 // R2: concrete type of type. | 451 // T2: concrete type of type. |
441 // Check if type argument is dynamic. | 452 // Check if type argument is dynamic. |
442 __ BranchEqual(T2, Object::dynamic_type(), is_instance_lbl); | 453 __ BranchEqual(T2, Object::dynamic_type(), is_instance_lbl); |
443 __ BranchEqual(T2, Type::ZoneHandle(zone(), Type::ObjectType()), | 454 __ BranchEqual(T2, Type::ZoneHandle(zone(), Type::ObjectType()), |
444 is_instance_lbl); | 455 is_instance_lbl); |
| 456 // TODO(regis): Optimize void type as well once allowed as type argument. |
445 | 457 |
446 // For Smi check quickly against int and num interfaces. | 458 // For Smi check quickly against int and num interfaces. |
447 Label not_smi; | 459 Label not_smi; |
448 __ andi(CMPRES1, A0, Immediate(kSmiTagMask)); | 460 __ andi(CMPRES1, A0, Immediate(kSmiTagMask)); |
449 __ bne(CMPRES1, ZR, ¬_smi); // Value is Smi? | 461 __ bne(CMPRES1, ZR, ¬_smi); // Value is Smi? |
450 __ BranchEqual(T2, Type::ZoneHandle(zone(), Type::IntType()), | 462 __ BranchEqual(T2, Type::ZoneHandle(zone(), Type::IntType()), |
451 is_instance_lbl); | 463 is_instance_lbl); |
452 __ BranchEqual(T2, Type::ZoneHandle(zone(), Type::Number()), | 464 __ BranchEqual(T2, Type::ZoneHandle(zone(), Type::Number()), |
453 is_instance_lbl); | 465 is_instance_lbl); |
454 // Smi must be handled in runtime. | 466 // Smi must be handled in runtime. |
455 Label fall_through; | 467 Label fall_through; |
456 __ b(&fall_through); | 468 __ b(&fall_through); |
457 | 469 |
458 __ Bind(¬_smi); | 470 __ Bind(¬_smi); |
459 // T1: instantiator type arguments. | |
460 // A0: instance. | 471 // A0: instance. |
| 472 // A1: instantiator type arguments. |
| 473 // A2: function type arguments. |
461 const Register kInstanceReg = A0; | 474 const Register kInstanceReg = A0; |
462 const Register kTypeArgumentsReg = A1; | 475 const Register kInstantiatorTypeArgumentsReg = A1; |
| 476 const Register kFunctionTypeArgumentsReg = A2; |
463 const Register kTempReg = kNoRegister; | 477 const Register kTempReg = kNoRegister; |
464 const SubtypeTestCache& type_test_cache = SubtypeTestCache::ZoneHandle( | 478 const SubtypeTestCache& type_test_cache = SubtypeTestCache::ZoneHandle( |
465 zone(), GenerateCallSubtypeTestStub( | 479 zone(), GenerateCallSubtypeTestStub( |
466 kTestTypeThreeArgs, kInstanceReg, kTypeArgumentsReg, | 480 kTestTypeFourArgs, kInstanceReg, |
| 481 kInstantiatorTypeArgumentsReg, kFunctionTypeArgumentsReg, |
467 kTempReg, is_instance_lbl, is_not_instance_lbl)); | 482 kTempReg, is_instance_lbl, is_not_instance_lbl)); |
468 __ Bind(&fall_through); | 483 __ Bind(&fall_through); |
469 return type_test_cache.raw(); | 484 return type_test_cache.raw(); |
470 } | 485 } |
471 if (type.IsType()) { | 486 if (type.IsType()) { |
472 const Register kInstanceReg = A0; | 487 const Register kInstanceReg = A0; |
473 const Register kTypeArgumentsReg = A1; | 488 const Register kInstantiatorTypeArgumentsReg = A1; |
| 489 const Register kFunctionTypeArgumentsReg = A2; |
474 __ andi(CMPRES1, kInstanceReg, Immediate(kSmiTagMask)); | 490 __ andi(CMPRES1, kInstanceReg, Immediate(kSmiTagMask)); |
475 __ beq(CMPRES1, ZR, is_not_instance_lbl); // Is instance Smi? | 491 __ beq(CMPRES1, ZR, is_not_instance_lbl); // Is instance Smi? |
476 __ lw(kTypeArgumentsReg, Address(SP, 0)); // Instantiator type args. | 492 __ lw(kInstantiatorTypeArgumentsReg, Address(SP, 1 * kWordSize)); |
| 493 __ lw(kFunctionTypeArgumentsReg, Address(SP, 0 * kWordSize)); |
477 // Uninstantiated type class is known at compile time, but the type | 494 // Uninstantiated type class is known at compile time, but the type |
478 // arguments are determined at runtime by the instantiator. | 495 // arguments are determined at runtime by the instantiator. |
479 const Register kTempReg = kNoRegister; | 496 const Register kTempReg = kNoRegister; |
480 return GenerateCallSubtypeTestStub(kTestTypeThreeArgs, kInstanceReg, | 497 return GenerateCallSubtypeTestStub(kTestTypeFourArgs, kInstanceReg, |
481 kTypeArgumentsReg, kTempReg, | 498 kInstantiatorTypeArgumentsReg, |
| 499 kFunctionTypeArgumentsReg, kTempReg, |
482 is_instance_lbl, is_not_instance_lbl); | 500 is_instance_lbl, is_not_instance_lbl); |
483 } | 501 } |
484 return SubtypeTestCache::null(); | 502 return SubtypeTestCache::null(); |
485 } | 503 } |
486 | 504 |
487 | 505 |
488 // Inputs: | 506 // Inputs: |
489 // - A0: instance being type checked (preserved). | 507 // - A0: instance being type checked (preserved). |
490 // - A1: optional instantiator type arguments (preserved). | 508 // - A1: optional instantiator type arguments (preserved). |
| 509 // - A2: optional function type arguments (preserved). |
491 // Returns: | 510 // Returns: |
492 // - preserved instance in A0 and optional instantiator type arguments in A1. | 511 // - preserved instance in A0, optional instantiator type arguments in A1, and |
| 512 // optional function type arguments in A2. |
493 // Clobbers: T0, T1, T2 | 513 // Clobbers: T0, T1, T2 |
494 // Note that this inlined code must be followed by the runtime_call code, as it | 514 // Note that this inlined code must be followed by the runtime_call code, as it |
495 // may fall through to it. Otherwise, this inline code will jump to the label | 515 // may fall through to it. Otherwise, this inline code will jump to the label |
496 // is_instance or to the label is_not_instance. | 516 // is_instance or to the label is_not_instance. |
497 RawSubtypeTestCache* FlowGraphCompiler::GenerateInlineInstanceof( | 517 RawSubtypeTestCache* FlowGraphCompiler::GenerateInlineInstanceof( |
498 TokenPosition token_pos, | 518 TokenPosition token_pos, |
499 const AbstractType& type, | 519 const AbstractType& type, |
500 Label* is_instance_lbl, | 520 Label* is_instance_lbl, |
501 Label* is_not_instance_lbl) { | 521 Label* is_not_instance_lbl) { |
502 __ Comment("InlineInstanceof"); | 522 __ Comment("InlineInstanceof"); |
(...skipping 29 matching lines...) Expand all Loading... |
532 | 552 |
533 | 553 |
534 // If instanceof type test cannot be performed successfully at compile time and | 554 // If instanceof type test cannot be performed successfully at compile time and |
535 // therefore eliminated, optimize it by adding inlined tests for: | 555 // therefore eliminated, optimize it by adding inlined tests for: |
536 // - NULL -> return type == Null (type is not Object or dynamic). | 556 // - NULL -> return type == Null (type is not Object or dynamic). |
537 // - Smi -> compile time subtype check (only if dst class is not parameterized). | 557 // - Smi -> compile time subtype check (only if dst class is not parameterized). |
538 // - Class equality (only if class is not parameterized). | 558 // - Class equality (only if class is not parameterized). |
539 // Inputs: | 559 // Inputs: |
540 // - A0: object. | 560 // - A0: object. |
541 // - A1: instantiator type arguments or raw_null. | 561 // - A1: instantiator type arguments or raw_null. |
| 562 // - A2: function type arguments or raw_null. |
542 // Returns: | 563 // Returns: |
543 // - true or false in V0. | 564 // - true or false in V0. |
544 void FlowGraphCompiler::GenerateInstanceOf(TokenPosition token_pos, | 565 void FlowGraphCompiler::GenerateInstanceOf(TokenPosition token_pos, |
545 intptr_t deopt_id, | 566 intptr_t deopt_id, |
546 const AbstractType& type, | 567 const AbstractType& type, |
547 LocationSummary* locs) { | 568 LocationSummary* locs) { |
548 ASSERT(type.IsFinalized() && !type.IsMalformed() && !type.IsMalbounded()); | 569 ASSERT(type.IsFinalized() && !type.IsMalformed() && !type.IsMalbounded()); |
549 ASSERT(!type.IsObjectType() && !type.IsDynamicType()); | 570 ASSERT(!type.IsObjectType() && !type.IsDynamicType()); |
550 | 571 |
551 // Preserve instantiator type arguments (A1). | 572 // Preserve instantiator type arguments (A1) and function type arguments (A2). |
552 __ addiu(SP, SP, Immediate(-1 * kWordSize)); | 573 __ addiu(SP, SP, Immediate(-2 * kWordSize)); |
553 __ sw(A1, Address(SP, 0 * kWordSize)); | 574 __ sw(A1, Address(SP, 1 * kWordSize)); |
| 575 __ sw(A2, Address(SP, 0 * kWordSize)); |
554 | 576 |
555 Label is_instance, is_not_instance; | 577 Label is_instance, is_not_instance; |
556 // If type is instantiated and non-parameterized, we can inline code | 578 // If type is instantiated and non-parameterized, we can inline code |
557 // checking whether the tested instance is a Smi. | 579 // checking whether the tested instance is a Smi. |
558 if (type.IsInstantiated()) { | 580 if (type.IsInstantiated()) { |
559 // A null object is only an instance of Null, Object, and dynamic. | 581 // A null object is only an instance of Null, Object, and dynamic. |
560 // Object and dynamic have already been checked above (if the type is | 582 // Object and dynamic have already been checked above (if the type is |
561 // instantiated). So we can return false here if the instance is null, | 583 // instantiated). So we can return false here if the instance is null, |
562 // unless the type is Null (and if the type is instantiated). | 584 // unless the type is Null (and if the type is instantiated). |
563 // We can only inline this null check if the type is instantiated at compile | 585 // We can only inline this null check if the type is instantiated at compile |
564 // time, since an uninstantiated type at compile time could be Null, Object, | 586 // time, since an uninstantiated type at compile time could be Null, Object, |
565 // or dynamic at run time. | 587 // or dynamic at run time. |
566 __ BranchEqual(A0, Object::null_object(), | 588 __ BranchEqual(A0, Object::null_object(), |
567 type.IsNullType() ? &is_instance : &is_not_instance); | 589 type.IsNullType() ? &is_instance : &is_not_instance); |
568 } | 590 } |
569 | 591 |
570 // Generate inline instanceof test. | 592 // Generate inline instanceof test. |
571 SubtypeTestCache& test_cache = SubtypeTestCache::ZoneHandle(zone()); | 593 SubtypeTestCache& test_cache = SubtypeTestCache::ZoneHandle(zone()); |
572 test_cache = | 594 test_cache = |
573 GenerateInlineInstanceof(token_pos, type, &is_instance, &is_not_instance); | 595 GenerateInlineInstanceof(token_pos, type, &is_instance, &is_not_instance); |
574 | 596 |
575 // test_cache is null if there is no fall-through. | 597 // test_cache is null if there is no fall-through. |
576 Label done; | 598 Label done; |
577 if (!test_cache.IsNull()) { | 599 if (!test_cache.IsNull()) { |
578 // Generate runtime call. | 600 // Generate runtime call. |
579 // Load instantiator type arguments (A1). | 601 __ lw(A1, Address(SP, 1 * kWordSize)); // Get instantiator type args. |
580 __ lw(A1, Address(SP, 0 * kWordSize)); | 602 __ lw(A2, Address(SP, 0 * kWordSize)); // Get function type args. |
581 | 603 __ addiu(SP, SP, Immediate(-6 * kWordSize)); |
582 __ addiu(SP, SP, Immediate(-5 * kWordSize)); | |
583 __ LoadObject(TMP, Object::null_object()); | 604 __ LoadObject(TMP, Object::null_object()); |
584 __ sw(TMP, Address(SP, 4 * kWordSize)); // Make room for the result. | 605 __ sw(TMP, Address(SP, 5 * kWordSize)); // Make room for the result. |
585 __ sw(A0, Address(SP, 3 * kWordSize)); // Push the instance. | 606 __ sw(A0, Address(SP, 4 * kWordSize)); // Push the instance. |
586 __ LoadObject(TMP, type); | 607 __ LoadObject(TMP, type); |
587 __ sw(TMP, Address(SP, 2 * kWordSize)); // Push the type. | 608 __ sw(TMP, Address(SP, 3 * kWordSize)); // Push the type. |
588 __ sw(A1, Address(SP, 1 * kWordSize)); // Push type arguments. | 609 __ sw(A1, Address(SP, 2 * kWordSize)); // Push instantiator type args. |
| 610 __ sw(A2, Address(SP, 1 * kWordSize)); // Push function type args. |
589 __ LoadUniqueObject(A0, test_cache); | 611 __ LoadUniqueObject(A0, test_cache); |
590 __ sw(A0, Address(SP, 0 * kWordSize)); | 612 __ sw(A0, Address(SP, 0 * kWordSize)); |
591 GenerateRuntimeCall(token_pos, deopt_id, kInstanceofRuntimeEntry, 4, locs); | 613 GenerateRuntimeCall(token_pos, deopt_id, kInstanceofRuntimeEntry, 5, locs); |
592 // Pop the parameters supplied to the runtime entry. The result of the | 614 // Pop the parameters supplied to the runtime entry. The result of the |
593 // instanceof runtime call will be left as the result of the operation. | 615 // instanceof runtime call will be left as the result of the operation. |
594 __ lw(T0, Address(SP, 4 * kWordSize)); | 616 __ lw(V0, Address(SP, 5 * kWordSize)); |
595 __ addiu(SP, SP, Immediate(5 * kWordSize)); | |
596 __ mov(V0, T0); | |
597 __ b(&done); | 617 __ b(&done); |
| 618 __ delay_slot()->addiu(SP, SP, Immediate(6 * kWordSize)); |
598 } | 619 } |
599 __ Bind(&is_not_instance); | 620 __ Bind(&is_not_instance); |
600 __ LoadObject(V0, Bool::Get(false)); | 621 __ LoadObject(V0, Bool::Get(false)); |
601 __ b(&done); | 622 __ b(&done); |
602 | 623 |
603 __ Bind(&is_instance); | 624 __ Bind(&is_instance); |
604 __ LoadObject(V0, Bool::Get(true)); | 625 __ LoadObject(V0, Bool::Get(true)); |
605 __ Bind(&done); | 626 __ Bind(&done); |
606 // Remove instantiator type arguments (A1). | 627 // Remove instantiator type arguments and function type arguments. |
607 __ Drop(1); | 628 __ Drop(2); |
608 } | 629 } |
609 | 630 |
610 | 631 |
611 // Optimize assignable type check by adding inlined tests for: | 632 // Optimize assignable type check by adding inlined tests for: |
612 // - NULL -> return NULL. | 633 // - NULL -> return NULL. |
613 // - Smi -> compile time subtype check (only if dst class is not parameterized). | 634 // - Smi -> compile time subtype check (only if dst class is not parameterized). |
614 // - Class equality (only if class is not parameterized). | 635 // - Class equality (only if class is not parameterized). |
615 // Inputs: | 636 // Inputs: |
616 // - A0: instance being type checked. | 637 // - A0: instance being type checked. |
617 // - A1: instantiator type arguments or raw_null. | 638 // - A1: instantiator type arguments or raw_null. |
| 639 // - A2: function type arguments or raw_null. |
618 // Returns: | 640 // Returns: |
619 // - object in A0 for successful assignable check (or throws TypeError). | 641 // - object in A0 for successful assignable check (or throws TypeError). |
620 // Clobbers: T0, T1, T2 | 642 // Clobbers: T0, T1, T2 |
621 // Performance notes: positive checks must be quick, negative checks can be slow | 643 // Performance notes: positive checks must be quick, negative checks can be slow |
622 // as they throw an exception. | 644 // as they throw an exception. |
623 void FlowGraphCompiler::GenerateAssertAssignable(TokenPosition token_pos, | 645 void FlowGraphCompiler::GenerateAssertAssignable(TokenPosition token_pos, |
624 intptr_t deopt_id, | 646 intptr_t deopt_id, |
625 const AbstractType& dst_type, | 647 const AbstractType& dst_type, |
626 const String& dst_name, | 648 const String& dst_name, |
627 LocationSummary* locs) { | 649 LocationSummary* locs) { |
628 __ Comment("AssertAssignable"); | 650 __ Comment("AssertAssignable"); |
629 ASSERT(!token_pos.IsClassifying()); | 651 ASSERT(!token_pos.IsClassifying()); |
630 ASSERT(!dst_type.IsNull()); | 652 ASSERT(!dst_type.IsNull()); |
631 ASSERT(dst_type.IsFinalized()); | 653 ASSERT(dst_type.IsFinalized()); |
632 // Assignable check is skipped in FlowGraphBuilder, not here. | 654 // Assignable check is skipped in FlowGraphBuilder, not here. |
633 ASSERT(dst_type.IsMalformedOrMalbounded() || | 655 ASSERT(dst_type.IsMalformedOrMalbounded() || |
634 (!dst_type.IsDynamicType() && !dst_type.IsObjectType())); | 656 (!dst_type.IsDynamicType() && !dst_type.IsObjectType())); |
635 // Preserve instantiator type arguments. | 657 |
636 __ addiu(SP, SP, Immediate(-1 * kWordSize)); | 658 // Preserve instantiator type arguments (A1) and function type arguments (A2). |
637 __ sw(A1, Address(SP, 0 * kWordSize)); | 659 __ addiu(SP, SP, Immediate(-2 * kWordSize)); |
| 660 __ sw(A1, Address(SP, 1 * kWordSize)); |
| 661 __ sw(A2, Address(SP, 0 * kWordSize)); |
638 | 662 |
639 // A null object is always assignable and is returned as result. | 663 // A null object is always assignable and is returned as result. |
640 Label is_assignable, runtime_call; | 664 Label is_assignable, runtime_call; |
641 | 665 |
642 __ BranchEqual(A0, Object::null_object(), &is_assignable); | 666 __ BranchEqual(A0, Object::null_object(), &is_assignable); |
643 __ delay_slot()->sw(A1, Address(SP, 0 * kWordSize)); | |
644 | 667 |
645 // Generate throw new TypeError() if the type is malformed or malbounded. | 668 // Generate throw new TypeError() if the type is malformed or malbounded. |
646 if (dst_type.IsMalformedOrMalbounded()) { | 669 if (dst_type.IsMalformedOrMalbounded()) { |
647 __ addiu(SP, SP, Immediate(-4 * kWordSize)); | 670 __ addiu(SP, SP, Immediate(-4 * kWordSize)); |
648 __ LoadObject(TMP, Object::null_object()); | 671 __ LoadObject(TMP, Object::null_object()); |
649 __ sw(TMP, Address(SP, 3 * kWordSize)); // Make room for the result. | 672 __ sw(TMP, Address(SP, 3 * kWordSize)); // Make room for the result. |
650 __ sw(A0, Address(SP, 2 * kWordSize)); // Push the source object. | 673 __ sw(A0, Address(SP, 2 * kWordSize)); // Push the source object. |
651 __ LoadObject(TMP, dst_name); | 674 __ LoadObject(TMP, dst_name); |
652 __ sw(TMP, Address(SP, 1 * kWordSize)); // Push the destination name. | 675 __ sw(TMP, Address(SP, 1 * kWordSize)); // Push the destination name. |
653 __ LoadObject(TMP, dst_type); | 676 __ LoadObject(TMP, dst_type); |
654 __ sw(TMP, Address(SP, 0 * kWordSize)); // Push the destination type. | 677 __ sw(TMP, Address(SP, 0 * kWordSize)); // Push the destination type. |
655 | 678 |
656 GenerateRuntimeCall(token_pos, deopt_id, kBadTypeErrorRuntimeEntry, 3, | 679 GenerateRuntimeCall(token_pos, deopt_id, kBadTypeErrorRuntimeEntry, 3, |
657 locs); | 680 locs); |
658 // We should never return here. | 681 // We should never return here. |
659 __ break_(0); | 682 __ break_(0); |
660 | 683 |
661 __ Bind(&is_assignable); // For a null object. | 684 __ Bind(&is_assignable); // For a null object. |
662 // Restore instantiator type arguments. | 685 __ lw(A1, Address(SP, 1 * kWordSize)); // Restore instantiator type args. |
663 __ lw(A1, Address(SP, 0 * kWordSize)); | 686 __ lw(A2, Address(SP, 0 * kWordSize)); // Restore function type args. |
664 __ addiu(SP, SP, Immediate(1 * kWordSize)); | 687 __ addiu(SP, SP, Immediate(2 * kWordSize)); |
665 return; | 688 return; |
666 } | 689 } |
667 | 690 |
668 // Generate inline type check, linking to runtime call if not assignable. | 691 // Generate inline type check, linking to runtime call if not assignable. |
669 SubtypeTestCache& test_cache = SubtypeTestCache::ZoneHandle(zone()); | 692 SubtypeTestCache& test_cache = SubtypeTestCache::ZoneHandle(zone()); |
670 test_cache = GenerateInlineInstanceof(token_pos, dst_type, &is_assignable, | 693 test_cache = GenerateInlineInstanceof(token_pos, dst_type, &is_assignable, |
671 &runtime_call); | 694 &runtime_call); |
672 | 695 |
673 __ Bind(&runtime_call); | 696 __ Bind(&runtime_call); |
674 // Load instantiator type arguments (A1). | 697 __ lw(A1, Address(SP, 1 * kWordSize)); // Load instantiator type args. |
675 __ lw(A1, Address(SP, 0 * kWordSize)); | 698 __ lw(A2, Address(SP, 0 * kWordSize)); // Load function type args. |
676 | 699 |
677 __ addiu(SP, SP, Immediate(-6 * kWordSize)); | 700 __ addiu(SP, SP, Immediate(-7 * kWordSize)); |
678 __ LoadObject(TMP, Object::null_object()); | 701 __ LoadObject(TMP, Object::null_object()); |
679 __ sw(TMP, Address(SP, 5 * kWordSize)); // Make room for the result. | 702 __ sw(TMP, Address(SP, 6 * kWordSize)); // Make room for the result. |
680 __ sw(A0, Address(SP, 4 * kWordSize)); // Push the source object. | 703 __ sw(A0, Address(SP, 5 * kWordSize)); // Push the source object. |
681 __ LoadObject(TMP, dst_type); | 704 __ LoadObject(TMP, dst_type); |
682 __ sw(TMP, Address(SP, 3 * kWordSize)); // Push the type of the destination. | 705 __ sw(TMP, Address(SP, 4 * kWordSize)); // Push the type of the destination. |
683 __ sw(A1, Address(SP, 2 * kWordSize)); // Push type arguments. | 706 __ sw(A1, Address(SP, 3 * kWordSize)); // Push instantiator type args. |
| 707 __ sw(A2, Address(SP, 2 * kWordSize)); // Push function type args. |
684 __ LoadObject(TMP, dst_name); | 708 __ LoadObject(TMP, dst_name); |
685 __ sw(TMP, Address(SP, 1 * kWordSize)); // Push the name of the destination. | 709 __ sw(TMP, Address(SP, 1 * kWordSize)); // Push the name of the destination. |
686 __ LoadUniqueObject(T0, test_cache); | 710 __ LoadUniqueObject(T0, test_cache); |
687 __ sw(T0, Address(SP, 0 * kWordSize)); | 711 __ sw(T0, Address(SP, 0 * kWordSize)); |
688 | 712 |
689 GenerateRuntimeCall(token_pos, deopt_id, kTypeCheckRuntimeEntry, 5, locs); | 713 GenerateRuntimeCall(token_pos, deopt_id, kTypeCheckRuntimeEntry, 6, locs); |
690 // Pop the parameters supplied to the runtime entry. The result of the | 714 // Pop the parameters supplied to the runtime entry. The result of the |
691 // type check runtime call is the checked value. | 715 // type check runtime call is the checked value. |
692 __ lw(A0, Address(SP, 5 * kWordSize)); | 716 __ lw(A0, Address(SP, 6 * kWordSize)); |
693 __ addiu(SP, SP, Immediate(6 * kWordSize)); | 717 __ addiu(SP, SP, Immediate(7 * kWordSize)); |
694 | 718 |
695 __ Bind(&is_assignable); | 719 __ Bind(&is_assignable); |
696 // Restore instantiator type arguments. | 720 __ lw(A1, Address(SP, 1 * kWordSize)); // Restore instantiator type args. |
697 __ lw(A1, Address(SP, 0 * kWordSize)); | 721 __ lw(A2, Address(SP, 0 * kWordSize)); // Restore function type args. |
698 __ addiu(SP, SP, Immediate(1 * kWordSize)); | 722 __ addiu(SP, SP, Immediate(2 * kWordSize)); |
699 } | 723 } |
700 | 724 |
701 | 725 |
702 void FlowGraphCompiler::EmitInstructionEpilogue(Instruction* instr) { | 726 void FlowGraphCompiler::EmitInstructionEpilogue(Instruction* instr) { |
703 if (is_optimizing()) return; | 727 if (is_optimizing()) return; |
704 Definition* defn = instr->AsDefinition(); | 728 Definition* defn = instr->AsDefinition(); |
705 if ((defn != NULL) && defn->HasTemp()) { | 729 if ((defn != NULL) && defn->HasTemp()) { |
706 __ Push(defn->locs()->out(0).reg()); | 730 __ Push(defn->locs()->out(0).reg()); |
707 } | 731 } |
708 } | 732 } |
(...skipping 1155 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1864 __ AddImmediate(SP, kDoubleSize); | 1888 __ AddImmediate(SP, kDoubleSize); |
1865 } | 1889 } |
1866 | 1890 |
1867 | 1891 |
1868 #undef __ | 1892 #undef __ |
1869 | 1893 |
1870 | 1894 |
1871 } // namespace dart | 1895 } // namespace dart |
1872 | 1896 |
1873 #endif // defined TARGET_ARCH_MIPS | 1897 #endif // defined TARGET_ARCH_MIPS |
OLD | NEW |