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