Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(695)

Side by Side Diff: runtime/vm/flow_graph_compiler_arm.cc

Issue 2813903003: Process a pair of registers in one instruction where possible on arm in the VM. (Closed)
Patch Set: Created 3 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | runtime/vm/intermediate_language_arm.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a 2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 #include "vm/globals.h" // Needed here to get TARGET_ARCH_ARM. 5 #include "vm/globals.h" // Needed here to get TARGET_ARCH_ARM.
6 #if defined(TARGET_ARCH_ARM) 6 #if defined(TARGET_ARCH_ARM)
7 7
8 #include "vm/flow_graph_compiler.h" 8 #include "vm/flow_graph_compiler.h"
9 9
10 #include "vm/ast_printer.h" 10 #include "vm/ast_printer.h"
(...skipping 190 matching lines...) Expand 10 before | Expand all | Expand 10 after
201 __ CompareObject(bool_register, Object::null_object()); 201 __ CompareObject(bool_register, Object::null_object());
202 __ b(&fall_through, EQ); 202 __ b(&fall_through, EQ);
203 __ CompareObject(bool_register, Bool::True()); 203 __ CompareObject(bool_register, Bool::True());
204 __ b(is_true, EQ); 204 __ b(is_true, EQ);
205 __ b(is_false); 205 __ b(is_false);
206 __ Bind(&fall_through); 206 __ Bind(&fall_through);
207 } 207 }
208 208
209 209
210 // R0: instance (must be preserved). 210 // R0: instance (must be preserved).
211 // R1: instantiator type arguments (if used). 211 // R2: instantiator type arguments (if used).
212 // R2: function type arguments (if used). 212 // R1: function type arguments (if used).
213 // R3: type test cache. 213 // R3: type test cache.
214 RawSubtypeTestCache* FlowGraphCompiler::GenerateCallSubtypeTestStub( 214 RawSubtypeTestCache* FlowGraphCompiler::GenerateCallSubtypeTestStub(
215 TypeTestStubKind test_kind, 215 TypeTestStubKind test_kind,
216 Register instance_reg, 216 Register instance_reg,
217 Register instantiator_type_arguments_reg, 217 Register instantiator_type_arguments_reg,
218 Register function_type_arguments_reg, 218 Register function_type_arguments_reg,
219 Register temp_reg, 219 Register temp_reg,
220 Label* is_instance_lbl, 220 Label* is_instance_lbl,
221 Label* is_not_instance_lbl) { 221 Label* is_not_instance_lbl) {
222 ASSERT(instance_reg == R0); 222 ASSERT(instance_reg == R0);
223 ASSERT(temp_reg == kNoRegister); // Unused on ARM. 223 ASSERT(temp_reg == kNoRegister); // Unused on ARM.
224 const SubtypeTestCache& type_test_cache = 224 const SubtypeTestCache& type_test_cache =
225 SubtypeTestCache::ZoneHandle(zone(), SubtypeTestCache::New()); 225 SubtypeTestCache::ZoneHandle(zone(), SubtypeTestCache::New());
226 __ LoadUniqueObject(R3, type_test_cache); 226 __ LoadUniqueObject(R3, type_test_cache);
227 if (test_kind == kTestTypeOneArg) { 227 if (test_kind == kTestTypeOneArg) {
228 ASSERT(instantiator_type_arguments_reg == kNoRegister); 228 ASSERT(instantiator_type_arguments_reg == kNoRegister);
229 ASSERT(function_type_arguments_reg == kNoRegister); 229 ASSERT(function_type_arguments_reg == kNoRegister);
230 __ BranchLink(*StubCode::Subtype1TestCache_entry()); 230 __ BranchLink(*StubCode::Subtype1TestCache_entry());
231 } else if (test_kind == kTestTypeTwoArgs) { 231 } else if (test_kind == kTestTypeTwoArgs) {
232 ASSERT(instantiator_type_arguments_reg == kNoRegister); 232 ASSERT(instantiator_type_arguments_reg == kNoRegister);
233 ASSERT(function_type_arguments_reg == kNoRegister); 233 ASSERT(function_type_arguments_reg == kNoRegister);
234 __ BranchLink(*StubCode::Subtype2TestCache_entry()); 234 __ BranchLink(*StubCode::Subtype2TestCache_entry());
235 } else if (test_kind == kTestTypeFourArgs) { 235 } else if (test_kind == kTestTypeFourArgs) {
236 ASSERT(instantiator_type_arguments_reg == R1); 236 ASSERT(instantiator_type_arguments_reg == R2);
237 ASSERT(function_type_arguments_reg == R2); 237 ASSERT(function_type_arguments_reg == R1);
238 __ BranchLink(*StubCode::Subtype4TestCache_entry()); 238 __ BranchLink(*StubCode::Subtype4TestCache_entry());
239 } else { 239 } else {
240 UNREACHABLE(); 240 UNREACHABLE();
241 } 241 }
242 // Result is in R1: null -> not found, otherwise Bool::True or Bool::False. 242 // Result is in R1: null -> not found, otherwise Bool::True or Bool::False.
243 GenerateBoolToJump(R1, is_instance_lbl, is_not_instance_lbl); 243 GenerateBoolToJump(R1, is_instance_lbl, is_not_instance_lbl);
244 return type_test_cache.raw(); 244 return type_test_cache.raw();
245 } 245 }
246 246
247 247
(...skipping 193 matching lines...) Expand 10 before | Expand all | Expand 10 after
441 RawSubtypeTestCache* FlowGraphCompiler::GenerateUninstantiatedTypeTest( 441 RawSubtypeTestCache* FlowGraphCompiler::GenerateUninstantiatedTypeTest(
442 TokenPosition token_pos, 442 TokenPosition token_pos,
443 const AbstractType& type, 443 const AbstractType& type,
444 Label* is_instance_lbl, 444 Label* is_instance_lbl,
445 Label* is_not_instance_lbl) { 445 Label* is_not_instance_lbl) {
446 __ Comment("UninstantiatedTypeTest"); 446 __ Comment("UninstantiatedTypeTest");
447 ASSERT(!type.IsInstantiated()); 447 ASSERT(!type.IsInstantiated());
448 // Skip check if destination is a dynamic type. 448 // Skip check if destination is a dynamic type.
449 if (type.IsTypeParameter()) { 449 if (type.IsTypeParameter()) {
450 const TypeParameter& type_param = TypeParameter::Cast(type); 450 const TypeParameter& type_param = TypeParameter::Cast(type);
451 __ ldr(R1, Address(SP, 1 * kWordSize)); // Get instantiator type args. 451 const Register kInstantiatorTypeArgumentsReg = R2;
452 __ ldr(R2, Address(SP, 0 * kWordSize)); // Get function type args. 452 const Register kFunctionTypeArgumentsReg = R1;
453 // TODO(regis): Renumber registers and use ldm. 453 __ ldm(IA, SP, (1 << kFunctionTypeArgumentsReg) |
454 // R1: instantiator type arguments. 454 (1 << kInstantiatorTypeArgumentsReg));
455 // R2: function type arguments. 455 // R2: instantiator type arguments.
456 // R1: function type arguments.
456 const Register kTypeArgumentsReg = 457 const Register kTypeArgumentsReg =
457 type_param.IsClassTypeParameter() ? R1 : R2; 458 type_param.IsClassTypeParameter() ? R2 : R1;
458 // Check if type arguments are null, i.e. equivalent to vector of dynamic. 459 // Check if type arguments are null, i.e. equivalent to vector of dynamic.
459 __ CompareObject(kTypeArgumentsReg, Object::null_object()); 460 __ CompareObject(kTypeArgumentsReg, Object::null_object());
460 __ b(is_instance_lbl, EQ); 461 __ b(is_instance_lbl, EQ);
461 __ ldr(R3, FieldAddress(kTypeArgumentsReg, 462 __ ldr(R3, FieldAddress(kTypeArgumentsReg,
462 TypeArguments::type_at_offset(type_param.index()))); 463 TypeArguments::type_at_offset(type_param.index())));
463 // R3: concrete type of type. 464 // R3: concrete type of type.
464 // Check if type argument is dynamic. 465 // Check if type argument is dynamic.
465 __ CompareObject(R3, Object::dynamic_type()); 466 __ CompareObject(R3, Object::dynamic_type());
466 __ b(is_instance_lbl, EQ); 467 __ b(is_instance_lbl, EQ);
467 __ CompareObject(R3, Type::ZoneHandle(zone(), Type::ObjectType())); 468 __ CompareObject(R3, Type::ZoneHandle(zone(), Type::ObjectType()));
468 __ b(is_instance_lbl, EQ); 469 __ b(is_instance_lbl, EQ);
469 // TODO(regis): Optimize void type as well once allowed as type argument. 470 // TODO(regis): Optimize void type as well once allowed as type argument.
470 471
471 // For Smi check quickly against int and num interfaces. 472 // For Smi check quickly against int and num interfaces.
472 Label not_smi; 473 Label not_smi;
473 __ tst(R0, Operand(kSmiTagMask)); // Value is Smi? 474 __ tst(R0, Operand(kSmiTagMask)); // Value is Smi?
474 __ b(&not_smi, NE); 475 __ b(&not_smi, NE);
475 __ CompareObject(R3, Type::ZoneHandle(zone(), Type::IntType())); 476 __ CompareObject(R3, Type::ZoneHandle(zone(), Type::IntType()));
476 __ b(is_instance_lbl, EQ); 477 __ b(is_instance_lbl, EQ);
477 __ CompareObject(R3, Type::ZoneHandle(zone(), Type::Number())); 478 __ CompareObject(R3, Type::ZoneHandle(zone(), Type::Number()));
478 __ b(is_instance_lbl, EQ); 479 __ b(is_instance_lbl, EQ);
479 // Smi must be handled in runtime. 480 // Smi must be handled in runtime.
480 Label fall_through; 481 Label fall_through;
481 __ b(&fall_through); 482 __ b(&fall_through);
482 483
483 __ Bind(&not_smi); 484 __ Bind(&not_smi);
484 // R0: instance. 485 // R0: instance.
485 // R1: instantiator type arguments. 486 // R2: instantiator type arguments.
486 // R2: function type arguments. 487 // R1: function type arguments.
487 const Register kInstanceReg = R0; 488 const Register kInstanceReg = R0;
488 const Register kInstantiatorTypeArgumentsReg = R1;
489 const Register kFunctionTypeArgumentsReg = R2;
490 const Register kTempReg = kNoRegister; 489 const Register kTempReg = kNoRegister;
491 const SubtypeTestCache& type_test_cache = SubtypeTestCache::ZoneHandle( 490 const SubtypeTestCache& type_test_cache = SubtypeTestCache::ZoneHandle(
492 zone(), GenerateCallSubtypeTestStub( 491 zone(), GenerateCallSubtypeTestStub(
493 kTestTypeFourArgs, kInstanceReg, 492 kTestTypeFourArgs, kInstanceReg,
494 kInstantiatorTypeArgumentsReg, kFunctionTypeArgumentsReg, 493 kInstantiatorTypeArgumentsReg, kFunctionTypeArgumentsReg,
495 kTempReg, is_instance_lbl, is_not_instance_lbl)); 494 kTempReg, is_instance_lbl, is_not_instance_lbl));
496 __ Bind(&fall_through); 495 __ Bind(&fall_through);
497 return type_test_cache.raw(); 496 return type_test_cache.raw();
498 } 497 }
499 if (type.IsType()) { 498 if (type.IsType()) {
500 const Register kInstanceReg = R0; 499 const Register kInstanceReg = R0;
501 const Register kInstantiatorTypeArgumentsReg = R1; 500 const Register kInstantiatorTypeArgumentsReg = R2;
502 const Register kFunctionTypeArgumentsReg = R2; 501 const Register kFunctionTypeArgumentsReg = R1;
503 __ tst(kInstanceReg, Operand(kSmiTagMask)); // Is instance Smi? 502 __ tst(kInstanceReg, Operand(kSmiTagMask)); // Is instance Smi?
504 __ b(is_not_instance_lbl, EQ); 503 __ b(is_not_instance_lbl, EQ);
505 __ ldr(kInstantiatorTypeArgumentsReg, Address(SP, 1 * kWordSize)); 504 __ ldm(IA, SP, (1 << kFunctionTypeArgumentsReg) |
506 __ ldr(kFunctionTypeArgumentsReg, Address(SP, 0 * kWordSize)); 505 (1 << kInstantiatorTypeArgumentsReg));
507 // TODO(regis): Renumber registers and use ldm.
508 // Uninstantiated type class is known at compile time, but the type 506 // Uninstantiated type class is known at compile time, but the type
509 // arguments are determined at runtime by the instantiator(s). 507 // arguments are determined at runtime by the instantiator(s).
510 const Register kTempReg = kNoRegister; 508 const Register kTempReg = kNoRegister;
511 return GenerateCallSubtypeTestStub(kTestTypeFourArgs, kInstanceReg, 509 return GenerateCallSubtypeTestStub(kTestTypeFourArgs, kInstanceReg,
512 kInstantiatorTypeArgumentsReg, 510 kInstantiatorTypeArgumentsReg,
513 kFunctionTypeArgumentsReg, kTempReg, 511 kFunctionTypeArgumentsReg, kTempReg,
514 is_instance_lbl, is_not_instance_lbl); 512 is_instance_lbl, is_not_instance_lbl);
515 } 513 }
516 return SubtypeTestCache::null(); 514 return SubtypeTestCache::null();
517 } 515 }
518 516
519 517
520 // Inputs: 518 // Inputs:
521 // - R0: instance being type checked (preserved). 519 // - R0: instance being type checked (preserved).
522 // - R1: optional instantiator type arguments (preserved). 520 // - R2: optional instantiator type arguments (preserved).
523 // - R2: optional function type arguments (preserved). 521 // - R1: optional function type arguments (preserved).
524 // Clobbers R3, R4, R8, R9. 522 // Clobbers R3, R4, R8, R9.
525 // Returns: 523 // Returns:
526 // - preserved instance in R0, optional instantiator type arguments in R1, and 524 // - preserved instance in R0, optional instantiator type arguments in R2, and
527 // optional function type arguments in R2. 525 // optional function type arguments in R1.
528 // Note that this inlined code must be followed by the runtime_call code, as it 526 // Note that this inlined code must be followed by the runtime_call code, as it
529 // may fall through to it. Otherwise, this inline code will jump to the label 527 // may fall through to it. Otherwise, this inline code will jump to the label
530 // is_instance or to the label is_not_instance. 528 // is_instance or to the label is_not_instance.
531 RawSubtypeTestCache* FlowGraphCompiler::GenerateInlineInstanceof( 529 RawSubtypeTestCache* FlowGraphCompiler::GenerateInlineInstanceof(
532 TokenPosition token_pos, 530 TokenPosition token_pos,
533 const AbstractType& type, 531 const AbstractType& type,
534 Label* is_instance_lbl, 532 Label* is_instance_lbl,
535 Label* is_not_instance_lbl) { 533 Label* is_not_instance_lbl) {
536 __ Comment("InlineInstanceof"); 534 __ Comment("InlineInstanceof");
537 if (type.IsVoidType()) { 535 if (type.IsVoidType()) {
(...skipping 27 matching lines...) Expand all
565 } 563 }
566 564
567 565
568 // If instanceof type test cannot be performed successfully at compile time and 566 // If instanceof type test cannot be performed successfully at compile time and
569 // therefore eliminated, optimize it by adding inlined tests for: 567 // therefore eliminated, optimize it by adding inlined tests for:
570 // - NULL -> return type == Null (type is not Object or dynamic). 568 // - NULL -> return type == Null (type is not Object or dynamic).
571 // - Smi -> compile time subtype check (only if dst class is not parameterized). 569 // - Smi -> compile time subtype check (only if dst class is not parameterized).
572 // - Class equality (only if class is not parameterized). 570 // - Class equality (only if class is not parameterized).
573 // Inputs: 571 // Inputs:
574 // - R0: object. 572 // - R0: object.
575 // - R1: instantiator type arguments or raw_null. 573 // - R2: instantiator type arguments or raw_null.
576 // - R2: function type arguments or raw_null. 574 // - R1: function type arguments or raw_null.
577 // Returns: 575 // Returns:
578 // - true or false in R0. 576 // - true or false in R0.
579 void FlowGraphCompiler::GenerateInstanceOf(TokenPosition token_pos, 577 void FlowGraphCompiler::GenerateInstanceOf(TokenPosition token_pos,
580 intptr_t deopt_id, 578 intptr_t deopt_id,
581 const AbstractType& type, 579 const AbstractType& type,
582 LocationSummary* locs) { 580 LocationSummary* locs) {
583 ASSERT(type.IsFinalized() && !type.IsMalformed() && !type.IsMalbounded()); 581 ASSERT(type.IsFinalized() && !type.IsMalformed() && !type.IsMalbounded());
584 ASSERT(!type.IsObjectType() && !type.IsDynamicType()); 582 ASSERT(!type.IsObjectType() && !type.IsDynamicType());
585 583 const Register kInstantiatorTypeArgumentsReg = R2;
586 __ Push(R1); // Store instantiator type arguments. 584 const Register kFunctionTypeArgumentsReg = R1;
587 __ Push(R2); // Store function type arguments. 585 __ PushList((1 << kInstantiatorTypeArgumentsReg) |
588 // TODO(regis): Renumber registers and use PushList. 586 (1 << kFunctionTypeArgumentsReg));
589
590 Label is_instance, is_not_instance; 587 Label is_instance, is_not_instance;
591 // If type is instantiated and non-parameterized, we can inline code 588 // If type is instantiated and non-parameterized, we can inline code
592 // checking whether the tested instance is a Smi. 589 // checking whether the tested instance is a Smi.
593 if (type.IsInstantiated()) { 590 if (type.IsInstantiated()) {
594 // A null object is only an instance of Null, Object, and dynamic. 591 // A null object is only an instance of Null, Object, and dynamic.
595 // Object and dynamic have already been checked above (if the type is 592 // Object and dynamic have already been checked above (if the type is
596 // instantiated). So we can return false here if the instance is null, 593 // instantiated). So we can return false here if the instance is null,
597 // unless the type is Null (and if the type is instantiated). 594 // unless the type is Null (and if the type is instantiated).
598 // We can only inline this null check if the type is instantiated at compile 595 // We can only inline this null check if the type is instantiated at compile
599 // time, since an uninstantiated type at compile time could be Null, Object, 596 // time, since an uninstantiated type at compile time could be Null, Object,
600 // or dynamic at run time. 597 // or dynamic at run time.
601 __ CompareObject(R0, Object::null_object()); 598 __ CompareObject(R0, Object::null_object());
602 __ b(type.IsNullType() ? &is_instance : &is_not_instance, EQ); 599 __ b(type.IsNullType() ? &is_instance : &is_not_instance, EQ);
603 } 600 }
604 601
605 // Generate inline instanceof test. 602 // Generate inline instanceof test.
606 SubtypeTestCache& test_cache = SubtypeTestCache::ZoneHandle(zone()); 603 SubtypeTestCache& test_cache = SubtypeTestCache::ZoneHandle(zone());
607 test_cache = 604 test_cache =
608 GenerateInlineInstanceof(token_pos, type, &is_instance, &is_not_instance); 605 GenerateInlineInstanceof(token_pos, type, &is_instance, &is_not_instance);
609 606
610 // test_cache is null if there is no fall-through. 607 // test_cache is null if there is no fall-through.
611 Label done; 608 Label done;
612 if (!test_cache.IsNull()) { 609 if (!test_cache.IsNull()) {
613 // Generate runtime call. 610 // Generate runtime call.
614 __ ldr(R1, Address(SP, 1 * kWordSize)); // Get instantiator type args. 611 __ ldm(IA, SP, (1 << kFunctionTypeArgumentsReg) |
615 __ ldr(R2, Address(SP, 0 * kWordSize)); // Get function type args. 612 (1 << kInstantiatorTypeArgumentsReg));
616 // TODO(regis): Renumber registers and use ldm.
617 __ PushObject(Object::null_object()); // Make room for the result. 613 __ PushObject(Object::null_object()); // Make room for the result.
618 __ Push(R0); // Push the instance. 614 __ Push(R0); // Push the instance.
619 __ PushObject(type); // Push the type. 615 __ PushObject(type); // Push the type.
620 __ Push(R1); // Instantiator type arguments. 616 __ PushList((1 << kInstantiatorTypeArgumentsReg) |
621 __ Push(R2); // Function type arguments. 617 (1 << kFunctionTypeArgumentsReg));
622 // TODO(regis): Renumber registers and use PushList.
623 __ LoadUniqueObject(R0, test_cache); 618 __ LoadUniqueObject(R0, test_cache);
624 __ Push(R0); 619 __ Push(R0);
625 GenerateRuntimeCall(token_pos, deopt_id, kInstanceofRuntimeEntry, 5, locs); 620 GenerateRuntimeCall(token_pos, deopt_id, kInstanceofRuntimeEntry, 5, locs);
626 // Pop the parameters supplied to the runtime entry. The result of the 621 // 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. 622 // instanceof runtime call will be left as the result of the operation.
628 __ Drop(5); 623 __ Drop(5);
629 __ Pop(R0); 624 __ Pop(R0);
630 __ b(&done); 625 __ b(&done);
631 } 626 }
632 __ Bind(&is_not_instance); 627 __ Bind(&is_not_instance);
633 __ LoadObject(R0, Bool::Get(false)); 628 __ LoadObject(R0, Bool::Get(false));
634 __ b(&done); 629 __ b(&done);
635 630
636 __ Bind(&is_instance); 631 __ Bind(&is_instance);
637 __ LoadObject(R0, Bool::Get(true)); 632 __ LoadObject(R0, Bool::Get(true));
638 __ Bind(&done); 633 __ Bind(&done);
639 // Remove instantiator type arguments and function type arguments. 634 // Remove instantiator type arguments and function type arguments.
640 __ Drop(2); 635 __ Drop(2);
641 } 636 }
642 637
643 638
644 // Optimize assignable type check by adding inlined tests for: 639 // Optimize assignable type check by adding inlined tests for:
645 // - NULL -> return NULL. 640 // - NULL -> return NULL.
646 // - Smi -> compile time subtype check (only if dst class is not parameterized). 641 // - Smi -> compile time subtype check (only if dst class is not parameterized).
647 // - Class equality (only if class is not parameterized). 642 // - Class equality (only if class is not parameterized).
648 // Inputs: 643 // Inputs:
649 // - R0: instance being type checked. 644 // - R0: instance being type checked.
650 // - R1: instantiator type arguments or raw_null. 645 // - R2: instantiator type arguments or raw_null.
651 // - R2: function type arguments or raw_null. 646 // - R1: function type arguments or raw_null.
652 // Returns: 647 // Returns:
653 // - object in R0 for successful assignable check (or throws TypeError). 648 // - object in R0 for successful assignable check (or throws TypeError).
654 // Performance notes: positive checks must be quick, negative checks can be slow 649 // Performance notes: positive checks must be quick, negative checks can be slow
655 // as they throw an exception. 650 // as they throw an exception.
656 void FlowGraphCompiler::GenerateAssertAssignable(TokenPosition token_pos, 651 void FlowGraphCompiler::GenerateAssertAssignable(TokenPosition token_pos,
657 intptr_t deopt_id, 652 intptr_t deopt_id,
658 const AbstractType& dst_type, 653 const AbstractType& dst_type,
659 const String& dst_name, 654 const String& dst_name,
660 LocationSummary* locs) { 655 LocationSummary* locs) {
661 ASSERT(!token_pos.IsClassifying()); 656 ASSERT(!token_pos.IsClassifying());
662 ASSERT(!dst_type.IsNull()); 657 ASSERT(!dst_type.IsNull());
663 ASSERT(dst_type.IsFinalized()); 658 ASSERT(dst_type.IsFinalized());
664 // Assignable check is skipped in FlowGraphBuilder, not here. 659 // Assignable check is skipped in FlowGraphBuilder, not here.
665 ASSERT(dst_type.IsMalformedOrMalbounded() || 660 ASSERT(dst_type.IsMalformedOrMalbounded() ||
666 (!dst_type.IsDynamicType() && !dst_type.IsObjectType())); 661 (!dst_type.IsDynamicType() && !dst_type.IsObjectType()));
667 __ Push(R1); // Store instantiator type arguments. 662 const Register kInstantiatorTypeArgumentsReg = R2;
668 __ Push(R2); // Store function type arguments. 663 const Register kFunctionTypeArgumentsReg = R1;
669 // TODO(regis): Renumber registers and use PushList. 664 __ PushList((1 << kInstantiatorTypeArgumentsReg) |
665 (1 << kFunctionTypeArgumentsReg));
670 // A null object is always assignable and is returned as result. 666 // A null object is always assignable and is returned as result.
671 Label is_assignable, runtime_call; 667 Label is_assignable, runtime_call;
672 __ CompareObject(R0, Object::null_object()); 668 __ CompareObject(R0, Object::null_object());
673 __ b(&is_assignable, EQ); 669 __ b(&is_assignable, EQ);
674 670
675 // Generate throw new TypeError() if the type is malformed or malbounded. 671 // Generate throw new TypeError() if the type is malformed or malbounded.
676 if (dst_type.IsMalformedOrMalbounded()) { 672 if (dst_type.IsMalformedOrMalbounded()) {
677 __ PushObject(Object::null_object()); // Make room for the result. 673 __ PushObject(Object::null_object()); // Make room for the result.
678 __ Push(R0); // Push the source object. 674 __ Push(R0); // Push the source object.
679 __ PushObject(dst_name); // Push the name of the destination. 675 __ PushObject(dst_name); // Push the name of the destination.
680 __ PushObject(dst_type); // Push the type of the destination. 676 __ PushObject(dst_type); // Push the type of the destination.
681 GenerateRuntimeCall(token_pos, deopt_id, kBadTypeErrorRuntimeEntry, 3, 677 GenerateRuntimeCall(token_pos, deopt_id, kBadTypeErrorRuntimeEntry, 3,
682 locs); 678 locs);
683 // We should never return here. 679 // We should never return here.
684 __ bkpt(0); 680 __ bkpt(0);
685 681
686 __ Bind(&is_assignable); // For a null object. 682 __ Bind(&is_assignable); // For a null object.
687 __ Pop(R2); // Remove pushed function type arguments. 683 __ PopList((1 << kFunctionTypeArgumentsReg) |
688 __ Pop(R1); // Remove pushed instantiator type arguments. 684 (1 << kInstantiatorTypeArgumentsReg));
689 // TODO(regis): Renumber registers and use PopList.
690 return; 685 return;
691 } 686 }
692 687
693 // Generate inline type check, linking to runtime call if not assignable. 688 // Generate inline type check, linking to runtime call if not assignable.
694 SubtypeTestCache& test_cache = SubtypeTestCache::ZoneHandle(zone()); 689 SubtypeTestCache& test_cache = SubtypeTestCache::ZoneHandle(zone());
695 test_cache = GenerateInlineInstanceof(token_pos, dst_type, &is_assignable, 690 test_cache = GenerateInlineInstanceof(token_pos, dst_type, &is_assignable,
696 &runtime_call); 691 &runtime_call);
697 692
698 __ Bind(&runtime_call); 693 __ Bind(&runtime_call);
699 __ ldr(R1, Address(SP, 1 * kWordSize)); // Get instantiator type args. 694 __ ldm(IA, SP, (1 << kFunctionTypeArgumentsReg) |
700 __ ldr(R2, Address(SP, 0 * kWordSize)); // Get function type args. 695 (1 << kInstantiatorTypeArgumentsReg));
701 // TODO(regis): Renumber registers and use ldm.
702 __ PushObject(Object::null_object()); // Make room for the result. 696 __ PushObject(Object::null_object()); // Make room for the result.
703 __ Push(R0); // Push the source object. 697 __ Push(R0); // Push the source object.
704 __ PushObject(dst_type); // Push the type of the destination. 698 __ PushObject(dst_type); // Push the type of the destination.
705 __ Push(R1); // Instantiator type arguments. 699 __ PushList((1 << kInstantiatorTypeArgumentsReg) |
706 __ Push(R2); // Function type arguments. 700 (1 << kFunctionTypeArgumentsReg));
707 // TODO(regis): Renumber registers and use PushList.
708 __ PushObject(dst_name); // Push the name of the destination. 701 __ PushObject(dst_name); // Push the name of the destination.
709 __ LoadUniqueObject(R0, test_cache); 702 __ LoadUniqueObject(R0, test_cache);
710 __ Push(R0); 703 __ Push(R0);
711 GenerateRuntimeCall(token_pos, deopt_id, kTypeCheckRuntimeEntry, 6, locs); 704 GenerateRuntimeCall(token_pos, deopt_id, kTypeCheckRuntimeEntry, 6, locs);
712 // Pop the parameters supplied to the runtime entry. The result of the 705 // Pop the parameters supplied to the runtime entry. The result of the
713 // type check runtime call is the checked value. 706 // type check runtime call is the checked value.
714 __ Drop(6); 707 __ Drop(6);
715 __ Pop(R0); 708 __ Pop(R0);
716 709
717 __ Bind(&is_assignable); 710 __ Bind(&is_assignable);
718 __ Pop(R2); // Remove pushed function type arguments. 711 __ PopList((1 << kFunctionTypeArgumentsReg) |
719 __ Pop(R1); // Remove pushed instantiator type arguments. 712 (1 << kInstantiatorTypeArgumentsReg));
720 // TODO(regis): Renumber registers and use PopList.
721 } 713 }
722 714
723 715
724 void FlowGraphCompiler::EmitInstructionEpilogue(Instruction* instr) { 716 void FlowGraphCompiler::EmitInstructionEpilogue(Instruction* instr) {
725 if (is_optimizing()) { 717 if (is_optimizing()) {
726 return; 718 return;
727 } 719 }
728 Definition* defn = instr->AsDefinition(); 720 Definition* defn = instr->AsDefinition();
729 if ((defn != NULL) && defn->HasTemp()) { 721 if ((defn != NULL) && defn->HasTemp()) {
730 __ Push(defn->locs()->out(0).reg()); 722 __ Push(defn->locs()->out(0).reg());
(...skipping 698 matching lines...) Expand 10 before | Expand all | Expand 10 after
1429 ClobberDeadTempRegisters(locs); 1421 ClobberDeadTempRegisters(locs);
1430 #endif 1422 #endif
1431 1423
1432 // TODO(vegorov): consider saving only caller save (volatile) registers. 1424 // TODO(vegorov): consider saving only caller save (volatile) registers.
1433 const intptr_t fpu_regs_count = locs->live_registers()->FpuRegisterCount(); 1425 const intptr_t fpu_regs_count = locs->live_registers()->FpuRegisterCount();
1434 if (fpu_regs_count > 0) { 1426 if (fpu_regs_count > 0) {
1435 __ AddImmediate(SP, -(fpu_regs_count * kFpuRegisterSize)); 1427 __ AddImmediate(SP, -(fpu_regs_count * kFpuRegisterSize));
1436 // Store fpu registers with the lowest register number at the lowest 1428 // Store fpu registers with the lowest register number at the lowest
1437 // address. 1429 // address.
1438 intptr_t offset = 0; 1430 intptr_t offset = 0;
1431 __ mov(IP, Operand(SP));
1439 for (intptr_t i = 0; i < kNumberOfFpuRegisters; ++i) { 1432 for (intptr_t i = 0; i < kNumberOfFpuRegisters; ++i) {
1440 QRegister fpu_reg = static_cast<QRegister>(i); 1433 QRegister fpu_reg = static_cast<QRegister>(i);
1441 if (locs->live_registers()->ContainsFpuRegister(fpu_reg)) { 1434 if (locs->live_registers()->ContainsFpuRegister(fpu_reg)) {
1442 DRegister d1 = EvenDRegisterOf(fpu_reg); 1435 DRegister d = EvenDRegisterOf(fpu_reg);
1443 DRegister d2 = OddDRegisterOf(fpu_reg); 1436 ASSERT(d + 1 == OddDRegisterOf(fpu_reg));
1444 // TODO(regis): merge stores using vstmd instruction. 1437 __ vstmd(IA_W, IP, d, 2);
1445 __ vstrd(d1, Address(SP, offset));
1446 __ vstrd(d2, Address(SP, offset + 2 * kWordSize));
1447 offset += kFpuRegisterSize; 1438 offset += kFpuRegisterSize;
1448 } 1439 }
1449 } 1440 }
1450 ASSERT(offset == (fpu_regs_count * kFpuRegisterSize)); 1441 ASSERT(offset == (fpu_regs_count * kFpuRegisterSize));
1451 } 1442 }
1452 1443
1453 // The order in which the registers are pushed must match the order 1444 // The order in which the registers are pushed must match the order
1454 // in which the registers are encoded in the safe point's stack map. 1445 // in which the registers are encoded in the safe point's stack map.
1455 // NOTE: This matches the order of ARM's multi-register push. 1446 // NOTE: This matches the order of ARM's multi-register push.
1456 RegList reg_list = 0; 1447 RegList reg_list = 0;
(...skipping 21 matching lines...) Expand all
1478 __ PopList(reg_list); 1469 __ PopList(reg_list);
1479 } 1470 }
1480 1471
1481 const intptr_t fpu_regs_count = locs->live_registers()->FpuRegisterCount(); 1472 const intptr_t fpu_regs_count = locs->live_registers()->FpuRegisterCount();
1482 if (fpu_regs_count > 0) { 1473 if (fpu_regs_count > 0) {
1483 // Fpu registers have the lowest register number at the lowest address. 1474 // Fpu registers have the lowest register number at the lowest address.
1484 intptr_t offset = 0; 1475 intptr_t offset = 0;
1485 for (intptr_t i = 0; i < kNumberOfFpuRegisters; ++i) { 1476 for (intptr_t i = 0; i < kNumberOfFpuRegisters; ++i) {
1486 QRegister fpu_reg = static_cast<QRegister>(i); 1477 QRegister fpu_reg = static_cast<QRegister>(i);
1487 if (locs->live_registers()->ContainsFpuRegister(fpu_reg)) { 1478 if (locs->live_registers()->ContainsFpuRegister(fpu_reg)) {
1488 DRegister d1 = EvenDRegisterOf(fpu_reg); 1479 DRegister d = EvenDRegisterOf(fpu_reg);
1489 DRegister d2 = OddDRegisterOf(fpu_reg); 1480 ASSERT(d + 1 == OddDRegisterOf(fpu_reg));
1490 // TODO(regis): merge loads using vldmd instruction. 1481 __ vldmd(IA_W, SP, d, 2);
1491 __ vldrd(d1, Address(SP, offset));
1492 __ vldrd(d2, Address(SP, offset + 2 * kWordSize));
1493 offset += kFpuRegisterSize; 1482 offset += kFpuRegisterSize;
1494 } 1483 }
1495 } 1484 }
1496 ASSERT(offset == (fpu_regs_count * kFpuRegisterSize)); 1485 ASSERT(offset == (fpu_regs_count * kFpuRegisterSize));
1497 __ AddImmediate(SP, offset);
1498 } 1486 }
1499 } 1487 }
1500 1488
1501 1489
1502 #if defined(DEBUG) 1490 #if defined(DEBUG)
1503 void FlowGraphCompiler::ClobberDeadTempRegisters(LocationSummary* locs) { 1491 void FlowGraphCompiler::ClobberDeadTempRegisters(LocationSummary* locs) {
1504 // Clobber temporaries that have not been manually preserved. 1492 // Clobber temporaries that have not been manually preserved.
1505 for (intptr_t i = 0; i < locs->temp_count(); ++i) { 1493 for (intptr_t i = 0; i < locs->temp_count(); ++i) {
1506 Location tmp = locs->temp(i); 1494 Location tmp = locs->temp(i);
1507 // TODO(zerny): clobber non-live temporary FPU registers. 1495 // TODO(zerny): clobber non-live temporary FPU registers.
(...skipping 415 matching lines...) Expand 10 before | Expand all | Expand 10 after
1923 DRegister dreg = EvenDRegisterOf(reg); 1911 DRegister dreg = EvenDRegisterOf(reg);
1924 __ vldrd(dreg, Address(SP, kDoubleSize, Address::PostIndex)); 1912 __ vldrd(dreg, Address(SP, kDoubleSize, Address::PostIndex));
1925 } 1913 }
1926 1914
1927 1915
1928 #undef __ 1916 #undef __
1929 1917
1930 } // namespace dart 1918 } // namespace dart
1931 1919
1932 #endif // defined TARGET_ARCH_ARM 1920 #endif // defined TARGET_ARCH_ARM
OLDNEW
« no previous file with comments | « no previous file | runtime/vm/intermediate_language_arm.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698