| 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" | 5 #include "vm/globals.h" |
| 6 #if defined(TARGET_ARCH_MIPS) | 6 #if defined(TARGET_ARCH_MIPS) |
| 7 | 7 |
| 8 #include "vm/assembler.h" | 8 #include "vm/assembler.h" |
| 9 #include "vm/code_generator.h" | 9 #include "vm/code_generator.h" |
| 10 #include "vm/compiler.h" | 10 #include "vm/compiler.h" |
| (...skipping 23 matching lines...) Expand all Loading... |
| 34 // SP : address of last argument in argument array. | 34 // SP : address of last argument in argument array. |
| 35 // SP + 4*S4 - 4 : address of first argument in argument array. | 35 // SP + 4*S4 - 4 : address of first argument in argument array. |
| 36 // SP + 4*S4 : address of return value. | 36 // SP + 4*S4 : address of return value. |
| 37 // S5 : address of the runtime function to call. | 37 // S5 : address of the runtime function to call. |
| 38 // S4 : number of arguments to the call. | 38 // S4 : number of arguments to the call. |
| 39 void StubCode::GenerateCallToRuntimeStub(Assembler* assembler) { | 39 void StubCode::GenerateCallToRuntimeStub(Assembler* assembler) { |
| 40 const intptr_t thread_offset = NativeArguments::thread_offset(); | 40 const intptr_t thread_offset = NativeArguments::thread_offset(); |
| 41 const intptr_t argc_tag_offset = NativeArguments::argc_tag_offset(); | 41 const intptr_t argc_tag_offset = NativeArguments::argc_tag_offset(); |
| 42 const intptr_t argv_offset = NativeArguments::argv_offset(); | 42 const intptr_t argv_offset = NativeArguments::argv_offset(); |
| 43 const intptr_t retval_offset = NativeArguments::retval_offset(); | 43 const intptr_t retval_offset = NativeArguments::retval_offset(); |
| 44 const intptr_t exitframe_last_param_slot_from_fp = 2; |
| 44 | 45 |
| 45 __ SetPrologueOffset(); | 46 __ SetPrologueOffset(); |
| 46 __ Comment("CallToRuntimeStub"); | 47 __ Comment("CallToRuntimeStub"); |
| 47 __ EnterStubFrame(); | 48 __ EnterStubFrame(); |
| 48 | 49 |
| 49 COMPILE_ASSERT((kAbiPreservedCpuRegs & (1 << S2)) != 0); | 50 COMPILE_ASSERT((kAbiPreservedCpuRegs & (1 << S6)) != 0); |
| 50 __ LoadIsolate(S2); | 51 __ LoadIsolate(S6); |
| 51 | 52 |
| 52 // Save exit frame information to enable stack walking as we are about | 53 // Save exit frame information to enable stack walking as we are about |
| 53 // to transition to Dart VM C++ code. | 54 // to transition to Dart VM C++ code. |
| 54 __ sw(FP, Address(THR, Thread::top_exit_frame_info_offset())); | 55 __ sw(FP, Address(THR, Thread::top_exit_frame_info_offset())); |
| 55 | 56 |
| 56 #if defined(DEBUG) | 57 #if defined(DEBUG) |
| 57 { Label ok; | 58 { Label ok; |
| 58 // Check that we are always entering from Dart code. | 59 // Check that we are always entering from Dart code. |
| 59 __ lw(T0, Address(S2, Isolate::vm_tag_offset())); | 60 __ lw(T0, Address(S6, Isolate::vm_tag_offset())); |
| 60 __ BranchEqual(T0, Immediate(VMTag::kDartTagId), &ok); | 61 __ BranchEqual(T0, Immediate(VMTag::kDartTagId), &ok); |
| 61 __ Stop("Not coming from Dart code."); | 62 __ Stop("Not coming from Dart code."); |
| 62 __ Bind(&ok); | 63 __ Bind(&ok); |
| 63 } | 64 } |
| 64 #endif | 65 #endif |
| 65 | 66 |
| 66 // Mark that the isolate is executing VM code. | 67 // Mark that the isolate is executing VM code. |
| 67 __ sw(S5, Address(S2, Isolate::vm_tag_offset())); | 68 __ sw(S5, Address(S6, Isolate::vm_tag_offset())); |
| 68 | 69 |
| 69 // Reserve space for arguments and align frame before entering C++ world. | 70 // Reserve space for arguments and align frame before entering C++ world. |
| 70 // NativeArguments are passed in registers. | 71 // NativeArguments are passed in registers. |
| 71 ASSERT(sizeof(NativeArguments) == 4 * kWordSize); | 72 ASSERT(sizeof(NativeArguments) == 4 * kWordSize); |
| 72 __ ReserveAlignedFrameSpace(4 * kWordSize); // Reserve space for arguments. | 73 __ ReserveAlignedFrameSpace(4 * kWordSize); // Reserve space for arguments. |
| 73 | 74 |
| 74 // Pass NativeArguments structure by value and call runtime. | 75 // Pass NativeArguments structure by value and call runtime. |
| 75 // Registers A0, A1, A2, and A3 are used. | 76 // Registers A0, A1, A2, and A3 are used. |
| 76 | 77 |
| 77 ASSERT(thread_offset == 0 * kWordSize); | 78 ASSERT(thread_offset == 0 * kWordSize); |
| 78 // Set thread in NativeArgs. | 79 // Set thread in NativeArgs. |
| 79 __ mov(A0, THR); | 80 __ mov(A0, THR); |
| 80 | 81 |
| 81 // There are no runtime calls to closures, so we do not need to set the tag | 82 // There are no runtime calls to closures, so we do not need to set the tag |
| 82 // bits kClosureFunctionBit and kInstanceFunctionBit in argc_tag_. | 83 // bits kClosureFunctionBit and kInstanceFunctionBit in argc_tag_. |
| 83 ASSERT(argc_tag_offset == 1 * kWordSize); | 84 ASSERT(argc_tag_offset == 1 * kWordSize); |
| 84 __ mov(A1, S4); // Set argc in NativeArguments. | 85 __ mov(A1, S4); // Set argc in NativeArguments. |
| 85 | 86 |
| 86 ASSERT(argv_offset == 2 * kWordSize); | 87 ASSERT(argv_offset == 2 * kWordSize); |
| 87 __ sll(A2, S4, 2); | 88 __ sll(A2, S4, 2); |
| 88 __ addu(A2, FP, A2); // Compute argv. | 89 __ addu(A2, FP, A2); // Compute argv. |
| 89 // Set argv in NativeArguments. | 90 // Set argv in NativeArguments. |
| 90 __ addiu(A2, A2, Immediate(kParamEndSlotFromFp * kWordSize)); | 91 __ addiu(A2, A2, Immediate(exitframe_last_param_slot_from_fp * kWordSize)); |
| 91 | 92 |
| 92 | 93 |
| 93 // Call runtime or redirection via simulator. | 94 // Call runtime or redirection via simulator. |
| 94 // We defensively always jalr through T9 because it is sometimes required by | 95 // We defensively always jalr through T9 because it is sometimes required by |
| 95 // the MIPS ABI. | 96 // the MIPS ABI. |
| 96 __ mov(T9, S5); | 97 __ mov(T9, S5); |
| 97 __ jalr(T9); | 98 __ jalr(T9); |
| 98 | 99 |
| 99 ASSERT(retval_offset == 3 * kWordSize); | 100 ASSERT(retval_offset == 3 * kWordSize); |
| 100 // Retval is next to 1st argument. | 101 // Retval is next to 1st argument. |
| 101 __ delay_slot()->addiu(A3, A2, Immediate(kWordSize)); | 102 __ delay_slot()->addiu(A3, A2, Immediate(kWordSize)); |
| 102 __ Comment("CallToRuntimeStub return"); | 103 __ Comment("CallToRuntimeStub return"); |
| 103 | 104 |
| 104 // Mark that the isolate is executing Dart code. | 105 // Mark that the isolate is executing Dart code. |
| 105 __ LoadImmediate(A2, VMTag::kDartTagId); | 106 __ LoadImmediate(A2, VMTag::kDartTagId); |
| 106 __ sw(A2, Address(S2, Isolate::vm_tag_offset())); | 107 __ sw(A2, Address(S6, Isolate::vm_tag_offset())); |
| 107 | 108 |
| 108 // Reset exit frame information in Isolate structure. | 109 // Reset exit frame information in Isolate structure. |
| 109 __ sw(ZR, Address(THR, Thread::top_exit_frame_info_offset())); | 110 __ sw(ZR, Address(THR, Thread::top_exit_frame_info_offset())); |
| 110 | 111 |
| 111 __ LeaveStubFrameAndReturn(); | 112 __ LeaveStubFrameAndReturn(); |
| 112 } | 113 } |
| 113 | 114 |
| 114 | 115 |
| 115 // Print the stop message. | 116 // Print the stop message. |
| 116 DEFINE_LEAF_RUNTIME_ENTRY(void, PrintStopMessage, 1, const char* message) { | 117 DEFINE_LEAF_RUNTIME_ENTRY(void, PrintStopMessage, 1, const char* message) { |
| (...skipping 23 matching lines...) Expand all Loading... |
| 140 void StubCode::GenerateCallNativeCFunctionStub(Assembler* assembler) { | 141 void StubCode::GenerateCallNativeCFunctionStub(Assembler* assembler) { |
| 141 const intptr_t thread_offset = NativeArguments::thread_offset(); | 142 const intptr_t thread_offset = NativeArguments::thread_offset(); |
| 142 const intptr_t argc_tag_offset = NativeArguments::argc_tag_offset(); | 143 const intptr_t argc_tag_offset = NativeArguments::argc_tag_offset(); |
| 143 const intptr_t argv_offset = NativeArguments::argv_offset(); | 144 const intptr_t argv_offset = NativeArguments::argv_offset(); |
| 144 const intptr_t retval_offset = NativeArguments::retval_offset(); | 145 const intptr_t retval_offset = NativeArguments::retval_offset(); |
| 145 | 146 |
| 146 __ SetPrologueOffset(); | 147 __ SetPrologueOffset(); |
| 147 __ Comment("CallNativeCFunctionStub"); | 148 __ Comment("CallNativeCFunctionStub"); |
| 148 __ EnterStubFrame(); | 149 __ EnterStubFrame(); |
| 149 | 150 |
| 150 COMPILE_ASSERT((kAbiPreservedCpuRegs & (1 << S2)) != 0); | 151 COMPILE_ASSERT((kAbiPreservedCpuRegs & (1 << S6)) != 0); |
| 151 __ LoadIsolate(S2); | 152 __ LoadIsolate(S6); |
| 152 | 153 |
| 153 // Save exit frame information to enable stack walking as we are about | 154 // Save exit frame information to enable stack walking as we are about |
| 154 // to transition to native code. | 155 // to transition to native code. |
| 155 __ sw(FP, Address(THR, Thread::top_exit_frame_info_offset())); | 156 __ sw(FP, Address(THR, Thread::top_exit_frame_info_offset())); |
| 156 | 157 |
| 157 #if defined(DEBUG) | 158 #if defined(DEBUG) |
| 158 { Label ok; | 159 { Label ok; |
| 159 // Check that we are always entering from Dart code. | 160 // Check that we are always entering from Dart code. |
| 160 __ lw(T0, Address(S2, Isolate::vm_tag_offset())); | 161 __ lw(T0, Address(S6, Isolate::vm_tag_offset())); |
| 161 __ BranchEqual(T0, Immediate(VMTag::kDartTagId), &ok); | 162 __ BranchEqual(T0, Immediate(VMTag::kDartTagId), &ok); |
| 162 __ Stop("Not coming from Dart code."); | 163 __ Stop("Not coming from Dart code."); |
| 163 __ Bind(&ok); | 164 __ Bind(&ok); |
| 164 } | 165 } |
| 165 #endif | 166 #endif |
| 166 | 167 |
| 167 // Mark that the isolate is executing Native code. | 168 // Mark that the isolate is executing Native code. |
| 168 __ sw(T5, Address(S2, Isolate::vm_tag_offset())); | 169 __ sw(T5, Address(S6, Isolate::vm_tag_offset())); |
| 169 | 170 |
| 170 // Initialize NativeArguments structure and call native function. | 171 // Initialize NativeArguments structure and call native function. |
| 171 // Registers A0, A1, A2, and A3 are used. | 172 // Registers A0, A1, A2, and A3 are used. |
| 172 | 173 |
| 173 ASSERT(thread_offset == 0 * kWordSize); | 174 ASSERT(thread_offset == 0 * kWordSize); |
| 174 // Set thread in NativeArgs. | 175 // Set thread in NativeArgs. |
| 175 __ mov(A0, THR); | 176 __ mov(A0, THR); |
| 176 | 177 |
| 177 // There are no native calls to closures, so we do not need to set the tag | 178 // There are no native calls to closures, so we do not need to set the tag |
| 178 // bits kClosureFunctionBit and kInstanceFunctionBit in argc_tag_. | 179 // bits kClosureFunctionBit and kInstanceFunctionBit in argc_tag_. |
| 179 ASSERT(argc_tag_offset == 1 * kWordSize); | 180 ASSERT(argc_tag_offset == 1 * kWordSize); |
| 180 // Set argc in NativeArguments: A1 already contains argc. | 181 // Set argc in NativeArguments: A1 already contains argc. |
| 181 | 182 |
| 182 ASSERT(argv_offset == 2 * kWordSize); | 183 ASSERT(argv_offset == 2 * kWordSize); |
| 183 // Set argv in NativeArguments: A2 already contains argv. | 184 // Set argv in NativeArguments: A2 already contains argv. |
| 184 | 185 |
| 185 ASSERT(retval_offset == 3 * kWordSize); | 186 ASSERT(retval_offset == 3 * kWordSize); |
| 186 // Set retval in NativeArgs. | 187 __ addiu(A3, FP, Immediate(3 * kWordSize)); // Set retval in NativeArgs. |
| 187 __ addiu(A3, FP, Immediate(kCallerSpSlotFromFp * kWordSize)); | |
| 188 | 188 |
| 189 // Passing the structure by value as in runtime calls would require changing | 189 // Passing the structure by value as in runtime calls would require changing |
| 190 // Dart API for native functions. | 190 // Dart API for native functions. |
| 191 // For now, space is reserved on the stack and we pass a pointer to it. | 191 // For now, space is reserved on the stack and we pass a pointer to it. |
| 192 __ addiu(SP, SP, Immediate(-4 * kWordSize)); | 192 __ addiu(SP, SP, Immediate(-4 * kWordSize)); |
| 193 __ sw(A3, Address(SP, 3 * kWordSize)); | 193 __ sw(A3, Address(SP, 3 * kWordSize)); |
| 194 __ sw(A2, Address(SP, 2 * kWordSize)); | 194 __ sw(A2, Address(SP, 2 * kWordSize)); |
| 195 __ sw(A1, Address(SP, 1 * kWordSize)); | 195 __ sw(A1, Address(SP, 1 * kWordSize)); |
| 196 __ sw(A0, Address(SP, 0 * kWordSize)); | 196 __ sw(A0, Address(SP, 0 * kWordSize)); |
| 197 __ mov(A0, SP); // Pass the pointer to the NativeArguments. | 197 __ mov(A0, SP); // Pass the pointer to the NativeArguments. |
| 198 | 198 |
| 199 | 199 |
| 200 __ mov(A1, T5); // Pass the function entrypoint. | 200 __ mov(A1, T5); // Pass the function entrypoint. |
| 201 __ ReserveAlignedFrameSpace(2 * kWordSize); // Just passing A0, A1. | 201 __ ReserveAlignedFrameSpace(2 * kWordSize); // Just passing A0, A1. |
| 202 // Call native wrapper function or redirection via simulator. | 202 // Call native wrapper function or redirection via simulator. |
| 203 #if defined(USING_SIMULATOR) | 203 #if defined(USING_SIMULATOR) |
| 204 uword entry = reinterpret_cast<uword>(NativeEntry::NativeCallWrapper); | 204 uword entry = reinterpret_cast<uword>(NativeEntry::NativeCallWrapper); |
| 205 entry = Simulator::RedirectExternalReference( | 205 entry = Simulator::RedirectExternalReference( |
| 206 entry, Simulator::kNativeCall, NativeEntry::kNumCallWrapperArguments); | 206 entry, Simulator::kNativeCall, NativeEntry::kNumCallWrapperArguments); |
| 207 __ LoadImmediate(T9, entry); | 207 __ LoadImmediate(T9, entry); |
| 208 __ jalr(T9); | 208 __ jalr(T9); |
| 209 #else | 209 #else |
| 210 __ BranchLink(&NativeEntry::NativeCallWrapperLabel(), kNotPatchable); | 210 __ BranchLink(&NativeEntry::NativeCallWrapperLabel(), kNotPatchable); |
| 211 #endif | 211 #endif |
| 212 __ Comment("CallNativeCFunctionStub return"); | 212 __ Comment("CallNativeCFunctionStub return"); |
| 213 | 213 |
| 214 // Mark that the isolate is executing Dart code. | 214 // Mark that the isolate is executing Dart code. |
| 215 __ LoadImmediate(A2, VMTag::kDartTagId); | 215 __ LoadImmediate(A2, VMTag::kDartTagId); |
| 216 __ sw(A2, Address(S2, Isolate::vm_tag_offset())); | 216 __ sw(A2, Address(S6, Isolate::vm_tag_offset())); |
| 217 | 217 |
| 218 // Reset exit frame information in Isolate structure. | 218 // Reset exit frame information in Isolate structure. |
| 219 __ sw(ZR, Address(THR, Thread::top_exit_frame_info_offset())); | 219 __ sw(ZR, Address(THR, Thread::top_exit_frame_info_offset())); |
| 220 | 220 |
| 221 __ LeaveStubFrameAndReturn(); | 221 __ LeaveStubFrameAndReturn(); |
| 222 } | 222 } |
| 223 | 223 |
| 224 | 224 |
| 225 // Input parameters: | 225 // Input parameters: |
| 226 // RA : return address. | 226 // RA : return address. |
| 227 // SP : address of return value. | 227 // SP : address of return value. |
| 228 // T5 : address of the native function to call. | 228 // T5 : address of the native function to call. |
| 229 // A2 : address of first argument in argument array. | 229 // A2 : address of first argument in argument array. |
| 230 // A1 : argc_tag including number of arguments and function kind. | 230 // A1 : argc_tag including number of arguments and function kind. |
| 231 void StubCode::GenerateCallBootstrapCFunctionStub(Assembler* assembler) { | 231 void StubCode::GenerateCallBootstrapCFunctionStub(Assembler* assembler) { |
| 232 const intptr_t thread_offset = NativeArguments::thread_offset(); | 232 const intptr_t thread_offset = NativeArguments::thread_offset(); |
| 233 const intptr_t argc_tag_offset = NativeArguments::argc_tag_offset(); | 233 const intptr_t argc_tag_offset = NativeArguments::argc_tag_offset(); |
| 234 const intptr_t argv_offset = NativeArguments::argv_offset(); | 234 const intptr_t argv_offset = NativeArguments::argv_offset(); |
| 235 const intptr_t retval_offset = NativeArguments::retval_offset(); | 235 const intptr_t retval_offset = NativeArguments::retval_offset(); |
| 236 | 236 |
| 237 __ SetPrologueOffset(); | 237 __ SetPrologueOffset(); |
| 238 __ Comment("CallNativeCFunctionStub"); | 238 __ Comment("CallNativeCFunctionStub"); |
| 239 __ EnterStubFrame(); | 239 __ EnterStubFrame(); |
| 240 | 240 |
| 241 COMPILE_ASSERT((kAbiPreservedCpuRegs & (1 << S2)) != 0); | 241 COMPILE_ASSERT((kAbiPreservedCpuRegs & (1 << S6)) != 0); |
| 242 __ LoadIsolate(S2); | 242 __ LoadIsolate(S6); |
| 243 | 243 |
| 244 // Save exit frame information to enable stack walking as we are about | 244 // Save exit frame information to enable stack walking as we are about |
| 245 // to transition to native code. | 245 // to transition to native code. |
| 246 __ sw(FP, Address(THR, Thread::top_exit_frame_info_offset())); | 246 __ sw(FP, Address(THR, Thread::top_exit_frame_info_offset())); |
| 247 | 247 |
| 248 #if defined(DEBUG) | 248 #if defined(DEBUG) |
| 249 { Label ok; | 249 { Label ok; |
| 250 // Check that we are always entering from Dart code. | 250 // Check that we are always entering from Dart code. |
| 251 __ lw(T0, Address(S2, Isolate::vm_tag_offset())); | 251 __ lw(T0, Address(S6, Isolate::vm_tag_offset())); |
| 252 __ BranchEqual(T0, Immediate(VMTag::kDartTagId), &ok); | 252 __ BranchEqual(T0, Immediate(VMTag::kDartTagId), &ok); |
| 253 __ Stop("Not coming from Dart code."); | 253 __ Stop("Not coming from Dart code."); |
| 254 __ Bind(&ok); | 254 __ Bind(&ok); |
| 255 } | 255 } |
| 256 #endif | 256 #endif |
| 257 | 257 |
| 258 // Mark that the isolate is executing Native code. | 258 // Mark that the isolate is executing Native code. |
| 259 __ sw(T5, Address(S2, Isolate::vm_tag_offset())); | 259 __ sw(T5, Address(S6, Isolate::vm_tag_offset())); |
| 260 | 260 |
| 261 // Initialize NativeArguments structure and call native function. | 261 // Initialize NativeArguments structure and call native function. |
| 262 // Registers A0, A1, A2, and A3 are used. | 262 // Registers A0, A1, A2, and A3 are used. |
| 263 | 263 |
| 264 ASSERT(thread_offset == 0 * kWordSize); | 264 ASSERT(thread_offset == 0 * kWordSize); |
| 265 // Set thread in NativeArgs. | 265 // Set thread in NativeArgs. |
| 266 __ mov(A0, THR); | 266 __ mov(A0, THR); |
| 267 | 267 |
| 268 // There are no native calls to closures, so we do not need to set the tag | 268 // There are no native calls to closures, so we do not need to set the tag |
| 269 // bits kClosureFunctionBit and kInstanceFunctionBit in argc_tag_. | 269 // bits kClosureFunctionBit and kInstanceFunctionBit in argc_tag_. |
| 270 ASSERT(argc_tag_offset == 1 * kWordSize); | 270 ASSERT(argc_tag_offset == 1 * kWordSize); |
| 271 // Set argc in NativeArguments: A1 already contains argc. | 271 // Set argc in NativeArguments: A1 already contains argc. |
| 272 | 272 |
| 273 ASSERT(argv_offset == 2 * kWordSize); | 273 ASSERT(argv_offset == 2 * kWordSize); |
| 274 // Set argv in NativeArguments: A2 already contains argv. | 274 // Set argv in NativeArguments: A2 already contains argv. |
| 275 | 275 |
| 276 ASSERT(retval_offset == 3 * kWordSize); | 276 ASSERT(retval_offset == 3 * kWordSize); |
| 277 // Set retval in NativeArgs. | 277 __ addiu(A3, FP, Immediate(3 * kWordSize)); // Set retval in NativeArgs. |
| 278 __ addiu(A3, FP, Immediate(kCallerSpSlotFromFp * kWordSize)); | |
| 279 | 278 |
| 280 // Passing the structure by value as in runtime calls would require changing | 279 // Passing the structure by value as in runtime calls would require changing |
| 281 // Dart API for native functions. | 280 // Dart API for native functions. |
| 282 // For now, space is reserved on the stack and we pass a pointer to it. | 281 // For now, space is reserved on the stack and we pass a pointer to it. |
| 283 __ addiu(SP, SP, Immediate(-4 * kWordSize)); | 282 __ addiu(SP, SP, Immediate(-4 * kWordSize)); |
| 284 __ sw(A3, Address(SP, 3 * kWordSize)); | 283 __ sw(A3, Address(SP, 3 * kWordSize)); |
| 285 __ sw(A2, Address(SP, 2 * kWordSize)); | 284 __ sw(A2, Address(SP, 2 * kWordSize)); |
| 286 __ sw(A1, Address(SP, 1 * kWordSize)); | 285 __ sw(A1, Address(SP, 1 * kWordSize)); |
| 287 __ sw(A0, Address(SP, 0 * kWordSize)); | 286 __ sw(A0, Address(SP, 0 * kWordSize)); |
| 288 __ mov(A0, SP); // Pass the pointer to the NativeArguments. | 287 __ mov(A0, SP); // Pass the pointer to the NativeArguments. |
| 289 | 288 |
| 290 __ ReserveAlignedFrameSpace(kWordSize); // Just passing A0. | 289 __ ReserveAlignedFrameSpace(kWordSize); // Just passing A0. |
| 291 | 290 |
| 292 // Call native function or redirection via simulator. | 291 // Call native function or redirection via simulator. |
| 293 | 292 |
| 294 // We defensively always jalr through T9 because it is sometimes required by | 293 // We defensively always jalr through T9 because it is sometimes required by |
| 295 // the MIPS ABI. | 294 // the MIPS ABI. |
| 296 __ mov(T9, T5); | 295 __ mov(T9, T5); |
| 297 __ jalr(T9); | 296 __ jalr(T9); |
| 298 __ Comment("CallNativeCFunctionStub return"); | 297 __ Comment("CallNativeCFunctionStub return"); |
| 299 | 298 |
| 300 // Mark that the isolate is executing Dart code. | 299 // Mark that the isolate is executing Dart code. |
| 301 __ LoadImmediate(A2, VMTag::kDartTagId); | 300 __ LoadImmediate(A2, VMTag::kDartTagId); |
| 302 __ sw(A2, Address(S2, Isolate::vm_tag_offset())); | 301 __ sw(A2, Address(S6, Isolate::vm_tag_offset())); |
| 303 | 302 |
| 304 // Reset exit frame information in Isolate structure. | 303 // Reset exit frame information in Isolate structure. |
| 305 __ sw(ZR, Address(THR, Thread::top_exit_frame_info_offset())); | 304 __ sw(ZR, Address(THR, Thread::top_exit_frame_info_offset())); |
| 306 | 305 |
| 307 __ LeaveStubFrameAndReturn(); | 306 __ LeaveStubFrameAndReturn(); |
| 308 } | 307 } |
| 309 | 308 |
| 310 | 309 |
| 311 // Input parameters: | 310 // Input parameters: |
| 312 // S4: arguments descriptor array. | 311 // S4: arguments descriptor array. |
| 313 void StubCode::GenerateCallStaticFunctionStub(Assembler* assembler) { | 312 void StubCode::GenerateCallStaticFunctionStub(Assembler* assembler) { |
| 314 __ Comment("CallStaticFunctionStub"); | 313 __ Comment("CallStaticFunctionStub"); |
| 315 __ EnterStubFrame(); | 314 __ EnterStubFrame(); |
| 316 // Setup space on stack for return value and preserve arguments descriptor. | 315 // Setup space on stack for return value and preserve arguments descriptor. |
| 317 | 316 |
| 318 __ addiu(SP, SP, Immediate(-2 * kWordSize)); | 317 __ addiu(SP, SP, Immediate(-2 * kWordSize)); |
| 319 __ sw(S4, Address(SP, 1 * kWordSize)); | 318 __ sw(S4, Address(SP, 1 * kWordSize)); |
| 320 __ LoadObject(TMP, Object::null_object()); | 319 __ LoadObject(TMP, Object::null_object()); |
| 321 __ sw(TMP, Address(SP, 0 * kWordSize)); | 320 __ sw(TMP, Address(SP, 0 * kWordSize)); |
| 322 | 321 |
| 323 __ CallRuntime(kPatchStaticCallRuntimeEntry, 0); | 322 __ CallRuntime(kPatchStaticCallRuntimeEntry, 0); |
| 324 __ Comment("CallStaticFunctionStub return"); | 323 __ Comment("CallStaticFunctionStub return"); |
| 325 | 324 |
| 326 // Get Code object result and restore arguments descriptor array. | 325 // Get Code object result and restore arguments descriptor array. |
| 327 __ lw(CODE_REG, Address(SP, 0 * kWordSize)); | 326 __ lw(T0, Address(SP, 0 * kWordSize)); |
| 328 __ lw(S4, Address(SP, 1 * kWordSize)); | 327 __ lw(S4, Address(SP, 1 * kWordSize)); |
| 329 __ addiu(SP, SP, Immediate(2 * kWordSize)); | 328 __ addiu(SP, SP, Immediate(2 * kWordSize)); |
| 330 | 329 |
| 331 __ lw(T0, FieldAddress(CODE_REG, Code::entry_point_offset())); | 330 __ lw(T0, FieldAddress(T0, Code::entry_point_offset())); |
| 332 | 331 |
| 333 // Remove the stub frame as we are about to jump to the dart function. | 332 // Remove the stub frame as we are about to jump to the dart function. |
| 334 __ LeaveStubFrameAndReturn(T0); | 333 __ LeaveStubFrameAndReturn(T0); |
| 335 } | 334 } |
| 336 | 335 |
| 337 | 336 |
| 338 // Called from a static call only when an invalid code has been entered | 337 // Called from a static call only when an invalid code has been entered |
| 339 // (invalid because its function was optimized or deoptimized). | 338 // (invalid because its function was optimized or deoptimized). |
| 340 // S4: arguments descriptor array. | 339 // S4: arguments descriptor array. |
| 341 void StubCode::GenerateFixCallersTargetStub(Assembler* assembler) { | 340 void StubCode::GenerateFixCallersTargetStub(Assembler* assembler) { |
| 342 // Load code pointer to this stub from the thread: | |
| 343 // The one that is passed in, is not correct - it points to the code object | |
| 344 // that needs to be replaced. | |
| 345 __ lw(CODE_REG, Address(THR, Thread::fix_callers_target_code_offset())); | |
| 346 // Create a stub frame as we are pushing some objects on the stack before | 341 // Create a stub frame as we are pushing some objects on the stack before |
| 347 // calling into the runtime. | 342 // calling into the runtime. |
| 343 __ Comment("FixCallersTarget"); |
| 348 __ EnterStubFrame(); | 344 __ EnterStubFrame(); |
| 349 // Setup space on stack for return value and preserve arguments descriptor. | 345 // Setup space on stack for return value and preserve arguments descriptor. |
| 350 __ addiu(SP, SP, Immediate(-2 * kWordSize)); | 346 __ addiu(SP, SP, Immediate(-2 * kWordSize)); |
| 351 __ sw(S4, Address(SP, 1 * kWordSize)); | 347 __ sw(S4, Address(SP, 1 * kWordSize)); |
| 352 __ LoadObject(TMP, Object::null_object()); | 348 __ LoadObject(TMP, Object::null_object()); |
| 353 __ sw(TMP, Address(SP, 0 * kWordSize)); | 349 __ sw(TMP, Address(SP, 0 * kWordSize)); |
| 354 __ CallRuntime(kFixCallersTargetRuntimeEntry, 0); | 350 __ CallRuntime(kFixCallersTargetRuntimeEntry, 0); |
| 355 // Get Code object result and restore arguments descriptor array. | 351 // Get Code object result and restore arguments descriptor array. |
| 356 __ lw(CODE_REG, Address(SP, 0 * kWordSize)); | 352 __ lw(T0, Address(SP, 0 * kWordSize)); |
| 357 __ lw(S4, Address(SP, 1 * kWordSize)); | 353 __ lw(S4, Address(SP, 1 * kWordSize)); |
| 358 __ addiu(SP, SP, Immediate(2 * kWordSize)); | 354 __ addiu(SP, SP, Immediate(2 * kWordSize)); |
| 359 | 355 |
| 360 // Jump to the dart function. | 356 // Jump to the dart function. |
| 361 __ lw(T0, FieldAddress(CODE_REG, Code::entry_point_offset())); | 357 __ lw(T0, FieldAddress(T0, Code::entry_point_offset())); |
| 362 | 358 |
| 363 // Remove the stub frame. | 359 // Remove the stub frame. |
| 364 __ LeaveStubFrameAndReturn(T0); | 360 __ LeaveStubFrameAndReturn(T0); |
| 365 } | 361 } |
| 366 | 362 |
| 367 | 363 |
| 368 // Called from object allocate instruction when the allocation stub has been | 364 // Called from object allocate instruction when the allocation stub has been |
| 369 // disabled. | 365 // disabled. |
| 370 void StubCode::GenerateFixAllocationStubTargetStub(Assembler* assembler) { | 366 void StubCode::GenerateFixAllocationStubTargetStub(Assembler* assembler) { |
| 371 // Load code pointer to this stub from the thread: | 367 __ Comment("FixAllocationStubTarget"); |
| 372 // The one that is passed in, is not correct - it points to the code object | |
| 373 // that needs to be replaced. | |
| 374 __ lw(CODE_REG, Address(THR, Thread::fix_allocation_stub_code_offset())); | |
| 375 __ EnterStubFrame(); | 368 __ EnterStubFrame(); |
| 376 // Setup space on stack for return value. | 369 // Setup space on stack for return value. |
| 377 __ addiu(SP, SP, Immediate(-1 * kWordSize)); | 370 __ addiu(SP, SP, Immediate(-1 * kWordSize)); |
| 378 __ LoadObject(TMP, Object::null_object()); | 371 __ LoadObject(TMP, Object::null_object()); |
| 379 __ sw(TMP, Address(SP, 0 * kWordSize)); | 372 __ sw(TMP, Address(SP, 0 * kWordSize)); |
| 380 __ CallRuntime(kFixAllocationStubTargetRuntimeEntry, 0); | 373 __ CallRuntime(kFixAllocationStubTargetRuntimeEntry, 0); |
| 381 // Get Code object result. | 374 // Get Code object result. |
| 382 __ lw(CODE_REG, Address(SP, 0 * kWordSize)); | 375 __ lw(T0, Address(SP, 0 * kWordSize)); |
| 383 __ addiu(SP, SP, Immediate(1 * kWordSize)); | 376 __ addiu(SP, SP, Immediate(1 * kWordSize)); |
| 384 | 377 |
| 385 // Jump to the dart function. | 378 // Jump to the dart function. |
| 386 __ lw(T0, FieldAddress(CODE_REG, Code::entry_point_offset())); | 379 __ lw(T0, FieldAddress(T0, Code::entry_point_offset())); |
| 387 | 380 |
| 388 // Remove the stub frame. | 381 // Remove the stub frame. |
| 389 __ LeaveStubFrameAndReturn(T0); | 382 __ LeaveStubFrameAndReturn(T0); |
| 390 } | 383 } |
| 391 | 384 |
| 392 | 385 |
| 393 // Input parameters: | 386 // Input parameters: |
| 394 // A1: Smi-tagged argument count, may be zero. | 387 // A1: Smi-tagged argument count, may be zero. |
| 395 // FP[kParamEndSlotFromFp + 1]: Last argument. | 388 // FP[kParamEndSlotFromFp + 1]: Last argument. |
| 396 static void PushArgumentsArray(Assembler* assembler) { | 389 static void PushArgumentsArray(Assembler* assembler) { |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 433 // - Push all registers that can contain values. | 426 // - Push all registers that can contain values. |
| 434 // - Call C routine to copy the stack and saved registers into temporary buffer. | 427 // - Call C routine to copy the stack and saved registers into temporary buffer. |
| 435 // - Adjust caller's frame to correct unoptimized frame size. | 428 // - Adjust caller's frame to correct unoptimized frame size. |
| 436 // - Fill the unoptimized frame. | 429 // - Fill the unoptimized frame. |
| 437 // - Materialize objects that require allocation (e.g. Double instances). | 430 // - Materialize objects that require allocation (e.g. Double instances). |
| 438 // GC can occur only after frame is fully rewritten. | 431 // GC can occur only after frame is fully rewritten. |
| 439 // Stack after EnterFrame(...) below: | 432 // Stack after EnterFrame(...) below: |
| 440 // +------------------+ | 433 // +------------------+ |
| 441 // | Saved PP | <- TOS | 434 // | Saved PP | <- TOS |
| 442 // +------------------+ | 435 // +------------------+ |
| 443 // | Saved CODE_REG | | |
| 444 // +------------------+ | |
| 445 // | Saved FP | <- FP of stub | 436 // | Saved FP | <- FP of stub |
| 446 // +------------------+ | 437 // +------------------+ |
| 447 // | Saved LR | (deoptimization point) | 438 // | Saved LR | (deoptimization point) |
| 448 // +------------------+ | 439 // +------------------+ |
| 449 // | Saved CODE_REG | | 440 // | PC marker | |
| 450 // +------------------+ | 441 // +------------------+ |
| 451 // | ... | <- SP of optimized frame | 442 // | ... | <- SP of optimized frame |
| 452 // | 443 // |
| 453 // Parts of the code cannot GC, part of the code can GC. | 444 // Parts of the code cannot GC, part of the code can GC. |
| 454 static void GenerateDeoptimizationSequence(Assembler* assembler, | 445 static void GenerateDeoptimizationSequence(Assembler* assembler, |
| 455 DeoptStubKind kind) { | 446 bool preserve_result) { |
| 456 const intptr_t kPushedRegistersSize = | 447 const intptr_t kPushedRegistersSize = |
| 457 kNumberOfCpuRegisters * kWordSize + kNumberOfFRegisters * kWordSize; | 448 kNumberOfCpuRegisters * kWordSize + |
| 449 4 * kWordSize + // PP, FP, RA, PC marker. |
| 450 kNumberOfFRegisters * kWordSize; |
| 458 | 451 |
| 459 __ SetPrologueOffset(); | 452 __ SetPrologueOffset(); |
| 460 __ Comment("GenerateDeoptimizationSequence"); | 453 __ Comment("GenerateDeoptimizationSequence"); |
| 461 // DeoptimizeCopyFrame expects a Dart frame. | 454 // DeoptimizeCopyFrame expects a Dart frame, i.e. EnterDartFrame(0), but there |
| 462 __ EnterStubFrame(kPushedRegistersSize); | 455 // is no need to set the correct PC marker or load PP, since they get patched. |
| 456 __ addiu(SP, SP, Immediate(-kPushedRegistersSize * kWordSize)); |
| 457 __ sw(ZR, Address(SP, kPushedRegistersSize - 1 * kWordSize)); |
| 458 __ sw(RA, Address(SP, kPushedRegistersSize - 2 * kWordSize)); |
| 459 __ sw(FP, Address(SP, kPushedRegistersSize - 3 * kWordSize)); |
| 460 __ sw(PP, Address(SP, kPushedRegistersSize - 4 * kWordSize)); |
| 461 __ addiu(FP, SP, Immediate(kPushedRegistersSize - 3 * kWordSize)); |
| 462 |
| 463 __ LoadPoolPointer(); |
| 463 | 464 |
| 464 // The code in this frame may not cause GC. kDeoptimizeCopyFrameRuntimeEntry | 465 // The code in this frame may not cause GC. kDeoptimizeCopyFrameRuntimeEntry |
| 465 // and kDeoptimizeFillFrameRuntimeEntry are leaf runtime calls. | 466 // and kDeoptimizeFillFrameRuntimeEntry are leaf runtime calls. |
| 466 const intptr_t saved_result_slot_from_fp = | 467 const intptr_t saved_result_slot_from_fp = |
| 467 kFirstLocalSlotFromFp + 1 - (kNumberOfCpuRegisters - V0); | 468 kFirstLocalSlotFromFp + 1 - (kNumberOfCpuRegisters - V0); |
| 468 // Result in V0 is preserved as part of pushing all registers below. | 469 // Result in V0 is preserved as part of pushing all registers below. |
| 469 | 470 |
| 470 // Push registers in their enumeration order: lowest register number at | 471 // Push registers in their enumeration order: lowest register number at |
| 471 // lowest address. | 472 // lowest address. |
| 472 for (int i = 0; i < kNumberOfCpuRegisters; i++) { | 473 for (int i = 0; i < kNumberOfCpuRegisters; i++) { |
| 473 const int slot = kNumberOfCpuRegisters - i; | 474 const int slot = 4 + kNumberOfCpuRegisters - i; |
| 474 Register reg = static_cast<Register>(i); | 475 Register reg = static_cast<Register>(i); |
| 475 if (reg == CODE_REG) { | 476 __ sw(reg, Address(SP, kPushedRegistersSize - slot * kWordSize)); |
| 476 // Save the original value of CODE_REG pushed before invoking this stub | |
| 477 // instead of the value used to call this stub. | |
| 478 COMPILE_ASSERT(TMP < CODE_REG); // Assert TMP is pushed first. | |
| 479 __ lw(TMP, Address(FP, kCallerSpSlotFromFp * kWordSize)); | |
| 480 __ sw(TMP, Address(SP, kPushedRegistersSize - slot * kWordSize)); | |
| 481 } else { | |
| 482 __ sw(reg, Address(SP, kPushedRegistersSize - slot * kWordSize)); | |
| 483 } | |
| 484 } | 477 } |
| 485 for (int i = 0; i < kNumberOfFRegisters; i++) { | 478 for (int i = 0; i < kNumberOfFRegisters; i++) { |
| 486 // These go below the CPU registers. | 479 // These go below the CPU registers. |
| 487 const int slot = kNumberOfCpuRegisters + kNumberOfFRegisters - i; | 480 const int slot = 4 + kNumberOfCpuRegisters + kNumberOfFRegisters - i; |
| 488 FRegister reg = static_cast<FRegister>(i); | 481 FRegister reg = static_cast<FRegister>(i); |
| 489 __ swc1(reg, Address(SP, kPushedRegistersSize - slot * kWordSize)); | 482 __ swc1(reg, Address(SP, kPushedRegistersSize - slot * kWordSize)); |
| 490 } | 483 } |
| 491 | 484 |
| 492 __ mov(A0, SP); // Pass address of saved registers block. | 485 __ mov(A0, SP); // Pass address of saved registers block. |
| 493 __ LoadImmediate(A1, (kind == kLazyDeopt) ? 1 : 0); | |
| 494 __ ReserveAlignedFrameSpace(1 * kWordSize); | 486 __ ReserveAlignedFrameSpace(1 * kWordSize); |
| 495 __ CallRuntime(kDeoptimizeCopyFrameRuntimeEntry, 2); | 487 __ CallRuntime(kDeoptimizeCopyFrameRuntimeEntry, 1); |
| 496 // Result (V0) is stack-size (FP - SP) in bytes, incl. the return address. | 488 // Result (V0) is stack-size (FP - SP) in bytes, incl. the return address. |
| 497 | 489 |
| 498 const bool preserve_result = (kind == kLazyDeopt); | |
| 499 if (preserve_result) { | 490 if (preserve_result) { |
| 500 // Restore result into T1 temporarily. | 491 // Restore result into T1 temporarily. |
| 501 __ lw(T1, Address(FP, saved_result_slot_from_fp * kWordSize)); | 492 __ lw(T1, Address(FP, saved_result_slot_from_fp * kWordSize)); |
| 502 } | 493 } |
| 503 | 494 |
| 504 __ RestoreCodePointer(); | |
| 505 __ LeaveDartFrame(); | 495 __ LeaveDartFrame(); |
| 506 __ subu(SP, FP, V0); | 496 __ subu(SP, FP, V0); |
| 507 | 497 |
| 508 // DeoptimizeFillFrame expects a Dart frame, i.e. EnterDartFrame(0), but there | 498 // DeoptimizeFillFrame expects a Dart frame, i.e. EnterDartFrame(0), but there |
| 509 // is no need to set the correct PC marker or load PP, since they get patched. | 499 // is no need to set the correct PC marker or load PP, since they get patched. |
| 510 __ EnterStubFrame(); | 500 __ EnterStubFrame(); |
| 511 | 501 |
| 512 __ mov(A0, FP); // Get last FP address. | 502 __ mov(A0, FP); // Get last FP address. |
| 513 if (preserve_result) { | 503 if (preserve_result) { |
| 514 __ Push(T1); // Preserve result as first local. | 504 __ Push(T1); // Preserve result as first local. |
| 515 } | 505 } |
| 516 __ ReserveAlignedFrameSpace(1 * kWordSize); | 506 __ ReserveAlignedFrameSpace(1 * kWordSize); |
| 517 __ CallRuntime(kDeoptimizeFillFrameRuntimeEntry, 1); // Pass last FP in A0. | 507 __ CallRuntime(kDeoptimizeFillFrameRuntimeEntry, 1); // Pass last FP in A0. |
| 518 if (preserve_result) { | 508 if (preserve_result) { |
| 519 // Restore result into T1. | 509 // Restore result into T1. |
| 520 __ lw(T1, Address(FP, kFirstLocalSlotFromFp * kWordSize)); | 510 __ lw(T1, Address(FP, kFirstLocalSlotFromFp * kWordSize)); |
| 521 } | 511 } |
| 522 // Code above cannot cause GC. | 512 // Code above cannot cause GC. |
| 523 __ RestoreCodePointer(); | |
| 524 __ LeaveStubFrame(); | 513 __ LeaveStubFrame(); |
| 525 | 514 |
| 526 // Frame is fully rewritten at this point and it is safe to perform a GC. | 515 // Frame is fully rewritten at this point and it is safe to perform a GC. |
| 527 // Materialize any objects that were deferred by FillFrame because they | 516 // Materialize any objects that were deferred by FillFrame because they |
| 528 // require allocation. | 517 // require allocation. |
| 529 // Enter stub frame with loading PP. The caller's PP is not materialized yet. | 518 // Enter stub frame with loading PP. The caller's PP is not materialized yet. |
| 530 __ EnterStubFrame(); | 519 __ EnterStubFrame(); |
| 531 if (preserve_result) { | 520 if (preserve_result) { |
| 532 __ Push(T1); // Preserve result, it will be GC-d here. | 521 __ Push(T1); // Preserve result, it will be GC-d here. |
| 533 } | 522 } |
| 534 __ PushObject(Smi::ZoneHandle()); // Space for the result. | 523 __ PushObject(Smi::ZoneHandle()); // Space for the result. |
| 535 __ CallRuntime(kDeoptimizeMaterializeRuntimeEntry, 0); | 524 __ CallRuntime(kDeoptimizeMaterializeRuntimeEntry, 0); |
| 536 // Result tells stub how many bytes to remove from the expression stack | 525 // Result tells stub how many bytes to remove from the expression stack |
| 537 // of the bottom-most frame. They were used as materialization arguments. | 526 // of the bottom-most frame. They were used as materialization arguments. |
| 538 __ Pop(T1); | 527 __ Pop(T1); |
| 539 if (preserve_result) { | 528 if (preserve_result) { |
| 540 __ Pop(V0); // Restore result. | 529 __ Pop(V0); // Restore result. |
| 541 } | 530 } |
| 542 __ LeaveStubFrame(); | 531 __ LeaveStubFrame(); |
| 543 // Remove materialization arguments. | 532 // Remove materialization arguments. |
| 544 __ SmiUntag(T1); | 533 __ SmiUntag(T1); |
| 545 __ addu(SP, SP, T1); | 534 __ addu(SP, SP, T1); |
| 546 __ Ret(); | 535 __ Ret(); |
| 547 } | 536 } |
| 548 | 537 |
| 549 | 538 |
| 550 void StubCode::GenerateDeoptimizeLazyStub(Assembler* assembler) { | 539 void StubCode::GenerateDeoptimizeLazyStub(Assembler* assembler) { |
| 551 // Correct return address to point just after the call that is being | 540 // Correct return address to point just after the call that is being |
| 552 // deoptimized. | 541 // deoptimized. |
| 553 __ AddImmediate(RA, -CallPattern::kDeoptCallLengthInBytes); | 542 __ AddImmediate(RA, -CallPattern::kFixedLengthInBytes); |
| 554 // Push zap value instead of CODE_REG for lazy deopt. | 543 GenerateDeoptimizationSequence(assembler, true); // Preserve V0. |
| 555 __ LoadImmediate(TMP, 0xf1f1f1f1); | |
| 556 __ Push(TMP); | |
| 557 GenerateDeoptimizationSequence(assembler, kLazyDeopt); | |
| 558 } | 544 } |
| 559 | 545 |
| 560 | 546 |
| 561 void StubCode::GenerateDeoptimizeStub(Assembler* assembler) { | 547 void StubCode::GenerateDeoptimizeStub(Assembler* assembler) { |
| 562 GenerateDeoptimizationSequence(assembler, kEagerDeopt); | 548 GenerateDeoptimizationSequence(assembler, false); // Don't preserve V0. |
| 563 } | 549 } |
| 564 | 550 |
| 565 | 551 |
| 566 static void GenerateDispatcherCode(Assembler* assembler, | 552 static void GenerateDispatcherCode(Assembler* assembler, |
| 567 Label* call_target_function) { | 553 Label* call_target_function) { |
| 568 __ Comment("NoSuchMethodDispatch"); | 554 __ Comment("NoSuchMethodDispatch"); |
| 569 // When lazily generated invocation dispatchers are disabled, the | 555 // When lazily generated invocation dispatchers are disabled, the |
| 570 // miss-handler may return null. | 556 // miss-handler may return null. |
| 571 __ BranchNotEqual(T0, Object::null_object(), call_target_function); | 557 __ BranchNotEqual(T0, Object::null_object(), call_target_function); |
| 572 __ EnterStubFrame(); | 558 __ EnterStubFrame(); |
| (...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 622 __ sw(S5, Address(SP, 1 * kWordSize)); | 608 __ sw(S5, Address(SP, 1 * kWordSize)); |
| 623 __ sw(S4, Address(SP, 0 * kWordSize)); | 609 __ sw(S4, Address(SP, 0 * kWordSize)); |
| 624 | 610 |
| 625 __ CallRuntime(kMegamorphicCacheMissHandlerRuntimeEntry, 3); | 611 __ CallRuntime(kMegamorphicCacheMissHandlerRuntimeEntry, 3); |
| 626 | 612 |
| 627 __ lw(T0, Address(SP, 3 * kWordSize)); // Get result function. | 613 __ lw(T0, Address(SP, 3 * kWordSize)); // Get result function. |
| 628 __ lw(S4, Address(SP, 4 * kWordSize)); // Restore argument descriptor. | 614 __ lw(S4, Address(SP, 4 * kWordSize)); // Restore argument descriptor. |
| 629 __ lw(S5, Address(SP, 5 * kWordSize)); // Restore IC data. | 615 __ lw(S5, Address(SP, 5 * kWordSize)); // Restore IC data. |
| 630 __ addiu(SP, SP, Immediate(6 * kWordSize)); | 616 __ addiu(SP, SP, Immediate(6 * kWordSize)); |
| 631 | 617 |
| 632 __ RestoreCodePointer(); | |
| 633 __ LeaveStubFrame(); | 618 __ LeaveStubFrame(); |
| 634 | 619 |
| 635 if (!FLAG_lazy_dispatchers) { | 620 if (!FLAG_lazy_dispatchers) { |
| 636 Label call_target_function; | 621 Label call_target_function; |
| 637 GenerateDispatcherCode(assembler, &call_target_function); | 622 GenerateDispatcherCode(assembler, &call_target_function); |
| 638 __ Bind(&call_target_function); | 623 __ Bind(&call_target_function); |
| 639 } | 624 } |
| 640 | 625 |
| 641 __ lw(CODE_REG, FieldAddress(T0, Function::code_offset())); | |
| 642 __ lw(T2, FieldAddress(T0, Function::entry_point_offset())); | 626 __ lw(T2, FieldAddress(T0, Function::entry_point_offset())); |
| 643 __ jr(T2); | 627 __ jr(T2); |
| 644 } | 628 } |
| 645 | 629 |
| 646 | 630 |
| 647 // Called for inline allocation of arrays. | 631 // Called for inline allocation of arrays. |
| 648 // Input parameters: | 632 // Input parameters: |
| 649 // RA: return address. | 633 // RA: return address. |
| 650 // A1: Array length as Smi (must be preserved). | 634 // A1: Array length as Smi (must be preserved). |
| 651 // A0: array element type (either NULL or an instantiated type). | 635 // A0: array element type (either NULL or an instantiated type). |
| (...skipping 137 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 789 __ lw(A0, Address(SP, 0 * kWordSize)); | 773 __ lw(A0, Address(SP, 0 * kWordSize)); |
| 790 __ addiu(SP, SP, Immediate(3 * kWordSize)); | 774 __ addiu(SP, SP, Immediate(3 * kWordSize)); |
| 791 | 775 |
| 792 __ LeaveStubFrameAndReturn(); | 776 __ LeaveStubFrameAndReturn(); |
| 793 } | 777 } |
| 794 | 778 |
| 795 | 779 |
| 796 // Called when invoking Dart code from C++ (VM code). | 780 // Called when invoking Dart code from C++ (VM code). |
| 797 // Input parameters: | 781 // Input parameters: |
| 798 // RA : points to return address. | 782 // RA : points to return address. |
| 799 // A0 : code object of the Dart function to call. | 783 // A0 : entrypoint of the Dart function to call. |
| 800 // A1 : arguments descriptor array. | 784 // A1 : arguments descriptor array. |
| 801 // A2 : arguments array. | 785 // A2 : arguments array. |
| 802 // A3 : current thread. | 786 // A3 : current thread. |
| 803 void StubCode::GenerateInvokeDartCodeStub(Assembler* assembler) { | 787 void StubCode::GenerateInvokeDartCodeStub(Assembler* assembler) { |
| 804 // Save frame pointer coming in. | 788 // Save frame pointer coming in. |
| 805 __ Comment("InvokeDartCodeStub"); | 789 __ Comment("InvokeDartCodeStub"); |
| 806 __ EnterFrame(); | 790 __ EnterFrame(); |
| 807 | 791 |
| 808 // Save new context and C++ ABI callee-saved registers. | 792 // Save new context and C++ ABI callee-saved registers. |
| 809 | 793 |
| (...skipping 12 matching lines...) Expand all Loading... |
| 822 | 806 |
| 823 for (intptr_t i = kAbiFirstPreservedFpuReg; | 807 for (intptr_t i = kAbiFirstPreservedFpuReg; |
| 824 i <= kAbiLastPreservedFpuReg; i++) { | 808 i <= kAbiLastPreservedFpuReg; i++) { |
| 825 FRegister r = static_cast<FRegister>(i); | 809 FRegister r = static_cast<FRegister>(i); |
| 826 const intptr_t slot = | 810 const intptr_t slot = |
| 827 kAbiPreservedCpuRegCount + kPreservedSlots + i - | 811 kAbiPreservedCpuRegCount + kPreservedSlots + i - |
| 828 kAbiFirstPreservedFpuReg; | 812 kAbiFirstPreservedFpuReg; |
| 829 __ swc1(r, Address(SP, slot * kWordSize)); | 813 __ swc1(r, Address(SP, slot * kWordSize)); |
| 830 } | 814 } |
| 831 | 815 |
| 832 // We now load the pool pointer(PP) with a GC safe value as we are about | 816 // We now load the pool pointer(PP) as we are about to invoke dart code and we |
| 833 // to invoke dart code. | 817 // could potentially invoke some intrinsic functions which need the PP to be |
| 834 __ LoadImmediate(PP, 0); | 818 // set up. |
| 819 __ LoadPoolPointer(); |
| 835 | 820 |
| 836 // Set up THR, which caches the current thread in Dart code. | 821 // Set up THR, which caches the current thread in Dart code. |
| 837 if (THR != A3) { | 822 if (THR != A3) { |
| 838 __ mov(THR, A3); | 823 __ mov(THR, A3); |
| 839 } | 824 } |
| 840 __ LoadIsolate(T2); | 825 __ LoadIsolate(T2); |
| 841 | 826 |
| 842 // Save the current VMTag on the stack. | 827 // Save the current VMTag on the stack. |
| 843 __ lw(T1, Address(T2, Isolate::vm_tag_offset())); | 828 __ lw(T1, Address(T2, Isolate::vm_tag_offset())); |
| 844 __ sw(T1, Address(SP, 2 * kWordSize)); | 829 __ sw(T1, Address(SP, 2 * kWordSize)); |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 883 __ Push(A3); | 868 __ Push(A3); |
| 884 __ addiu(A1, A1, Immediate(1)); | 869 __ addiu(A1, A1, Immediate(1)); |
| 885 __ BranchSignedLess(A1, T1, &push_arguments); | 870 __ BranchSignedLess(A1, T1, &push_arguments); |
| 886 __ delay_slot()->addiu(A2, A2, Immediate(kWordSize)); | 871 __ delay_slot()->addiu(A2, A2, Immediate(kWordSize)); |
| 887 | 872 |
| 888 __ Bind(&done_push_arguments); | 873 __ Bind(&done_push_arguments); |
| 889 | 874 |
| 890 // Call the Dart code entrypoint. | 875 // Call the Dart code entrypoint. |
| 891 // We are calling into Dart code, here, so there is no need to call through | 876 // We are calling into Dart code, here, so there is no need to call through |
| 892 // T9 to match the ABI. | 877 // T9 to match the ABI. |
| 893 __ lw(CODE_REG, Address(A0, VMHandles::kOffsetOfRawPtrInHandle)); | |
| 894 __ lw(A0, FieldAddress(CODE_REG, Code::entry_point_offset())); | |
| 895 __ jalr(A0); // S4 is the arguments descriptor array. | 878 __ jalr(A0); // S4 is the arguments descriptor array. |
| 896 __ Comment("InvokeDartCodeStub return"); | 879 __ Comment("InvokeDartCodeStub return"); |
| 897 | 880 |
| 898 // Get rid of arguments pushed on the stack. | 881 // Get rid of arguments pushed on the stack. |
| 899 __ AddImmediate(SP, FP, kExitLinkSlotFromEntryFp * kWordSize); | 882 __ AddImmediate(SP, FP, kExitLinkSlotFromEntryFp * kWordSize); |
| 900 | 883 |
| 901 __ LoadIsolate(S2); | 884 __ LoadIsolate(S6); |
| 902 | 885 |
| 903 // Restore the current VMTag from the stack. | 886 // Restore the current VMTag from the stack. |
| 904 __ lw(T1, Address(SP, 2 * kWordSize)); | 887 __ lw(T1, Address(SP, 2 * kWordSize)); |
| 905 __ sw(T1, Address(S2, Isolate::vm_tag_offset())); | 888 __ sw(T1, Address(S6, Isolate::vm_tag_offset())); |
| 906 | 889 |
| 907 // Restore the saved top resource and top exit frame info back into the | 890 // Restore the saved top resource and top exit frame info back into the |
| 908 // Isolate structure. Uses T0 as a temporary register for this. | 891 // Isolate structure. Uses T0 as a temporary register for this. |
| 909 __ lw(T0, Address(SP, 1 * kWordSize)); | 892 __ lw(T0, Address(SP, 1 * kWordSize)); |
| 910 __ sw(T0, Address(THR, Thread::top_resource_offset())); | 893 __ sw(T0, Address(THR, Thread::top_resource_offset())); |
| 911 __ lw(T0, Address(SP, 0 * kWordSize)); | 894 __ lw(T0, Address(SP, 0 * kWordSize)); |
| 912 __ sw(T0, Address(THR, Thread::top_exit_frame_info_offset())); | 895 __ sw(T0, Address(THR, Thread::top_exit_frame_info_offset())); |
| 913 | 896 |
| 914 // Restore C++ ABI callee-saved registers. | 897 // Restore C++ ABI callee-saved registers. |
| 915 for (int i = S0; i <= S7; i++) { | 898 for (int i = S0; i <= S7; i++) { |
| (...skipping 202 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1118 // Restore callee-saved registers, tear down frame. | 1101 // Restore callee-saved registers, tear down frame. |
| 1119 __ LeaveCallRuntimeFrame(); | 1102 __ LeaveCallRuntimeFrame(); |
| 1120 __ Ret(); | 1103 __ Ret(); |
| 1121 } | 1104 } |
| 1122 | 1105 |
| 1123 | 1106 |
| 1124 // Called for inline allocation of objects. | 1107 // Called for inline allocation of objects. |
| 1125 // Input parameters: | 1108 // Input parameters: |
| 1126 // RA : return address. | 1109 // RA : return address. |
| 1127 // SP + 0 : type arguments object (only if class is parameterized). | 1110 // SP + 0 : type arguments object (only if class is parameterized). |
| 1128 void StubCode::GenerateAllocationStubForClass(Assembler* assembler, | 1111 // Returns patch_code_pc offset where patching code for disabling the stub |
| 1129 const Class& cls) { | 1112 // has been generated (similar to regularly generated Dart code). |
| 1113 void StubCode::GenerateAllocationStubForClass( |
| 1114 Assembler* assembler, const Class& cls, |
| 1115 uword* entry_patch_offset, uword* patch_code_pc_offset) { |
| 1130 __ Comment("AllocationStubForClass"); | 1116 __ Comment("AllocationStubForClass"); |
| 1117 *entry_patch_offset = assembler->CodeSize(); |
| 1131 // The generated code is different if the class is parameterized. | 1118 // The generated code is different if the class is parameterized. |
| 1132 const bool is_cls_parameterized = cls.NumTypeArguments() > 0; | 1119 const bool is_cls_parameterized = cls.NumTypeArguments() > 0; |
| 1133 ASSERT(!is_cls_parameterized || | 1120 ASSERT(!is_cls_parameterized || |
| 1134 (cls.type_arguments_field_offset() != Class::kNoTypeArguments)); | 1121 (cls.type_arguments_field_offset() != Class::kNoTypeArguments)); |
| 1135 // kInlineInstanceSize is a constant used as a threshold for determining | 1122 // kInlineInstanceSize is a constant used as a threshold for determining |
| 1136 // when the object initialization should be done as a loop or as | 1123 // when the object initialization should be done as a loop or as |
| 1137 // straight line code. | 1124 // straight line code. |
| 1138 const int kInlineInstanceSize = 12; | 1125 const int kInlineInstanceSize = 12; |
| 1139 const intptr_t instance_size = cls.instance_size(); | 1126 const intptr_t instance_size = cls.instance_size(); |
| 1140 ASSERT(instance_size > 0); | 1127 ASSERT(instance_size > 0); |
| (...skipping 102 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1243 __ sw(T7, Address(SP, 0 * kWordSize)); | 1230 __ sw(T7, Address(SP, 0 * kWordSize)); |
| 1244 } | 1231 } |
| 1245 __ CallRuntime(kAllocateObjectRuntimeEntry, 2); // Allocate object. | 1232 __ CallRuntime(kAllocateObjectRuntimeEntry, 2); // Allocate object. |
| 1246 __ Comment("AllocationStubForClass return"); | 1233 __ Comment("AllocationStubForClass return"); |
| 1247 // Pop result (newly allocated object). | 1234 // Pop result (newly allocated object). |
| 1248 __ lw(V0, Address(SP, 2 * kWordSize)); | 1235 __ lw(V0, Address(SP, 2 * kWordSize)); |
| 1249 __ addiu(SP, SP, Immediate(3 * kWordSize)); // Pop arguments. | 1236 __ addiu(SP, SP, Immediate(3 * kWordSize)); // Pop arguments. |
| 1250 // V0: new object | 1237 // V0: new object |
| 1251 // Restore the frame pointer and return. | 1238 // Restore the frame pointer and return. |
| 1252 __ LeaveStubFrameAndReturn(RA); | 1239 __ LeaveStubFrameAndReturn(RA); |
| 1240 *patch_code_pc_offset = assembler->CodeSize(); |
| 1241 __ BranchPatchable(*StubCode::FixAllocationStubTarget_entry()); |
| 1253 } | 1242 } |
| 1254 | 1243 |
| 1255 | 1244 |
| 1256 // Called for invoking "dynamic noSuchMethod(Invocation invocation)" function | 1245 // Called for invoking "dynamic noSuchMethod(Invocation invocation)" function |
| 1257 // from the entry code of a dart function after an error in passed argument | 1246 // from the entry code of a dart function after an error in passed argument |
| 1258 // name or number is detected. | 1247 // name or number is detected. |
| 1259 // Input parameters: | 1248 // Input parameters: |
| 1260 // RA : return address. | 1249 // RA : return address. |
| 1261 // SP : address of last argument. | 1250 // SP : address of last argument. |
| 1262 // S4: arguments descriptor array. | 1251 // S4: arguments descriptor array. |
| (...skipping 299 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1562 __ CallRuntime(handle_ic_miss, num_args + 1); | 1551 __ CallRuntime(handle_ic_miss, num_args + 1); |
| 1563 __ Comment("NArgsCheckInlineCacheStub return"); | 1552 __ Comment("NArgsCheckInlineCacheStub return"); |
| 1564 // Pop returned function object into T3. | 1553 // Pop returned function object into T3. |
| 1565 // Restore arguments descriptor array and IC data array. | 1554 // Restore arguments descriptor array and IC data array. |
| 1566 __ lw(T3, Address(SP, (num_slots - 3) * kWordSize)); | 1555 __ lw(T3, Address(SP, (num_slots - 3) * kWordSize)); |
| 1567 __ lw(S4, Address(SP, (num_slots - 2) * kWordSize)); | 1556 __ lw(S4, Address(SP, (num_slots - 2) * kWordSize)); |
| 1568 __ lw(S5, Address(SP, (num_slots - 1) * kWordSize)); | 1557 __ lw(S5, Address(SP, (num_slots - 1) * kWordSize)); |
| 1569 // Remove the call arguments pushed earlier, including the IC data object | 1558 // Remove the call arguments pushed earlier, including the IC data object |
| 1570 // and the arguments descriptor array. | 1559 // and the arguments descriptor array. |
| 1571 __ addiu(SP, SP, Immediate(num_slots * kWordSize)); | 1560 __ addiu(SP, SP, Immediate(num_slots * kWordSize)); |
| 1572 if (range_collection_mode == kCollectRanges) { | |
| 1573 __ RestoreCodePointer(); | |
| 1574 } | |
| 1575 __ LeaveStubFrame(); | 1561 __ LeaveStubFrame(); |
| 1576 | 1562 |
| 1577 Label call_target_function; | 1563 Label call_target_function; |
| 1578 if (!FLAG_lazy_dispatchers) { | 1564 if (!FLAG_lazy_dispatchers) { |
| 1579 __ mov(T0, T3); | 1565 __ mov(T0, T3); |
| 1580 GenerateDispatcherCode(assembler, &call_target_function); | 1566 GenerateDispatcherCode(assembler, &call_target_function); |
| 1581 } else { | 1567 } else { |
| 1582 __ b(&call_target_function); | 1568 __ b(&call_target_function); |
| 1583 } | 1569 } |
| 1584 | 1570 |
| (...skipping 27 matching lines...) Expand all Loading... |
| 1612 __ lw(T1, Address(SP, 1 * kWordSize)); | 1598 __ lw(T1, Address(SP, 1 * kWordSize)); |
| 1613 } | 1599 } |
| 1614 __ EnterStubFrame(); | 1600 __ EnterStubFrame(); |
| 1615 __ addiu(SP, SP, Immediate(- frame_size * kWordSize)); | 1601 __ addiu(SP, SP, Immediate(- frame_size * kWordSize)); |
| 1616 __ sw(RA, Address(SP, (frame_size - 1) * kWordSize)); // Return address. | 1602 __ sw(RA, Address(SP, (frame_size - 1) * kWordSize)); // Return address. |
| 1617 __ sw(S5, Address(SP, (frame_size - 2) * kWordSize)); // Preserve IC data. | 1603 __ sw(S5, Address(SP, (frame_size - 2) * kWordSize)); // Preserve IC data. |
| 1618 __ sw(T3, Address(SP, 0 * kWordSize)); | 1604 __ sw(T3, Address(SP, 0 * kWordSize)); |
| 1619 if (num_args == 2) { | 1605 if (num_args == 2) { |
| 1620 __ sw(T1, Address(SP, 1 * kWordSize)); | 1606 __ sw(T1, Address(SP, 1 * kWordSize)); |
| 1621 } | 1607 } |
| 1622 __ lw(CODE_REG, FieldAddress(T0, Function::code_offset())); | |
| 1623 __ jalr(T4); | 1608 __ jalr(T4); |
| 1624 __ lw(S5, Address(SP, (frame_size - 2) * kWordSize)); | 1609 __ lw(S5, Address(SP, (frame_size - 2) * kWordSize)); |
| 1625 __ lw(RA, Address(SP, (frame_size - 1) * kWordSize)); | 1610 __ lw(RA, Address(SP, (frame_size - 1) * kWordSize)); |
| 1626 Label done; | 1611 Label done; |
| 1627 __ UpdateRangeFeedback(V0, 2, S5, T1, &done); | 1612 __ UpdateRangeFeedback(V0, 2, S5, T1, &done); |
| 1628 __ Bind(&done); | 1613 __ Bind(&done); |
| 1629 __ addiu(SP, SP, Immediate(frame_size * kWordSize)); | 1614 __ addiu(SP, SP, Immediate(frame_size * kWordSize)); |
| 1630 __ RestoreCodePointer(); | |
| 1631 __ LeaveStubFrame(); | 1615 __ LeaveStubFrame(); |
| 1632 __ Ret(); | 1616 __ Ret(); |
| 1633 } else { | 1617 } else { |
| 1634 __ lw(CODE_REG, FieldAddress(T0, Function::code_offset())); | |
| 1635 __ jr(T4); | 1618 __ jr(T4); |
| 1636 } | 1619 } |
| 1637 | 1620 |
| 1638 // Call single step callback in debugger. | 1621 // Call single step callback in debugger. |
| 1639 if (FLAG_support_debugger && !optimized) { | 1622 if (FLAG_support_debugger && !optimized) { |
| 1640 __ Bind(&stepping); | 1623 __ Bind(&stepping); |
| 1641 __ EnterStubFrame(); | 1624 __ EnterStubFrame(); |
| 1642 __ addiu(SP, SP, Immediate(-2 * kWordSize)); | 1625 __ addiu(SP, SP, Immediate(-2 * kWordSize)); |
| 1643 __ sw(S5, Address(SP, 1 * kWordSize)); // Preserve IC data. | 1626 __ sw(S5, Address(SP, 1 * kWordSize)); // Preserve IC data. |
| 1644 __ sw(RA, Address(SP, 0 * kWordSize)); // Return address. | 1627 __ sw(RA, Address(SP, 0 * kWordSize)); // Return address. |
| 1645 __ CallRuntime(kSingleStepHandlerRuntimeEntry, 0); | 1628 __ CallRuntime(kSingleStepHandlerRuntimeEntry, 0); |
| 1646 __ lw(RA, Address(SP, 0 * kWordSize)); | 1629 __ lw(RA, Address(SP, 0 * kWordSize)); |
| 1647 __ lw(S5, Address(SP, 1 * kWordSize)); | 1630 __ lw(S5, Address(SP, 1 * kWordSize)); |
| 1648 __ addiu(SP, SP, Immediate(2 * kWordSize)); | 1631 __ addiu(SP, SP, Immediate(2 * kWordSize)); |
| 1649 __ RestoreCodePointer(); | |
| 1650 __ LeaveStubFrame(); | 1632 __ LeaveStubFrame(); |
| 1651 __ b(&done_stepping); | 1633 __ b(&done_stepping); |
| 1652 } | 1634 } |
| 1653 } | 1635 } |
| 1654 | 1636 |
| 1655 | 1637 |
| 1656 // Use inline cache data array to invoke the target or continue in inline | 1638 // Use inline cache data array to invoke the target or continue in inline |
| 1657 // cache miss handler. Stub for 1-argument check (receiver class). | 1639 // cache miss handler. Stub for 1-argument check (receiver class). |
| 1658 // RA: Return address. | 1640 // RA: Return address. |
| 1659 // S5: Inline cache data object. | 1641 // S5: Inline cache data object. |
| (...skipping 125 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1785 __ LoadImmediate(T4, Smi::RawValue(Smi::kMaxValue)); | 1767 __ LoadImmediate(T4, Smi::RawValue(Smi::kMaxValue)); |
| 1786 __ movz(T4, T7, CMPRES1); | 1768 __ movz(T4, T7, CMPRES1); |
| 1787 __ sw(T4, Address(T0, count_offset)); | 1769 __ sw(T4, Address(T0, count_offset)); |
| 1788 } | 1770 } |
| 1789 | 1771 |
| 1790 // Load arguments descriptor into S4. | 1772 // Load arguments descriptor into S4. |
| 1791 __ lw(S4, FieldAddress(S5, ICData::arguments_descriptor_offset())); | 1773 __ lw(S4, FieldAddress(S5, ICData::arguments_descriptor_offset())); |
| 1792 | 1774 |
| 1793 // Get function and call it, if possible. | 1775 // Get function and call it, if possible. |
| 1794 __ lw(T0, Address(T0, target_offset)); | 1776 __ lw(T0, Address(T0, target_offset)); |
| 1795 __ lw(CODE_REG, FieldAddress(T0, Function::code_offset())); | |
| 1796 __ lw(T4, FieldAddress(T0, Function::entry_point_offset())); | 1777 __ lw(T4, FieldAddress(T0, Function::entry_point_offset())); |
| 1797 __ jr(T4); | 1778 __ jr(T4); |
| 1798 | 1779 |
| 1799 // Call single step callback in debugger. | 1780 // Call single step callback in debugger. |
| 1800 if (FLAG_support_debugger) { | 1781 if (FLAG_support_debugger) { |
| 1801 __ Bind(&stepping); | 1782 __ Bind(&stepping); |
| 1802 __ EnterStubFrame(); | 1783 __ EnterStubFrame(); |
| 1803 __ addiu(SP, SP, Immediate(-2 * kWordSize)); | 1784 __ addiu(SP, SP, Immediate(-2 * kWordSize)); |
| 1804 __ sw(S5, Address(SP, 1 * kWordSize)); // Preserve IC data. | 1785 __ sw(S5, Address(SP, 1 * kWordSize)); // Preserve IC data. |
| 1805 __ sw(RA, Address(SP, 0 * kWordSize)); // Return address. | 1786 __ sw(RA, Address(SP, 0 * kWordSize)); // Return address. |
| 1806 __ CallRuntime(kSingleStepHandlerRuntimeEntry, 0); | 1787 __ CallRuntime(kSingleStepHandlerRuntimeEntry, 0); |
| 1807 __ lw(RA, Address(SP, 0 * kWordSize)); | 1788 __ lw(RA, Address(SP, 0 * kWordSize)); |
| 1808 __ lw(S5, Address(SP, 1 * kWordSize)); | 1789 __ lw(S5, Address(SP, 1 * kWordSize)); |
| 1809 __ addiu(SP, SP, Immediate(2 * kWordSize)); | 1790 __ addiu(SP, SP, Immediate(2 * kWordSize)); |
| 1810 __ RestoreCodePointer(); | |
| 1811 __ LeaveStubFrame(); | 1791 __ LeaveStubFrame(); |
| 1812 __ b(&done_stepping); | 1792 __ b(&done_stepping); |
| 1813 } | 1793 } |
| 1814 } | 1794 } |
| 1815 | 1795 |
| 1816 | 1796 |
| 1817 void StubCode::GenerateOneArgUnoptimizedStaticCallStub(Assembler* assembler) { | 1797 void StubCode::GenerateOneArgUnoptimizedStaticCallStub(Assembler* assembler) { |
| 1818 GenerateUsageCounterIncrement(assembler, T0); | 1798 GenerateUsageCounterIncrement(assembler, T0); |
| 1819 GenerateNArgsCheckInlineCacheStub( | 1799 GenerateNArgsCheckInlineCacheStub( |
| 1820 assembler, 1, kStaticCallMissHandlerOneArgRuntimeEntry, Token::kILLEGAL, | 1800 assembler, 1, kStaticCallMissHandlerOneArgRuntimeEntry, Token::kILLEGAL, |
| (...skipping 19 matching lines...) Expand all Loading... |
| 1840 __ sw(S5, Address(SP, 2 * kWordSize)); // Preserve IC data object. | 1820 __ sw(S5, Address(SP, 2 * kWordSize)); // Preserve IC data object. |
| 1841 __ sw(S4, Address(SP, 1 * kWordSize)); // Preserve args descriptor array. | 1821 __ sw(S4, Address(SP, 1 * kWordSize)); // Preserve args descriptor array. |
| 1842 __ sw(T0, Address(SP, 0 * kWordSize)); // Pass function. | 1822 __ sw(T0, Address(SP, 0 * kWordSize)); // Pass function. |
| 1843 __ CallRuntime(kCompileFunctionRuntimeEntry, 1); | 1823 __ CallRuntime(kCompileFunctionRuntimeEntry, 1); |
| 1844 __ lw(T0, Address(SP, 0 * kWordSize)); // Restore function. | 1824 __ lw(T0, Address(SP, 0 * kWordSize)); // Restore function. |
| 1845 __ lw(S4, Address(SP, 1 * kWordSize)); // Restore args descriptor array. | 1825 __ lw(S4, Address(SP, 1 * kWordSize)); // Restore args descriptor array. |
| 1846 __ lw(S5, Address(SP, 2 * kWordSize)); // Restore IC data array. | 1826 __ lw(S5, Address(SP, 2 * kWordSize)); // Restore IC data array. |
| 1847 __ addiu(SP, SP, Immediate(3 * kWordSize)); | 1827 __ addiu(SP, SP, Immediate(3 * kWordSize)); |
| 1848 __ LeaveStubFrame(); | 1828 __ LeaveStubFrame(); |
| 1849 | 1829 |
| 1850 __ lw(CODE_REG, FieldAddress(T0, Function::code_offset())); | |
| 1851 __ lw(T2, FieldAddress(T0, Function::entry_point_offset())); | 1830 __ lw(T2, FieldAddress(T0, Function::entry_point_offset())); |
| 1852 __ jr(T2); | 1831 __ jr(T2); |
| 1853 } | 1832 } |
| 1854 | 1833 |
| 1855 | 1834 |
| 1856 // S5: Contains an ICData. | 1835 // S5: Contains an ICData. |
| 1857 void StubCode::GenerateICCallBreakpointStub(Assembler* assembler) { | 1836 void StubCode::GenerateICCallBreakpointStub(Assembler* assembler) { |
| 1858 __ Comment("ICCallBreakpoint stub"); | 1837 __ Comment("ICCallBreakpoint stub"); |
| 1859 __ EnterStubFrame(); | 1838 __ EnterStubFrame(); |
| 1860 __ addiu(SP, SP, Immediate(-2 * kWordSize)); | 1839 __ addiu(SP, SP, Immediate(-2 * kWordSize)); |
| 1861 __ sw(S5, Address(SP, 1 * kWordSize)); | 1840 __ sw(S5, Address(SP, 1 * kWordSize)); |
| 1862 __ LoadObject(TMP, Object::null_object()); | 1841 __ LoadObject(TMP, Object::null_object()); |
| 1863 __ sw(TMP, Address(SP, 0 * kWordSize)); | 1842 __ sw(TMP, Address(SP, 0 * kWordSize)); |
| 1864 | 1843 |
| 1865 __ CallRuntime(kBreakpointRuntimeHandlerRuntimeEntry, 0); | 1844 __ CallRuntime(kBreakpointRuntimeHandlerRuntimeEntry, 0); |
| 1866 | 1845 |
| 1867 __ lw(S5, Address(SP, 1 * kWordSize)); | 1846 __ lw(S5, Address(SP, 1 * kWordSize)); |
| 1868 __ lw(CODE_REG, Address(SP, 0 * kWordSize)); | 1847 __ lw(T0, Address(SP, 0 * kWordSize)); |
| 1869 __ addiu(SP, SP, Immediate(2 * kWordSize)); | 1848 __ addiu(SP, SP, Immediate(2 * kWordSize)); |
| 1870 __ LeaveStubFrame(); | 1849 __ LeaveStubFrame(); |
| 1871 __ lw(T0, FieldAddress(CODE_REG, Code::entry_point_offset())); | |
| 1872 __ jr(T0); | 1850 __ jr(T0); |
| 1873 } | 1851 } |
| 1874 | 1852 |
| 1875 | 1853 |
| 1876 void StubCode::GenerateRuntimeCallBreakpointStub(Assembler* assembler) { | 1854 void StubCode::GenerateRuntimeCallBreakpointStub(Assembler* assembler) { |
| 1877 __ Comment("RuntimeCallBreakpoint stub"); | 1855 __ Comment("RuntimeCallBreakpoint stub"); |
| 1878 __ EnterStubFrame(); | 1856 __ EnterStubFrame(); |
| 1879 __ addiu(SP, SP, Immediate(-1 * kWordSize)); | 1857 __ addiu(SP, SP, Immediate(-1 * kWordSize)); |
| 1880 __ LoadObject(TMP, Object::null_object()); | 1858 __ LoadObject(TMP, Object::null_object()); |
| 1881 __ sw(TMP, Address(SP, 0 * kWordSize)); | 1859 __ sw(TMP, Address(SP, 0 * kWordSize)); |
| 1882 | 1860 |
| 1883 __ CallRuntime(kBreakpointRuntimeHandlerRuntimeEntry, 0); | 1861 __ CallRuntime(kBreakpointRuntimeHandlerRuntimeEntry, 0); |
| 1884 | 1862 |
| 1885 __ lw(CODE_REG, Address(SP, 0 * kWordSize)); | 1863 __ lw(T0, Address(SP, 0 * kWordSize)); |
| 1886 __ addiu(SP, SP, Immediate(3 * kWordSize)); | 1864 __ addiu(SP, SP, Immediate(3 * kWordSize)); |
| 1887 __ LeaveStubFrame(); | 1865 __ LeaveStubFrame(); |
| 1888 __ lw(T0, FieldAddress(CODE_REG, Code::entry_point_offset())); | |
| 1889 __ jr(T0); | 1866 __ jr(T0); |
| 1890 } | 1867 } |
| 1891 | 1868 |
| 1892 | 1869 |
| 1893 // Called only from unoptimized code. All relevant registers have been saved. | 1870 // Called only from unoptimized code. All relevant registers have been saved. |
| 1894 // RA: return address. | 1871 // RA: return address. |
| 1895 void StubCode::GenerateDebugStepCheckStub(Assembler* assembler) { | 1872 void StubCode::GenerateDebugStepCheckStub(Assembler* assembler) { |
| 1896 // Check single stepping. | 1873 // Check single stepping. |
| 1897 Label stepping, done_stepping; | 1874 Label stepping, done_stepping; |
| 1898 __ LoadIsolate(T0); | 1875 __ LoadIsolate(T0); |
| (...skipping 170 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2069 __ Comment("OptimizeFunctionStub"); | 2046 __ Comment("OptimizeFunctionStub"); |
| 2070 __ EnterStubFrame(); | 2047 __ EnterStubFrame(); |
| 2071 __ addiu(SP, SP, Immediate(-3 * kWordSize)); | 2048 __ addiu(SP, SP, Immediate(-3 * kWordSize)); |
| 2072 __ sw(S4, Address(SP, 2 * kWordSize)); | 2049 __ sw(S4, Address(SP, 2 * kWordSize)); |
| 2073 // Setup space on stack for return value. | 2050 // Setup space on stack for return value. |
| 2074 __ LoadObject(TMP, Object::null_object()); | 2051 __ LoadObject(TMP, Object::null_object()); |
| 2075 __ sw(TMP, Address(SP, 1 * kWordSize)); | 2052 __ sw(TMP, Address(SP, 1 * kWordSize)); |
| 2076 __ sw(T0, Address(SP, 0 * kWordSize)); | 2053 __ sw(T0, Address(SP, 0 * kWordSize)); |
| 2077 __ CallRuntime(kOptimizeInvokedFunctionRuntimeEntry, 1); | 2054 __ CallRuntime(kOptimizeInvokedFunctionRuntimeEntry, 1); |
| 2078 __ Comment("OptimizeFunctionStub return"); | 2055 __ Comment("OptimizeFunctionStub return"); |
| 2079 __ lw(CODE_REG, Address(SP, 1 * kWordSize)); // Get Code object | 2056 __ lw(T0, Address(SP, 1 * kWordSize)); // Get Code object |
| 2080 __ lw(S4, Address(SP, 2 * kWordSize)); // Restore argument descriptor. | 2057 __ lw(S4, Address(SP, 2 * kWordSize)); // Restore argument descriptor. |
| 2081 __ addiu(SP, SP, Immediate(3 * kWordSize)); // Discard argument. | 2058 __ addiu(SP, SP, Immediate(3 * kWordSize)); // Discard argument. |
| 2082 | 2059 |
| 2083 __ lw(T0, FieldAddress(CODE_REG, Code::entry_point_offset())); | 2060 __ lw(T0, FieldAddress(T0, Code::entry_point_offset())); |
| 2084 __ LeaveStubFrameAndReturn(T0); | 2061 __ LeaveStubFrameAndReturn(T0); |
| 2085 __ break_(0); | 2062 __ break_(0); |
| 2086 } | 2063 } |
| 2087 | 2064 |
| 2088 | 2065 |
| 2089 // Does identical check (object references are equal or not equal) with special | 2066 // Does identical check (object references are equal or not equal) with special |
| 2090 // checks for boxed numbers. | 2067 // checks for boxed numbers. |
| 2091 // Returns: CMPRES1 is zero if equal, non-zero otherwise. | 2068 // Returns: CMPRES1 is zero if equal, non-zero otherwise. |
| 2092 // Note: A Mint cannot contain a value that would fit in Smi, a Bigint | 2069 // Note: A Mint cannot contain a value that would fit in Smi, a Bigint |
| 2093 // cannot contain a value that fits in Mint or Smi. | 2070 // cannot contain a value that fits in Mint or Smi. |
| (...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2194 | 2171 |
| 2195 // Call single step callback in debugger. | 2172 // Call single step callback in debugger. |
| 2196 if (FLAG_support_debugger) { | 2173 if (FLAG_support_debugger) { |
| 2197 __ Bind(&stepping); | 2174 __ Bind(&stepping); |
| 2198 __ EnterStubFrame(); | 2175 __ EnterStubFrame(); |
| 2199 __ addiu(SP, SP, Immediate(-1 * kWordSize)); | 2176 __ addiu(SP, SP, Immediate(-1 * kWordSize)); |
| 2200 __ sw(RA, Address(SP, 0 * kWordSize)); // Return address. | 2177 __ sw(RA, Address(SP, 0 * kWordSize)); // Return address. |
| 2201 __ CallRuntime(kSingleStepHandlerRuntimeEntry, 0); | 2178 __ CallRuntime(kSingleStepHandlerRuntimeEntry, 0); |
| 2202 __ lw(RA, Address(SP, 0 * kWordSize)); | 2179 __ lw(RA, Address(SP, 0 * kWordSize)); |
| 2203 __ addiu(SP, SP, Immediate(1 * kWordSize)); | 2180 __ addiu(SP, SP, Immediate(1 * kWordSize)); |
| 2204 __ RestoreCodePointer(); | |
| 2205 __ LeaveStubFrame(); | 2181 __ LeaveStubFrame(); |
| 2206 __ b(&done_stepping); | 2182 __ b(&done_stepping); |
| 2207 } | 2183 } |
| 2208 } | 2184 } |
| 2209 | 2185 |
| 2210 | 2186 |
| 2211 // Called from optimized code only. | 2187 // Called from optimized code only. |
| 2212 // SP + 4: left operand. | 2188 // SP + 4: left operand. |
| 2213 // SP + 0: right operand. | 2189 // SP + 0: right operand. |
| 2214 // Returns: CMPRES1 is zero if equal, non-zero otherwise. | 2190 // Returns: CMPRES1 is zero if equal, non-zero otherwise. |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2255 | 2231 |
| 2256 __ Bind(&call_target_function); | 2232 __ Bind(&call_target_function); |
| 2257 // Call the target found in the cache. For a class id match, this is a | 2233 // Call the target found in the cache. For a class id match, this is a |
| 2258 // proper target for the given name and arguments descriptor. If the | 2234 // proper target for the given name and arguments descriptor. If the |
| 2259 // illegal class id was found, the target is a cache miss handler that can | 2235 // illegal class id was found, the target is a cache miss handler that can |
| 2260 // be invoked as a normal Dart function. | 2236 // be invoked as a normal Dart function. |
| 2261 __ sll(T1, T3, 2); | 2237 __ sll(T1, T3, 2); |
| 2262 __ addu(T1, T2, T1); | 2238 __ addu(T1, T2, T1); |
| 2263 __ lw(T0, FieldAddress(T1, base + kWordSize)); | 2239 __ lw(T0, FieldAddress(T1, base + kWordSize)); |
| 2264 | 2240 |
| 2265 __ lw(CODE_REG, FieldAddress(T0, Function::code_offset())); | |
| 2266 __ lw(target, FieldAddress(T0, Function::entry_point_offset())); | 2241 __ lw(target, FieldAddress(T0, Function::entry_point_offset())); |
| 2267 } | 2242 } |
| 2268 | 2243 |
| 2269 | 2244 |
| 2270 // Called from megamorphic calls. | 2245 // Called from megamorphic calls. |
| 2271 // T0: receiver. | 2246 // T0: receiver. |
| 2272 // T1: lookup cache. | 2247 // T1: lookup cache. |
| 2273 // Result: | 2248 // Result: |
| 2274 // T1: entry point. | 2249 // T1: entry point. |
| 2275 void StubCode::GenerateMegamorphicLookupStub(Assembler* assembler) { | 2250 void StubCode::GenerateMegamorphicLookupStub(Assembler* assembler) { |
| 2276 EmitMegamorphicLookup(assembler, T0, T1, T1); | 2251 EmitMegamorphicLookup(assembler, T0, T1, T1); |
| 2277 __ Ret(); | 2252 __ Ret(); |
| 2278 } | 2253 } |
| 2279 | 2254 |
| 2280 } // namespace dart | 2255 } // namespace dart |
| 2281 | 2256 |
| 2282 #endif // defined TARGET_ARCH_MIPS | 2257 #endif // defined TARGET_ARCH_MIPS |
| OLD | NEW |