| 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 "lib/error.h" | 10 #include "lib/error.h" |
| (...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 86 Label* is_instance_lbl, | 86 Label* is_instance_lbl, |
| 87 Label* is_not_instance_lbl) { | 87 Label* is_not_instance_lbl) { |
| 88 __ TraceSimMsg("CallSubtypeTestStub"); | 88 __ TraceSimMsg("CallSubtypeTestStub"); |
| 89 ASSERT(instance_reg == A0); | 89 ASSERT(instance_reg == A0); |
| 90 ASSERT(temp_reg == kNoRegister); // Unused on MIPS. | 90 ASSERT(temp_reg == kNoRegister); // Unused on MIPS. |
| 91 const SubtypeTestCache& type_test_cache = | 91 const SubtypeTestCache& type_test_cache = |
| 92 SubtypeTestCache::ZoneHandle(SubtypeTestCache::New()); | 92 SubtypeTestCache::ZoneHandle(SubtypeTestCache::New()); |
| 93 __ LoadObject(A2, type_test_cache); | 93 __ LoadObject(A2, type_test_cache); |
| 94 if (test_kind == kTestTypeOneArg) { | 94 if (test_kind == kTestTypeOneArg) { |
| 95 ASSERT(type_arguments_reg == kNoRegister); | 95 ASSERT(type_arguments_reg == kNoRegister); |
| 96 __ LoadImmediate(A1, reinterpret_cast<intptr_t>(Object::null())); | 96 intptr_t null = reinterpret_cast<intptr_t>(Object::null()); |
| 97 uint16_t null_lo = Utils::Low16Bits(null); |
| 98 uint16_t null_hi = Utils::High16Bits(null); |
| 99 __ lui(A1, Immediate(null_hi)); |
| 97 __ BranchLink(&StubCode::Subtype1TestCacheLabel()); | 100 __ BranchLink(&StubCode::Subtype1TestCacheLabel()); |
| 101 __ delay_slot()->ori(A1, A1, Immediate(null_lo)); |
| 98 } else if (test_kind == kTestTypeTwoArgs) { | 102 } else if (test_kind == kTestTypeTwoArgs) { |
| 99 ASSERT(type_arguments_reg == kNoRegister); | 103 ASSERT(type_arguments_reg == kNoRegister); |
| 100 __ LoadImmediate(A1, reinterpret_cast<intptr_t>(Object::null())); | 104 intptr_t null = reinterpret_cast<intptr_t>(Object::null()); |
| 105 uint16_t null_lo = Utils::Low16Bits(null); |
| 106 uint16_t null_hi = Utils::High16Bits(null); |
| 107 __ lui(A1, Immediate(null_hi)); |
| 101 __ BranchLink(&StubCode::Subtype2TestCacheLabel()); | 108 __ BranchLink(&StubCode::Subtype2TestCacheLabel()); |
| 109 __ delay_slot()->ori(A1, A1, Immediate(null_lo)); |
| 102 } else if (test_kind == kTestTypeThreeArgs) { | 110 } else if (test_kind == kTestTypeThreeArgs) { |
| 103 ASSERT(type_arguments_reg == A1); | 111 ASSERT(type_arguments_reg == A1); |
| 104 __ BranchLink(&StubCode::Subtype3TestCacheLabel()); | 112 __ BranchLink(&StubCode::Subtype3TestCacheLabel()); |
| 105 } else { | 113 } else { |
| 106 UNREACHABLE(); | 114 UNREACHABLE(); |
| 107 } | 115 } |
| 108 // Result is in V0: null -> not found, otherwise Bool::True or Bool::False. | 116 // Result is in V0: null -> not found, otherwise Bool::True or Bool::False. |
| 109 GenerateBoolToJump(V0, is_instance_lbl, is_not_instance_lbl); | 117 GenerateBoolToJump(V0, is_instance_lbl, is_not_instance_lbl); |
| 110 return type_test_cache.raw(); | 118 return type_test_cache.raw(); |
| 111 } | 119 } |
| (...skipping 350 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 462 __ TraceSimMsg("AssertAssignable"); | 470 __ TraceSimMsg("AssertAssignable"); |
| 463 ASSERT(token_pos >= 0); | 471 ASSERT(token_pos >= 0); |
| 464 ASSERT(!dst_type.IsNull()); | 472 ASSERT(!dst_type.IsNull()); |
| 465 ASSERT(dst_type.IsFinalized()); | 473 ASSERT(dst_type.IsFinalized()); |
| 466 // Assignable check is skipped in FlowGraphBuilder, not here. | 474 // Assignable check is skipped in FlowGraphBuilder, not here. |
| 467 ASSERT(dst_type.IsMalformed() || | 475 ASSERT(dst_type.IsMalformed() || |
| 468 (!dst_type.IsDynamicType() && !dst_type.IsObjectType())); | 476 (!dst_type.IsDynamicType() && !dst_type.IsObjectType())); |
| 469 // Preserve instantiator and its type arguments. | 477 // Preserve instantiator and its type arguments. |
| 470 __ addiu(SP, SP, Immediate(-2 * kWordSize)); | 478 __ addiu(SP, SP, Immediate(-2 * kWordSize)); |
| 471 __ sw(A2, Address(SP, 1 * kWordSize)); | 479 __ sw(A2, Address(SP, 1 * kWordSize)); |
| 472 __ sw(A1, Address(SP, 0 * kWordSize)); | 480 |
| 473 // A null object is always assignable and is returned as result. | 481 // A null object is always assignable and is returned as result. |
| 474 Label is_assignable, runtime_call; | 482 Label is_assignable, runtime_call; |
| 475 __ BranchEqual(A0, reinterpret_cast<int32_t>(Object::null()), &is_assignable); | 483 __ BranchEqual(A0, reinterpret_cast<int32_t>(Object::null()), &is_assignable); |
| 484 __ delay_slot()->sw(A1, Address(SP, 0 * kWordSize)); |
| 476 | 485 |
| 477 if (!FLAG_eliminate_type_checks) { | 486 if (!FLAG_eliminate_type_checks) { |
| 478 // If type checks are not eliminated during the graph building then | 487 // If type checks are not eliminated during the graph building then |
| 479 // a transition sentinel can be seen here. | 488 // a transition sentinel can be seen here. |
| 480 __ BranchEqual(A0, Object::transition_sentinel(), &is_assignable); | 489 __ BranchEqual(A0, Object::transition_sentinel(), &is_assignable); |
| 481 } | 490 } |
| 482 | 491 |
| 483 // Generate throw new TypeError() if the type is malformed. | 492 // Generate throw new TypeError() if the type is malformed. |
| 484 if (dst_type.IsMalformed()) { | 493 if (dst_type.IsMalformed()) { |
| 485 const Error& error = Error::Handle(dst_type.malformed_error()); | 494 const Error& error = Error::Handle(dst_type.malformed_error()); |
| (...skipping 133 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 619 __ subu(T1, T1, T2); | 628 __ subu(T1, T1, T2); |
| 620 __ sll(T1, T1, 1); | 629 __ sll(T1, T1, 1); |
| 621 __ addu(T1, FP, T1); | 630 __ addu(T1, FP, T1); |
| 622 __ AddImmediate(T1, kLastParamSlotIndex * kWordSize); | 631 __ AddImmediate(T1, kLastParamSlotIndex * kWordSize); |
| 623 | 632 |
| 624 // Let T0 point to the last copied positional argument, i.e. to | 633 // Let T0 point to the last copied positional argument, i.e. to |
| 625 // fp[kFirstLocalSlotIndex - (num_pos_args - 1)]. | 634 // fp[kFirstLocalSlotIndex - (num_pos_args - 1)]. |
| 626 __ AddImmediate(T0, FP, (kFirstLocalSlotIndex + 1) * kWordSize); | 635 __ AddImmediate(T0, FP, (kFirstLocalSlotIndex + 1) * kWordSize); |
| 627 __ sll(T2, T2, 1); // T2 is a Smi. | 636 __ sll(T2, T2, 1); // T2 is a Smi. |
| 628 | 637 |
| 629 Label loop, loop_condition; | 638 Label loop, loop_exit; |
| 630 __ b(&loop_condition); | 639 __ blez(T2, &loop_exit); |
| 631 __ delay_slot()->subu(T0, T0, T2); | 640 __ delay_slot()->subu(T0, T0, T2); |
| 632 // We do not use the final allocation index of the variable here, i.e. | |
| 633 // scope->VariableAt(i)->index(), because captured variables still need | |
| 634 // to be copied to the context that is not yet allocated. | |
| 635 __ Bind(&loop); | 641 __ Bind(&loop); |
| 636 __ addu(T4, T1, T2); | 642 __ addu(T4, T1, T2); |
| 643 __ lw(T3, Address(T4, -kWordSize)); |
| 644 __ addiu(T2, T2, Immediate(-kWordSize)); |
| 637 __ addu(T5, T0, T2); | 645 __ addu(T5, T0, T2); |
| 638 __ lw(T3, Address(T4)); | 646 __ bgtz(T2, &loop); |
| 639 __ sw(T3, Address(T5)); | 647 __ delay_slot()->sw(T3, Address(T5)); |
| 640 __ Bind(&loop_condition); | 648 __ Bind(&loop_exit); |
| 641 __ addiu(T2, T2, Immediate(-kWordSize)); | |
| 642 __ bgez(T2, &loop); | |
| 643 | 649 |
| 644 // Copy or initialize optional named arguments. | 650 // Copy or initialize optional named arguments. |
| 645 Label all_arguments_processed; | 651 Label all_arguments_processed; |
| 646 if (num_opt_named_params > 0) { | 652 if (num_opt_named_params > 0) { |
| 647 // Start by alphabetically sorting the names of the optional parameters. | 653 // Start by alphabetically sorting the names of the optional parameters. |
| 648 LocalVariable** opt_param = new LocalVariable*[num_opt_named_params]; | 654 LocalVariable** opt_param = new LocalVariable*[num_opt_named_params]; |
| 649 int* opt_param_position = new int[num_opt_named_params]; | 655 int* opt_param_position = new int[num_opt_named_params]; |
| 650 for (int pos = num_fixed_params; pos < num_params; pos++) { | 656 for (int pos = num_fixed_params; pos < num_params; pos++) { |
| 651 LocalVariable* parameter = scope->VariableAt(pos); | 657 LocalVariable* parameter = scope->VariableAt(pos); |
| 652 const String& opt_param_name = parameter->name(); | 658 const String& opt_param_name = parameter->name(); |
| (...skipping 130 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 783 __ LeaveDartFrame(); | 789 __ LeaveDartFrame(); |
| 784 __ Ret(); | 790 __ Ret(); |
| 785 | 791 |
| 786 __ Bind(&all_arguments_processed); | 792 __ Bind(&all_arguments_processed); |
| 787 // Nullify originally passed arguments only after they have been copied and | 793 // Nullify originally passed arguments only after they have been copied and |
| 788 // checked, otherwise noSuchMethod would not see their original values. | 794 // checked, otherwise noSuchMethod would not see their original values. |
| 789 // This step can be skipped in case we decide that formal parameters are | 795 // This step can be skipped in case we decide that formal parameters are |
| 790 // implicitly final, since garbage collecting the unmodified value is not | 796 // implicitly final, since garbage collecting the unmodified value is not |
| 791 // an issue anymore. | 797 // an issue anymore. |
| 792 | 798 |
| 799 __ LoadImmediate(T0, reinterpret_cast<intptr_t>(Object::null())); |
| 800 |
| 793 // S4 : arguments descriptor array. | 801 // S4 : arguments descriptor array. |
| 794 __ lw(T2, FieldAddress(S4, ArgumentsDescriptor::count_offset())); | 802 __ lw(T2, FieldAddress(S4, ArgumentsDescriptor::count_offset())); |
| 795 __ sll(T2, T2, 1); // T2 is a Smi. | 803 __ sll(T2, T2, 1); // T2 is a Smi. |
| 796 | 804 |
| 797 __ LoadImmediate(T0, reinterpret_cast<intptr_t>(Object::null())); | 805 Label null_args_loop, null_args_loop_exit; |
| 798 Label null_args_loop, null_args_loop_condition; | 806 __ blez(T2, &null_args_loop_exit); |
| 799 | |
| 800 __ b(&null_args_loop_condition); | |
| 801 __ delay_slot()->addiu(T1, FP, Immediate(kLastParamSlotIndex * kWordSize)); | 807 __ delay_slot()->addiu(T1, FP, Immediate(kLastParamSlotIndex * kWordSize)); |
| 802 | |
| 803 __ Bind(&null_args_loop); | 808 __ Bind(&null_args_loop); |
| 809 __ addiu(T2, T2, Immediate(-kWordSize)); |
| 804 __ addu(T3, T1, T2); | 810 __ addu(T3, T1, T2); |
| 805 __ sw(T0, Address(T3)); | 811 __ bgtz(T2, &null_args_loop); |
| 806 | 812 __ delay_slot()->sw(T0, Address(T3)); |
| 807 __ Bind(&null_args_loop_condition); | 813 __ Bind(&null_args_loop_exit); |
| 808 __ addiu(T2, T2, Immediate(-kWordSize)); | |
| 809 __ bgez(T2, &null_args_loop); | |
| 810 } | 814 } |
| 811 | 815 |
| 812 | 816 |
| 813 void FlowGraphCompiler::GenerateInlinedGetter(intptr_t offset) { | 817 void FlowGraphCompiler::GenerateInlinedGetter(intptr_t offset) { |
| 814 // RA: return address. | 818 // RA: return address. |
| 815 // SP: receiver. | 819 // SP: receiver. |
| 816 // Sequence node has one return node, its input is load field node. | 820 // Sequence node has one return node, its input is load field node. |
| 817 __ lw(V0, Address(SP, 0 * kWordSize)); | 821 __ lw(V0, Address(SP, 0 * kWordSize)); |
| 818 __ lw(V0, Address(V0, offset - kHeapObjectTag)); | 822 __ lw(V0, Address(V0, offset - kHeapObjectTag)); |
| 819 __ Ret(); | 823 __ Ret(); |
| 820 } | 824 } |
| 821 | 825 |
| 822 | 826 |
| 823 void FlowGraphCompiler::GenerateInlinedSetter(intptr_t offset) { | 827 void FlowGraphCompiler::GenerateInlinedSetter(intptr_t offset) { |
| 824 // RA: return address. | 828 // RA: return address. |
| 825 // SP+1: receiver. | 829 // SP+1: receiver. |
| 826 // SP+0: value. | 830 // SP+0: value. |
| 827 // Sequence node has one store node and one return NULL node. | 831 // Sequence node has one store node and one return NULL node. |
| 828 __ lw(T0, Address(SP, 1 * kWordSize)); // Receiver. | 832 __ lw(T0, Address(SP, 1 * kWordSize)); // Receiver. |
| 829 __ lw(T1, Address(SP, 0 * kWordSize)); // Value. | 833 __ lw(T1, Address(SP, 0 * kWordSize)); // Value. |
| 830 __ StoreIntoObject(T0, FieldAddress(T0, offset), T1); | 834 __ StoreIntoObject(T0, FieldAddress(T0, offset), T1); |
| 831 __ LoadImmediate(V0, reinterpret_cast<intptr_t>(Object::null())); | 835 intptr_t null = reinterpret_cast<intptr_t>(Object::null()); |
| 836 uint16_t null_lo = Utils::Low16Bits(null); |
| 837 uint16_t null_hi = Utils::High16Bits(null); |
| 838 __ lui(V0, Immediate(null_hi)); |
| 832 __ Ret(); | 839 __ Ret(); |
| 840 __ delay_slot()->ori(V0, V0, Immediate(null_lo)); |
| 833 } | 841 } |
| 834 | 842 |
| 835 | 843 |
| 836 void FlowGraphCompiler::EmitFrameEntry() { | 844 void FlowGraphCompiler::EmitFrameEntry() { |
| 837 __ TraceSimMsg("FrameEntry"); | 845 __ TraceSimMsg("FrameEntry"); |
| 838 const Function& function = parsed_function().function(); | 846 const Function& function = parsed_function().function(); |
| 839 if (CanOptimizeFunction() && function.is_optimizable()) { | 847 if (CanOptimizeFunction() && function.is_optimizable()) { |
| 840 const bool can_optimize = !is_optimizing() || may_reoptimize(); | 848 const bool can_optimize = !is_optimizing() || may_reoptimize(); |
| 841 const Register function_reg = T0; | 849 const Register function_reg = T0; |
| 842 if (can_optimize) { | 850 if (can_optimize) { |
| (...skipping 351 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1194 | 1202 |
| 1195 | 1203 |
| 1196 void FlowGraphCompiler::EmitEqualityRegConstCompare(Register reg, | 1204 void FlowGraphCompiler::EmitEqualityRegConstCompare(Register reg, |
| 1197 const Object& obj, | 1205 const Object& obj, |
| 1198 bool needs_number_check) { | 1206 bool needs_number_check) { |
| 1199 if (needs_number_check && | 1207 if (needs_number_check && |
| 1200 (obj.IsMint() || obj.IsDouble() || obj.IsBigint())) { | 1208 (obj.IsMint() || obj.IsDouble() || obj.IsBigint())) { |
| 1201 __ addiu(SP, SP, Immediate(-2 * kWordSize)); | 1209 __ addiu(SP, SP, Immediate(-2 * kWordSize)); |
| 1202 __ sw(reg, Address(SP, 1 * kWordSize)); | 1210 __ sw(reg, Address(SP, 1 * kWordSize)); |
| 1203 __ LoadObject(TMP1, obj); | 1211 __ LoadObject(TMP1, obj); |
| 1204 __ sw(TMP1, Address(SP, 0 * kWordSize)); | |
| 1205 __ BranchLink(&StubCode::IdenticalWithNumberCheckLabel()); | 1212 __ BranchLink(&StubCode::IdenticalWithNumberCheckLabel()); |
| 1213 __ delay_slot()->sw(TMP1, Address(SP, 0 * kWordSize)); |
| 1206 __ lw(reg, Address(SP, 1 * kWordSize)); // Restore 'reg'. | 1214 __ lw(reg, Address(SP, 1 * kWordSize)); // Restore 'reg'. |
| 1207 __ addiu(SP, SP, Immediate(2 * kWordSize)); // Discard constant. | 1215 __ addiu(SP, SP, Immediate(2 * kWordSize)); // Discard constant. |
| 1208 return; | 1216 return; |
| 1209 } | 1217 } |
| 1210 __ CompareObject(CMPRES, reg, obj); | 1218 __ CompareObject(CMPRES, reg, obj); |
| 1211 } | 1219 } |
| 1212 | 1220 |
| 1213 | 1221 |
| 1214 void FlowGraphCompiler::EmitEqualityRegRegCompare(Register left, | 1222 void FlowGraphCompiler::EmitEqualityRegRegCompare(Register left, |
| 1215 Register right, | 1223 Register right, |
| 1216 bool needs_number_check) { | 1224 bool needs_number_check) { |
| 1217 __ TraceSimMsg("EqualityRegRegCompare"); | 1225 __ TraceSimMsg("EqualityRegRegCompare"); |
| 1218 if (needs_number_check) { | 1226 if (needs_number_check) { |
| 1219 __ addiu(SP, SP, Immediate(-2 * kWordSize)); | 1227 __ addiu(SP, SP, Immediate(-2 * kWordSize)); |
| 1220 __ sw(left, Address(SP, 1 * kWordSize)); | 1228 __ sw(left, Address(SP, 1 * kWordSize)); |
| 1221 __ sw(right, Address(SP, 0 * kWordSize)); | |
| 1222 __ BranchLink(&StubCode::IdenticalWithNumberCheckLabel()); | 1229 __ BranchLink(&StubCode::IdenticalWithNumberCheckLabel()); |
| 1230 __ delay_slot()->sw(right, Address(SP, 0 * kWordSize)); |
| 1223 __ TraceSimMsg("EqualityRegRegCompare return"); | 1231 __ TraceSimMsg("EqualityRegRegCompare return"); |
| 1224 // Stub returns result in CMPRES. If it is 0, then left and right are equal. | 1232 // Stub returns result in CMPRES. If it is 0, then left and right are equal. |
| 1225 __ lw(right, Address(SP, 0 * kWordSize)); | 1233 __ lw(right, Address(SP, 0 * kWordSize)); |
| 1226 __ lw(left, Address(SP, 1 * kWordSize)); | 1234 __ lw(left, Address(SP, 1 * kWordSize)); |
| 1227 __ addiu(SP, SP, Immediate(2 * kWordSize)); | 1235 __ addiu(SP, SP, Immediate(2 * kWordSize)); |
| 1228 } else { | 1236 } else { |
| 1229 __ subu(CMPRES, left, right); | 1237 __ subu(CMPRES, left, right); |
| 1230 } | 1238 } |
| 1231 } | 1239 } |
| 1232 | 1240 |
| (...skipping 328 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1561 __ AddImmediate(SP, kDoubleSize); | 1569 __ AddImmediate(SP, kDoubleSize); |
| 1562 } | 1570 } |
| 1563 | 1571 |
| 1564 | 1572 |
| 1565 #undef __ | 1573 #undef __ |
| 1566 | 1574 |
| 1567 | 1575 |
| 1568 } // namespace dart | 1576 } // namespace dart |
| 1569 | 1577 |
| 1570 #endif // defined TARGET_ARCH_MIPS | 1578 #endif // defined TARGET_ARCH_MIPS |
| OLD | NEW |