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 |