| 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 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 89 | 89 |
| 90 // Emit all kMaterializeObject instructions describing objects to be | 90 // Emit all kMaterializeObject instructions describing objects to be |
| 91 // materialized on the deoptimization as a prefix to the deoptimization info. | 91 // materialized on the deoptimization as a prefix to the deoptimization info. |
| 92 EmitMaterializations(deopt_env_, builder); | 92 EmitMaterializations(deopt_env_, builder); |
| 93 | 93 |
| 94 // The real frame starts here. | 94 // The real frame starts here. |
| 95 builder->MarkFrameStart(); | 95 builder->MarkFrameStart(); |
| 96 | 96 |
| 97 Zone* zone = compiler->zone(); | 97 Zone* zone = compiler->zone(); |
| 98 | 98 |
| 99 // Current PP, FP, and PC. |
| 99 builder->AddPp(current->function(), slot_ix++); | 100 builder->AddPp(current->function(), slot_ix++); |
| 100 builder->AddPcMarker(Function::Handle(zone), slot_ix++); | |
| 101 builder->AddCallerFp(slot_ix++); | 101 builder->AddCallerFp(slot_ix++); |
| 102 builder->AddReturnAddress(current->function(), deopt_id(), slot_ix++); | 102 builder->AddReturnAddress(current->function(), deopt_id(), slot_ix++); |
| 103 | 103 |
| 104 // Callee's PC marker is not used anymore. Pass Code::null() to set to 0. |
| 105 builder->AddPcMarker(Function::Handle(zone), slot_ix++); |
| 104 | 106 |
| 105 // Emit all values that are needed for materialization as a part of the | 107 // Emit all values that are needed for materialization as a part of the |
| 106 // expression stack for the bottom-most frame. This guarantees that GC | 108 // expression stack for the bottom-most frame. This guarantees that GC |
| 107 // will be able to find them during materialization. | 109 // will be able to find them during materialization. |
| 108 slot_ix = builder->EmitMaterializationArguments(slot_ix); | 110 slot_ix = builder->EmitMaterializationArguments(slot_ix); |
| 109 | 111 |
| 110 // For the innermost environment, set outgoing arguments and the locals. | 112 // For the innermost environment, set outgoing arguments and the locals. |
| 111 for (intptr_t i = current->Length() - 1; | 113 for (intptr_t i = current->Length() - 1; |
| 112 i >= current->fixed_parameter_count(); | 114 i >= current->fixed_parameter_count(); |
| 113 i--) { | 115 i--) { |
| 114 builder->AddCopy(current->ValueAt(i), current->LocationAt(i), slot_ix++); | 116 builder->AddCopy(current->ValueAt(i), current->LocationAt(i), slot_ix++); |
| 115 } | 117 } |
| 116 | 118 |
| 117 Environment* previous = current; | 119 Environment* previous = current; |
| 118 current = current->outer(); | 120 current = current->outer(); |
| 119 while (current != NULL) { | 121 while (current != NULL) { |
| 122 // PP, FP, and PC. |
| 120 builder->AddPp(current->function(), slot_ix++); | 123 builder->AddPp(current->function(), slot_ix++); |
| 121 builder->AddPcMarker(previous->function(), slot_ix++); | |
| 122 builder->AddCallerFp(slot_ix++); | 124 builder->AddCallerFp(slot_ix++); |
| 123 | 125 |
| 124 // For any outer environment the deopt id is that of the call instruction | 126 // For any outer environment the deopt id is that of the call instruction |
| 125 // which is recorded in the outer environment. | 127 // which is recorded in the outer environment. |
| 126 builder->AddReturnAddress( | 128 builder->AddReturnAddress( |
| 127 current->function(), | 129 current->function(), |
| 128 Isolate::ToDeoptAfter(current->deopt_id()), | 130 Isolate::ToDeoptAfter(current->deopt_id()), |
| 129 slot_ix++); | 131 slot_ix++); |
| 130 | 132 |
| 133 // PC marker. |
| 134 builder->AddPcMarker(previous->function(), slot_ix++); |
| 135 |
| 131 // The values of outgoing arguments can be changed from the inlined call so | 136 // The values of outgoing arguments can be changed from the inlined call so |
| 132 // we must read them from the previous environment. | 137 // we must read them from the previous environment. |
| 133 for (intptr_t i = previous->fixed_parameter_count() - 1; i >= 0; i--) { | 138 for (intptr_t i = previous->fixed_parameter_count() - 1; i >= 0; i--) { |
| 134 builder->AddCopy(previous->ValueAt(i), | 139 builder->AddCopy(previous->ValueAt(i), |
| 135 previous->LocationAt(i), | 140 previous->LocationAt(i), |
| 136 slot_ix++); | 141 slot_ix++); |
| 137 } | 142 } |
| 138 | 143 |
| 139 // Set the locals, note that outgoing arguments are not in the environment. | 144 // Set the locals, note that outgoing arguments are not in the environment. |
| 140 for (intptr_t i = current->Length() - 1; | 145 for (intptr_t i = current->Length() - 1; |
| 141 i >= current->fixed_parameter_count(); | 146 i >= current->fixed_parameter_count(); |
| 142 i--) { | 147 i--) { |
| 143 builder->AddCopy(current->ValueAt(i), | 148 builder->AddCopy(current->ValueAt(i), |
| 144 current->LocationAt(i), | 149 current->LocationAt(i), |
| 145 slot_ix++); | 150 slot_ix++); |
| 146 } | 151 } |
| 147 | 152 |
| 148 // Iterate on the outer environment. | 153 // Iterate on the outer environment. |
| 149 previous = current; | 154 previous = current; |
| 150 current = current->outer(); | 155 current = current->outer(); |
| 151 } | 156 } |
| 152 // The previous pointer is now the outermost environment. | 157 // The previous pointer is now the outermost environment. |
| 153 ASSERT(previous != NULL); | 158 ASSERT(previous != NULL); |
| 154 | 159 |
| 155 // Set slots for the outermost environment. | 160 // For the outermost environment, set caller PC, caller PP, and caller FP. |
| 156 builder->AddCallerPp(slot_ix++); | 161 builder->AddCallerPp(slot_ix++); |
| 157 builder->AddPcMarker(previous->function(), slot_ix++); | |
| 158 builder->AddCallerFp(slot_ix++); | 162 builder->AddCallerFp(slot_ix++); |
| 159 builder->AddCallerPc(slot_ix++); | 163 builder->AddCallerPc(slot_ix++); |
| 160 | 164 |
| 165 // PC marker. |
| 166 builder->AddPcMarker(previous->function(), slot_ix++); |
| 167 |
| 161 // For the outermost environment, set the incoming arguments. | 168 // For the outermost environment, set the incoming arguments. |
| 162 for (intptr_t i = previous->fixed_parameter_count() - 1; i >= 0; i--) { | 169 for (intptr_t i = previous->fixed_parameter_count() - 1; i >= 0; i--) { |
| 163 builder->AddCopy(previous->ValueAt(i), previous->LocationAt(i), slot_ix++); | 170 builder->AddCopy(previous->ValueAt(i), previous->LocationAt(i), slot_ix++); |
| 164 } | 171 } |
| 165 | 172 |
| 166 return builder->CreateDeoptInfo(deopt_table); | 173 return builder->CreateDeoptInfo(deopt_table); |
| 167 } | 174 } |
| 168 | 175 |
| 169 | 176 |
| 170 void CompilerDeoptInfoWithStub::GenerateCode(FlowGraphCompiler* compiler, | 177 void CompilerDeoptInfoWithStub::GenerateCode(FlowGraphCompiler* compiler, |
| 171 intptr_t stub_ix) { | 178 intptr_t stub_ix) { |
| 172 // Calls do not need stubs, they share a deoptimization trampoline. | 179 // Calls do not need stubs, they share a deoptimization trampoline. |
| 173 ASSERT(reason() != ICData::kDeoptAtCall); | 180 ASSERT(reason() != ICData::kDeoptAtCall); |
| 174 Assembler* assem = compiler->assembler(); | 181 Assembler* assem = compiler->assembler(); |
| 175 #define __ assem-> | 182 #define __ assem-> |
| 176 __ Comment("%s", Name()); | 183 __ Comment("%s", Name()); |
| 177 __ Bind(entry_label()); | 184 __ Bind(entry_label()); |
| 178 if (FLAG_trap_on_deoptimization) { | 185 if (FLAG_trap_on_deoptimization) { |
| 179 __ break_(0); | 186 __ break_(0); |
| 180 } | 187 } |
| 181 | 188 |
| 182 ASSERT(deopt_env() != NULL); | 189 ASSERT(deopt_env() != NULL); |
| 183 __ Push(CODE_REG); | 190 |
| 184 __ BranchLink(*StubCode::Deoptimize_entry()); | 191 __ BranchLink(*StubCode::Deoptimize_entry()); |
| 185 set_pc_offset(assem->CodeSize()); | 192 set_pc_offset(assem->CodeSize()); |
| 186 #undef __ | 193 #undef __ |
| 187 } | 194 } |
| 188 | 195 |
| 189 | 196 |
| 190 #define __ assembler()-> | 197 #define __ assembler()-> |
| 191 | 198 |
| 192 | 199 |
| 193 // Fall through if bool_register contains null. | 200 // Fall through if bool_register contains null. |
| (...skipping 720 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 914 if (check_correct_named_args) { | 921 if (check_correct_named_args) { |
| 915 __ lw(T1, FieldAddress(S4, ArgumentsDescriptor::count_offset())); | 922 __ lw(T1, FieldAddress(S4, ArgumentsDescriptor::count_offset())); |
| 916 __ SmiUntag(T1); | 923 __ SmiUntag(T1); |
| 917 // Check that T2 equals T1, i.e. no named arguments passed. | 924 // Check that T2 equals T1, i.e. no named arguments passed. |
| 918 __ beq(T2, T1, &all_arguments_processed); | 925 __ beq(T2, T1, &all_arguments_processed); |
| 919 } | 926 } |
| 920 } | 927 } |
| 921 | 928 |
| 922 __ Bind(&wrong_num_arguments); | 929 __ Bind(&wrong_num_arguments); |
| 923 if (function.IsClosureFunction()) { | 930 if (function.IsClosureFunction()) { |
| 924 __ LeaveDartFrame(kKeepCalleePP); // Arguments are still on the stack. | 931 __ LeaveDartFrame(); // The arguments are still on the stack. |
| 925 __ Branch(*StubCode::CallClosureNoSuchMethod_entry()); | 932 __ Branch(*StubCode::CallClosureNoSuchMethod_entry()); |
| 926 // The noSuchMethod call may return to the caller, but not here. | 933 // The noSuchMethod call may return to the caller, but not here. |
| 927 } else if (check_correct_named_args) { | 934 } else if (check_correct_named_args) { |
| 928 __ Stop("Wrong arguments"); | 935 __ Stop("Wrong arguments"); |
| 929 } | 936 } |
| 930 | 937 |
| 931 __ Bind(&all_arguments_processed); | 938 __ Bind(&all_arguments_processed); |
| 932 // Nullify originally passed arguments only after they have been copied and | 939 // Nullify originally passed arguments only after they have been copied and |
| 933 // checked, otherwise noSuchMethod would not see their original values. | 940 // checked, otherwise noSuchMethod would not see their original values. |
| 934 // This step can be skipped in case we decide that formal parameters are | 941 // This step can be skipped in case we decide that formal parameters are |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 972 // Sequence node has one store node and one return NULL node. | 979 // Sequence node has one store node and one return NULL node. |
| 973 __ Comment("Inlined Setter"); | 980 __ Comment("Inlined Setter"); |
| 974 __ lw(T0, Address(SP, 1 * kWordSize)); // Receiver. | 981 __ lw(T0, Address(SP, 1 * kWordSize)); // Receiver. |
| 975 __ lw(T1, Address(SP, 0 * kWordSize)); // Value. | 982 __ lw(T1, Address(SP, 0 * kWordSize)); // Value. |
| 976 __ StoreIntoObjectOffset(T0, offset, T1); | 983 __ StoreIntoObjectOffset(T0, offset, T1); |
| 977 __ LoadObject(V0, Object::null_object()); | 984 __ LoadObject(V0, Object::null_object()); |
| 978 __ Ret(); | 985 __ Ret(); |
| 979 } | 986 } |
| 980 | 987 |
| 981 | 988 |
| 982 static const Register new_pp = T7; | |
| 983 | |
| 984 | |
| 985 void FlowGraphCompiler::EmitFrameEntry() { | 989 void FlowGraphCompiler::EmitFrameEntry() { |
| 986 const Function& function = parsed_function().function(); | 990 const Function& function = parsed_function().function(); |
| 987 if (CanOptimizeFunction() && | 991 if (CanOptimizeFunction() && |
| 988 function.IsOptimizable() && | 992 function.IsOptimizable() && |
| 989 (!is_optimizing() || may_reoptimize())) { | 993 (!is_optimizing() || may_reoptimize())) { |
| 990 const Register function_reg = T0; | 994 const Register function_reg = T0; |
| 991 | 995 |
| 996 __ GetNextPC(T2, TMP); |
| 997 |
| 998 // Calculate offset of pool pointer from the PC. |
| 999 const intptr_t object_pool_pc_dist = |
| 1000 Instructions::HeaderSize() - Instructions::object_pool_offset() + |
| 1001 assembler()->CodeSize() - 1 * Instr::kInstrSize; |
| 1002 |
| 1003 // Preserve PP of caller. |
| 1004 __ mov(T1, PP); |
| 992 // Temporarily setup pool pointer for this dart function. | 1005 // Temporarily setup pool pointer for this dart function. |
| 993 __ LoadPoolPointer(new_pp); | 1006 __ lw(PP, Address(T2, -object_pool_pc_dist)); |
| 994 // Load function object from object pool. | 1007 // Load function object from object pool. |
| 995 __ LoadFunctionFromCalleePool(function_reg, function, new_pp); | 1008 __ LoadObject(function_reg, function); // Uses PP. |
| 1009 // Restore PP of caller. |
| 1010 __ mov(PP, T1); |
| 1011 |
| 1012 // Patch point is after the eventually inlined function object. |
| 1013 entry_patch_pc_offset_ = assembler()->CodeSize(); |
| 996 | 1014 |
| 997 __ lw(T1, FieldAddress(function_reg, Function::usage_counter_offset())); | 1015 __ lw(T1, FieldAddress(function_reg, Function::usage_counter_offset())); |
| 998 // Reoptimization of an optimized function is triggered by counting in | 1016 // Reoptimization of an optimized function is triggered by counting in |
| 999 // IC stubs, but not at the entry of the function. | 1017 // IC stubs, but not at the entry of the function. |
| 1000 if (!is_optimizing()) { | 1018 if (!is_optimizing()) { |
| 1001 __ addiu(T1, T1, Immediate(1)); | 1019 __ addiu(T1, T1, Immediate(1)); |
| 1002 __ sw(T1, FieldAddress(function_reg, Function::usage_counter_offset())); | 1020 __ sw(T1, FieldAddress(function_reg, Function::usage_counter_offset())); |
| 1003 } | 1021 } |
| 1004 | 1022 |
| 1005 // Skip Branch if T1 is less than the threshold. | 1023 // Skip Branch if T1 is less than the threshold. |
| 1006 Label dont_branch; | 1024 Label dont_branch; |
| 1007 __ BranchSignedLess( | 1025 __ BranchSignedLess( |
| 1008 T1, Immediate(GetOptimizationThreshold()), &dont_branch); | 1026 T1, Immediate(GetOptimizationThreshold()), &dont_branch); |
| 1009 | 1027 |
| 1010 ASSERT(function_reg == T0); | 1028 ASSERT(function_reg == T0); |
| 1011 __ Branch(*StubCode::OptimizeFunction_entry(), new_pp); | 1029 __ Branch(*StubCode::OptimizeFunction_entry()); |
| 1012 | 1030 |
| 1013 __ Bind(&dont_branch); | 1031 __ Bind(&dont_branch); |
| 1032 |
| 1033 } else if (!flow_graph().IsCompiledForOsr()) { |
| 1034 entry_patch_pc_offset_ = assembler()->CodeSize(); |
| 1014 } | 1035 } |
| 1015 __ Comment("Enter frame"); | 1036 __ Comment("Enter frame"); |
| 1016 if (flow_graph().IsCompiledForOsr()) { | 1037 if (flow_graph().IsCompiledForOsr()) { |
| 1017 intptr_t extra_slots = StackSize() | 1038 intptr_t extra_slots = StackSize() |
| 1018 - flow_graph().num_stack_locals() | 1039 - flow_graph().num_stack_locals() |
| 1019 - flow_graph().num_copied_params(); | 1040 - flow_graph().num_copied_params(); |
| 1020 ASSERT(extra_slots >= 0); | 1041 ASSERT(extra_slots >= 0); |
| 1021 __ EnterOsrFrame(extra_slots * kWordSize); | 1042 __ EnterOsrFrame(extra_slots * kWordSize); |
| 1022 } else { | 1043 } else { |
| 1023 ASSERT(StackSize() >= 0); | 1044 ASSERT(StackSize() >= 0); |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1064 Label correct_num_arguments, wrong_num_arguments; | 1085 Label correct_num_arguments, wrong_num_arguments; |
| 1065 __ lw(T0, FieldAddress(S4, ArgumentsDescriptor::count_offset())); | 1086 __ lw(T0, FieldAddress(S4, ArgumentsDescriptor::count_offset())); |
| 1066 __ BranchNotEqual(T0, Immediate(Smi::RawValue(num_fixed_params)), | 1087 __ BranchNotEqual(T0, Immediate(Smi::RawValue(num_fixed_params)), |
| 1067 &wrong_num_arguments); | 1088 &wrong_num_arguments); |
| 1068 | 1089 |
| 1069 __ lw(T1, FieldAddress(S4, | 1090 __ lw(T1, FieldAddress(S4, |
| 1070 ArgumentsDescriptor::positional_count_offset())); | 1091 ArgumentsDescriptor::positional_count_offset())); |
| 1071 __ beq(T0, T1, &correct_num_arguments); | 1092 __ beq(T0, T1, &correct_num_arguments); |
| 1072 __ Bind(&wrong_num_arguments); | 1093 __ Bind(&wrong_num_arguments); |
| 1073 if (function.IsClosureFunction()) { | 1094 if (function.IsClosureFunction()) { |
| 1074 __ LeaveDartFrame(kKeepCalleePP); // Arguments are still on the stack. | 1095 __ LeaveDartFrame(); // The arguments are still on the stack. |
| 1075 __ Branch(*StubCode::CallClosureNoSuchMethod_entry()); | 1096 __ Branch(*StubCode::CallClosureNoSuchMethod_entry()); |
| 1076 // The noSuchMethod call may return to the caller, but not here. | 1097 // The noSuchMethod call may return to the caller, but not here. |
| 1077 } else { | 1098 } else { |
| 1078 __ Stop("Wrong number of arguments"); | 1099 __ Stop("Wrong number of arguments"); |
| 1079 } | 1100 } |
| 1080 __ Bind(&correct_num_arguments); | 1101 __ Bind(&correct_num_arguments); |
| 1081 } | 1102 } |
| 1082 } else if (!flow_graph().IsCompiledForOsr()) { | 1103 } else if (!flow_graph().IsCompiledForOsr()) { |
| 1083 CopyParameters(); | 1104 CopyParameters(); |
| 1084 } | 1105 } |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1117 ASSERT(num_locals > 1); | 1138 ASSERT(num_locals > 1); |
| 1118 __ sw(V0, Address(FP, (slot_base - i) * kWordSize)); | 1139 __ sw(V0, Address(FP, (slot_base - i) * kWordSize)); |
| 1119 } | 1140 } |
| 1120 } | 1141 } |
| 1121 } | 1142 } |
| 1122 | 1143 |
| 1123 VisitBlocks(); | 1144 VisitBlocks(); |
| 1124 | 1145 |
| 1125 __ break_(0); | 1146 __ break_(0); |
| 1126 GenerateDeferredCode(); | 1147 GenerateDeferredCode(); |
| 1148 // Emit function patching code. This will be swapped with the first 5 bytes |
| 1149 // at entry point. |
| 1150 patch_code_pc_offset_ = assembler()->CodeSize(); |
| 1151 __ BranchPatchable(*StubCode::FixCallersTarget_entry()); |
| 1127 | 1152 |
| 1128 if (is_optimizing()) { | 1153 if (is_optimizing()) { |
| 1129 lazy_deopt_pc_offset_ = assembler()->CodeSize(); | 1154 lazy_deopt_pc_offset_ = assembler()->CodeSize(); |
| 1130 __ Branch(*StubCode::DeoptimizeLazy_entry()); | 1155 __ Branch(*StubCode::DeoptimizeLazy_entry()); |
| 1131 } | 1156 } |
| 1132 } | 1157 } |
| 1133 | 1158 |
| 1134 | 1159 |
| 1135 void FlowGraphCompiler::GenerateCall(intptr_t token_pos, | 1160 void FlowGraphCompiler::GenerateCall(intptr_t token_pos, |
| 1136 const StubEntry& stub_entry, | 1161 const StubEntry& stub_entry, |
| (...skipping 696 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1833 __ AddImmediate(SP, kDoubleSize); | 1858 __ AddImmediate(SP, kDoubleSize); |
| 1834 } | 1859 } |
| 1835 | 1860 |
| 1836 | 1861 |
| 1837 #undef __ | 1862 #undef __ |
| 1838 | 1863 |
| 1839 | 1864 |
| 1840 } // namespace dart | 1865 } // namespace dart |
| 1841 | 1866 |
| 1842 #endif // defined TARGET_ARCH_MIPS | 1867 #endif // defined TARGET_ARCH_MIPS |
| OLD | NEW |