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