| 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_ARM) | 6 #if defined(TARGET_ARCH_ARM) |
| 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/cpu.h" | 10 #include "vm/cpu.h" |
| (...skipping 24 matching lines...) Expand all Loading... |
| 35 // SP : address of last argument in argument array. | 35 // SP : address of last argument in argument array. |
| 36 // SP + 4*R4 - 4 : address of first argument in argument array. | 36 // SP + 4*R4 - 4 : address of first argument in argument array. |
| 37 // SP + 4*R4 : address of return value. | 37 // SP + 4*R4 : address of return value. |
| 38 // R5 : address of the runtime function to call. | 38 // R5 : address of the runtime function to call. |
| 39 // R4 : number of arguments to the call. | 39 // R4 : number of arguments to the call. |
| 40 void StubCode::GenerateCallToRuntimeStub(Assembler* assembler) { | 40 void StubCode::GenerateCallToRuntimeStub(Assembler* assembler) { |
| 41 const intptr_t thread_offset = NativeArguments::thread_offset(); | 41 const intptr_t thread_offset = NativeArguments::thread_offset(); |
| 42 const intptr_t argc_tag_offset = NativeArguments::argc_tag_offset(); | 42 const intptr_t argc_tag_offset = NativeArguments::argc_tag_offset(); |
| 43 const intptr_t argv_offset = NativeArguments::argv_offset(); | 43 const intptr_t argv_offset = NativeArguments::argv_offset(); |
| 44 const intptr_t retval_offset = NativeArguments::retval_offset(); | 44 const intptr_t retval_offset = NativeArguments::retval_offset(); |
| 45 const intptr_t exitframe_last_param_slot_from_fp = 2; | |
| 46 | 45 |
| 47 __ EnterStubFrame(); | 46 __ EnterStubFrame(); |
| 48 | 47 |
| 49 COMPILE_ASSERT((kAbiPreservedCpuRegs & (1 << R9)) != 0); | 48 COMPILE_ASSERT((kAbiPreservedCpuRegs & (1 << R7)) != 0); |
| 50 __ LoadIsolate(R9); | 49 __ LoadIsolate(R7); |
| 51 | 50 |
| 52 // Save exit frame information to enable stack walking as we are about | 51 // Save exit frame information to enable stack walking as we are about |
| 53 // to transition to Dart VM C++ code. | 52 // to transition to Dart VM C++ code. |
| 54 __ StoreToOffset(kWord, FP, THR, Thread::top_exit_frame_info_offset()); | 53 __ StoreToOffset(kWord, FP, THR, Thread::top_exit_frame_info_offset()); |
| 55 | 54 |
| 56 #if defined(DEBUG) | 55 #if defined(DEBUG) |
| 57 { Label ok; | 56 { Label ok; |
| 58 // Check that we are always entering from Dart code. | 57 // Check that we are always entering from Dart code. |
| 59 __ LoadFromOffset(kWord, R6, R9, Isolate::vm_tag_offset()); | 58 __ LoadFromOffset(kWord, R6, R7, Isolate::vm_tag_offset()); |
| 60 __ CompareImmediate(R6, VMTag::kDartTagId); | 59 __ CompareImmediate(R6, VMTag::kDartTagId); |
| 61 __ b(&ok, EQ); | 60 __ b(&ok, EQ); |
| 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 __ StoreToOffset(kWord, R5, R9, Isolate::vm_tag_offset()); | 67 __ StoreToOffset(kWord, R5, R7, 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(0); | 72 __ ReserveAlignedFrameSpace(0); |
| 74 | 73 |
| 75 // Pass NativeArguments structure by value and call runtime. | 74 // Pass NativeArguments structure by value and call runtime. |
| 76 // Registers R0, R1, R2, and R3 are used. | 75 // Registers R0, R1, R2, and R3 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(R0, Operand(THR)); | 79 __ mov(R0, Operand(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(R1, Operand(R4)); // Set argc in NativeArguments. | 84 __ mov(R1, Operand(R4)); // Set argc in NativeArguments. |
| 86 | 85 |
| 87 ASSERT(argv_offset == 2 * kWordSize); | 86 ASSERT(argv_offset == 2 * kWordSize); |
| 88 __ add(R2, FP, Operand(R4, LSL, 2)); // Compute argv. | 87 __ add(R2, FP, Operand(R4, LSL, 2)); // Compute argv. |
| 89 // Set argv in NativeArguments. | 88 // Set argv in NativeArguments. |
| 90 __ AddImmediate(R2, exitframe_last_param_slot_from_fp * kWordSize); | 89 __ AddImmediate(R2, kParamEndSlotFromFp * kWordSize); |
| 91 | 90 |
| 92 ASSERT(retval_offset == 3 * kWordSize); | 91 ASSERT(retval_offset == 3 * kWordSize); |
| 93 __ add(R3, R2, Operand(kWordSize)); // Retval is next to 1st argument. | 92 __ add(R3, R2, Operand(kWordSize)); // Retval is next to 1st argument. |
| 94 | 93 |
| 95 // Call runtime or redirection via simulator. | 94 // Call runtime or redirection via simulator. |
| 96 __ blx(R5); | 95 __ blx(R5); |
| 97 | 96 |
| 98 // Mark that the isolate is executing Dart code. | 97 // Mark that the isolate is executing Dart code. |
| 99 __ LoadImmediate(R2, VMTag::kDartTagId); | 98 __ LoadImmediate(R2, VMTag::kDartTagId); |
| 100 __ StoreToOffset(kWord, R2, R9, Isolate::vm_tag_offset()); | 99 __ StoreToOffset(kWord, R2, R7, Isolate::vm_tag_offset()); |
| 101 | 100 |
| 102 // Reset exit frame information in Isolate structure. | 101 // Reset exit frame information in Isolate structure. |
| 103 __ LoadImmediate(R2, 0); | 102 __ LoadImmediate(R2, 0); |
| 104 __ StoreToOffset(kWord, R2, THR, Thread::top_exit_frame_info_offset()); | 103 __ StoreToOffset(kWord, R2, THR, Thread::top_exit_frame_info_offset()); |
| 105 | 104 |
| 106 __ LeaveStubFrame(); | 105 __ LeaveStubFrame(); |
| 107 __ Ret(); | 106 __ Ret(); |
| 108 } | 107 } |
| 109 | 108 |
| 110 | 109 |
| (...skipping 23 matching lines...) Expand all Loading... |
| 134 // R2 : address of first argument in argument array. | 133 // R2 : address of first argument in argument array. |
| 135 // R1 : argc_tag including number of arguments and function kind. | 134 // R1 : argc_tag including number of arguments and function kind. |
| 136 void StubCode::GenerateCallNativeCFunctionStub(Assembler* assembler) { | 135 void StubCode::GenerateCallNativeCFunctionStub(Assembler* assembler) { |
| 137 const intptr_t thread_offset = NativeArguments::thread_offset(); | 136 const intptr_t thread_offset = NativeArguments::thread_offset(); |
| 138 const intptr_t argc_tag_offset = NativeArguments::argc_tag_offset(); | 137 const intptr_t argc_tag_offset = NativeArguments::argc_tag_offset(); |
| 139 const intptr_t argv_offset = NativeArguments::argv_offset(); | 138 const intptr_t argv_offset = NativeArguments::argv_offset(); |
| 140 const intptr_t retval_offset = NativeArguments::retval_offset(); | 139 const intptr_t retval_offset = NativeArguments::retval_offset(); |
| 141 | 140 |
| 142 __ EnterStubFrame(); | 141 __ EnterStubFrame(); |
| 143 | 142 |
| 144 COMPILE_ASSERT((kAbiPreservedCpuRegs & (1 << R9)) != 0); | 143 COMPILE_ASSERT((kAbiPreservedCpuRegs & (1 << R7)) != 0); |
| 145 __ LoadIsolate(R9); | 144 __ LoadIsolate(R7); |
| 146 | 145 |
| 147 // Save exit frame information to enable stack walking as we are about | 146 // Save exit frame information to enable stack walking as we are about |
| 148 // to transition to native code. | 147 // to transition to native code. |
| 149 __ StoreToOffset(kWord, FP, THR, Thread::top_exit_frame_info_offset()); | 148 __ StoreToOffset(kWord, FP, THR, Thread::top_exit_frame_info_offset()); |
| 150 | 149 |
| 151 #if defined(DEBUG) | 150 #if defined(DEBUG) |
| 152 { Label ok; | 151 { Label ok; |
| 153 // Check that we are always entering from Dart code. | 152 // Check that we are always entering from Dart code. |
| 154 __ LoadFromOffset(kWord, R6, R9, Isolate::vm_tag_offset()); | 153 __ LoadFromOffset(kWord, R6, R7, Isolate::vm_tag_offset()); |
| 155 __ CompareImmediate(R6, VMTag::kDartTagId); | 154 __ CompareImmediate(R6, VMTag::kDartTagId); |
| 156 __ b(&ok, EQ); | 155 __ b(&ok, EQ); |
| 157 __ Stop("Not coming from Dart code."); | 156 __ Stop("Not coming from Dart code."); |
| 158 __ Bind(&ok); | 157 __ Bind(&ok); |
| 159 } | 158 } |
| 160 #endif | 159 #endif |
| 161 | 160 |
| 162 // Mark that the isolate is executing Native code. | 161 // Mark that the isolate is executing Native code. |
| 163 __ StoreToOffset(kWord, R5, R9, Isolate::vm_tag_offset()); | 162 __ StoreToOffset(kWord, R5, R7, Isolate::vm_tag_offset()); |
| 164 | 163 |
| 165 // Reserve space for the native arguments structure passed on the stack (the | 164 // Reserve space for the native arguments structure passed on the stack (the |
| 166 // outgoing pointer parameter to the native arguments structure is passed in | 165 // outgoing pointer parameter to the native arguments structure is passed in |
| 167 // R0) and align frame before entering the C++ world. | 166 // R0) and align frame before entering the C++ world. |
| 168 __ ReserveAlignedFrameSpace(sizeof(NativeArguments)); | 167 __ ReserveAlignedFrameSpace(sizeof(NativeArguments)); |
| 169 | 168 |
| 170 // Initialize NativeArguments structure and call native function. | 169 // Initialize NativeArguments structure and call native function. |
| 171 // Registers R0, R1, R2, and R3 are used. | 170 // Registers R0, R1, R2, and R3 are used. |
| 172 | 171 |
| 173 ASSERT(thread_offset == 0 * kWordSize); | 172 ASSERT(thread_offset == 0 * kWordSize); |
| 174 // Set thread in NativeArgs. | 173 // Set thread in NativeArgs. |
| 175 __ mov(R0, Operand(THR)); | 174 __ mov(R0, Operand(THR)); |
| 176 | 175 |
| 177 // There are no native calls to closures, so we do not need to set the tag | 176 // There are no native calls to closures, so we do not need to set the tag |
| 178 // bits kClosureFunctionBit and kInstanceFunctionBit in argc_tag_. | 177 // bits kClosureFunctionBit and kInstanceFunctionBit in argc_tag_. |
| 179 ASSERT(argc_tag_offset == 1 * kWordSize); | 178 ASSERT(argc_tag_offset == 1 * kWordSize); |
| 180 // Set argc in NativeArguments: R1 already contains argc. | 179 // Set argc in NativeArguments: R1 already contains argc. |
| 181 | 180 |
| 182 ASSERT(argv_offset == 2 * kWordSize); | 181 ASSERT(argv_offset == 2 * kWordSize); |
| 183 // Set argv in NativeArguments: R2 already contains argv. | 182 // Set argv in NativeArguments: R2 already contains argv. |
| 184 | 183 |
| 185 ASSERT(retval_offset == 3 * kWordSize); | 184 ASSERT(retval_offset == 3 * kWordSize); |
| 186 __ add(R3, FP, Operand(3 * kWordSize)); // Set retval in NativeArgs. | 185 // Set retval in NativeArgs. |
| 186 __ add(R3, FP, Operand(kCallerSpSlotFromFp * kWordSize)); |
| 187 | 187 |
| 188 // Passing the structure by value as in runtime calls would require changing | 188 // Passing the structure by value as in runtime calls would require changing |
| 189 // Dart API for native functions. | 189 // Dart API for native functions. |
| 190 // For now, space is reserved on the stack and we pass a pointer to it. | 190 // For now, space is reserved on the stack and we pass a pointer to it. |
| 191 __ stm(IA, SP, (1 << R0) | (1 << R1) | (1 << R2) | (1 << R3)); | 191 __ stm(IA, SP, (1 << R0) | (1 << R1) | (1 << R2) | (1 << R3)); |
| 192 __ mov(R0, Operand(SP)); // Pass the pointer to the NativeArguments. | 192 __ mov(R0, Operand(SP)); // Pass the pointer to the NativeArguments. |
| 193 | 193 |
| 194 __ mov(R1, Operand(R5)); // Pass the function entrypoint to call. | 194 __ mov(R1, Operand(R5)); // Pass the function entrypoint to call. |
| 195 // Call native function invocation wrapper or redirection via simulator. | 195 // Call native function invocation wrapper or redirection via simulator. |
| 196 #if defined(USING_SIMULATOR) | 196 #if defined(USING_SIMULATOR) |
| 197 uword entry = reinterpret_cast<uword>(NativeEntry::NativeCallWrapper); | 197 uword entry = reinterpret_cast<uword>(NativeEntry::NativeCallWrapper); |
| 198 entry = Simulator::RedirectExternalReference( | 198 const ExternalLabel label(Simulator::RedirectExternalReference( |
| 199 entry, Simulator::kNativeCall, NativeEntry::kNumCallWrapperArguments); | 199 entry, Simulator::kNativeCall, NativeEntry::kNumCallWrapperArguments)); |
| 200 __ LoadImmediate(R2, entry); | 200 __ LoadExternalLabel(R2, &label, kNotPatchable); |
| 201 __ blx(R2); | 201 __ blx(R2); |
| 202 #else | 202 #else |
| 203 __ BranchLink(&NativeEntry::NativeCallWrapperLabel(), kNotPatchable); | 203 __ LoadExternalLabel( |
| 204 LR, &NativeEntry::NativeCallWrapperLabel(), kNotPatchable); |
| 205 __ blx(LR); |
| 204 #endif | 206 #endif |
| 205 | 207 |
| 206 // Mark that the isolate is executing Dart code. | 208 // Mark that the isolate is executing Dart code. |
| 207 __ LoadImmediate(R2, VMTag::kDartTagId); | 209 __ LoadImmediate(R2, VMTag::kDartTagId); |
| 208 __ StoreToOffset(kWord, R2, R9, Isolate::vm_tag_offset()); | 210 __ StoreToOffset(kWord, R2, R7, Isolate::vm_tag_offset()); |
| 209 | 211 |
| 210 // Reset exit frame information in Isolate structure. | 212 // Reset exit frame information in Isolate structure. |
| 211 __ LoadImmediate(R2, 0); | 213 __ LoadImmediate(R2, 0); |
| 212 __ StoreToOffset(kWord, R2, THR, Thread::top_exit_frame_info_offset()); | 214 __ StoreToOffset(kWord, R2, THR, Thread::top_exit_frame_info_offset()); |
| 213 | 215 |
| 214 __ LeaveStubFrame(); | 216 __ LeaveStubFrame(); |
| 215 __ Ret(); | 217 __ Ret(); |
| 216 } | 218 } |
| 217 | 219 |
| 218 | 220 |
| 219 // Input parameters: | 221 // Input parameters: |
| 220 // LR : return address. | 222 // LR : return address. |
| 221 // SP : address of return value. | 223 // SP : address of return value. |
| 222 // R5 : address of the native function to call. | 224 // R5 : address of the native function to call. |
| 223 // R2 : address of first argument in argument array. | 225 // R2 : address of first argument in argument array. |
| 224 // R1 : argc_tag including number of arguments and function kind. | 226 // R1 : argc_tag including number of arguments and function kind. |
| 225 void StubCode::GenerateCallBootstrapCFunctionStub(Assembler* assembler) { | 227 void StubCode::GenerateCallBootstrapCFunctionStub(Assembler* assembler) { |
| 226 const intptr_t thread_offset = NativeArguments::thread_offset(); | 228 const intptr_t thread_offset = NativeArguments::thread_offset(); |
| 227 const intptr_t argc_tag_offset = NativeArguments::argc_tag_offset(); | 229 const intptr_t argc_tag_offset = NativeArguments::argc_tag_offset(); |
| 228 const intptr_t argv_offset = NativeArguments::argv_offset(); | 230 const intptr_t argv_offset = NativeArguments::argv_offset(); |
| 229 const intptr_t retval_offset = NativeArguments::retval_offset(); | 231 const intptr_t retval_offset = NativeArguments::retval_offset(); |
| 230 | 232 |
| 231 __ EnterStubFrame(); | 233 __ EnterStubFrame(); |
| 232 | 234 |
| 233 COMPILE_ASSERT((kAbiPreservedCpuRegs & (1 << R9)) != 0); | 235 COMPILE_ASSERT((kAbiPreservedCpuRegs & (1 << R7)) != 0); |
| 234 __ LoadIsolate(R9); | 236 __ LoadIsolate(R7); |
| 235 | 237 |
| 236 // Save exit frame information to enable stack walking as we are about | 238 // Save exit frame information to enable stack walking as we are about |
| 237 // to transition to native code. | 239 // to transition to native code. |
| 238 __ StoreToOffset(kWord, FP, THR, Thread::top_exit_frame_info_offset()); | 240 __ StoreToOffset(kWord, FP, THR, Thread::top_exit_frame_info_offset()); |
| 239 | 241 |
| 240 #if defined(DEBUG) | 242 #if defined(DEBUG) |
| 241 { Label ok; | 243 { Label ok; |
| 242 // Check that we are always entering from Dart code. | 244 // Check that we are always entering from Dart code. |
| 243 __ LoadFromOffset(kWord, R6, R9, Isolate::vm_tag_offset()); | 245 __ LoadFromOffset(kWord, R6, R7, Isolate::vm_tag_offset()); |
| 244 __ CompareImmediate(R6, VMTag::kDartTagId); | 246 __ CompareImmediate(R6, VMTag::kDartTagId); |
| 245 __ b(&ok, EQ); | 247 __ b(&ok, EQ); |
| 246 __ Stop("Not coming from Dart code."); | 248 __ Stop("Not coming from Dart code."); |
| 247 __ Bind(&ok); | 249 __ Bind(&ok); |
| 248 } | 250 } |
| 249 #endif | 251 #endif |
| 250 | 252 |
| 251 // Mark that the isolate is executing Native code. | 253 // Mark that the isolate is executing Native code. |
| 252 __ StoreToOffset(kWord, R5, R9, Isolate::vm_tag_offset()); | 254 __ StoreToOffset(kWord, R5, R7, Isolate::vm_tag_offset()); |
| 253 | 255 |
| 254 // Reserve space for the native arguments structure passed on the stack (the | 256 // Reserve space for the native arguments structure passed on the stack (the |
| 255 // outgoing pointer parameter to the native arguments structure is passed in | 257 // outgoing pointer parameter to the native arguments structure is passed in |
| 256 // R0) and align frame before entering the C++ world. | 258 // R0) and align frame before entering the C++ world. |
| 257 __ ReserveAlignedFrameSpace(sizeof(NativeArguments)); | 259 __ ReserveAlignedFrameSpace(sizeof(NativeArguments)); |
| 258 | 260 |
| 259 // Initialize NativeArguments structure and call native function. | 261 // Initialize NativeArguments structure and call native function. |
| 260 // Registers R0, R1, R2, and R3 are used. | 262 // Registers R0, R1, R2, and R3 are used. |
| 261 | 263 |
| 262 ASSERT(thread_offset == 0 * kWordSize); | 264 ASSERT(thread_offset == 0 * kWordSize); |
| 263 // Set thread in NativeArgs. | 265 // Set thread in NativeArgs. |
| 264 __ mov(R0, Operand(THR)); | 266 __ mov(R0, Operand(THR)); |
| 265 | 267 |
| 266 // 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 |
| 267 // bits kClosureFunctionBit and kInstanceFunctionBit in argc_tag_. | 269 // bits kClosureFunctionBit and kInstanceFunctionBit in argc_tag_. |
| 268 ASSERT(argc_tag_offset == 1 * kWordSize); | 270 ASSERT(argc_tag_offset == 1 * kWordSize); |
| 269 // Set argc in NativeArguments: R1 already contains argc. | 271 // Set argc in NativeArguments: R1 already contains argc. |
| 270 | 272 |
| 271 ASSERT(argv_offset == 2 * kWordSize); | 273 ASSERT(argv_offset == 2 * kWordSize); |
| 272 // Set argv in NativeArguments: R2 already contains argv. | 274 // Set argv in NativeArguments: R2 already contains argv. |
| 273 | 275 |
| 274 ASSERT(retval_offset == 3 * kWordSize); | 276 ASSERT(retval_offset == 3 * kWordSize); |
| 275 __ add(R3, FP, Operand(3 * kWordSize)); // Set retval in NativeArgs. | 277 // Set retval in NativeArgs. |
| 278 __ add(R3, FP, Operand(kCallerSpSlotFromFp * kWordSize)); |
| 276 | 279 |
| 277 // 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 |
| 278 // Dart API for native functions. | 281 // Dart API for native functions. |
| 279 // 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. |
| 280 __ stm(IA, SP, (1 << R0) | (1 << R1) | (1 << R2) | (1 << R3)); | 283 __ stm(IA, SP, (1 << R0) | (1 << R1) | (1 << R2) | (1 << R3)); |
| 281 __ mov(R0, Operand(SP)); // Pass the pointer to the NativeArguments. | 284 __ mov(R0, Operand(SP)); // Pass the pointer to the NativeArguments. |
| 282 | 285 |
| 283 // Call native function or redirection via simulator. | 286 // Call native function or redirection via simulator. |
| 284 __ blx(R5); | 287 __ blx(R5); |
| 285 | 288 |
| 286 // Mark that the isolate is executing Dart code. | 289 // Mark that the isolate is executing Dart code. |
| 287 __ LoadImmediate(R2, VMTag::kDartTagId); | 290 __ LoadImmediate(R2, VMTag::kDartTagId); |
| 288 __ StoreToOffset(kWord, R2, R9, Isolate::vm_tag_offset()); | 291 __ StoreToOffset(kWord, R2, R7, Isolate::vm_tag_offset()); |
| 289 | 292 |
| 290 // Reset exit frame information in Isolate structure. | 293 // Reset exit frame information in Isolate structure. |
| 291 __ LoadImmediate(R2, 0); | 294 __ LoadImmediate(R2, 0); |
| 292 __ StoreToOffset(kWord, R2, THR, Thread::top_exit_frame_info_offset()); | 295 __ StoreToOffset(kWord, R2, THR, Thread::top_exit_frame_info_offset()); |
| 293 | 296 |
| 294 __ LeaveStubFrame(); | 297 __ LeaveStubFrame(); |
| 295 __ Ret(); | 298 __ Ret(); |
| 296 } | 299 } |
| 297 | 300 |
| 298 | 301 |
| 299 // Input parameters: | 302 // Input parameters: |
| 300 // R4: arguments descriptor array. | 303 // R4: arguments descriptor array. |
| 301 void StubCode::GenerateCallStaticFunctionStub(Assembler* assembler) { | 304 void StubCode::GenerateCallStaticFunctionStub(Assembler* assembler) { |
| 302 // Create a stub frame as we are pushing some objects on the stack before | 305 // Create a stub frame as we are pushing some objects on the stack before |
| 303 // calling into the runtime. | 306 // calling into the runtime. |
| 304 __ EnterStubFrame(); | 307 __ EnterStubFrame(); |
| 305 // Setup space on stack for return value and preserve arguments descriptor. | 308 // Setup space on stack for return value and preserve arguments descriptor. |
| 306 __ LoadObject(R0, Object::null_object()); | 309 __ LoadObject(R0, Object::null_object()); |
| 307 __ PushList((1 << R0) | (1 << R4)); | 310 __ PushList((1 << R0) | (1 << R4)); |
| 308 __ CallRuntime(kPatchStaticCallRuntimeEntry, 0); | 311 __ CallRuntime(kPatchStaticCallRuntimeEntry, 0); |
| 309 // Get Code object result and restore arguments descriptor array. | 312 // Get Code object result and restore arguments descriptor array. |
| 310 __ PopList((1 << R0) | (1 << R4)); | 313 __ PopList((1 << R0) | (1 << R4)); |
| 311 // Remove the stub frame. | 314 // Remove the stub frame. |
| 312 __ LeaveStubFrame(); | 315 __ LeaveStubFrame(); |
| 313 // Jump to the dart function. | 316 // Jump to the dart function. |
| 317 __ mov(CODE_REG, Operand(R0)); |
| 314 __ ldr(R0, FieldAddress(R0, Code::entry_point_offset())); | 318 __ ldr(R0, FieldAddress(R0, Code::entry_point_offset())); |
| 315 __ bx(R0); | 319 __ bx(R0); |
| 316 } | 320 } |
| 317 | 321 |
| 318 | 322 |
| 319 // Called from a static call only when an invalid code has been entered | 323 // Called from a static call only when an invalid code has been entered |
| 320 // (invalid because its function was optimized or deoptimized). | 324 // (invalid because its function was optimized or deoptimized). |
| 321 // R4: arguments descriptor array. | 325 // R4: arguments descriptor array. |
| 322 void StubCode::GenerateFixCallersTargetStub(Assembler* assembler) { | 326 void StubCode::GenerateFixCallersTargetStub(Assembler* assembler) { |
| 327 // Load code pointer to this stub from the thread: |
| 328 // The one that is passed in, is not correct - it points to the code object |
| 329 // that needs to be replaced. |
| 330 __ ldr(CODE_REG, Address(THR, Thread::fix_callers_target_code_offset())); |
| 323 // Create a stub frame as we are pushing some objects on the stack before | 331 // Create a stub frame as we are pushing some objects on the stack before |
| 324 // calling into the runtime. | 332 // calling into the runtime. |
| 325 __ EnterStubFrame(); | 333 __ EnterStubFrame(); |
| 326 // Setup space on stack for return value and preserve arguments descriptor. | 334 // Setup space on stack for return value and preserve arguments descriptor. |
| 327 __ LoadObject(R0, Object::null_object()); | 335 __ LoadObject(R0, Object::null_object()); |
| 328 __ PushList((1 << R0) | (1 << R4)); | 336 __ PushList((1 << R0) | (1 << R4)); |
| 329 __ CallRuntime(kFixCallersTargetRuntimeEntry, 0); | 337 __ CallRuntime(kFixCallersTargetRuntimeEntry, 0); |
| 330 // Get Code object result and restore arguments descriptor array. | 338 // Get Code object result and restore arguments descriptor array. |
| 331 __ PopList((1 << R0) | (1 << R4)); | 339 __ PopList((1 << R0) | (1 << R4)); |
| 332 // Remove the stub frame. | 340 // Remove the stub frame. |
| 333 __ LeaveStubFrame(); | 341 __ LeaveStubFrame(); |
| 334 // Jump to the dart function. | 342 // Jump to the dart function. |
| 343 __ mov(CODE_REG, Operand(R0)); |
| 335 __ ldr(R0, FieldAddress(R0, Code::entry_point_offset())); | 344 __ ldr(R0, FieldAddress(R0, Code::entry_point_offset())); |
| 336 __ bx(R0); | 345 __ bx(R0); |
| 337 } | 346 } |
| 338 | 347 |
| 339 | 348 |
| 340 // Called from object allocate instruction when the allocation stub has been | 349 // Called from object allocate instruction when the allocation stub has been |
| 341 // disabled. | 350 // disabled. |
| 342 void StubCode::GenerateFixAllocationStubTargetStub(Assembler* assembler) { | 351 void StubCode::GenerateFixAllocationStubTargetStub(Assembler* assembler) { |
| 352 // Load code pointer to this stub from the thread: |
| 353 // The one that is passed in, is not correct - it points to the code object |
| 354 // that needs to be replaced. |
| 355 __ ldr(CODE_REG, Address(THR, Thread::fix_allocation_stub_code_offset())); |
| 343 __ EnterStubFrame(); | 356 __ EnterStubFrame(); |
| 344 // Setup space on stack for return value. | 357 // Setup space on stack for return value. |
| 345 __ LoadObject(R0, Object::null_object()); | 358 __ LoadObject(R0, Object::null_object()); |
| 346 __ Push(R0); | 359 __ Push(R0); |
| 347 __ CallRuntime(kFixAllocationStubTargetRuntimeEntry, 0); | 360 __ CallRuntime(kFixAllocationStubTargetRuntimeEntry, 0); |
| 348 // Get Code object result. | 361 // Get Code object result. |
| 349 __ Pop(R0); | 362 __ Pop(R0); |
| 350 // Remove the stub frame. | 363 // Remove the stub frame. |
| 351 __ LeaveStubFrame(); | 364 __ LeaveStubFrame(); |
| 352 // Jump to the dart function. | 365 // Jump to the dart function. |
| 366 __ mov(CODE_REG, Operand(R0)); |
| 353 __ ldr(R0, FieldAddress(R0, Code::entry_point_offset())); | 367 __ ldr(R0, FieldAddress(R0, Code::entry_point_offset())); |
| 354 __ bx(R0); | 368 __ bx(R0); |
| 355 } | 369 } |
| 356 | 370 |
| 357 | 371 |
| 358 // Input parameters: | 372 // Input parameters: |
| 359 // R2: smi-tagged argument count, may be zero. | 373 // R2: smi-tagged argument count, may be zero. |
| 360 // FP[kParamEndSlotFromFp + 1]: last argument. | 374 // FP[kParamEndSlotFromFp + 1]: last argument. |
| 361 static void PushArgumentsArray(Assembler* assembler) { | 375 static void PushArgumentsArray(Assembler* assembler) { |
| 362 // Allocate array to store arguments of caller. | 376 // Allocate array to store arguments of caller. |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 396 // - Materialize objects that require allocation (e.g. Double instances). | 410 // - Materialize objects that require allocation (e.g. Double instances). |
| 397 // GC can occur only after frame is fully rewritten. | 411 // GC can occur only after frame is fully rewritten. |
| 398 // Stack after EnterFrame(...) below: | 412 // Stack after EnterFrame(...) below: |
| 399 // +------------------+ | 413 // +------------------+ |
| 400 // | Saved PP | <- TOS | 414 // | Saved PP | <- TOS |
| 401 // +------------------+ | 415 // +------------------+ |
| 402 // | Saved FP | <- FP of stub | 416 // | Saved FP | <- FP of stub |
| 403 // +------------------+ | 417 // +------------------+ |
| 404 // | Saved LR | (deoptimization point) | 418 // | Saved LR | (deoptimization point) |
| 405 // +------------------+ | 419 // +------------------+ |
| 406 // | PC marker | | 420 // | pc marker | |
| 421 // +------------------+ |
| 422 // | Saved CODE_REG | |
| 407 // +------------------+ | 423 // +------------------+ |
| 408 // | ... | <- SP of optimized frame | 424 // | ... | <- SP of optimized frame |
| 409 // | 425 // |
| 410 // Parts of the code cannot GC, part of the code can GC. | 426 // Parts of the code cannot GC, part of the code can GC. |
| 411 static void GenerateDeoptimizationSequence(Assembler* assembler, | 427 static void GenerateDeoptimizationSequence(Assembler* assembler, |
| 412 bool preserve_result) { | 428 DeoptStubKind kind) { |
| 413 // DeoptimizeCopyFrame expects a Dart frame, i.e. EnterDartFrame(0), but there | 429 // DeoptimizeCopyFrame expects a Dart frame, i.e. EnterDartFrame(0), but there |
| 414 // is no need to set the correct PC marker or load PP, since they get patched. | 430 // is no need to set the correct PC marker or load PP, since they get patched. |
| 415 | 431 |
| 416 // IP has the potentially live LR value. LR was clobbered by the call with | 432 // IP has the potentially live LR value. LR was clobbered by the call with |
| 417 // the return address, so move it into IP to set up the Dart frame. | 433 // the return address, so move it into IP to set up the Dart frame. |
| 418 __ eor(IP, IP, Operand(LR)); | 434 __ eor(IP, IP, Operand(LR)); |
| 419 __ eor(LR, IP, Operand(LR)); | 435 __ eor(LR, IP, Operand(LR)); |
| 420 __ eor(IP, IP, Operand(LR)); | 436 __ eor(IP, IP, Operand(LR)); |
| 421 | 437 |
| 422 // Set up the frame manually. We can't use EnterFrame because we can't | 438 // Set up the frame manually with return address now stored in IP. |
| 423 // clobber LR (or any other register) with 0, yet. | 439 __ EnterFrame((1 << PP) | (1 << CODE_REG) | (1 << FP) | (1 << IP), 0); |
| 424 __ sub(SP, SP, Operand(kWordSize)); // Make room for PC marker of 0. | |
| 425 __ Push(IP); // Push return address. | |
| 426 __ Push(FP); | |
| 427 __ mov(FP, Operand(SP)); | |
| 428 __ Push(PP); | |
| 429 | |
| 430 __ LoadPoolPointer(); | 440 __ LoadPoolPointer(); |
| 431 | 441 |
| 432 // Now that IP holding the return address has been written to the stack, | |
| 433 // we can clobber it with 0 to write the null PC marker. | |
| 434 __ mov(IP, Operand(0)); | |
| 435 __ str(IP, Address(SP, +3 * kWordSize)); | |
| 436 | |
| 437 // The code in this frame may not cause GC. kDeoptimizeCopyFrameRuntimeEntry | 442 // The code in this frame may not cause GC. kDeoptimizeCopyFrameRuntimeEntry |
| 438 // and kDeoptimizeFillFrameRuntimeEntry are leaf runtime calls. | 443 // and kDeoptimizeFillFrameRuntimeEntry are leaf runtime calls. |
| 439 const intptr_t saved_result_slot_from_fp = | 444 const intptr_t saved_result_slot_from_fp = |
| 440 kFirstLocalSlotFromFp + 1 - (kNumberOfCpuRegisters - R0); | 445 kFirstLocalSlotFromFp + 1 - (kNumberOfCpuRegisters - R0); |
| 441 // Result in R0 is preserved as part of pushing all registers below. | 446 // Result in R0 is preserved as part of pushing all registers below. |
| 442 | 447 |
| 443 // Push registers in their enumeration order: lowest register number at | 448 // Push registers in their enumeration order: lowest register number at |
| 444 // lowest address. | 449 // lowest address. |
| 445 __ PushList(kAllCpuRegistersList); | 450 for (intptr_t i = kNumberOfCpuRegisters - 1; i >= 0; --i) { |
| 451 if (i == CODE_REG) { |
| 452 // Save the original value of CODE_REG pushed before invoking this stub |
| 453 // instead of the value used to call this stub. |
| 454 COMPILE_ASSERT(IP > CODE_REG); // Assert IP is pushed first. |
| 455 __ ldr(IP, Address(FP, kCallerSpSlotFromFp * kWordSize)); |
| 456 __ Push(IP); |
| 457 } else { |
| 458 __ Push(static_cast<Register>(i)); |
| 459 } |
| 460 } |
| 446 | 461 |
| 447 if (TargetCPUFeatures::vfp_supported()) { | 462 if (TargetCPUFeatures::vfp_supported()) { |
| 448 ASSERT(kFpuRegisterSize == 4 * kWordSize); | 463 ASSERT(kFpuRegisterSize == 4 * kWordSize); |
| 449 if (kNumberOfDRegisters > 16) { | 464 if (kNumberOfDRegisters > 16) { |
| 450 __ vstmd(DB_W, SP, D16, kNumberOfDRegisters - 16); | 465 __ vstmd(DB_W, SP, D16, kNumberOfDRegisters - 16); |
| 451 __ vstmd(DB_W, SP, D0, 16); | 466 __ vstmd(DB_W, SP, D0, 16); |
| 452 } else { | 467 } else { |
| 453 __ vstmd(DB_W, SP, D0, kNumberOfDRegisters); | 468 __ vstmd(DB_W, SP, D0, kNumberOfDRegisters); |
| 454 } | 469 } |
| 455 } else { | 470 } else { |
| 456 __ AddImmediate(SP, SP, -kNumberOfFpuRegisters * kFpuRegisterSize); | 471 __ AddImmediate(SP, SP, -kNumberOfFpuRegisters * kFpuRegisterSize); |
| 457 } | 472 } |
| 458 | 473 |
| 459 __ mov(R0, Operand(SP)); // Pass address of saved registers block. | 474 __ mov(R0, Operand(SP)); // Pass address of saved registers block. |
| 475 __ mov(R1, Operand(kind == kLazyDeopt ? 1 : 0)); |
| 460 __ ReserveAlignedFrameSpace(0); | 476 __ ReserveAlignedFrameSpace(0); |
| 461 __ CallRuntime(kDeoptimizeCopyFrameRuntimeEntry, 1); | 477 __ CallRuntime(kDeoptimizeCopyFrameRuntimeEntry, 2); |
| 462 // Result (R0) is stack-size (FP - SP) in bytes. | 478 // Result (R0) is stack-size (FP - SP) in bytes. |
| 463 | 479 |
| 480 const bool preserve_result = (kind == kLazyDeopt); |
| 464 if (preserve_result) { | 481 if (preserve_result) { |
| 465 // Restore result into R1 temporarily. | 482 // Restore result into R1 temporarily. |
| 466 __ ldr(R1, Address(FP, saved_result_slot_from_fp * kWordSize)); | 483 __ ldr(R1, Address(FP, saved_result_slot_from_fp * kWordSize)); |
| 467 } | 484 } |
| 468 | 485 |
| 486 __ RestoreCodePointer(); |
| 469 __ LeaveDartFrame(); | 487 __ LeaveDartFrame(); |
| 470 __ sub(SP, FP, Operand(R0)); | 488 __ sub(SP, FP, Operand(R0)); |
| 471 | 489 |
| 472 // DeoptimizeFillFrame expects a Dart frame, i.e. EnterDartFrame(0), but there | 490 // DeoptimizeFillFrame expects a Dart frame, i.e. EnterDartFrame(0), but there |
| 473 // is no need to set the correct PC marker or load PP, since they get patched. | 491 // is no need to set the correct PC marker or load PP, since they get patched. |
| 474 __ EnterStubFrame(); | 492 __ EnterStubFrame(); |
| 475 __ mov(R0, Operand(FP)); // Get last FP address. | 493 __ mov(R0, Operand(FP)); // Get last FP address. |
| 476 if (preserve_result) { | 494 if (preserve_result) { |
| 477 __ Push(R1); // Preserve result as first local. | 495 __ Push(R1); // Preserve result as first local. |
| 478 } | 496 } |
| 479 __ ReserveAlignedFrameSpace(0); | 497 __ ReserveAlignedFrameSpace(0); |
| 480 __ CallRuntime(kDeoptimizeFillFrameRuntimeEntry, 1); // Pass last FP in R0. | 498 __ CallRuntime(kDeoptimizeFillFrameRuntimeEntry, 1); // Pass last FP in R0. |
| 481 if (preserve_result) { | 499 if (preserve_result) { |
| 482 // Restore result into R1. | 500 // Restore result into R1. |
| 483 __ ldr(R1, Address(FP, kFirstLocalSlotFromFp * kWordSize)); | 501 __ ldr(R1, Address(FP, kFirstLocalSlotFromFp * kWordSize)); |
| 484 } | 502 } |
| 485 // Code above cannot cause GC. | 503 // Code above cannot cause GC. |
| 504 __ RestoreCodePointer(); |
| 486 __ LeaveStubFrame(); | 505 __ LeaveStubFrame(); |
| 487 | 506 |
| 488 // Frame is fully rewritten at this point and it is safe to perform a GC. | 507 // Frame is fully rewritten at this point and it is safe to perform a GC. |
| 489 // Materialize any objects that were deferred by FillFrame because they | 508 // Materialize any objects that were deferred by FillFrame because they |
| 490 // require allocation. | 509 // require allocation. |
| 491 // Enter stub frame with loading PP. The caller's PP is not materialized yet. | 510 // Enter stub frame with loading PP. The caller's PP is not materialized yet. |
| 492 __ EnterStubFrame(); | 511 __ EnterStubFrame(); |
| 493 if (preserve_result) { | 512 if (preserve_result) { |
| 494 __ Push(R1); // Preserve result, it will be GC-d here. | 513 __ Push(R1); // Preserve result, it will be GC-d here. |
| 495 } | 514 } |
| 496 __ PushObject(Smi::ZoneHandle()); // Space for the result. | 515 __ PushObject(Smi::ZoneHandle()); // Space for the result. |
| 497 __ CallRuntime(kDeoptimizeMaterializeRuntimeEntry, 0); | 516 __ CallRuntime(kDeoptimizeMaterializeRuntimeEntry, 0); |
| 498 // Result tells stub how many bytes to remove from the expression stack | 517 // Result tells stub how many bytes to remove from the expression stack |
| 499 // of the bottom-most frame. They were used as materialization arguments. | 518 // of the bottom-most frame. They were used as materialization arguments. |
| 500 __ Pop(R1); | 519 __ Pop(R1); |
| 501 if (preserve_result) { | 520 if (preserve_result) { |
| 502 __ Pop(R0); // Restore result. | 521 __ Pop(R0); // Restore result. |
| 503 } | 522 } |
| 504 __ LeaveStubFrame(); | 523 __ LeaveStubFrame(); |
| 505 // Remove materialization arguments. | 524 // Remove materialization arguments. |
| 506 __ add(SP, SP, Operand(R1, ASR, kSmiTagSize)); | 525 __ add(SP, SP, Operand(R1, ASR, kSmiTagSize)); |
| 507 __ Ret(); | 526 __ Ret(); |
| 508 } | 527 } |
| 509 | 528 |
| 510 | 529 |
| 511 void StubCode::GenerateDeoptimizeLazyStub(Assembler* assembler) { | 530 void StubCode::GenerateDeoptimizeLazyStub(Assembler* assembler) { |
| 512 // Correct return address to point just after the call that is being | 531 // Correct return address to point just after the call that is being |
| 513 // deoptimized. | 532 // deoptimized. |
| 514 __ AddImmediate(LR, -CallPattern::LengthInBytes()); | 533 __ AddImmediate(LR, -CallPattern::DeoptCallPatternLengthInBytes()); |
| 515 GenerateDeoptimizationSequence(assembler, true); // Preserve R0. | 534 // Push zap value instead of CODE_REG for lazy deopt. |
| 535 __ LoadImmediate(IP, 0xf1f1f1f1); |
| 536 __ Push(IP); |
| 537 GenerateDeoptimizationSequence(assembler, kLazyDeopt); |
| 516 } | 538 } |
| 517 | 539 |
| 518 | 540 |
| 519 void StubCode::GenerateDeoptimizeStub(Assembler* assembler) { | 541 void StubCode::GenerateDeoptimizeStub(Assembler* assembler) { |
| 520 GenerateDeoptimizationSequence(assembler, false); // Don't preserve R0. | 542 GenerateDeoptimizationSequence(assembler, kEagerDeopt); |
| 521 } | 543 } |
| 522 | 544 |
| 523 | 545 |
| 524 static void GenerateDispatcherCode(Assembler* assembler, | 546 static void GenerateDispatcherCode(Assembler* assembler, |
| 525 Label* call_target_function) { | 547 Label* call_target_function) { |
| 526 __ Comment("NoSuchMethodDispatch"); | 548 __ Comment("NoSuchMethodDispatch"); |
| 527 // When lazily generated invocation dispatchers are disabled, the | 549 // When lazily generated invocation dispatchers are disabled, the |
| 528 // miss-handler may return null. | 550 // miss-handler may return null. |
| 529 __ CompareObject(R0, Object::null_object()); | 551 __ CompareObject(R0, Object::null_object()); |
| 530 __ b(call_target_function, NE); | 552 __ b(call_target_function, NE); |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 566 __ LoadObject(IP, Object::null_object()); | 588 __ LoadObject(IP, Object::null_object()); |
| 567 __ PushList((1 << R4) | (1 << R5) | (1 << R6) | (1 << IP)); | 589 __ PushList((1 << R4) | (1 << R5) | (1 << R6) | (1 << IP)); |
| 568 __ CallRuntime(kMegamorphicCacheMissHandlerRuntimeEntry, 3); | 590 __ CallRuntime(kMegamorphicCacheMissHandlerRuntimeEntry, 3); |
| 569 // Remove arguments. | 591 // Remove arguments. |
| 570 __ Drop(3); | 592 __ Drop(3); |
| 571 __ Pop(R0); // Get result into R0 (target function). | 593 __ Pop(R0); // Get result into R0 (target function). |
| 572 | 594 |
| 573 // Restore IC data and arguments descriptor. | 595 // Restore IC data and arguments descriptor. |
| 574 __ PopList((1 << R4) | (1 << R5)); | 596 __ PopList((1 << R4) | (1 << R5)); |
| 575 | 597 |
| 598 __ RestoreCodePointer(); |
| 576 __ LeaveStubFrame(); | 599 __ LeaveStubFrame(); |
| 577 | 600 |
| 578 if (!FLAG_lazy_dispatchers) { | 601 if (!FLAG_lazy_dispatchers) { |
| 579 Label call_target_function; | 602 Label call_target_function; |
| 580 GenerateDispatcherCode(assembler, &call_target_function); | 603 GenerateDispatcherCode(assembler, &call_target_function); |
| 581 __ Bind(&call_target_function); | 604 __ Bind(&call_target_function); |
| 582 } | 605 } |
| 583 | 606 |
| 584 // Tail-call to target function. | 607 // Tail-call to target function. |
| 608 __ ldr(CODE_REG, FieldAddress(R0, Function::code_offset())); |
| 585 __ ldr(R2, FieldAddress(R0, Function::entry_point_offset())); | 609 __ ldr(R2, FieldAddress(R0, Function::entry_point_offset())); |
| 586 __ bx(R2); | 610 __ bx(R2); |
| 587 } | 611 } |
| 588 | 612 |
| 589 | 613 |
| 590 // Called for inline allocation of arrays. | 614 // Called for inline allocation of arrays. |
| 591 // Input parameters: | 615 // Input parameters: |
| 592 // LR: return address. | 616 // LR: return address. |
| 593 // R1: array element type (either NULL or an instantiated type). | 617 // R1: array element type (either NULL or an instantiated type). |
| 594 // R2: array length as Smi (must be preserved). | 618 // R2: array length as Smi (must be preserved). |
| (...skipping 18 matching lines...) Expand all Loading... |
| 613 const intptr_t max_len = | 637 const intptr_t max_len = |
| 614 reinterpret_cast<int32_t>(Smi::New(Array::kMaxElements)); | 638 reinterpret_cast<int32_t>(Smi::New(Array::kMaxElements)); |
| 615 __ CompareImmediate(R3, max_len); | 639 __ CompareImmediate(R3, max_len); |
| 616 __ b(&slow_case, GT); | 640 __ b(&slow_case, GT); |
| 617 | 641 |
| 618 const intptr_t cid = kArrayCid; | 642 const intptr_t cid = kArrayCid; |
| 619 __ MaybeTraceAllocation(cid, R4, &slow_case, | 643 __ MaybeTraceAllocation(cid, R4, &slow_case, |
| 620 /* inline_isolate = */ false); | 644 /* inline_isolate = */ false); |
| 621 | 645 |
| 622 const intptr_t fixed_size = sizeof(RawArray) + kObjectAlignment - 1; | 646 const intptr_t fixed_size = sizeof(RawArray) + kObjectAlignment - 1; |
| 623 __ LoadImmediate(R9, fixed_size); | 647 __ LoadImmediate(R5, fixed_size); |
| 624 __ add(R9, R9, Operand(R3, LSL, 1)); // R3 is a Smi. | 648 __ add(R5, R5, Operand(R3, LSL, 1)); // R3 is a Smi. |
| 625 ASSERT(kSmiTagShift == 1); | 649 ASSERT(kSmiTagShift == 1); |
| 626 __ bic(R9, R9, Operand(kObjectAlignment - 1)); | 650 __ bic(R5, R5, Operand(kObjectAlignment - 1)); |
| 627 | 651 |
| 628 // R9: Allocation size. | 652 // R5: Allocation size. |
| 629 Heap::Space space = Heap::SpaceForAllocation(cid); | 653 Heap::Space space = Heap::SpaceForAllocation(cid); |
| 630 __ LoadIsolate(R6); | 654 __ LoadIsolate(R6); |
| 631 __ ldr(R6, Address(R6, Isolate::heap_offset())); | 655 __ ldr(R6, Address(R6, Isolate::heap_offset())); |
| 632 // Potential new object start. | 656 // Potential new object start. |
| 633 __ ldr(R0, Address(R6, Heap::TopOffset(space))); | 657 __ ldr(R0, Address(R6, Heap::TopOffset(space))); |
| 634 __ adds(R7, R0, Operand(R9)); // Potential next object start. | 658 __ adds(R7, R0, Operand(R5)); // Potential next object start. |
| 635 __ b(&slow_case, CS); // Branch if unsigned overflow. | 659 __ b(&slow_case, CS); // Branch if unsigned overflow. |
| 636 | 660 |
| 637 // Check if the allocation fits into the remaining space. | 661 // Check if the allocation fits into the remaining space. |
| 638 // R0: potential new object start. | 662 // R0: potential new object start. |
| 639 // R7: potential next object start. | 663 // R7: potential next object start. |
| 640 // R9: allocation size. | 664 // R5: allocation size. |
| 641 __ ldr(R3, Address(R6, Heap::EndOffset(space))); | 665 __ ldr(R3, Address(R6, Heap::EndOffset(space))); |
| 642 __ cmp(R7, Operand(R3)); | 666 __ cmp(R7, Operand(R3)); |
| 643 __ b(&slow_case, CS); | 667 __ b(&slow_case, CS); |
| 644 | 668 |
| 645 // Successfully allocated the object(s), now update top to point to | 669 // Successfully allocated the object(s), now update top to point to |
| 646 // next object start and initialize the object. | 670 // next object start and initialize the object. |
| 647 __ LoadAllocationStatsAddress(R3, cid, /* inline_isolate = */ false); | 671 __ LoadAllocationStatsAddress(R3, cid, /* inline_isolate = */ false); |
| 648 __ str(R7, Address(R6, Heap::TopOffset(space))); | 672 __ str(R7, Address(R6, Heap::TopOffset(space))); |
| 649 __ add(R0, R0, Operand(kHeapObjectTag)); | 673 __ add(R0, R0, Operand(kHeapObjectTag)); |
| 650 | 674 |
| 651 // Initialize the tags. | 675 // Initialize the tags. |
| 652 // R0: new object start as a tagged pointer. | 676 // R0: new object start as a tagged pointer. |
| 653 // R3: allocation stats address. | 677 // R3: allocation stats address. |
| 654 // R7: new object end address. | 678 // R7: new object end address. |
| 655 // R9: allocation size. | 679 // R5: allocation size. |
| 656 { | 680 { |
| 657 const intptr_t shift = RawObject::kSizeTagPos - kObjectAlignmentLog2; | 681 const intptr_t shift = RawObject::kSizeTagPos - kObjectAlignmentLog2; |
| 658 | 682 |
| 659 __ CompareImmediate(R9, RawObject::SizeTag::kMaxSizeTag); | 683 __ CompareImmediate(R5, RawObject::SizeTag::kMaxSizeTag); |
| 660 __ mov(R6, Operand(R9, LSL, shift), LS); | 684 __ mov(R6, Operand(R5, LSL, shift), LS); |
| 661 __ mov(R6, Operand(0), HI); | 685 __ mov(R6, Operand(0), HI); |
| 662 | 686 |
| 663 // Get the class index and insert it into the tags. | 687 // Get the class index and insert it into the tags. |
| 664 // R6: size and bit tags. | 688 // R6: size and bit tags. |
| 665 __ LoadImmediate(TMP, RawObject::ClassIdTag::encode(cid)); | 689 __ LoadImmediate(TMP, RawObject::ClassIdTag::encode(cid)); |
| 666 __ orr(R6, R6, Operand(TMP)); | 690 __ orr(R6, R6, Operand(TMP)); |
| 667 __ str(R6, FieldAddress(R0, Array::tags_offset())); // Store tags. | 691 __ str(R6, FieldAddress(R0, Array::tags_offset())); // Store tags. |
| 668 } | 692 } |
| 669 | 693 |
| 670 // R0: new object start as a tagged pointer. | 694 // R0: new object start as a tagged pointer. |
| 671 // R7: new object end address. | 695 // R7: new object end address. |
| 672 // Store the type argument field. | 696 // Store the type argument field. |
| 673 __ InitializeFieldNoBarrier(R0, | 697 __ InitializeFieldNoBarrier(R0, |
| 674 FieldAddress(R0, Array::type_arguments_offset()), | 698 FieldAddress(R0, Array::type_arguments_offset()), |
| 675 R1); | 699 R1); |
| 676 | 700 |
| 677 // Set the length field. | 701 // Set the length field. |
| 678 __ InitializeFieldNoBarrier(R0, | 702 __ InitializeFieldNoBarrier(R0, |
| 679 FieldAddress(R0, Array::length_offset()), | 703 FieldAddress(R0, Array::length_offset()), |
| 680 R2); | 704 R2); |
| 681 | 705 |
| 682 // Initialize all array elements to raw_null. | 706 // Initialize all array elements to raw_null. |
| 683 // R0: new object start as a tagged pointer. | 707 // R0: new object start as a tagged pointer. |
| 684 // R3: allocation stats address. | 708 // R3: allocation stats address. |
| 685 // R4, R5: null | 709 // R4, R5: null |
| 686 // R6: iterator which initially points to the start of the variable | 710 // R6: iterator which initially points to the start of the variable |
| 687 // data area to be initialized. | 711 // data area to be initialized. |
| 688 // R7: new object end address. | 712 // R7: new object end address. |
| 689 // R9: allocation size. | 713 // R5: allocation size. |
| 714 __ IncrementAllocationStatsWithSize(R3, R5, space); |
| 690 | 715 |
| 691 __ LoadObject(R4, Object::null_object()); | 716 __ LoadObject(R4, Object::null_object()); |
| 692 __ mov(R5, Operand(R4)); | 717 __ mov(R5, Operand(R4)); |
| 693 __ AddImmediate(R6, R0, sizeof(RawArray) - kHeapObjectTag); | 718 __ AddImmediate(R6, R0, sizeof(RawArray) - kHeapObjectTag); |
| 694 __ InitializeFieldsNoBarrier(R0, R6, R7, R4, R5); | 719 __ InitializeFieldsNoBarrier(R0, R6, R7, R4, R5); |
| 695 __ IncrementAllocationStatsWithSize(R3, R9, space); | |
| 696 __ Ret(); // Returns the newly allocated object in R0. | 720 __ Ret(); // Returns the newly allocated object in R0. |
| 697 // Unable to allocate the array using the fast inline code, just call | 721 // Unable to allocate the array using the fast inline code, just call |
| 698 // into the runtime. | 722 // into the runtime. |
| 699 __ Bind(&slow_case); | 723 __ Bind(&slow_case); |
| 700 | 724 |
| 701 // Create a stub frame as we are pushing some objects on the stack before | 725 // Create a stub frame as we are pushing some objects on the stack before |
| 702 // calling into the runtime. | 726 // calling into the runtime. |
| 703 __ EnterStubFrame(); | 727 __ EnterStubFrame(); |
| 704 __ LoadObject(IP, Object::null_object()); | 728 __ LoadObject(IP, Object::null_object()); |
| 705 // Setup space on stack for return value. | 729 // Setup space on stack for return value. |
| 706 // Push array length as Smi and element type. | 730 // Push array length as Smi and element type. |
| 707 __ PushList((1 << R1) | (1 << R2) | (1 << IP)); | 731 __ PushList((1 << R1) | (1 << R2) | (1 << IP)); |
| 708 __ CallRuntime(kAllocateArrayRuntimeEntry, 2); | 732 __ CallRuntime(kAllocateArrayRuntimeEntry, 2); |
| 709 // Pop arguments; result is popped in IP. | 733 // Pop arguments; result is popped in IP. |
| 710 __ PopList((1 << R1) | (1 << R2) | (1 << IP)); // R2 is restored. | 734 __ PopList((1 << R1) | (1 << R2) | (1 << IP)); // R2 is restored. |
| 711 __ mov(R0, Operand(IP)); | 735 __ mov(R0, Operand(IP)); |
| 712 __ LeaveStubFrame(); | 736 __ LeaveStubFrame(); |
| 713 __ Ret(); | 737 __ Ret(); |
| 714 } | 738 } |
| 715 | 739 |
| 716 | 740 |
| 717 // Called when invoking Dart code from C++ (VM code). | 741 // Called when invoking Dart code from C++ (VM code). |
| 718 // Input parameters: | 742 // Input parameters: |
| 719 // LR : points to return address. | 743 // LR : points to return address. |
| 720 // R0 : entrypoint of the Dart function to call. | 744 // R0 : code object of the Dart function to call. |
| 721 // R1 : arguments descriptor array. | 745 // R1 : arguments descriptor array. |
| 722 // R2 : arguments array. | 746 // R2 : arguments array. |
| 723 // R3 : current thread. | 747 // R3 : current thread. |
| 724 void StubCode::GenerateInvokeDartCodeStub(Assembler* assembler) { | 748 void StubCode::GenerateInvokeDartCodeStub(Assembler* assembler) { |
| 725 // Save frame pointer coming in. | 749 // Save frame pointer coming in. |
| 726 __ EnterFrame((1 << FP) | (1 << LR), 0); | 750 __ EnterFrame((1 << FP) | (1 << LR), 0); |
| 727 | 751 |
| 752 // Push code object to PC marker slot. |
| 753 __ ldr(IP, Address(R3, Thread::invoke_dart_code_stub_offset())); |
| 754 __ Push(IP); |
| 755 |
| 728 // Save new context and C++ ABI callee-saved registers. | 756 // Save new context and C++ ABI callee-saved registers. |
| 729 __ PushList(kAbiPreservedCpuRegs); | 757 __ PushList(kAbiPreservedCpuRegs); |
| 730 | 758 |
| 731 const DRegister firstd = EvenDRegisterOf(kAbiFirstPreservedFpuReg); | 759 const DRegister firstd = EvenDRegisterOf(kAbiFirstPreservedFpuReg); |
| 732 if (TargetCPUFeatures::vfp_supported()) { | 760 if (TargetCPUFeatures::vfp_supported()) { |
| 733 ASSERT(2 * kAbiPreservedFpuRegCount < 16); | 761 ASSERT(2 * kAbiPreservedFpuRegCount < 16); |
| 734 // Save FPU registers. 2 D registers per Q register. | 762 // Save FPU registers. 2 D registers per Q register. |
| 735 __ vstmd(DB_W, SP, firstd, 2 * kAbiPreservedFpuRegCount); | 763 __ vstmd(DB_W, SP, firstd, 2 * kAbiPreservedFpuRegCount); |
| 736 } else { | 764 } else { |
| 737 __ sub(SP, SP, Operand(kAbiPreservedFpuRegCount * kFpuRegisterSize)); | 765 __ sub(SP, SP, Operand(kAbiPreservedFpuRegCount * kFpuRegisterSize)); |
| 738 } | 766 } |
| 739 | 767 |
| 740 // We now load the pool pointer(PP) as we are about to invoke dart code and we | |
| 741 // could potentially invoke some intrinsic functions which need the PP to be | |
| 742 // set up. | |
| 743 __ LoadPoolPointer(); | |
| 744 | |
| 745 // Set up THR, which caches the current thread in Dart code. | 768 // Set up THR, which caches the current thread in Dart code. |
| 746 if (THR != R3) { | 769 if (THR != R3) { |
| 747 __ mov(THR, Operand(R3)); | 770 __ mov(THR, Operand(R3)); |
| 748 } | 771 } |
| 749 __ LoadIsolate(R9); | 772 __ LoadIsolate(R7); |
| 750 | 773 |
| 751 // Save the current VMTag on the stack. | 774 // Save the current VMTag on the stack. |
| 752 __ LoadFromOffset(kWord, R5, R9, Isolate::vm_tag_offset()); | 775 __ LoadFromOffset(kWord, R5, R7, Isolate::vm_tag_offset()); |
| 753 __ Push(R5); | 776 __ Push(R5); |
| 754 | 777 |
| 755 // Mark that the isolate is executing Dart code. | 778 // Mark that the isolate is executing Dart code. |
| 756 __ LoadImmediate(R5, VMTag::kDartTagId); | 779 __ LoadImmediate(R5, VMTag::kDartTagId); |
| 757 __ StoreToOffset(kWord, R5, R9, Isolate::vm_tag_offset()); | 780 __ StoreToOffset(kWord, R5, R7, Isolate::vm_tag_offset()); |
| 758 | 781 |
| 759 // Save top resource and top exit frame info. Use R4-6 as temporary registers. | 782 // Save top resource and top exit frame info. Use R4-6 as temporary registers. |
| 760 // StackFrameIterator reads the top exit frame info saved in this frame. | 783 // StackFrameIterator reads the top exit frame info saved in this frame. |
| 761 __ LoadFromOffset(kWord, R5, THR, Thread::top_exit_frame_info_offset()); | 784 __ LoadFromOffset(kWord, R5, THR, Thread::top_exit_frame_info_offset()); |
| 762 __ LoadFromOffset(kWord, R4, THR, Thread::top_resource_offset()); | 785 __ LoadFromOffset(kWord, R4, THR, Thread::top_resource_offset()); |
| 763 __ LoadImmediate(R6, 0); | 786 __ LoadImmediate(R6, 0); |
| 764 __ StoreToOffset(kWord, R6, THR, Thread::top_resource_offset()); | 787 __ StoreToOffset(kWord, R6, THR, Thread::top_resource_offset()); |
| 765 __ StoreToOffset(kWord, R6, THR, Thread::top_exit_frame_info_offset()); | 788 __ StoreToOffset(kWord, R6, THR, Thread::top_exit_frame_info_offset()); |
| 766 | 789 |
| 767 // kExitLinkSlotFromEntryFp must be kept in sync with the code below. | 790 // kExitLinkSlotFromEntryFp must be kept in sync with the code below. |
| 768 __ Push(R4); | 791 __ Push(R4); |
| 769 ASSERT(kExitLinkSlotFromEntryFp == -26); | 792 ASSERT(kExitLinkSlotFromEntryFp == -27); |
| 770 __ Push(R5); | 793 __ Push(R5); |
| 771 | 794 |
| 772 // Load arguments descriptor array into R4, which is passed to Dart code. | 795 // Load arguments descriptor array into R4, which is passed to Dart code. |
| 773 __ ldr(R4, Address(R1, VMHandles::kOffsetOfRawPtrInHandle)); | 796 __ ldr(R4, Address(R1, VMHandles::kOffsetOfRawPtrInHandle)); |
| 774 | 797 |
| 775 // Load number of arguments into R5. | 798 // Load number of arguments into R5. |
| 776 __ ldr(R5, FieldAddress(R4, ArgumentsDescriptor::count_offset())); | 799 __ ldr(R5, FieldAddress(R4, ArgumentsDescriptor::count_offset())); |
| 777 __ SmiUntag(R5); | 800 __ SmiUntag(R5); |
| 778 | 801 |
| 779 // Compute address of 'arguments array' data area into R2. | 802 // Compute address of 'arguments array' data area into R2. |
| 780 __ ldr(R2, Address(R2, VMHandles::kOffsetOfRawPtrInHandle)); | 803 __ ldr(R2, Address(R2, VMHandles::kOffsetOfRawPtrInHandle)); |
| 781 __ AddImmediate(R2, R2, Array::data_offset() - kHeapObjectTag); | 804 __ AddImmediate(R2, R2, Array::data_offset() - kHeapObjectTag); |
| 782 | 805 |
| 783 // Set up arguments for the Dart call. | 806 // Set up arguments for the Dart call. |
| 784 Label push_arguments; | 807 Label push_arguments; |
| 785 Label done_push_arguments; | 808 Label done_push_arguments; |
| 786 __ CompareImmediate(R5, 0); // check if there are arguments. | 809 __ CompareImmediate(R5, 0); // check if there are arguments. |
| 787 __ b(&done_push_arguments, EQ); | 810 __ b(&done_push_arguments, EQ); |
| 788 __ LoadImmediate(R1, 0); | 811 __ LoadImmediate(R1, 0); |
| 789 __ Bind(&push_arguments); | 812 __ Bind(&push_arguments); |
| 790 __ ldr(R3, Address(R2)); | 813 __ ldr(R3, Address(R2)); |
| 791 __ Push(R3); | 814 __ Push(R3); |
| 792 __ AddImmediate(R2, kWordSize); | 815 __ AddImmediate(R2, kWordSize); |
| 793 __ AddImmediate(R1, 1); | 816 __ AddImmediate(R1, 1); |
| 794 __ cmp(R1, Operand(R5)); | 817 __ cmp(R1, Operand(R5)); |
| 795 __ b(&push_arguments, LT); | 818 __ b(&push_arguments, LT); |
| 796 __ Bind(&done_push_arguments); | 819 __ Bind(&done_push_arguments); |
| 797 | 820 |
| 798 // Call the Dart code entrypoint. | 821 // Call the Dart code entrypoint. |
| 822 __ LoadImmediate(PP, 0); // GC safe value into PP. |
| 823 __ ldr(CODE_REG, Address(R0, VMHandles::kOffsetOfRawPtrInHandle)); |
| 824 __ ldr(R0, FieldAddress(CODE_REG, Code::entry_point_offset())); |
| 799 __ blx(R0); // R4 is the arguments descriptor array. | 825 __ blx(R0); // R4 is the arguments descriptor array. |
| 800 | 826 |
| 801 // Get rid of arguments pushed on the stack. | 827 // Get rid of arguments pushed on the stack. |
| 802 __ AddImmediate(SP, FP, kExitLinkSlotFromEntryFp * kWordSize); | 828 __ AddImmediate(SP, FP, kExitLinkSlotFromEntryFp * kWordSize); |
| 803 | 829 |
| 804 __ LoadIsolate(R9); | 830 __ LoadIsolate(R7); |
| 805 // Restore the saved top exit frame info and top resource back into the | 831 // Restore the saved top exit frame info and top resource back into the |
| 806 // Isolate structure. Uses R5 as a temporary register for this. | 832 // Isolate structure. Uses R5 as a temporary register for this. |
| 807 __ Pop(R5); | 833 __ Pop(R5); |
| 808 __ StoreToOffset(kWord, R5, THR, Thread::top_exit_frame_info_offset()); | 834 __ StoreToOffset(kWord, R5, THR, Thread::top_exit_frame_info_offset()); |
| 809 __ Pop(R5); | 835 __ Pop(R5); |
| 810 __ StoreToOffset(kWord, R5, THR, Thread::top_resource_offset()); | 836 __ StoreToOffset(kWord, R5, THR, Thread::top_resource_offset()); |
| 811 | 837 |
| 812 // Restore the current VMTag from the stack. | 838 // Restore the current VMTag from the stack. |
| 813 __ Pop(R4); | 839 __ Pop(R4); |
| 814 __ StoreToOffset(kWord, R4, R9, Isolate::vm_tag_offset()); | 840 __ StoreToOffset(kWord, R4, R7, Isolate::vm_tag_offset()); |
| 815 | 841 |
| 816 // Restore C++ ABI callee-saved registers. | 842 // Restore C++ ABI callee-saved registers. |
| 817 if (TargetCPUFeatures::vfp_supported()) { | 843 if (TargetCPUFeatures::vfp_supported()) { |
| 818 // Restore FPU registers. 2 D registers per Q register. | 844 // Restore FPU registers. 2 D registers per Q register. |
| 819 __ vldmd(IA_W, SP, firstd, 2 * kAbiPreservedFpuRegCount); | 845 __ vldmd(IA_W, SP, firstd, 2 * kAbiPreservedFpuRegCount); |
| 820 } else { | 846 } else { |
| 821 __ AddImmediate(SP, kAbiPreservedFpuRegCount * kFpuRegisterSize); | 847 __ AddImmediate(SP, kAbiPreservedFpuRegCount * kFpuRegisterSize); |
| 822 } | 848 } |
| 823 // Restore CPU registers. | 849 // Restore CPU registers. |
| 824 __ PopList(kAbiPreservedCpuRegs); | 850 __ PopList(kAbiPreservedCpuRegs); |
| (...skipping 198 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1023 // Restore callee-saved registers, tear down frame. | 1049 // Restore callee-saved registers, tear down frame. |
| 1024 __ LeaveCallRuntimeFrame(); | 1050 __ LeaveCallRuntimeFrame(); |
| 1025 __ Ret(); | 1051 __ Ret(); |
| 1026 } | 1052 } |
| 1027 | 1053 |
| 1028 | 1054 |
| 1029 // Called for inline allocation of objects. | 1055 // Called for inline allocation of objects. |
| 1030 // Input parameters: | 1056 // Input parameters: |
| 1031 // LR : return address. | 1057 // LR : return address. |
| 1032 // SP + 0 : type arguments object (only if class is parameterized). | 1058 // SP + 0 : type arguments object (only if class is parameterized). |
| 1033 // Returns patch_code_pc offset where patching code for disabling the stub | 1059 void StubCode::GenerateAllocationStubForClass(Assembler* assembler, |
| 1034 // has been generated (similar to regularly generated Dart code). | 1060 const Class& cls) { |
| 1035 void StubCode::GenerateAllocationStubForClass( | 1061 // Must load pool pointer before being able to patch. |
| 1036 Assembler* assembler, const Class& cls, | 1062 Register new_pp = R7; |
| 1037 uword* entry_patch_offset, uword* patch_code_pc_offset) { | 1063 __ LoadPoolPointer(new_pp); |
| 1038 *entry_patch_offset = assembler->CodeSize(); | |
| 1039 // The generated code is different if the class is parameterized. | 1064 // The generated code is different if the class is parameterized. |
| 1040 const bool is_cls_parameterized = cls.NumTypeArguments() > 0; | 1065 const bool is_cls_parameterized = cls.NumTypeArguments() > 0; |
| 1041 ASSERT(!is_cls_parameterized || | 1066 ASSERT(!is_cls_parameterized || |
| 1042 (cls.type_arguments_field_offset() != Class::kNoTypeArguments)); | 1067 (cls.type_arguments_field_offset() != Class::kNoTypeArguments)); |
| 1043 // kInlineInstanceSize is a constant used as a threshold for determining | 1068 // kInlineInstanceSize is a constant used as a threshold for determining |
| 1044 // when the object initialization should be done as a loop or as | 1069 // when the object initialization should be done as a loop or as |
| 1045 // straight line code. | 1070 // straight line code. |
| 1046 const int kInlineInstanceSize = 12; | 1071 const int kInlineInstanceSize = 12; |
| 1047 const intptr_t instance_size = cls.instance_size(); | 1072 const intptr_t instance_size = cls.instance_size(); |
| 1048 ASSERT(instance_size > 0); | 1073 ASSERT(instance_size > 0); |
| (...skipping 105 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1154 // Push null type arguments. | 1179 // Push null type arguments. |
| 1155 __ Push(R2); | 1180 __ Push(R2); |
| 1156 } | 1181 } |
| 1157 __ CallRuntime(kAllocateObjectRuntimeEntry, 2); // Allocate object. | 1182 __ CallRuntime(kAllocateObjectRuntimeEntry, 2); // Allocate object. |
| 1158 __ Drop(2); // Pop arguments. | 1183 __ Drop(2); // Pop arguments. |
| 1159 __ Pop(R0); // Pop result (newly allocated object). | 1184 __ Pop(R0); // Pop result (newly allocated object). |
| 1160 // R0: new object | 1185 // R0: new object |
| 1161 // Restore the frame pointer. | 1186 // Restore the frame pointer. |
| 1162 __ LeaveStubFrame(); | 1187 __ LeaveStubFrame(); |
| 1163 __ Ret(); | 1188 __ Ret(); |
| 1164 *patch_code_pc_offset = assembler->CodeSize(); | |
| 1165 __ BranchPatchable(*StubCode::FixAllocationStubTarget_entry()); | |
| 1166 } | 1189 } |
| 1167 | 1190 |
| 1168 | 1191 |
| 1169 // Called for invoking "dynamic noSuchMethod(Invocation invocation)" function | 1192 // Called for invoking "dynamic noSuchMethod(Invocation invocation)" function |
| 1170 // from the entry code of a dart function after an error in passed argument | 1193 // from the entry code of a dart function after an error in passed argument |
| 1171 // name or number is detected. | 1194 // name or number is detected. |
| 1172 // Input parameters: | 1195 // Input parameters: |
| 1173 // LR : return address. | 1196 // LR : return address. |
| 1174 // SP : address of last argument. | 1197 // SP : address of last argument. |
| 1175 // R4: arguments descriptor array. | 1198 // R4: arguments descriptor array. |
| (...skipping 134 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1310 // - Check if 'num_args' (including receiver) match any IC data group. | 1333 // - Check if 'num_args' (including receiver) match any IC data group. |
| 1311 // - Match found -> jump to target. | 1334 // - Match found -> jump to target. |
| 1312 // - Match not found -> jump to IC miss. | 1335 // - Match not found -> jump to IC miss. |
| 1313 void StubCode::GenerateNArgsCheckInlineCacheStub( | 1336 void StubCode::GenerateNArgsCheckInlineCacheStub( |
| 1314 Assembler* assembler, | 1337 Assembler* assembler, |
| 1315 intptr_t num_args, | 1338 intptr_t num_args, |
| 1316 const RuntimeEntry& handle_ic_miss, | 1339 const RuntimeEntry& handle_ic_miss, |
| 1317 Token::Kind kind, | 1340 Token::Kind kind, |
| 1318 RangeCollectionMode range_collection_mode, | 1341 RangeCollectionMode range_collection_mode, |
| 1319 bool optimized) { | 1342 bool optimized) { |
| 1343 __ CheckCodePointer(); |
| 1320 ASSERT(num_args > 0); | 1344 ASSERT(num_args > 0); |
| 1321 #if defined(DEBUG) | 1345 #if defined(DEBUG) |
| 1322 { Label ok; | 1346 { Label ok; |
| 1323 // Check that the IC data array has NumArgsTested() == num_args. | 1347 // Check that the IC data array has NumArgsTested() == num_args. |
| 1324 // 'NumArgsTested' is stored in the least significant bits of 'state_bits'. | 1348 // 'NumArgsTested' is stored in the least significant bits of 'state_bits'. |
| 1325 __ ldr(R6, FieldAddress(R5, ICData::state_bits_offset())); | 1349 __ ldr(R6, FieldAddress(R5, ICData::state_bits_offset())); |
| 1326 ASSERT(ICData::NumArgsTestedShift() == 0); // No shift needed. | 1350 ASSERT(ICData::NumArgsTestedShift() == 0); // No shift needed. |
| 1327 __ and_(R6, R6, Operand(ICData::NumArgsTestedMask())); | 1351 __ and_(R6, R6, Operand(ICData::NumArgsTestedMask())); |
| 1328 __ CompareImmediate(R6, num_args); | 1352 __ CompareImmediate(R6, num_args); |
| 1329 __ b(&ok, EQ); | 1353 __ b(&ok, EQ); |
| (...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1434 __ Push(IP); | 1458 __ Push(IP); |
| 1435 } | 1459 } |
| 1436 // Pass IC data object. | 1460 // Pass IC data object. |
| 1437 __ Push(R5); | 1461 __ Push(R5); |
| 1438 __ CallRuntime(handle_ic_miss, num_args + 1); | 1462 __ CallRuntime(handle_ic_miss, num_args + 1); |
| 1439 // Remove the call arguments pushed earlier, including the IC data object. | 1463 // Remove the call arguments pushed earlier, including the IC data object. |
| 1440 __ Drop(num_args + 1); | 1464 __ Drop(num_args + 1); |
| 1441 // Pop returned function object into R0. | 1465 // Pop returned function object into R0. |
| 1442 // Restore arguments descriptor array and IC data array. | 1466 // Restore arguments descriptor array and IC data array. |
| 1443 __ PopList((1 << R0) | (1 << R4) | (1 << R5)); | 1467 __ PopList((1 << R0) | (1 << R4) | (1 << R5)); |
| 1468 if (range_collection_mode == kCollectRanges) { |
| 1469 __ RestoreCodePointer(); |
| 1470 } |
| 1444 __ LeaveStubFrame(); | 1471 __ LeaveStubFrame(); |
| 1445 Label call_target_function; | 1472 Label call_target_function; |
| 1446 if (!FLAG_lazy_dispatchers) { | 1473 if (!FLAG_lazy_dispatchers) { |
| 1447 GenerateDispatcherCode(assembler, &call_target_function); | 1474 GenerateDispatcherCode(assembler, &call_target_function); |
| 1448 } else { | 1475 } else { |
| 1449 __ b(&call_target_function); | 1476 __ b(&call_target_function); |
| 1450 } | 1477 } |
| 1451 | 1478 |
| 1452 __ Bind(&found); | 1479 __ Bind(&found); |
| 1453 // R6: pointer to an IC data check group. | 1480 // R6: pointer to an IC data check group. |
| (...skipping 17 matching lines...) Expand all Loading... |
| 1471 __ ldr(R1, Address(SP, 0 * kWordSize)); | 1498 __ ldr(R1, Address(SP, 0 * kWordSize)); |
| 1472 if (num_args == 2) { | 1499 if (num_args == 2) { |
| 1473 __ ldr(R3, Address(SP, 1 * kWordSize)); | 1500 __ ldr(R3, Address(SP, 1 * kWordSize)); |
| 1474 } | 1501 } |
| 1475 __ EnterStubFrame(); | 1502 __ EnterStubFrame(); |
| 1476 if (num_args == 2) { | 1503 if (num_args == 2) { |
| 1477 __ PushList((1 << R1) | (1 << R3) | (1 << R5)); | 1504 __ PushList((1 << R1) | (1 << R3) | (1 << R5)); |
| 1478 } else { | 1505 } else { |
| 1479 __ PushList((1 << R1) | (1 << R5)); | 1506 __ PushList((1 << R1) | (1 << R5)); |
| 1480 } | 1507 } |
| 1508 __ ldr(CODE_REG, FieldAddress(R0, Function::code_offset())); |
| 1481 __ blx(R2); | 1509 __ blx(R2); |
| 1482 | 1510 |
| 1483 Label done; | 1511 Label done; |
| 1484 __ ldr(R5, Address(FP, kFirstLocalSlotFromFp * kWordSize)); | 1512 __ ldr(R5, Address(FP, kFirstLocalSlotFromFp * kWordSize)); |
| 1485 __ UpdateRangeFeedback(R0, 2, R5, R1, R4, &done); | 1513 __ UpdateRangeFeedback(R0, 2, R5, R1, R4, &done); |
| 1486 __ Bind(&done); | 1514 __ Bind(&done); |
| 1515 __ RestoreCodePointer(); |
| 1487 __ LeaveStubFrame(); | 1516 __ LeaveStubFrame(); |
| 1488 __ Ret(); | 1517 __ Ret(); |
| 1489 } else { | 1518 } else { |
| 1519 __ ldr(CODE_REG, FieldAddress(R0, Function::code_offset())); |
| 1490 __ bx(R2); | 1520 __ bx(R2); |
| 1491 } | 1521 } |
| 1492 | 1522 |
| 1493 if (FLAG_support_debugger && !optimized) { | 1523 if (FLAG_support_debugger && !optimized) { |
| 1494 __ Bind(&stepping); | 1524 __ Bind(&stepping); |
| 1495 __ EnterStubFrame(); | 1525 __ EnterStubFrame(); |
| 1496 __ Push(R5); // Preserve IC data. | 1526 __ Push(R5); // Preserve IC data. |
| 1497 __ CallRuntime(kSingleStepHandlerRuntimeEntry, 0); | 1527 __ CallRuntime(kSingleStepHandlerRuntimeEntry, 0); |
| 1498 __ Pop(R5); | 1528 __ Pop(R5); |
| 1529 __ RestoreCodePointer(); |
| 1499 __ LeaveStubFrame(); | 1530 __ LeaveStubFrame(); |
| 1500 __ b(&done_stepping); | 1531 __ b(&done_stepping); |
| 1501 } | 1532 } |
| 1502 } | 1533 } |
| 1503 | 1534 |
| 1504 | 1535 |
| 1505 // Use inline cache data array to invoke the target or continue in inline | 1536 // Use inline cache data array to invoke the target or continue in inline |
| 1506 // cache miss handler. Stub for 1-argument check (receiver class). | 1537 // cache miss handler. Stub for 1-argument check (receiver class). |
| 1507 // LR: return address. | 1538 // LR: return address. |
| 1508 // R5: inline cache data object. | 1539 // R5: inline cache data object. |
| (...skipping 130 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1639 __ adds(R1, R1, Operand(Smi::RawValue(1))); | 1670 __ adds(R1, R1, Operand(Smi::RawValue(1))); |
| 1640 __ LoadImmediate(R1, Smi::RawValue(Smi::kMaxValue), VS); // Overflow. | 1671 __ LoadImmediate(R1, Smi::RawValue(Smi::kMaxValue), VS); // Overflow. |
| 1641 __ StoreIntoSmiField(Address(R6, count_offset), R1); | 1672 __ StoreIntoSmiField(Address(R6, count_offset), R1); |
| 1642 } | 1673 } |
| 1643 | 1674 |
| 1644 // Load arguments descriptor into R4. | 1675 // Load arguments descriptor into R4. |
| 1645 __ ldr(R4, FieldAddress(R5, ICData::arguments_descriptor_offset())); | 1676 __ ldr(R4, FieldAddress(R5, ICData::arguments_descriptor_offset())); |
| 1646 | 1677 |
| 1647 // Get function and call it, if possible. | 1678 // Get function and call it, if possible. |
| 1648 __ LoadFromOffset(kWord, R0, R6, target_offset); | 1679 __ LoadFromOffset(kWord, R0, R6, target_offset); |
| 1680 __ ldr(CODE_REG, FieldAddress(R0, Function::code_offset())); |
| 1649 __ ldr(R2, FieldAddress(R0, Function::entry_point_offset())); | 1681 __ ldr(R2, FieldAddress(R0, Function::entry_point_offset())); |
| 1650 __ bx(R2); | 1682 __ bx(R2); |
| 1651 | 1683 |
| 1652 if (FLAG_support_debugger) { | 1684 if (FLAG_support_debugger) { |
| 1653 __ Bind(&stepping); | 1685 __ Bind(&stepping); |
| 1654 __ EnterStubFrame(); | 1686 __ EnterStubFrame(); |
| 1655 __ Push(R5); // Preserve IC data. | 1687 __ Push(R5); // Preserve IC data. |
| 1656 __ CallRuntime(kSingleStepHandlerRuntimeEntry, 0); | 1688 __ CallRuntime(kSingleStepHandlerRuntimeEntry, 0); |
| 1657 __ Pop(R5); | 1689 __ Pop(R5); |
| 1690 __ RestoreCodePointer(); |
| 1658 __ LeaveStubFrame(); | 1691 __ LeaveStubFrame(); |
| 1659 __ b(&done_stepping); | 1692 __ b(&done_stepping); |
| 1660 } | 1693 } |
| 1661 } | 1694 } |
| 1662 | 1695 |
| 1663 | 1696 |
| 1664 void StubCode::GenerateOneArgUnoptimizedStaticCallStub(Assembler* assembler) { | 1697 void StubCode::GenerateOneArgUnoptimizedStaticCallStub(Assembler* assembler) { |
| 1665 GenerateUsageCounterIncrement(assembler, R6); | 1698 GenerateUsageCounterIncrement(assembler, R6); |
| 1666 GenerateNArgsCheckInlineCacheStub( | 1699 GenerateNArgsCheckInlineCacheStub( |
| 1667 assembler, 1, kStaticCallMissHandlerOneArgRuntimeEntry, Token::kILLEGAL, | 1700 assembler, 1, kStaticCallMissHandlerOneArgRuntimeEntry, Token::kILLEGAL, |
| (...skipping 16 matching lines...) Expand all Loading... |
| 1684 void StubCode::GenerateLazyCompileStub(Assembler* assembler) { | 1717 void StubCode::GenerateLazyCompileStub(Assembler* assembler) { |
| 1685 // Preserve arg desc. and IC data object. | 1718 // Preserve arg desc. and IC data object. |
| 1686 __ EnterStubFrame(); | 1719 __ EnterStubFrame(); |
| 1687 __ PushList((1 << R4) | (1 << R5)); | 1720 __ PushList((1 << R4) | (1 << R5)); |
| 1688 __ Push(R0); // Pass function. | 1721 __ Push(R0); // Pass function. |
| 1689 __ CallRuntime(kCompileFunctionRuntimeEntry, 1); | 1722 __ CallRuntime(kCompileFunctionRuntimeEntry, 1); |
| 1690 __ Pop(R0); // Restore argument. | 1723 __ Pop(R0); // Restore argument. |
| 1691 __ PopList((1 << R4) | (1 << R5)); // Restore arg desc. and IC data. | 1724 __ PopList((1 << R4) | (1 << R5)); // Restore arg desc. and IC data. |
| 1692 __ LeaveStubFrame(); | 1725 __ LeaveStubFrame(); |
| 1693 | 1726 |
| 1727 __ ldr(CODE_REG, FieldAddress(R0, Function::code_offset())); |
| 1694 __ ldr(R2, FieldAddress(R0, Function::entry_point_offset())); | 1728 __ ldr(R2, FieldAddress(R0, Function::entry_point_offset())); |
| 1695 __ bx(R2); | 1729 __ bx(R2); |
| 1696 } | 1730 } |
| 1697 | 1731 |
| 1698 | 1732 |
| 1699 // R5: Contains an ICData. | 1733 // R5: Contains an ICData. |
| 1700 void StubCode::GenerateICCallBreakpointStub(Assembler* assembler) { | 1734 void StubCode::GenerateICCallBreakpointStub(Assembler* assembler) { |
| 1701 __ EnterStubFrame(); | 1735 __ EnterStubFrame(); |
| 1702 __ LoadObject(R0, Object::null_object()); | 1736 __ LoadObject(R0, Object::null_object()); |
| 1703 // Preserve arguments descriptor and make room for result. | 1737 // Preserve arguments descriptor and make room for result. |
| 1704 __ PushList((1 << R0) | (1 << R5)); | 1738 __ PushList((1 << R0) | (1 << R5)); |
| 1705 __ CallRuntime(kBreakpointRuntimeHandlerRuntimeEntry, 0); | 1739 __ CallRuntime(kBreakpointRuntimeHandlerRuntimeEntry, 0); |
| 1706 __ PopList((1 << R0) | (1 << R5)); | 1740 __ PopList((1 << R0) | (1 << R5)); |
| 1707 __ LeaveStubFrame(); | 1741 __ LeaveStubFrame(); |
| 1742 __ mov(CODE_REG, Operand(R0)); |
| 1743 __ ldr(R0, FieldAddress(CODE_REG, Code::entry_point_offset())); |
| 1708 __ bx(R0); | 1744 __ bx(R0); |
| 1709 } | 1745 } |
| 1710 | 1746 |
| 1711 | 1747 |
| 1712 void StubCode::GenerateRuntimeCallBreakpointStub(Assembler* assembler) { | 1748 void StubCode::GenerateRuntimeCallBreakpointStub(Assembler* assembler) { |
| 1713 __ EnterStubFrame(); | 1749 __ EnterStubFrame(); |
| 1714 __ LoadObject(R0, Object::null_object()); | 1750 __ LoadObject(R0, Object::null_object()); |
| 1715 // Make room for result. | 1751 // Make room for result. |
| 1716 __ PushList((1 << R0)); | 1752 __ PushList((1 << R0)); |
| 1717 __ CallRuntime(kBreakpointRuntimeHandlerRuntimeEntry, 0); | 1753 __ CallRuntime(kBreakpointRuntimeHandlerRuntimeEntry, 0); |
| 1718 __ PopList((1 << R0)); | 1754 __ PopList((1 << CODE_REG)); |
| 1719 __ LeaveStubFrame(); | 1755 __ LeaveStubFrame(); |
| 1756 __ ldr(R0, FieldAddress(CODE_REG, Code::entry_point_offset())); |
| 1720 __ bx(R0); | 1757 __ bx(R0); |
| 1721 } | 1758 } |
| 1722 | 1759 |
| 1723 | 1760 |
| 1724 // Called only from unoptimized code. All relevant registers have been saved. | 1761 // Called only from unoptimized code. All relevant registers have been saved. |
| 1725 void StubCode::GenerateDebugStepCheckStub( | 1762 void StubCode::GenerateDebugStepCheckStub( |
| 1726 Assembler* assembler) { | 1763 Assembler* assembler) { |
| 1727 // Check single stepping. | 1764 // Check single stepping. |
| 1728 Label stepping, done_stepping; | 1765 Label stepping, done_stepping; |
| 1729 __ LoadIsolate(R1); | 1766 __ LoadIsolate(R1); |
| (...skipping 159 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1889 void StubCode::GenerateOptimizeFunctionStub(Assembler* assembler) { | 1926 void StubCode::GenerateOptimizeFunctionStub(Assembler* assembler) { |
| 1890 __ EnterStubFrame(); | 1927 __ EnterStubFrame(); |
| 1891 __ Push(R4); | 1928 __ Push(R4); |
| 1892 __ LoadObject(IP, Object::null_object()); | 1929 __ LoadObject(IP, Object::null_object()); |
| 1893 __ Push(IP); // Setup space on stack for return value. | 1930 __ Push(IP); // Setup space on stack for return value. |
| 1894 __ Push(R6); | 1931 __ Push(R6); |
| 1895 __ CallRuntime(kOptimizeInvokedFunctionRuntimeEntry, 1); | 1932 __ CallRuntime(kOptimizeInvokedFunctionRuntimeEntry, 1); |
| 1896 __ Pop(R0); // Discard argument. | 1933 __ Pop(R0); // Discard argument. |
| 1897 __ Pop(R0); // Get Code object | 1934 __ Pop(R0); // Get Code object |
| 1898 __ Pop(R4); // Restore argument descriptor. | 1935 __ Pop(R4); // Restore argument descriptor. |
| 1936 __ LeaveStubFrame(); |
| 1937 __ mov(CODE_REG, Operand(R0)); |
| 1899 __ ldr(R0, FieldAddress(R0, Code::entry_point_offset())); | 1938 __ ldr(R0, FieldAddress(R0, Code::entry_point_offset())); |
| 1900 __ LeaveStubFrame(); | |
| 1901 __ bx(R0); | 1939 __ bx(R0); |
| 1902 __ bkpt(0); | 1940 __ bkpt(0); |
| 1903 } | 1941 } |
| 1904 | 1942 |
| 1905 | 1943 |
| 1906 // Does identical check (object references are equal or not equal) with special | 1944 // Does identical check (object references are equal or not equal) with special |
| 1907 // checks for boxed numbers. | 1945 // checks for boxed numbers. |
| 1908 // LR: return address. | 1946 // LR: return address. |
| 1909 // Return Zero condition flag set if equal. | 1947 // Return Zero condition flag set if equal. |
| 1910 // Note: A Mint cannot contain a value that would fit in Smi, a Bigint | 1948 // Note: A Mint cannot contain a value that would fit in Smi, a Bigint |
| (...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1992 const Register right = R0; | 2030 const Register right = R0; |
| 1993 __ ldr(left, Address(SP, 1 * kWordSize)); | 2031 __ ldr(left, Address(SP, 1 * kWordSize)); |
| 1994 __ ldr(right, Address(SP, 0 * kWordSize)); | 2032 __ ldr(right, Address(SP, 0 * kWordSize)); |
| 1995 GenerateIdenticalWithNumberCheckStub(assembler, left, right, temp); | 2033 GenerateIdenticalWithNumberCheckStub(assembler, left, right, temp); |
| 1996 __ Ret(); | 2034 __ Ret(); |
| 1997 | 2035 |
| 1998 if (FLAG_support_debugger) { | 2036 if (FLAG_support_debugger) { |
| 1999 __ Bind(&stepping); | 2037 __ Bind(&stepping); |
| 2000 __ EnterStubFrame(); | 2038 __ EnterStubFrame(); |
| 2001 __ CallRuntime(kSingleStepHandlerRuntimeEntry, 0); | 2039 __ CallRuntime(kSingleStepHandlerRuntimeEntry, 0); |
| 2040 __ RestoreCodePointer(); |
| 2002 __ LeaveStubFrame(); | 2041 __ LeaveStubFrame(); |
| 2003 __ b(&done_stepping); | 2042 __ b(&done_stepping); |
| 2004 } | 2043 } |
| 2005 } | 2044 } |
| 2006 | 2045 |
| 2007 | 2046 |
| 2008 // Called from optimized code only. | 2047 // Called from optimized code only. |
| 2009 // LR: return address. | 2048 // LR: return address. |
| 2010 // SP + 4: left operand. | 2049 // SP + 4: left operand. |
| 2011 // SP + 0: right operand. | 2050 // SP + 0: right operand. |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2051 __ cmp(R4, Operand(R0)); | 2090 __ cmp(R4, Operand(R0)); |
| 2052 __ b(&update, NE); | 2091 __ b(&update, NE); |
| 2053 | 2092 |
| 2054 __ Bind(&call_target_function); | 2093 __ Bind(&call_target_function); |
| 2055 // Call the target found in the cache. For a class id match, this is a | 2094 // Call the target found in the cache. For a class id match, this is a |
| 2056 // proper target for the given name and arguments descriptor. If the | 2095 // proper target for the given name and arguments descriptor. If the |
| 2057 // illegal class id was found, the target is a cache miss handler that can | 2096 // illegal class id was found, the target is a cache miss handler that can |
| 2058 // be invoked as a normal Dart function. | 2097 // be invoked as a normal Dart function. |
| 2059 __ add(IP, R2, Operand(R3, LSL, 2)); | 2098 __ add(IP, R2, Operand(R3, LSL, 2)); |
| 2060 __ ldr(R0, FieldAddress(IP, base + kWordSize)); | 2099 __ ldr(R0, FieldAddress(IP, base + kWordSize)); |
| 2100 __ ldr(CODE_REG, FieldAddress(R0, Function::code_offset())); |
| 2061 __ ldr(target, FieldAddress(R0, Function::entry_point_offset())); | 2101 __ ldr(target, FieldAddress(R0, Function::entry_point_offset())); |
| 2062 } | 2102 } |
| 2063 | 2103 |
| 2064 | 2104 |
| 2065 // Called from megamorphic calls. | 2105 // Called from megamorphic calls. |
| 2066 // R0: receiver. | 2106 // R0: receiver. |
| 2067 // R1: lookup cache. | 2107 // R1: lookup cache. |
| 2068 // Result: | 2108 // Result: |
| 2069 // R1: entry point. | 2109 // R1: entry point. |
| 2070 void StubCode::GenerateMegamorphicLookupStub(Assembler* assembler) { | 2110 void StubCode::GenerateMegamorphicLookupStub(Assembler* assembler) { |
| 2071 EmitMegamorphicLookup(assembler, R0, R1, R1); | 2111 EmitMegamorphicLookup(assembler, R0, R1, R1); |
| 2072 __ Ret(); | 2112 __ Ret(); |
| 2073 } | 2113 } |
| 2074 | 2114 |
| 2075 } // namespace dart | 2115 } // namespace dart |
| 2076 | 2116 |
| 2077 #endif // defined TARGET_ARCH_ARM | 2117 #endif // defined TARGET_ARCH_ARM |
| OLD | NEW |