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