Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 #include "vm/globals.h" | 5 #include "vm/globals.h" |
| 6 #if defined(TARGET_ARCH_MIPS) | 6 #if defined(TARGET_ARCH_MIPS) |
| 7 | 7 |
| 8 #include "vm/assembler.h" | 8 #include "vm/assembler.h" |
| 9 #include "vm/code_generator.h" | 9 #include "vm/code_generator.h" |
| 10 #include "vm/compiler.h" | |
| 10 #include "vm/dart_entry.h" | 11 #include "vm/dart_entry.h" |
| 11 #include "vm/flow_graph_compiler.h" | 12 #include "vm/flow_graph_compiler.h" |
| 12 #include "vm/instructions.h" | 13 #include "vm/instructions.h" |
| 14 #include "vm/object_store.h" | |
| 13 #include "vm/stack_frame.h" | 15 #include "vm/stack_frame.h" |
| 14 #include "vm/stub_code.h" | 16 #include "vm/stub_code.h" |
| 15 | 17 |
| 16 #define __ assembler-> | 18 #define __ assembler-> |
| 17 | 19 |
| 18 namespace dart { | 20 namespace dart { |
| 19 | 21 |
| 20 DEFINE_FLAG(bool, inline_alloc, true, "Inline allocation of objects."); | 22 DEFINE_FLAG(bool, inline_alloc, true, "Inline allocation of objects."); |
| 21 DEFINE_FLAG(bool, use_slow_path, false, | 23 DEFINE_FLAG(bool, use_slow_path, false, |
| 22 "Set to true for debugging & verifying the slow paths."); | 24 "Set to true for debugging & verifying the slow paths."); |
| 23 DECLARE_FLAG(int, optimization_counter_threshold); | 25 DECLARE_FLAG(int, optimization_counter_threshold); |
| 24 DECLARE_FLAG(bool, trace_optimized_ic_calls); | 26 DECLARE_FLAG(bool, trace_optimized_ic_calls); |
| 25 | 27 |
| 26 | 28 |
| 27 // Input parameters: | 29 // Input parameters: |
| 28 // RA : return address. | 30 // RA : return address. |
| 29 // SP : address of last argument in argument array. | 31 // SP : address of last argument in argument array. |
| 30 // SP + 4*S4 - 4 : address of first argument in argument array. | 32 // SP + 4*S4 - 4 : address of first argument in argument array. |
| 31 // SP + 4*S4 : address of return value. | 33 // SP + 4*S4 : address of return value. |
| 32 // S5 : address of the runtime function to call. | 34 // S5 : address of the runtime function to call. |
| 33 // S4 : number of arguments to the call. | 35 // S4 : number of arguments to the call. |
| 34 void StubCode::GenerateCallToRuntimeStub(Assembler* assembler) { | 36 void StubCode::GenerateCallToRuntimeStub(Assembler* assembler) { |
| 35 const intptr_t isolate_offset = NativeArguments::isolate_offset(); | 37 const intptr_t isolate_offset = NativeArguments::isolate_offset(); |
| 36 const intptr_t argc_tag_offset = NativeArguments::argc_tag_offset(); | 38 const intptr_t argc_tag_offset = NativeArguments::argc_tag_offset(); |
| 37 const intptr_t argv_offset = NativeArguments::argv_offset(); | 39 const intptr_t argv_offset = NativeArguments::argv_offset(); |
| 38 const intptr_t retval_offset = NativeArguments::retval_offset(); | 40 const intptr_t retval_offset = NativeArguments::retval_offset(); |
| 39 | 41 |
| 42 __ Msg("CallToRuntimeStub"); | |
| 40 __ addiu(SP, SP, Immediate(-2 * kWordSize)); | 43 __ addiu(SP, SP, Immediate(-2 * kWordSize)); |
| 41 __ sw(RA, Address(SP, 1 * kWordSize)); | 44 __ sw(RA, Address(SP, 1 * kWordSize)); |
| 42 __ sw(FP, Address(SP, 0 * kWordSize)); | 45 __ sw(FP, Address(SP, 0 * kWordSize)); |
| 43 __ mov(FP, SP); | 46 __ mov(FP, SP); |
| 44 | 47 |
| 45 // Load current Isolate pointer from Context structure into R0. | 48 // Load current Isolate pointer from Context structure into R0. |
| 46 __ lw(A0, FieldAddress(CTX, Context::isolate_offset())); | 49 __ lw(A0, FieldAddress(CTX, Context::isolate_offset())); |
| 47 | 50 |
| 48 // 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 |
| 49 // to transition to Dart VM C++ code. | 52 // to transition to Dart VM C++ code. |
| (...skipping 24 matching lines...) Expand all Loading... | |
| 74 ASSERT(argv_offset == 2 * kWordSize); | 77 ASSERT(argv_offset == 2 * kWordSize); |
| 75 __ sll(A2, S4, 2); | 78 __ sll(A2, S4, 2); |
| 76 __ addu(A2, FP, A2); // Compute argv. | 79 __ addu(A2, FP, A2); // Compute argv. |
| 77 __ addiu(A2, A2, Immediate(kWordSize)); // Set argv in NativeArguments. | 80 __ addiu(A2, A2, Immediate(kWordSize)); // Set argv in NativeArguments. |
| 78 | 81 |
| 79 ASSERT(retval_offset == 3 * kWordSize); | 82 ASSERT(retval_offset == 3 * kWordSize); |
| 80 __ addiu(A3, A2, Immediate(kWordSize)); // Retval is next to 1st argument. | 83 __ addiu(A3, A2, Immediate(kWordSize)); // Retval is next to 1st argument. |
| 81 | 84 |
| 82 // Call runtime or redirection via simulator. | 85 // Call runtime or redirection via simulator. |
| 83 __ jalr(S5); | 86 __ jalr(S5); |
| 87 __ Msg("CallToRuntimeStub return"); | |
| 84 | 88 |
| 85 // Reset exit frame information in Isolate structure. | 89 // Reset exit frame information in Isolate structure. |
| 86 __ sw(ZR, Address(CTX, Isolate::top_exit_frame_info_offset())); | 90 __ sw(ZR, Address(CTX, Isolate::top_exit_frame_info_offset())); |
| 87 | 91 |
| 88 // Load Context pointer from Isolate structure into A2. | 92 // Load Context pointer from Isolate structure into A2. |
| 89 __ lw(A2, Address(CTX, Isolate::top_context_offset())); | 93 __ lw(A2, Address(CTX, Isolate::top_context_offset())); |
| 90 | 94 |
| 91 // Reset Context pointer in Isolate structure. | 95 // Reset Context pointer in Isolate structure. |
| 92 __ LoadImmediate(A3, reinterpret_cast<intptr_t>(Object::null())); | 96 __ LoadImmediate(A3, reinterpret_cast<intptr_t>(Object::null())); |
| 93 __ sw(A3, Address(CTX, Isolate::top_context_offset())); | 97 __ sw(A3, Address(CTX, Isolate::top_context_offset())); |
| (...skipping 19 matching lines...) Expand all Loading... | |
| 113 // SP : address of return value. | 117 // SP : address of return value. |
| 114 // T5 : address of the native function to call. | 118 // T5 : address of the native function to call. |
| 115 // A2 : address of first argument in argument array. | 119 // A2 : address of first argument in argument array. |
| 116 // A1 : argc_tag including number of arguments and function kind. | 120 // A1 : argc_tag including number of arguments and function kind. |
| 117 void StubCode::GenerateCallNativeCFunctionStub(Assembler* assembler) { | 121 void StubCode::GenerateCallNativeCFunctionStub(Assembler* assembler) { |
| 118 const intptr_t isolate_offset = NativeArguments::isolate_offset(); | 122 const intptr_t isolate_offset = NativeArguments::isolate_offset(); |
| 119 const intptr_t argc_tag_offset = NativeArguments::argc_tag_offset(); | 123 const intptr_t argc_tag_offset = NativeArguments::argc_tag_offset(); |
| 120 const intptr_t argv_offset = NativeArguments::argv_offset(); | 124 const intptr_t argv_offset = NativeArguments::argv_offset(); |
| 121 const intptr_t retval_offset = NativeArguments::retval_offset(); | 125 const intptr_t retval_offset = NativeArguments::retval_offset(); |
| 122 | 126 |
| 127 __ Msg("CallNativeCFunctionStub"); | |
| 123 __ addiu(SP, SP, Immediate(-2 * kWordSize)); | 128 __ addiu(SP, SP, Immediate(-2 * kWordSize)); |
| 124 __ sw(RA, Address(SP, 1 * kWordSize)); | 129 __ sw(RA, Address(SP, 1 * kWordSize)); |
| 125 __ sw(FP, Address(SP, 0 * kWordSize)); | 130 __ sw(FP, Address(SP, 0 * kWordSize)); |
| 126 __ mov(FP, SP); | 131 __ mov(FP, SP); |
| 127 | 132 |
| 128 // Load current Isolate pointer from Context structure into A0. | 133 // Load current Isolate pointer from Context structure into A0. |
| 129 __ lw(A0, FieldAddress(CTX, Context::isolate_offset())); | 134 __ lw(A0, FieldAddress(CTX, Context::isolate_offset())); |
| 130 | 135 |
| 131 // Save exit frame information to enable stack walking as we are about | 136 // Save exit frame information to enable stack walking as we are about |
| 132 // to transition to native code. | 137 // to transition to native code. |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 166 __ addiu(SP, SP, Immediate(-4 * kWordSize)); | 171 __ addiu(SP, SP, Immediate(-4 * kWordSize)); |
| 167 __ sw(A3, Address(SP, 3 * kWordSize)); | 172 __ sw(A3, Address(SP, 3 * kWordSize)); |
| 168 __ sw(A2, Address(SP, 2 * kWordSize)); | 173 __ sw(A2, Address(SP, 2 * kWordSize)); |
| 169 __ sw(A1, Address(SP, 1 * kWordSize)); | 174 __ sw(A1, Address(SP, 1 * kWordSize)); |
| 170 __ sw(A0, Address(SP, 0 * kWordSize)); | 175 __ sw(A0, Address(SP, 0 * kWordSize)); |
| 171 | 176 |
| 172 __ mov(A0, SP); // Pass the pointer to the NativeArguments. | 177 __ mov(A0, SP); // Pass the pointer to the NativeArguments. |
| 173 | 178 |
| 174 // Call native function or redirection via simulator. | 179 // Call native function or redirection via simulator. |
| 175 __ jalr(T5); | 180 __ jalr(T5); |
| 181 __ Msg("CallNativeCFunctionStub return"); | |
| 176 | 182 |
| 177 // Reset exit frame information in Isolate structure. | 183 // Reset exit frame information in Isolate structure. |
| 178 __ sw(ZR, Address(CTX, Isolate::top_exit_frame_info_offset())); | 184 __ sw(ZR, Address(CTX, Isolate::top_exit_frame_info_offset())); |
| 179 | 185 |
| 180 // Load Context pointer from Isolate structure into R2. | 186 // Load Context pointer from Isolate structure into A2. |
| 181 __ lw(A2, Address(CTX, Isolate::top_context_offset())); | 187 __ lw(A2, Address(CTX, Isolate::top_context_offset())); |
| 182 | 188 |
| 183 // Reset Context pointer in Isolate structure. | 189 // Reset Context pointer in Isolate structure. |
| 184 __ LoadImmediate(A3, reinterpret_cast<intptr_t>(Object::null())); | 190 __ LoadImmediate(A3, reinterpret_cast<intptr_t>(Object::null())); |
| 185 __ sw(A3, Address(CTX, Isolate::top_context_offset())); | 191 __ sw(A3, Address(CTX, Isolate::top_context_offset())); |
| 186 | 192 |
| 187 // Cache Context pointer into CTX while executing Dart code. | 193 // Cache Context pointer into CTX while executing Dart code. |
| 188 __ mov(CTX, A2); | 194 __ mov(CTX, A2); |
| 189 | 195 |
| 190 __ mov(SP, FP); | 196 __ mov(SP, FP); |
| 191 __ lw(RA, Address(SP, 1 * kWordSize)); | 197 __ lw(RA, Address(SP, 1 * kWordSize)); |
| 192 __ lw(FP, Address(SP, 0 * kWordSize)); | 198 __ lw(FP, Address(SP, 0 * kWordSize)); |
| 193 __ Ret(); | 199 __ Ret(); |
| 194 __ delay_slot()->addiu(SP, SP, Immediate(2 * kWordSize)); | 200 __ delay_slot()->addiu(SP, SP, Immediate(2 * kWordSize)); |
| 195 } | 201 } |
| 196 | 202 |
| 197 | 203 |
| 198 // Input parameters: | 204 // Input parameters: |
| 199 // S4: arguments descriptor array. | 205 // S4: arguments descriptor array. |
| 200 void StubCode::GenerateCallStaticFunctionStub(Assembler* assembler) { | 206 void StubCode::GenerateCallStaticFunctionStub(Assembler* assembler) { |
| 207 __ Msg("CallStaticFunctionStub"); | |
| 201 __ EnterStubFrame(); | 208 __ EnterStubFrame(); |
| 202 // Setup space on stack for return value and preserve arguments descriptor. | 209 // Setup space on stack for return value and preserve arguments descriptor. |
| 203 __ LoadImmediate(T0, reinterpret_cast<intptr_t>(Object::null())); | 210 __ LoadImmediate(T0, reinterpret_cast<intptr_t>(Object::null())); |
| 204 | 211 |
| 205 __ addiu(SP, SP, Immediate(-2 * kWordSize)); | 212 __ addiu(SP, SP, Immediate(-2 * kWordSize)); |
| 206 __ sw(S4, Address(SP, 1 * kWordSize)); | 213 __ sw(S4, Address(SP, 1 * kWordSize)); |
| 207 __ sw(T0, Address(SP, 0 * kWordSize)); | 214 __ sw(T0, Address(SP, 0 * kWordSize)); |
| 208 | 215 |
| 209 __ CallRuntime(kPatchStaticCallRuntimeEntry); | 216 __ CallRuntime(kPatchStaticCallRuntimeEntry); |
| 217 __ Msg("CallStaticFunctionStub return"); | |
| 210 | 218 |
| 211 // Get Code object result and restore arguments descriptor array. | 219 // Get Code object result and restore arguments descriptor array. |
| 212 __ lw(T0, Address(SP, 0 * kWordSize)); | 220 __ lw(T0, Address(SP, 0 * kWordSize)); |
| 213 __ lw(S4, Address(SP, 1 * kWordSize)); | 221 __ lw(S4, Address(SP, 1 * kWordSize)); |
| 214 __ addiu(SP, SP, Immediate(2 * kWordSize)); | 222 __ addiu(SP, SP, Immediate(2 * kWordSize)); |
| 215 | 223 |
| 216 // Remove the stub frame as we are about to jump to the dart function. | 224 // Remove the stub frame as we are about to jump to the dart function. |
| 217 __ LeaveStubFrame(); | 225 __ LeaveStubFrame(); |
| 218 | 226 |
| 219 __ lw(T0, FieldAddress(T0, Code::instructions_offset())); | 227 __ lw(T0, FieldAddress(T0, Code::instructions_offset())); |
| (...skipping 20 matching lines...) Expand all Loading... | |
| 240 void StubCode::GenerateDeoptimizeStub(Assembler* assembler) { | 248 void StubCode::GenerateDeoptimizeStub(Assembler* assembler) { |
| 241 __ Unimplemented("Deoptimize stub"); | 249 __ Unimplemented("Deoptimize stub"); |
| 242 } | 250 } |
| 243 | 251 |
| 244 | 252 |
| 245 void StubCode::GenerateMegamorphicMissStub(Assembler* assembler) { | 253 void StubCode::GenerateMegamorphicMissStub(Assembler* assembler) { |
| 246 __ Unimplemented("MegamorphicMiss stub"); | 254 __ Unimplemented("MegamorphicMiss stub"); |
| 247 } | 255 } |
| 248 | 256 |
| 249 | 257 |
| 258 // Called for inline allocation of arrays. | |
| 259 // Input parameters: | |
| 260 // LR: return address. | |
|
regis
2013/04/19 18:06:38
RA?
There are other occurrences of LR, search for
zra
2013/04/19 18:21:54
Done.
| |
| 261 // A1: Array length as Smi. | |
| 262 // A0: array element type (either NULL or an instantiated type). | |
| 263 // NOTE: A1 cannot be clobbered here as the caller relies on it being saved. | |
| 264 // The newly allocated object is returned in V0. | |
| 250 void StubCode::GenerateAllocateArrayStub(Assembler* assembler) { | 265 void StubCode::GenerateAllocateArrayStub(Assembler* assembler) { |
| 251 __ Unimplemented("AllocateArray stub"); | 266 __ Msg("AllocateArrayStub"); |
| 252 } | 267 Label slow_case; |
| 253 | 268 if (FLAG_inline_alloc) { |
| 254 | 269 // Compute the size to be allocated, it is based on the array length |
| 270 // and is computed as: | |
| 271 // RoundedAllocationSize((array_length * kwordSize) + sizeof(RawArray)). | |
| 272 // Assert that length is a Smi. | |
| 273 if (FLAG_use_slow_path) { | |
| 274 __ b(&slow_case); | |
| 275 } else { | |
| 276 __ andi(CMPRES, A1, Immediate(kSmiTagMask)); | |
| 277 __ bne(CMPRES, ZR, &slow_case); | |
| 278 } | |
| 279 __ lw(T0, FieldAddress(CTX, Context::isolate_offset())); | |
| 280 __ lw(T0, Address(T0, Isolate::heap_offset())); | |
| 281 __ lw(T0, Address(T0, Heap::new_space_offset())); | |
| 282 | |
| 283 // Calculate and align allocation size. | |
| 284 // Load new object start and calculate next object start. | |
| 285 // A0: array element type. | |
| 286 // A1: Array length as Smi. | |
| 287 // T0: Points to new space object. | |
| 288 __ lw(V0, Address(T0, Scavenger::top_offset())); | |
| 289 intptr_t fixed_size = sizeof(RawArray) + kObjectAlignment - 1; | |
| 290 __ LoadImmediate(T3, fixed_size); | |
| 291 __ sll(TMP1, A1, 1); // A1 is Smi. | |
| 292 __ addu(T3, T3, TMP1); | |
| 293 ASSERT(kSmiTagShift == 1); | |
| 294 __ LoadImmediate(TMP1, ~(kObjectAlignment - 1)); | |
| 295 __ and_(T3, T3, TMP1); | |
| 296 __ addu(T2, T3, V0); | |
| 297 | |
| 298 // Check if the allocation fits into the remaining space. | |
| 299 // V0: potential new object start. | |
| 300 // A0: array element type. | |
| 301 // A1: array length as Smi. | |
| 302 // T0: points to new space object. | |
| 303 // T2: potential next object start. | |
| 304 // T3: array size. | |
| 305 __ lw(TMP1, Address(T0, Scavenger::end_offset())); | |
| 306 __ BranchGreaterEqual(T2, TMP1, &slow_case); | |
| 307 | |
| 308 // Successfully allocated the object(s), now update top to point to | |
| 309 // next object start and initialize the object. | |
| 310 // V0: potential new object start. | |
| 311 // T2: potential next object start. | |
| 312 // T0: Points to new space object. | |
| 313 __ sw(T2, Address(T0, Scavenger::top_offset())); | |
| 314 __ addiu(V0, V0, Immediate(kHeapObjectTag)); | |
| 315 | |
| 316 // V0: new object start as a tagged pointer. | |
| 317 // A0: array element type. | |
| 318 // A1: Array length as Smi. | |
| 319 // T2: new object end address. | |
| 320 | |
| 321 // Store the type argument field. | |
| 322 __ StoreIntoObjectNoBarrier( | |
| 323 V0, | |
| 324 FieldAddress(V0, Array::type_arguments_offset()), | |
| 325 A0); | |
| 326 | |
| 327 // Set the length field. | |
| 328 __ StoreIntoObjectNoBarrier( | |
| 329 V0, | |
| 330 FieldAddress(V0, Array::length_offset()), | |
| 331 A1); | |
| 332 | |
| 333 // Calculate the size tag. | |
| 334 // V0: new object start as a tagged pointer. | |
| 335 // A1: Array length as Smi. | |
| 336 // T2: new object end address. | |
| 337 // T3: array size. | |
| 338 const intptr_t shift = RawObject::kSizeTagBit - kObjectAlignmentLog2; | |
| 339 // If no size tag overflow, shift T3 left, else set T3 to zero. | |
| 340 __ LoadImmediate(TMP2, RawObject::SizeTag::kMaxSizeTag); | |
| 341 __ sltu(CMPRES, TMP2, T3); // CMPRES = TMP2 < T3 ? 1 : 0 | |
| 342 __ sll(TMP1, T3, shift); // TMP1 = T3 << shift; | |
| 343 __ movz(T3, TMP1, CMPRES); // T3 = TMP2 >= T3 ? 0 : T3 | |
| 344 __ movn(T3, ZR, CMPRES); // T3 = TMP2 < T3 ? TMP1 : T3 | |
| 345 | |
| 346 // Get the class index and insert it into the tags. | |
| 347 __ LoadImmediate(TMP1, RawObject::ClassIdTag::encode(kArrayCid)); | |
| 348 __ or_(T3, T3, TMP1); | |
| 349 __ sw(T3, FieldAddress(V0, Array::tags_offset())); | |
| 350 | |
| 351 // Initialize all array elements to raw_null. | |
| 352 // V0: new object start as a tagged pointer. | |
| 353 // T2: new object end address. | |
| 354 // A1: Array length as Smi. | |
| 355 __ AddImmediate(T3, V0, Array::data_offset() - kHeapObjectTag); | |
| 356 // R1: iterator which initially points to the start of the variable | |
| 357 // data area to be initialized. | |
| 358 __ LoadImmediate(TMP1, reinterpret_cast<intptr_t>(Object::null())); | |
| 359 Label loop, test; | |
| 360 __ b(&test); | |
| 361 __ Bind(&loop); | |
| 362 // TODO(cshapiro): StoreIntoObjectNoBarrier | |
| 363 __ sw(TMP1, Address(T3, 0)); | |
| 364 __ AddImmediate(T3, kWordSize); | |
| 365 __ Bind(&test); | |
| 366 __ bne(T3, T2, &loop); | |
| 367 | |
| 368 // Done allocating and initializing the array. | |
| 369 // V0: new object. | |
| 370 // A1: Array length as Smi (preserved for the caller.) | |
| 371 __ Ret(); | |
| 372 } | |
| 373 | |
| 374 // Unable to allocate the array using the fast inline code, just call | |
| 375 // into the runtime. | |
| 376 __ Bind(&slow_case); | |
| 377 // Create a stub frame as we are pushing some objects on the stack before | |
| 378 // calling into the runtime. | |
| 379 __ EnterStubFrame(); | |
| 380 __ LoadImmediate(TMP1, reinterpret_cast<intptr_t>(Object::null())); | |
| 381 // Setup space on stack for return value. | |
| 382 // Push array length as Smi and element type. | |
| 383 __ addiu(SP, SP, Immediate(-3 * kWordSize)); | |
| 384 __ sw(TMP1, Address(SP, 2 * kWordSize)); | |
| 385 __ sw(A1, Address(SP, 1 * kWordSize)); | |
| 386 __ sw(T3, Address(SP, 0 * kWordSize)); | |
| 387 __ CallRuntime(kAllocateArrayRuntimeEntry); | |
| 388 __ Msg("AllocateArrayStub return"); | |
| 389 // Pop arguments; result is popped in IP. | |
| 390 __ lw(TMP1, Address(SP, 2 * kWordSize)); | |
| 391 __ lw(A1, Address(SP, 1 * kWordSize)); | |
| 392 __ lw(T3, Address(SP, 0 * kWordSize)); | |
| 393 __ addiu(SP, SP, Immediate(3 * kWordSize)); | |
| 394 __ mov(V0, TMP1); | |
| 395 __ LeaveStubFrame(); | |
| 396 __ Ret(); | |
| 397 } | |
| 398 | |
| 399 | |
| 400 // Input parameters: | |
| 401 // A1: Smi-tagged argument count, may be zero. | |
| 402 // FP[kLastParamSlotIndex]: Last argument. | |
| 403 static void PushArgumentsArray(Assembler* assembler) { | |
| 404 // Allocate array to store arguments of caller. | |
| 405 __ LoadImmediate(A0, reinterpret_cast<intptr_t>(Object::null())); | |
| 406 // A0: Null element type for raw Array. | |
| 407 // A1: Smi-tagged argument count, may be zero. | |
| 408 __ BranchLink(&StubCode::AllocateArrayLabel()); | |
| 409 // V0: newly allocated array. | |
| 410 // A1: Smi-tagged argument count, may be zero (was preserved by the stub). | |
| 411 __ Push(V0); // Array is in V0 and on top of stack. | |
| 412 __ sll(T1, A1, 1); | |
| 413 __ addu(T1, FP, T1); | |
| 414 __ AddImmediate(T1, (kLastParamSlotIndex - 1) * kWordSize); | |
| 415 __ AddImmediate(T2, V0, Array::data_offset() - kHeapObjectTag); | |
| 416 | |
| 417 Label loop, loop_condition; | |
| 418 __ b(&loop_condition); | |
| 419 __ Bind(&loop); | |
| 420 __ lw(TMP, Address(T1)); | |
| 421 __ sw(TMP, Address(T2)); | |
| 422 __ AddImmediate(T1, -kWordSize); | |
| 423 __ AddImmediate(T3, kWordSize); | |
| 424 __ Bind(&loop_condition); | |
| 425 __ AddImmediate(A1, -Smi::RawValue(1)); // A1 is Smi. | |
| 426 __ BranchGreaterEqual(A1, ZR, &loop); | |
| 427 } | |
| 428 | |
| 429 | |
| 430 // Input parameters: | |
| 431 // LR: return address. | |
| 432 // SP: address of last argument. | |
| 433 // S4: Arguments descriptor array. | |
| 434 // Return: V0. | |
| 435 // Note: The closure object is the first argument to the function being | |
| 436 // called, the stub accesses the closure from this location directly | |
| 437 // when trying to resolve the call. | |
| 255 void StubCode::GenerateCallClosureFunctionStub(Assembler* assembler) { | 438 void StubCode::GenerateCallClosureFunctionStub(Assembler* assembler) { |
| 256 __ Unimplemented("CallClosureFunction stub"); | 439 // Load num_args. |
| 257 } | 440 __ Msg("GenerateCallClosureFunctionStub"); |
| 258 | 441 __ lw(T0, FieldAddress(S4, ArgumentsDescriptor::count_offset())); |
| 259 | 442 __ LoadImmediate(TMP1, Smi::RawValue(1)); |
| 443 __ subu(T0, T0, TMP1); | |
| 444 | |
| 445 // Load closure object in T1. | |
| 446 __ sll(T1, T0, 1); // T0 (num_args - 1) is a Smi. | |
| 447 __ addu(T1, SP, T1); | |
| 448 __ lw(T1, Address(T1)); | |
| 449 | |
| 450 // Verify that T1 is a closure by checking its class. | |
| 451 Label not_closure; | |
| 452 | |
| 453 __ LoadImmediate(T7, reinterpret_cast<intptr_t>(Object::null())); | |
| 454 // See if it is not a closure, but null object. | |
| 455 __ beq(T1, T7, ¬_closure); | |
| 456 | |
| 457 __ andi(CMPRES, T1, Immediate(kSmiTagMask)); | |
| 458 __ beq(CMPRES, ZR, ¬_closure); // Not a closure, but a smi. | |
| 459 | |
| 460 // Verify that the class of the object is a closure class by checking that | |
| 461 // class.signature_function() is not null. | |
| 462 __ LoadClass(T0, T1); | |
| 463 __ lw(T0, FieldAddress(T0, Class::signature_function_offset())); | |
| 464 | |
| 465 // See if actual class is not a closure class. | |
| 466 __ beq(T0, T7, ¬_closure); | |
| 467 | |
| 468 // T0 is just the signature function. Load the actual closure function. | |
| 469 __ lw(T2, FieldAddress(T1, Closure::function_offset())); | |
| 470 | |
| 471 // Load closure context in CTX; note that CTX has already been preserved. | |
| 472 __ lw(CTX, FieldAddress(T1, Closure::context_offset())); | |
| 473 | |
| 474 Label function_compiled; | |
| 475 // Load closure function code in T0. | |
| 476 __ lw(T0, FieldAddress(T2, Function::code_offset())); | |
| 477 __ bne(T0, T7, &function_compiled); | |
| 478 | |
| 479 // Create a stub frame as we are pushing some objects on the stack before | |
| 480 // calling into the runtime. | |
| 481 __ EnterStubFrame(); | |
| 482 | |
| 483 // Preserve arguments descriptor array and read-only function object argument. | |
| 484 __ addiu(SP, SP, Immediate(-2 * kWordSize)); | |
| 485 __ sw(S4, Address(SP, 1 * kWordSize)); | |
| 486 __ sw(T2, Address(SP, 0 * kWordSize)); | |
| 487 __ CallRuntime(kCompileFunctionRuntimeEntry); | |
| 488 __ Msg("GenerateCallClosureFunctionStub return"); | |
| 489 // Restore arguments descriptor array and read-only function object argument. | |
| 490 __ lw(T2, Address(SP, 0 * kWordSize)); | |
| 491 __ lw(S4, Address(SP, 1 * kWordSize)); | |
| 492 __ addiu(SP, SP, Immediate(2 * kWordSize)); | |
| 493 // Restore T0. | |
| 494 __ lw(T0, FieldAddress(T2, Function::code_offset())); | |
| 495 | |
| 496 // Remove the stub frame as we are about to jump to the closure function. | |
| 497 __ LeaveStubFrame(); | |
| 498 | |
| 499 __ Bind(&function_compiled); | |
| 500 // T0: Code. | |
| 501 // S4: Arguments descriptor array. | |
| 502 __ lw(T0, FieldAddress(T0, Code::instructions_offset())); | |
| 503 __ AddImmediate(T0, Instructions::HeaderSize() - kHeapObjectTag); | |
| 504 __ jr(T0); | |
| 505 | |
| 506 __ Bind(¬_closure); | |
| 507 // Call runtime to attempt to resolve and invoke a call method on a | |
| 508 // non-closure object, passing the non-closure object and its arguments array, | |
| 509 // returning here. | |
| 510 // If no call method exists, throw a NoSuchMethodError. | |
| 511 // T1: non-closure object. | |
| 512 // S4: arguments descriptor array. | |
| 513 | |
| 514 // Create a stub frame as we are pushing some objects on the stack before | |
| 515 // calling into the runtime. | |
| 516 __ EnterStubFrame(); | |
| 517 | |
| 518 // Setup space on stack for result from error reporting. | |
| 519 __ addiu(SP, SP, Immediate(2 * kWordSize)); | |
| 520 __ sw(T7, Address(SP, 1 * kWordSize)); // Arguments descriptor and raw null. | |
| 521 __ sw(S4, Address(SP, 0 * kWordSize)); | |
| 522 | |
| 523 // Load smi-tagged arguments array length, including the non-closure. | |
| 524 __ lw(A1, FieldAddress(S4, ArgumentsDescriptor::count_offset())); | |
| 525 PushArgumentsArray(assembler); | |
| 526 | |
| 527 // Stack: | |
| 528 // TOS + 0: Argument array. | |
| 529 // TOS + 1: Arguments descriptor array. | |
| 530 // TOS + 2: Place for result from the call. | |
| 531 // TOS + 3: Saved FP of previous frame. | |
| 532 // TOS + 4: Dart code return address | |
| 533 // TOS + 5: PC marker (0 for stub). | |
| 534 // TOS + 6: Last argument of caller. | |
| 535 // .... | |
| 536 __ CallRuntime(kInvokeNonClosureRuntimeEntry); | |
| 537 // Remove arguments. | |
| 538 __ Drop(2); | |
| 539 __ Pop(V0); // Get result into R0. | |
| 540 | |
| 541 // Remove the stub frame as we are about to return. | |
| 542 __ LeaveStubFrame(); | |
| 543 __ Ret(); | |
| 544 } | |
| 545 | |
| 546 | |
| 260 // Called when invoking Dart code from C++ (VM code). | 547 // Called when invoking Dart code from C++ (VM code). |
| 261 // Input parameters: | 548 // Input parameters: |
| 262 // RA : points to return address. | 549 // RA : points to return address. |
| 263 // A0 : entrypoint of the Dart function to call. | 550 // A0 : entrypoint of the Dart function to call. |
| 264 // A1 : arguments descriptor array. | 551 // A1 : arguments descriptor array. |
| 265 // A2 : arguments array. | 552 // A2 : arguments array. |
| 266 // A3 : new context containing the current isolate pointer. | 553 // A3 : new context containing the current isolate pointer. |
| 267 void StubCode::GenerateInvokeDartCodeStub(Assembler* assembler) { | 554 void StubCode::GenerateInvokeDartCodeStub(Assembler* assembler) { |
| 268 // Save frame pointer coming in. | 555 // Save frame pointer coming in. |
| 556 __ Msg("InvokeDartCodeStub"); | |
| 269 __ EnterStubFrame(); | 557 __ EnterStubFrame(); |
| 270 | 558 |
| 271 // Save new context and C++ ABI callee-saved registers. | 559 // Save new context and C++ ABI callee-saved registers. |
| 272 const intptr_t kNewContextOffset = | 560 const intptr_t kNewContextOffset = |
| 273 -(1 + kAbiPreservedCpuRegCount) * kWordSize; | 561 -(1 + kAbiPreservedCpuRegCount) * kWordSize; |
| 274 | 562 |
| 275 __ addiu(SP, SP, Immediate(-(3 + kAbiPreservedCpuRegCount) * kWordSize)); | 563 __ addiu(SP, SP, Immediate(-(3 + kAbiPreservedCpuRegCount) * kWordSize)); |
| 276 for (int i = S0; i <= S7; i++) { | 564 for (int i = S0; i <= S7; i++) { |
| 277 Register r = static_cast<Register>(i); | 565 Register r = static_cast<Register>(i); |
| 278 __ sw(r, Address(SP, (i - S0 + 3) * kWordSize)); | 566 __ sw(r, Address(SP, (i - S0 + 3) * kWordSize)); |
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 332 __ lw(A3, Address(A2)); | 620 __ lw(A3, Address(A2)); |
| 333 __ Push(A3); | 621 __ Push(A3); |
| 334 __ addiu(A1, A1, Immediate(1)); | 622 __ addiu(A1, A1, Immediate(1)); |
| 335 __ BranchLess(A1, T1, &push_arguments); | 623 __ BranchLess(A1, T1, &push_arguments); |
| 336 __ delay_slot()->addiu(A2, A2, Immediate(kWordSize)); | 624 __ delay_slot()->addiu(A2, A2, Immediate(kWordSize)); |
| 337 | 625 |
| 338 __ Bind(&done_push_arguments); | 626 __ Bind(&done_push_arguments); |
| 339 | 627 |
| 340 // Call the Dart code entrypoint. | 628 // Call the Dart code entrypoint. |
| 341 __ jalr(A0); // S4 is the arguments descriptor array. | 629 __ jalr(A0); // S4 is the arguments descriptor array. |
| 630 __ Msg("InvokeDartCodeStub return"); | |
| 342 | 631 |
| 343 // Read the saved new Context pointer. | 632 // Read the saved new Context pointer. |
| 344 __ lw(CTX, Address(FP, kNewContextOffset)); | 633 __ lw(CTX, Address(FP, kNewContextOffset)); |
| 345 __ lw(CTX, Address(CTX, VMHandles::kOffsetOfRawPtrInHandle)); | 634 __ lw(CTX, Address(CTX, VMHandles::kOffsetOfRawPtrInHandle)); |
| 346 | 635 |
| 347 // Get rid of arguments pushed on the stack. | 636 // Get rid of arguments pushed on the stack. |
| 348 __ AddImmediate(SP, FP, kSavedContextOffsetInEntryFrame); | 637 __ AddImmediate(SP, FP, kSavedContextOffsetInEntryFrame); |
| 349 | 638 |
| 350 // Load Isolate pointer from Context structure into CTX. Drop Context. | 639 // Load Isolate pointer from Context structure into CTX. Drop Context. |
| 351 __ lw(CTX, FieldAddress(CTX, Context::isolate_offset())); | 640 __ lw(CTX, FieldAddress(CTX, Context::isolate_offset())); |
| (...skipping 27 matching lines...) Expand all Loading... | |
| 379 | 668 |
| 380 | 669 |
| 381 DECLARE_LEAF_RUNTIME_ENTRY(void, StoreBufferBlockProcess, Isolate* isolate); | 670 DECLARE_LEAF_RUNTIME_ENTRY(void, StoreBufferBlockProcess, Isolate* isolate); |
| 382 | 671 |
| 383 | 672 |
| 384 // Helper stub to implement Assembler::StoreIntoObject. | 673 // Helper stub to implement Assembler::StoreIntoObject. |
| 385 // Input parameters: | 674 // Input parameters: |
| 386 // T0: Address (i.e. object) being stored into. | 675 // T0: Address (i.e. object) being stored into. |
| 387 void StubCode::GenerateUpdateStoreBufferStub(Assembler* assembler) { | 676 void StubCode::GenerateUpdateStoreBufferStub(Assembler* assembler) { |
| 388 // Save values being destroyed. | 677 // Save values being destroyed. |
| 678 __ Msg("UpdateStoreBufferStub"); | |
| 389 __ addiu(SP, SP, Immediate(-3 * kWordSize)); | 679 __ addiu(SP, SP, Immediate(-3 * kWordSize)); |
| 390 __ sw(T3, Address(SP, 2 * kWordSize)); | 680 __ sw(T3, Address(SP, 2 * kWordSize)); |
| 391 __ sw(T2, Address(SP, 1 * kWordSize)); | 681 __ sw(T2, Address(SP, 1 * kWordSize)); |
| 392 __ sw(T1, Address(SP, 0 * kWordSize)); | 682 __ sw(T1, Address(SP, 0 * kWordSize)); |
| 393 | 683 |
| 394 // Load the isolate out of the context. | 684 // Load the isolate out of the context. |
| 395 // Spilled: T1, T2, T3. | 685 // Spilled: T1, T2, T3. |
| 396 // T0: Address being stored. | 686 // T0: Address being stored. |
| 397 __ lw(T1, FieldAddress(CTX, Context::isolate_offset())); | 687 __ lw(T1, FieldAddress(CTX, Context::isolate_offset())); |
| 398 | 688 |
| 399 // Load top_ out of the StoreBufferBlock and add the address to the pointers_. | 689 // Load top_ out of the StoreBufferBlock and add the address to the pointers_. |
| 400 // T1: Isolate. | 690 // T1: Isolate. |
| 401 intptr_t store_buffer_offset = Isolate::store_buffer_block_offset(); | 691 intptr_t store_buffer_offset = Isolate::store_buffer_block_offset(); |
| 402 __ lw(T2, Address(T1, store_buffer_offset + StoreBufferBlock::top_offset())); | 692 __ lw(T2, Address(T1, store_buffer_offset + StoreBufferBlock::top_offset())); |
| 403 __ sll(T3, T2, 1); | 693 __ sll(T3, T2, 2); |
| 404 __ addu(T3, T1, T3); | 694 __ addu(T3, T1, T3); |
| 405 __ sw(T0, | 695 __ sw(T0, |
| 406 Address(T3, store_buffer_offset + StoreBufferBlock::pointers_offset())); | 696 Address(T3, store_buffer_offset + StoreBufferBlock::pointers_offset())); |
| 407 | 697 |
| 408 // Increment top_ and check for overflow. | 698 // Increment top_ and check for overflow. |
| 409 // T2: top_ | 699 // T2: top_ |
| 410 // T1: Isolate | 700 // T1: Isolate |
| 411 Label L; | 701 Label L; |
| 412 __ AddImmediate(T2, 1); | 702 __ AddImmediate(T2, 1); |
| 413 __ sw(T2, Address(T1, store_buffer_offset + StoreBufferBlock::top_offset())); | 703 __ sw(T2, Address(T1, store_buffer_offset + StoreBufferBlock::top_offset())); |
| 414 __ addiu(CMPRES, T2, Immediate(-StoreBufferBlock::kSize)); | 704 __ addiu(CMPRES, T2, Immediate(-StoreBufferBlock::kSize)); |
| 415 // Restore values. | 705 // Restore values. |
| 416 __ lw(T1, Address(SP, 0 * kWordSize)); | 706 __ lw(T1, Address(SP, 0 * kWordSize)); |
| 417 __ lw(T2, Address(SP, 1 * kWordSize)); | 707 __ lw(T2, Address(SP, 1 * kWordSize)); |
| 418 __ lw(T3, Address(SP, 2 * kWordSize)); | 708 __ lw(T3, Address(SP, 2 * kWordSize)); |
| 419 __ beq(CMPRES, ZR, &L); | 709 __ beq(CMPRES, ZR, &L); |
| 420 __ delay_slot()->addiu(SP, SP, Immediate(3 * kWordSize)); | 710 __ delay_slot()->addiu(SP, SP, Immediate(3 * kWordSize)); |
| 421 __ Ret(); | 711 __ Ret(); |
| 422 | 712 |
| 423 // Handle overflow: Call the runtime leaf function. | 713 // Handle overflow: Call the runtime leaf function. |
| 424 __ Bind(&L); | 714 __ Bind(&L); |
| 425 // Setup frame, push callee-saved registers. | 715 // Setup frame, push callee-saved registers. |
| 426 | 716 |
| 427 __ EnterCallRuntimeFrame(0 * kWordSize); | 717 __ EnterCallRuntimeFrame(0 * kWordSize); |
| 428 __ lw(T0, FieldAddress(CTX, Context::isolate_offset())); | 718 __ lw(T0, FieldAddress(CTX, Context::isolate_offset())); |
| 429 __ CallRuntime(kStoreBufferBlockProcessRuntimeEntry); | 719 __ CallRuntime(kStoreBufferBlockProcessRuntimeEntry); |
| 720 __ Msg("UpdateStoreBufferStub return"); | |
| 430 // Restore callee-saved registers, tear down frame. | 721 // Restore callee-saved registers, tear down frame. |
| 431 __ LeaveCallRuntimeFrame(); | 722 __ LeaveCallRuntimeFrame(); |
| 432 __ Ret(); | 723 __ Ret(); |
| 433 } | 724 } |
| 434 | 725 |
| 435 | 726 |
| 436 // Called for inline allocation of objects. | 727 // Called for inline allocation of objects. |
| 437 // Input parameters: | 728 // Input parameters: |
| 438 // RA : return address. | 729 // RA : return address. |
| 439 // SP + 4 : type arguments object (only if class is parameterized). | 730 // SP + 4 : type arguments object (only if class is parameterized). |
| 440 // SP + 0 : type arguments of instantiator (only if class is parameterized). | 731 // SP + 0 : type arguments of instantiator (only if class is parameterized). |
| 441 void StubCode::GenerateAllocationStubForClass(Assembler* assembler, | 732 void StubCode::GenerateAllocationStubForClass(Assembler* assembler, |
| 442 const Class& cls) { | 733 const Class& cls) { |
| 734 __ Msg("AllocationStubForClass"); | |
| 443 // The generated code is different if the class is parameterized. | 735 // The generated code is different if the class is parameterized. |
| 444 const bool is_cls_parameterized = | 736 const bool is_cls_parameterized = |
| 445 cls.type_arguments_field_offset() != Class::kNoTypeArguments; | 737 cls.type_arguments_field_offset() != Class::kNoTypeArguments; |
| 446 // kInlineInstanceSize is a constant used as a threshold for determining | 738 // kInlineInstanceSize is a constant used as a threshold for determining |
| 447 // when the object initialization should be done as a loop or as | 739 // when the object initialization should be done as a loop or as |
| 448 // straight line code. | 740 // straight line code. |
| 449 const int kInlineInstanceSize = 12; | 741 const int kInlineInstanceSize = 12; |
| 450 const intptr_t instance_size = cls.instance_size(); | 742 const intptr_t instance_size = cls.instance_size(); |
| 451 ASSERT(instance_size > 0); | 743 ASSERT(instance_size > 0); |
| 452 const intptr_t type_args_size = InstantiatedTypeArguments::InstanceSize(); | 744 const intptr_t type_args_size = InstantiatedTypeArguments::InstanceSize(); |
| (...skipping 18 matching lines...) Expand all Loading... | |
| 471 __ Bind(&no_instantiator); | 763 __ Bind(&no_instantiator); |
| 472 // T4: potential new object end and, if T4 != T3, potential new | 764 // T4: potential new object end and, if T4 != T3, potential new |
| 473 // InstantiatedTypeArguments object start. | 765 // InstantiatedTypeArguments object start. |
| 474 } | 766 } |
| 475 // Check if the allocation fits into the remaining space. | 767 // Check if the allocation fits into the remaining space. |
| 476 // T2: potential new object start. | 768 // T2: potential new object start. |
| 477 // T3: potential next object start. | 769 // T3: potential next object start. |
| 478 if (FLAG_use_slow_path) { | 770 if (FLAG_use_slow_path) { |
| 479 __ b(&slow_case); | 771 __ b(&slow_case); |
| 480 } else { | 772 } else { |
| 481 __ BranchGreaterEqual(T3, heap->EndAddress(), &slow_case); | 773 __ LoadImmediate(TMP1, heap->EndAddress()); |
| 774 __ lw(TMP1, Address(TMP1)); | |
| 775 __ BranchGreaterEqual(T3, TMP1, &slow_case); | |
| 482 } | 776 } |
| 483 | 777 |
| 484 // Successfully allocated the object(s), now update top to point to | 778 // Successfully allocated the object(s), now update top to point to |
| 485 // next object start and initialize the object. | 779 // next object start and initialize the object. |
| 486 __ sw(T3, Address(T5)); | 780 __ sw(T3, Address(T5)); |
| 487 | 781 |
| 488 if (is_cls_parameterized) { | 782 if (is_cls_parameterized) { |
| 489 // Initialize the type arguments field in the object. | 783 // Initialize the type arguments field in the object. |
| 490 // T2: new object start. | 784 // T2: new object start. |
| 491 // T4: potential new object end and, if T4 != T3, potential new | 785 // T4: potential new object end and, if T4 != T3, potential new |
| (...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 559 __ AddImmediate(T4, kWordSize); | 853 __ AddImmediate(T4, kWordSize); |
| 560 __ b(&init_loop); | 854 __ b(&init_loop); |
| 561 __ Bind(&done); | 855 __ Bind(&done); |
| 562 } | 856 } |
| 563 if (is_cls_parameterized) { | 857 if (is_cls_parameterized) { |
| 564 // R1: new object type arguments. | 858 // R1: new object type arguments. |
| 565 // Set the type arguments in the new object. | 859 // Set the type arguments in the new object. |
| 566 __ sw(T1, Address(T2, cls.type_arguments_field_offset())); | 860 __ sw(T1, Address(T2, cls.type_arguments_field_offset())); |
| 567 } | 861 } |
| 568 // Done allocating and initializing the instance. | 862 // Done allocating and initializing the instance. |
| 569 // R2: new object still missing its heap tag. | 863 // T2: new object still missing its heap tag. |
| 570 __ Ret(); | 864 __ Ret(); |
| 571 __ delay_slot()->addiu(V0, T2, Immediate(kHeapObjectTag)); | 865 __ delay_slot()->addiu(V0, T2, Immediate(kHeapObjectTag)); |
| 572 | 866 |
| 573 __ Bind(&slow_case); | 867 __ Bind(&slow_case); |
| 574 } | 868 } |
| 575 if (is_cls_parameterized) { | 869 if (is_cls_parameterized) { |
| 576 __ lw(T1, Address(SP, 1 * kWordSize)); | 870 __ lw(T1, Address(SP, 1 * kWordSize)); |
| 577 __ lw(T0, Address(SP, 0 * kWordSize)); | 871 __ lw(T0, Address(SP, 0 * kWordSize)); |
| 578 } | 872 } |
| 579 // Create a stub frame as we are pushing some objects on the stack before | 873 // Create a stub frame as we are pushing some objects on the stack before |
| 580 // calling into the runtime. | 874 // calling into the runtime. |
| 581 __ EnterStubFrame(true); // Uses pool pointer to pass cls to runtime. | 875 __ EnterStubFrame(true); // Uses pool pointer to pass cls to runtime. |
| 582 __ LoadImmediate(T2, reinterpret_cast<intptr_t>(Object::null())); | 876 __ LoadImmediate(T2, reinterpret_cast<intptr_t>(Object::null())); |
| 583 __ Push(T2); // Setup space on stack for return value. | 877 __ Push(T2); // Setup space on stack for return value. |
| 584 __ PushObject(cls); // Push class of object to be allocated. | 878 __ PushObject(cls); // Push class of object to be allocated. |
| 585 if (is_cls_parameterized) { | 879 if (is_cls_parameterized) { |
| 586 // Push type arguments of object to be allocated and of instantiator. | 880 // Push type arguments of object to be allocated and of instantiator. |
| 587 __ addiu(SP, SP, Immediate(-2 * kWordSize)); | 881 __ addiu(SP, SP, Immediate(-2 * kWordSize)); |
| 588 __ sw(T1, Address(SP, 1 * kWordSize)); | 882 __ sw(T1, Address(SP, 1 * kWordSize)); |
| 589 __ sw(T0, Address(SP, 0 * kWordSize)); | 883 __ sw(T0, Address(SP, 0 * kWordSize)); |
| 590 } else { | 884 } else { |
| 591 // Push null type arguments and kNoInstantiator. | 885 // Push null type arguments and kNoInstantiator. |
| 592 __ LoadImmediate(T1, Smi::RawValue(StubCode::kNoInstantiator)); | 886 __ LoadImmediate(T1, Smi::RawValue(StubCode::kNoInstantiator)); |
| 593 __ addiu(SP, SP, Immediate(-2 * kWordSize)); | 887 __ addiu(SP, SP, Immediate(-2 * kWordSize)); |
| 594 __ sw(T2, Address(SP, 1 * kWordSize)); | 888 __ sw(T2, Address(SP, 1 * kWordSize)); |
| 595 __ sw(T1, Address(SP, 0 * kWordSize)); | 889 __ sw(T1, Address(SP, 0 * kWordSize)); |
| 596 } | 890 } |
| 597 __ CallRuntime(kAllocateObjectRuntimeEntry); // Allocate object. | 891 __ CallRuntime(kAllocateObjectRuntimeEntry); // Allocate object. |
| 892 __ Msg("AllocationStubForClass return"); | |
| 598 __ Drop(3); // Pop arguments. | 893 __ Drop(3); // Pop arguments. |
| 599 __ Pop(V0); // Pop result (newly allocated object). | 894 __ Pop(V0); // Pop result (newly allocated object). |
| 600 // V0: new object | 895 // V0: new object |
| 601 // Restore the frame pointer. | 896 // Restore the frame pointer. |
| 602 __ LeaveStubFrame(true); | 897 __ LeaveStubFrame(true); |
| 603 __ Ret(); | 898 __ Ret(); |
| 604 } | 899 } |
| 605 | 900 |
| 606 | 901 |
| 902 // Called for inline allocation of closures. | |
| 903 // Input parameters: | |
| 904 // RA: return address. | |
| 905 // SP + 4 : receiver (null if not an implicit instance closure). | |
| 906 // SP + 0 : type arguments object (null if class is no parameterized). | |
| 607 void StubCode::GenerateAllocationStubForClosure(Assembler* assembler, | 907 void StubCode::GenerateAllocationStubForClosure(Assembler* assembler, |
| 608 const Function& func) { | 908 const Function& func) { |
| 609 __ Unimplemented("AllocateClosure stub"); | 909 ASSERT(func.IsClosureFunction()); |
| 910 const bool is_implicit_static_closure = | |
| 911 func.IsImplicitStaticClosureFunction(); | |
| 912 const bool is_implicit_instance_closure = | |
| 913 func.IsImplicitInstanceClosureFunction(); | |
| 914 const Class& cls = Class::ZoneHandle(func.signature_class()); | |
| 915 const bool has_type_arguments = cls.HasTypeArguments(); | |
| 916 | |
| 917 __ Msg("AllocationStubForClosure"); | |
| 918 __ EnterStubFrame(true); // Uses pool pointer to refer to function. | |
| 919 const intptr_t kTypeArgumentsFPOffset = 4 * kWordSize; | |
| 920 const intptr_t kReceiverFPOffset = 5 * kWordSize; | |
| 921 const intptr_t closure_size = Closure::InstanceSize(); | |
| 922 const intptr_t context_size = Context::InstanceSize(1); // Captured receiver. | |
| 923 if (FLAG_inline_alloc && | |
| 924 PageSpace::IsPageAllocatableSize(closure_size + context_size)) { | |
| 925 Label slow_case; | |
| 926 Heap* heap = Isolate::Current()->heap(); | |
| 927 __ LoadImmediate(T5, heap->TopAddress()); | |
| 928 __ lw(T2, Address(T5)); | |
| 929 __ AddImmediate(T3, T2, closure_size); | |
| 930 if (is_implicit_instance_closure) { | |
| 931 __ mov(T4, T3); // T4: new context address. | |
| 932 __ AddImmediate(T3, context_size); | |
| 933 } | |
| 934 // Check if the allocation fits into the remaining space. | |
| 935 // T2: potential new closure object. | |
| 936 // T3: address of top of heap. | |
| 937 // T4: potential new context object (only if is_implicit_closure). | |
| 938 if (FLAG_use_slow_path) { | |
| 939 __ b(&slow_case); | |
| 940 } else { | |
| 941 __ LoadImmediate(TMP1, heap->EndAddress()); | |
| 942 __ lw(TMP1, Address(TMP1)); | |
| 943 __ BranchGreaterEqual(T3, TMP1, &slow_case); | |
| 944 } | |
| 945 | |
| 946 // Successfully allocated the object, now update top to point to | |
| 947 // next object start and initialize the object. | |
| 948 __ sw(T3, Address(T5)); | |
| 949 | |
| 950 // T2: new closure object. | |
| 951 // T4: new context object (only if is_implicit_closure). | |
| 952 // Set the tags. | |
| 953 uword tags = 0; | |
| 954 tags = RawObject::SizeTag::update(closure_size, tags); | |
| 955 tags = RawObject::ClassIdTag::update(cls.id(), tags); | |
| 956 __ LoadImmediate(T0, tags); | |
| 957 __ sw(T0, Address(T2, Instance::tags_offset())); | |
| 958 | |
| 959 // Initialize the function field in the object. | |
| 960 // T2: new closure object. | |
| 961 // T4: new context object (only if is_implicit_closure). | |
| 962 __ LoadObject(T0, func); // Load function of closure to be allocated. | |
| 963 __ sw(T0, Address(T2, Closure::function_offset())); | |
| 964 | |
| 965 // Setup the context for this closure. | |
| 966 if (is_implicit_static_closure) { | |
| 967 ObjectStore* object_store = Isolate::Current()->object_store(); | |
| 968 ASSERT(object_store != NULL); | |
| 969 const Context& empty_context = | |
| 970 Context::ZoneHandle(object_store->empty_context()); | |
| 971 __ LoadObject(T0, empty_context); | |
| 972 __ sw(T0, Address(T0, Closure::context_offset())); | |
| 973 } else if (is_implicit_instance_closure) { | |
| 974 // Initialize the new context capturing the receiver. | |
| 975 const Class& context_class = Class::ZoneHandle(Object::context_class()); | |
| 976 // Set the tags. | |
| 977 uword tags = 0; | |
| 978 tags = RawObject::SizeTag::update(context_size, tags); | |
| 979 tags = RawObject::ClassIdTag::update(context_class.id(), tags); | |
| 980 __ LoadImmediate(T0, tags); | |
| 981 __ sw(T0, Address(T4, Context::tags_offset())); | |
| 982 | |
| 983 // Set number of variables field to 1 (for captured receiver). | |
| 984 __ LoadImmediate(T0, 1); | |
| 985 __ sw(T0, Address(T4, Context::num_variables_offset())); | |
| 986 | |
| 987 // Set isolate field to isolate of current context. | |
| 988 __ lw(T0, FieldAddress(CTX, Context::isolate_offset())); | |
| 989 __ sw(T0, Address(T4, Context::isolate_offset())); | |
| 990 | |
| 991 // Set the parent to null. | |
| 992 __ LoadImmediate(T0, reinterpret_cast<intptr_t>(Object::null())); | |
| 993 __ sw(T0, Address(T4, Context::parent_offset())); | |
| 994 | |
| 995 // Initialize the context variable to the receiver. | |
| 996 __ lw(T0, Address(FP, kReceiverFPOffset)); | |
| 997 __ sw(T0, Address(T4, Context::variable_offset(0))); | |
| 998 | |
| 999 // Set the newly allocated context in the newly allocated closure. | |
| 1000 __ AddImmediate(T1, T4, kHeapObjectTag); | |
| 1001 __ sw(T1, Address(T2, Closure::context_offset())); | |
| 1002 } else { | |
| 1003 __ sw(CTX, Address(T2, Closure::context_offset())); | |
| 1004 } | |
| 1005 | |
| 1006 // Set the type arguments field in the newly allocated closure. | |
| 1007 __ lw(T0, Address(FP, kTypeArgumentsFPOffset)); | |
| 1008 __ sw(T0, Address(T2, Closure::type_arguments_offset())); | |
| 1009 | |
| 1010 // Done allocating and initializing the instance. | |
| 1011 // V0: new object. | |
| 1012 __ addiu(V0, T2, Immediate(kHeapObjectTag)); | |
| 1013 __ LeaveStubFrame(true); | |
| 1014 __ Ret(); | |
| 1015 | |
| 1016 __ Bind(&slow_case); | |
| 1017 } | |
| 1018 | |
| 1019 __ LoadImmediate(V0, reinterpret_cast<intptr_t>(Object::null())); | |
| 1020 __ Push(V0); // Setup space on stack for return value. | |
| 1021 __ PushObject(func); | |
| 1022 if (is_implicit_static_closure) { | |
| 1023 __ CallRuntime(kAllocateImplicitStaticClosureRuntimeEntry); | |
| 1024 __ Msg("AllocationStubForClosure return"); | |
| 1025 } else { | |
| 1026 if (is_implicit_instance_closure) { | |
| 1027 __ lw(T1, Address(FP, kReceiverFPOffset)); | |
| 1028 __ Push(T1); // Receiver. | |
| 1029 } | |
| 1030 if (has_type_arguments) { | |
| 1031 __ lw(V0, Address(FP, kTypeArgumentsFPOffset)); | |
| 1032 } | |
| 1033 __ Push(V0); // Push type arguments of closure to be allocated or null. | |
| 1034 | |
| 1035 if (is_implicit_instance_closure) { | |
| 1036 __ CallRuntime(kAllocateImplicitInstanceClosureRuntimeEntry); | |
| 1037 __ Msg("AllocationStubForClosure return"); | |
| 1038 __ Drop(2); | |
| 1039 } else { | |
| 1040 ASSERT(func.IsNonImplicitClosureFunction()); | |
| 1041 __ CallRuntime(kAllocateClosureRuntimeEntry); | |
| 1042 __ Msg("AllocationStubForClosure return"); | |
| 1043 __ Drop(1); // Pop argument (type arguments of object). | |
| 1044 } | |
| 1045 } | |
| 1046 __ Drop(1); // Pop function object. | |
| 1047 __ Pop(V0); | |
| 1048 // V0: new object | |
| 1049 // Restore the frame pointer. | |
| 1050 __ LeaveStubFrame(true); | |
| 1051 __ Ret(); | |
| 610 } | 1052 } |
| 611 | 1053 |
| 612 | 1054 |
| 613 void StubCode::GenerateCallNoSuchMethodFunctionStub(Assembler* assembler) { | 1055 void StubCode::GenerateCallNoSuchMethodFunctionStub(Assembler* assembler) { |
| 614 __ Unimplemented("CallNoSuchMethodFunction stub"); | 1056 __ Unimplemented("CallNoSuchMethodFunction stub"); |
| 615 } | 1057 } |
| 616 | 1058 |
| 617 | 1059 |
| 618 void StubCode::GenerateOptimizedUsageCounterIncrement(Assembler* assembler) { | 1060 void StubCode::GenerateOptimizedUsageCounterIncrement(Assembler* assembler) { |
| 619 __ Unimplemented("OptimizedUsageCounterIncrement stub"); | 1061 __ Unimplemented("OptimizedUsageCounterIncrement stub"); |
| 620 } | 1062 } |
| 621 | 1063 |
| 622 | 1064 |
| 623 // Loads function into 'temp_reg'. | 1065 // Loads function into 'temp_reg'. |
| 624 void StubCode::GenerateUsageCounterIncrement(Assembler* assembler, | 1066 void StubCode::GenerateUsageCounterIncrement(Assembler* assembler, |
| 625 Register temp_reg) { | 1067 Register temp_reg) { |
| 1068 __ Msg("UsageCounterIncrement"); | |
| 626 Register ic_reg = S5; | 1069 Register ic_reg = S5; |
| 627 Register func_reg = temp_reg; | 1070 Register func_reg = temp_reg; |
| 628 ASSERT(temp_reg == T0); | 1071 ASSERT(temp_reg == T0); |
| 629 __ lw(func_reg, FieldAddress(ic_reg, ICData::function_offset())); | 1072 __ lw(func_reg, FieldAddress(ic_reg, ICData::function_offset())); |
| 630 __ lw(T1, FieldAddress(func_reg, Function::usage_counter_offset())); | 1073 __ lw(T1, FieldAddress(func_reg, Function::usage_counter_offset())); |
| 631 Label is_hot; | 1074 Label is_hot; |
| 632 if (FlowGraphCompiler::CanOptimize()) { | 1075 if (FlowGraphCompiler::CanOptimize()) { |
| 633 ASSERT(FLAG_optimization_counter_threshold > 1); | 1076 ASSERT(FLAG_optimization_counter_threshold > 1); |
| 634 // The usage_counter is always less than FLAG_optimization_counter_threshold | 1077 // The usage_counter is always less than FLAG_optimization_counter_threshold |
| 635 // except when the function gets optimized. | 1078 // except when the function gets optimized. |
| (...skipping 14 matching lines...) Expand all Loading... | |
| 650 // S4: Arguments descriptor array. | 1093 // S4: Arguments descriptor array. |
| 651 // Control flow: | 1094 // Control flow: |
| 652 // - If receiver is null -> jump to IC miss. | 1095 // - If receiver is null -> jump to IC miss. |
| 653 // - If receiver is Smi -> load Smi class. | 1096 // - If receiver is Smi -> load Smi class. |
| 654 // - If receiver is not-Smi -> load receiver's class. | 1097 // - If receiver is not-Smi -> load receiver's class. |
| 655 // - Check if 'num_args' (including receiver) match any IC data group. | 1098 // - Check if 'num_args' (including receiver) match any IC data group. |
| 656 // - Match found -> jump to target. | 1099 // - Match found -> jump to target. |
| 657 // - Match not found -> jump to IC miss. | 1100 // - Match not found -> jump to IC miss. |
| 658 void StubCode::GenerateNArgsCheckInlineCacheStub(Assembler* assembler, | 1101 void StubCode::GenerateNArgsCheckInlineCacheStub(Assembler* assembler, |
| 659 intptr_t num_args) { | 1102 intptr_t num_args) { |
| 1103 __ Msg("NArgsCheckInlineCacheStub"); | |
| 660 ASSERT(num_args > 0); | 1104 ASSERT(num_args > 0); |
| 661 #if defined(DEBUG) | 1105 #if defined(DEBUG) |
| 662 { Label ok; | 1106 { Label ok; |
| 663 // Check that the IC data array has NumberOfArgumentsChecked() == num_args. | 1107 // Check that the IC data array has NumberOfArgumentsChecked() == num_args. |
| 664 // 'num_args_tested' is stored as an untagged int. | 1108 // 'num_args_tested' is stored as an untagged int. |
| 665 __ lw(T0, FieldAddress(S5, ICData::num_args_tested_offset())); | 1109 __ lw(T0, FieldAddress(S5, ICData::num_args_tested_offset())); |
| 666 __ BranchEqual(T0, num_args, &ok); | 1110 __ BranchEqual(T0, num_args, &ok); |
| 667 __ Stop("Incorrect stub for IC data"); | 1111 __ Stop("Incorrect stub for IC data"); |
| 668 __ Bind(&ok); | 1112 __ Bind(&ok); |
| 669 } | 1113 } |
| 670 #endif // DEBUG | 1114 #endif // DEBUG |
| 671 | 1115 |
| 672 // Preserve return address, since LR is needed for subroutine call. | 1116 // Preserve return address, since LR is needed for subroutine call. |
| 673 __ mov(T2, RA); | 1117 __ mov(T2, RA); |
| 674 // Loop that checks if there is an IC data match. | 1118 // Loop that checks if there is an IC data match. |
| 675 Label loop, update, test, found, get_class_id_as_smi; | 1119 Label loop, update, test, found, get_class_id_as_smi; |
| 676 // S5: IC data object (preserved). | 1120 // S5: IC data object (preserved). |
| 677 __ lw(T0, FieldAddress(S5, ICData::ic_data_offset())); | 1121 __ lw(T0, FieldAddress(S5, ICData::ic_data_offset())); |
| 678 // T0: ic_data_array with check entries: classes and target functions. | 1122 // T0: ic_data_array with check entries: classes and target functions. |
| 679 __ AddImmediate(T0, Array::data_offset() - kHeapObjectTag); | 1123 __ AddImmediate(T0, Array::data_offset() - kHeapObjectTag); |
| 680 // T0: points directly to the first ic data array element. | 1124 // T0: points directly to the first ic data array element. |
| 681 | 1125 |
| 682 // Get the receiver's class ID (first read number of arguments from | 1126 // Get the receiver's class ID (first read number of arguments from |
| 683 // arguments descriptor array and then access the receiver from the stack). | 1127 // arguments descriptor array and then access the receiver from the stack). |
| 684 __ lw(T1, FieldAddress(S4, ArgumentsDescriptor::count_offset())); | 1128 __ lw(T1, FieldAddress(S4, ArgumentsDescriptor::count_offset())); |
| 685 __ AddImmediate(T1, -Smi::RawValue(1)); | 1129 __ LoadImmediate(TMP1, Smi::RawValue(1)); |
| 1130 __ subu(T1, T1, TMP1); | |
| 686 __ sll(T3, T1, 1); // T1 (argument_count - 1) is smi. | 1131 __ sll(T3, T1, 1); // T1 (argument_count - 1) is smi. |
| 687 __ addu(T3, T3, SP); | 1132 __ addu(T3, T3, SP); |
| 688 __ bal(&get_class_id_as_smi); | 1133 __ bal(&get_class_id_as_smi); |
| 689 __ delay_slot()->lw(T3, Address(T3)); | 1134 __ delay_slot()->lw(T3, Address(T3)); |
| 690 // T1: argument_count - 1 (smi). | 1135 // T1: argument_count - 1 (smi). |
| 691 // T3: receiver's class ID (smi). | 1136 // T3: receiver's class ID (smi). |
| 692 __ b(&test); | 1137 __ b(&test); |
| 693 __ delay_slot()->lw(T4, Address(T0)); // First class id (smi) to check. | 1138 __ delay_slot()->lw(T4, Address(T0)); // First class id (smi) to check. |
| 694 | 1139 |
| 695 __ Bind(&loop); | 1140 __ Bind(&loop); |
| (...skipping 18 matching lines...) Expand all Loading... | |
| 714 __ bne(T3, T4, &skip); | 1159 __ bne(T3, T4, &skip); |
| 715 __ b(&found); // Break. | 1160 __ b(&found); // Break. |
| 716 __ delay_slot()->mov(RA, T2); // Restore return address if found. | 1161 __ delay_slot()->mov(RA, T2); // Restore return address if found. |
| 717 __ Bind(&skip); | 1162 __ Bind(&skip); |
| 718 } | 1163 } |
| 719 } | 1164 } |
| 720 __ Bind(&update); | 1165 __ Bind(&update); |
| 721 // Reload receiver class ID. It has not been destroyed when num_args == 1. | 1166 // Reload receiver class ID. It has not been destroyed when num_args == 1. |
| 722 if (num_args > 1) { | 1167 if (num_args > 1) { |
| 723 __ sll(T3, T1, 1); | 1168 __ sll(T3, T1, 1); |
| 724 __ addu(T3, SP, T3); | 1169 __ addu(T3, T3, SP); |
| 725 __ bal(&get_class_id_as_smi); | 1170 __ bal(&get_class_id_as_smi); |
| 726 __ delay_slot()->lw(T3, Address(T3)); | 1171 __ delay_slot()->lw(T3, Address(T3)); |
| 727 } | 1172 } |
| 728 | 1173 |
| 729 const intptr_t entry_size = ICData::TestEntryLengthFor(num_args) * kWordSize; | 1174 const intptr_t entry_size = ICData::TestEntryLengthFor(num_args) * kWordSize; |
| 730 __ AddImmediate(T0, entry_size); // Next entry. | 1175 __ AddImmediate(T0, entry_size); // Next entry. |
| 731 __ lw(T4, Address(T0)); // Next class ID. | 1176 __ lw(T4, Address(T0)); // Next class ID. |
| 732 | 1177 |
| 733 __ Bind(&test); | 1178 __ Bind(&test); |
| 734 __ BranchNotEqual(T4, Smi::RawValue(kIllegalCid), &loop); // Done? | 1179 __ BranchNotEqual(T4, Smi::RawValue(kIllegalCid), &loop); // Done? |
| 735 | 1180 |
| 736 // IC miss. | 1181 // IC miss. |
| 737 // Restore return address. | 1182 // Restore return address. |
| 738 __ mov(RA, T2); | 1183 __ mov(RA, T2); |
| 739 | 1184 |
| 740 // Compute address of arguments (first read number of arguments from | 1185 // Compute address of arguments (first read number of arguments from |
| 741 // arguments descriptor array and then compute address on the stack). | 1186 // arguments descriptor array and then compute address on the stack). |
| 742 // T1: argument_count - 1 (smi). | 1187 // T1: argument_count - 1 (smi). |
| 743 __ sll(T1, T1, 1); | 1188 __ sll(T1, T1, 1); // T1 is Smi. |
| 744 __ addu(T1, SP, T1); // T1 is Smi. | 1189 __ addu(T1, SP, T1); |
| 745 // T1: address of receiver. | 1190 // T1: address of receiver. |
| 746 // Create a stub frame as we are pushing some objects on the stack before | 1191 // Create a stub frame as we are pushing some objects on the stack before |
| 747 // calling into the runtime. | 1192 // calling into the runtime. |
| 748 __ EnterStubFrame(); | 1193 __ EnterStubFrame(); |
| 749 __ LoadImmediate(T3, reinterpret_cast<intptr_t>(Object::null())); | 1194 __ LoadImmediate(T3, reinterpret_cast<intptr_t>(Object::null())); |
| 750 // Preserve IC data object and arguments descriptor array and | 1195 // Preserve IC data object and arguments descriptor array and |
| 751 // setup space on stack for result (target code object). | 1196 // setup space on stack for result (target code object). |
| 752 __ addiu(SP, SP, Immediate(-3 * kWordSize)); | 1197 __ addiu(SP, SP, Immediate(-3 * kWordSize)); |
| 753 __ sw(S5, Address(SP, 2 * kWordSize)); | 1198 __ sw(S5, Address(SP, 2 * kWordSize)); |
| 754 __ sw(S4, Address(SP, 1 * kWordSize)); | 1199 __ sw(S4, Address(SP, 1 * kWordSize)); |
| (...skipping 10 matching lines...) Expand all Loading... | |
| 765 | 1210 |
| 766 if (num_args == 1) { | 1211 if (num_args == 1) { |
| 767 __ CallRuntime(kInlineCacheMissHandlerOneArgRuntimeEntry); | 1212 __ CallRuntime(kInlineCacheMissHandlerOneArgRuntimeEntry); |
| 768 } else if (num_args == 2) { | 1213 } else if (num_args == 2) { |
| 769 __ CallRuntime(kInlineCacheMissHandlerTwoArgsRuntimeEntry); | 1214 __ CallRuntime(kInlineCacheMissHandlerTwoArgsRuntimeEntry); |
| 770 } else if (num_args == 3) { | 1215 } else if (num_args == 3) { |
| 771 __ CallRuntime(kInlineCacheMissHandlerThreeArgsRuntimeEntry); | 1216 __ CallRuntime(kInlineCacheMissHandlerThreeArgsRuntimeEntry); |
| 772 } else { | 1217 } else { |
| 773 UNIMPLEMENTED(); | 1218 UNIMPLEMENTED(); |
| 774 } | 1219 } |
| 1220 __ Msg("NArgsCheckInlineCacheStub return"); | |
| 775 // Remove the call arguments pushed earlier, including the IC data object | 1221 // Remove the call arguments pushed earlier, including the IC data object |
| 776 // and the arguments descriptor array. | 1222 // and the arguments descriptor array. |
| 777 __ Drop(num_args + 2); | 1223 __ Drop(num_args + 2); |
| 778 // Pop returned code object into T3 (null if not found). | 1224 // Pop returned code object into T3 (null if not found). |
| 779 // Restore arguments descriptor array and IC data array. | 1225 // Restore arguments descriptor array and IC data array. |
| 780 __ lw(T3, Address(SP, 0 * kWordSize)); | 1226 __ lw(T3, Address(SP, 0 * kWordSize)); |
| 781 __ lw(S4, Address(SP, 1 * kWordSize)); | 1227 __ lw(S4, Address(SP, 1 * kWordSize)); |
| 782 __ lw(S5, Address(SP, 2 * kWordSize)); | 1228 __ lw(S5, Address(SP, 2 * kWordSize)); |
| 783 __ addiu(SP, SP, Immediate(3 * kWordSize)); | 1229 __ addiu(SP, SP, Immediate(3 * kWordSize)); |
| 784 __ LeaveStubFrame(); | 1230 __ LeaveStubFrame(); |
| (...skipping 16 matching lines...) Expand all Loading... | |
| 801 | 1247 |
| 802 __ AddImmediateDetectOverflow(T4, T4, Smi::RawValue(1), T5); | 1248 __ AddImmediateDetectOverflow(T4, T4, Smi::RawValue(1), T5); |
| 803 | 1249 |
| 804 __ bgez(T5, &call_target_function); // No overflow. | 1250 __ bgez(T5, &call_target_function); // No overflow. |
| 805 __ delay_slot()->sw(T4, Address(T0, count_offset)); | 1251 __ delay_slot()->sw(T4, Address(T0, count_offset)); |
| 806 | 1252 |
| 807 __ LoadImmediate(T1, Smi::RawValue(Smi::kMaxValue)); | 1253 __ LoadImmediate(T1, Smi::RawValue(Smi::kMaxValue)); |
| 808 __ sw(T1, Address(T0, count_offset)); | 1254 __ sw(T1, Address(T0, count_offset)); |
| 809 | 1255 |
| 810 __ Bind(&call_target_function); | 1256 __ Bind(&call_target_function); |
| 811 // T0: Target function. | 1257 // T3: Target function. |
| 812 __ lw(T3, FieldAddress(T3, Function::code_offset())); | 1258 __ lw(T3, FieldAddress(T3, Function::code_offset())); |
| 813 __ lw(T3, FieldAddress(T3, Code::instructions_offset())); | 1259 __ lw(T3, FieldAddress(T3, Code::instructions_offset())); |
| 814 __ AddImmediate(T3, Instructions::HeaderSize() - kHeapObjectTag); | 1260 __ AddImmediate(T3, Instructions::HeaderSize() - kHeapObjectTag); |
| 815 __ jr(T3); | 1261 __ jr(T3); |
| 816 | 1262 |
| 817 // Instance in T3, return its class-id in T3 as Smi. | 1263 // Instance in T3, return its class-id in T3 as Smi. |
| 818 __ Bind(&get_class_id_as_smi); | 1264 __ Bind(&get_class_id_as_smi); |
| 819 Label not_smi; | 1265 Label not_smi; |
| 820 // Test if Smi -> load Smi class for comparison. | 1266 // Test if Smi -> load Smi class for comparison. |
| 821 __ andi(TMP1, T3, Immediate(kSmiTagMask)); | 1267 __ andi(TMP1, T3, Immediate(kSmiTagMask)); |
| (...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 905 } | 1351 } |
| 906 | 1352 |
| 907 | 1353 |
| 908 // Used to check class and type arguments. Arguments passed in registers: | 1354 // Used to check class and type arguments. Arguments passed in registers: |
| 909 // RA: return address. | 1355 // RA: return address. |
| 910 // A0: instance (must be preserved). | 1356 // A0: instance (must be preserved). |
| 911 // A1: instantiator type arguments or NULL. | 1357 // A1: instantiator type arguments or NULL. |
| 912 // A2: cache array. | 1358 // A2: cache array. |
| 913 // Result in V0: null -> not found, otherwise result (true or false). | 1359 // Result in V0: null -> not found, otherwise result (true or false). |
| 914 static void GenerateSubtypeNTestCacheStub(Assembler* assembler, int n) { | 1360 static void GenerateSubtypeNTestCacheStub(Assembler* assembler, int n) { |
| 1361 __ Msg("SubtypeNTestCacheStub"); | |
| 915 ASSERT((1 <= n) && (n <= 3)); | 1362 ASSERT((1 <= n) && (n <= 3)); |
| 916 if (n > 1) { | 1363 if (n > 1) { |
| 917 // Get instance type arguments. | 1364 // Get instance type arguments. |
| 918 __ LoadClass(T0, A0); | 1365 __ LoadClass(T0, A0); |
| 919 // Compute instance type arguments into R4. | 1366 // Compute instance type arguments into R4. |
| 920 Label has_no_type_arguments; | 1367 Label has_no_type_arguments; |
| 921 __ LoadImmediate(T1, reinterpret_cast<intptr_t>(Object::null())); | 1368 __ LoadImmediate(T1, reinterpret_cast<intptr_t>(Object::null())); |
| 922 __ lw(T2, FieldAddress(T0, | 1369 __ lw(T2, FieldAddress(T0, |
| 923 Class::type_arguments_field_offset_in_words_offset())); | 1370 Class::type_arguments_field_offset_in_words_offset())); |
| 924 __ BranchEqual(T2, Class::kNoTypeArguments, &has_no_type_arguments); | 1371 __ BranchEqual(T2, Class::kNoTypeArguments, &has_no_type_arguments); |
| (...skipping 14 matching lines...) Expand all Loading... | |
| 939 Label loop, found, not_found, next_iteration; | 1386 Label loop, found, not_found, next_iteration; |
| 940 // T0: instance class id. | 1387 // T0: instance class id. |
| 941 // T1: instance type arguments. | 1388 // T1: instance type arguments. |
| 942 // T2: Entry start. | 1389 // T2: Entry start. |
| 943 __ SmiTag(T0); | 1390 __ SmiTag(T0); |
| 944 __ Bind(&loop); | 1391 __ Bind(&loop); |
| 945 __ lw(T3, Address(T2, kWordSize * SubtypeTestCache::kInstanceClassId)); | 1392 __ lw(T3, Address(T2, kWordSize * SubtypeTestCache::kInstanceClassId)); |
| 946 __ BranchEqual(T3, reinterpret_cast<intptr_t>(Object::null()), ¬_found); | 1393 __ BranchEqual(T3, reinterpret_cast<intptr_t>(Object::null()), ¬_found); |
| 947 | 1394 |
| 948 if (n == 1) { | 1395 if (n == 1) { |
| 949 __ BranchEqual(T3, T0, &found); | 1396 __ beq(T3, T0, &found); |
| 950 } else { | 1397 } else { |
| 951 __ BranchNotEqual(T3, T0, &next_iteration); | 1398 __ bne(T3, T0, &next_iteration); |
| 952 __ lw(T3, | 1399 __ lw(T3, |
| 953 Address(T2, kWordSize * SubtypeTestCache::kInstanceTypeArguments)); | 1400 Address(T2, kWordSize * SubtypeTestCache::kInstanceTypeArguments)); |
| 954 if (n == 2) { | 1401 if (n == 2) { |
| 955 __ BranchEqual(T3, T1, &found); | 1402 __ beq(T3, T1, &found); |
| 956 } else { | 1403 } else { |
| 957 __ BranchNotEqual(T3, T1, &next_iteration); | 1404 __ bne(T3, T1, &next_iteration); |
| 958 __ lw(T3, Address(T2, kWordSize * | 1405 __ lw(T3, Address(T2, kWordSize * |
| 959 SubtypeTestCache::kInstantiatorTypeArguments)); | 1406 SubtypeTestCache::kInstantiatorTypeArguments)); |
| 960 __ BranchEqual(T3, A1, &found); | 1407 __ beq(T3, A1, &found); |
| 961 } | 1408 } |
| 962 } | 1409 } |
| 963 __ Bind(&next_iteration); | 1410 __ Bind(&next_iteration); |
| 964 __ AddImmediate(T2, kWordSize * SubtypeTestCache::kTestEntryLength); | 1411 __ AddImmediate(T2, kWordSize * SubtypeTestCache::kTestEntryLength); |
| 965 __ b(&loop); | 1412 __ b(&loop); |
| 966 // Fall through to not found. | 1413 // Fall through to not found. |
| 967 __ Bind(¬_found); | 1414 __ Bind(¬_found); |
| 968 __ LoadImmediate(V0, reinterpret_cast<intptr_t>(Object::null())); | 1415 __ LoadImmediate(V0, reinterpret_cast<intptr_t>(Object::null())); |
| 969 __ Ret(); | 1416 __ Ret(); |
| 970 | 1417 |
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1024 | 1471 |
| 1025 void StubCode::GenerateEqualityWithNullArgStub(Assembler* assembler) { | 1472 void StubCode::GenerateEqualityWithNullArgStub(Assembler* assembler) { |
| 1026 __ Unimplemented("EqualityWithNullArg Stub"); | 1473 __ Unimplemented("EqualityWithNullArg Stub"); |
| 1027 } | 1474 } |
| 1028 | 1475 |
| 1029 | 1476 |
| 1030 // Calls to the runtime to optimize the given function. | 1477 // Calls to the runtime to optimize the given function. |
| 1031 // T0: function to be reoptimized. | 1478 // T0: function to be reoptimized. |
| 1032 // S4: argument descriptor (preserved). | 1479 // S4: argument descriptor (preserved). |
| 1033 void StubCode::GenerateOptimizeFunctionStub(Assembler* assembler) { | 1480 void StubCode::GenerateOptimizeFunctionStub(Assembler* assembler) { |
| 1481 __ Msg("OptimizeFunctionStub"); | |
| 1034 __ EnterStubFrame(); | 1482 __ EnterStubFrame(); |
| 1035 __ Push(S4); | 1483 __ addiu(SP, SP, Immediate(-3 * kWordSize)); |
| 1484 __ sw(S4, Address(SP, 2 * kWordSize)); | |
| 1485 // Setup space on stack for return value. | |
| 1036 __ LoadImmediate(TMP, reinterpret_cast<intptr_t>(Object::null())); | 1486 __ LoadImmediate(TMP, reinterpret_cast<intptr_t>(Object::null())); |
| 1037 __ Push(TMP); // Setup space on stack for return value. | 1487 __ sw(TMP1, Address(SP, 1 * kWordSize)); |
| 1038 __ Push(T0); | 1488 __ sw(T0, Address(SP, 0 * kWordSize)); |
| 1039 __ CallRuntime(kOptimizeInvokedFunctionRuntimeEntry); | 1489 __ CallRuntime(kOptimizeInvokedFunctionRuntimeEntry); |
| 1040 __ Pop(T0); // Discard argument. | 1490 __ Msg("OptimizeFunctionStub return"); |
| 1041 __ Pop(T0); // Get Code object | 1491 __ lw(T0, Address(SP, 1 * kWordSize)); // Get Code object |
| 1042 __ Pop(S4); // Restore argument descriptor. | 1492 __ lw(S4, Address(SP, 2 * kWordSize)); // Restore argument descriptor. |
| 1493 __ addiu(SP, SP, Immediate(3 * kWordSize)); // Discard argument. | |
| 1494 | |
| 1043 __ lw(T0, FieldAddress(T0, Code::instructions_offset())); | 1495 __ lw(T0, FieldAddress(T0, Code::instructions_offset())); |
| 1044 __ AddImmediate(T0, Instructions::HeaderSize() - kHeapObjectTag); | 1496 __ AddImmediate(T0, Instructions::HeaderSize() - kHeapObjectTag); |
| 1045 __ LeaveStubFrame(); | 1497 __ LeaveStubFrame(); |
| 1046 __ jr(T0); | 1498 __ jr(T0); |
| 1047 __ break_(0); | 1499 __ break_(0); |
| 1048 } | 1500 } |
| 1049 | 1501 |
| 1050 | 1502 |
| 1051 DECLARE_LEAF_RUNTIME_ENTRY(intptr_t, | 1503 DECLARE_LEAF_RUNTIME_ENTRY(intptr_t, |
| 1052 BigintCompare, | 1504 BigintCompare, |
| 1053 RawBigint* left, | 1505 RawBigint* left, |
| 1054 RawBigint* right); | 1506 RawBigint* right); |
| 1055 | 1507 |
| 1056 | 1508 |
| 1057 // Does identical check (object references are equal or not equal) with special | 1509 // Does identical check (object references are equal or not equal) with special |
| 1058 // checks for boxed numbers. | 1510 // checks for boxed numbers. |
| 1059 // LR: return address. | 1511 // LR: return address. |
| 1060 // SP + 4: left operand. | 1512 // SP + 4: left operand. |
| 1061 // SP + 0: right operand. | 1513 // SP + 0: right operand. |
| 1062 // Return: CMPRES is zero if equal, non-zero otherwise. | 1514 // Return: CMPRES is zero if equal, non-zero otherwise. |
| 1063 // Note: A Mint cannot contain a value that would fit in Smi, a Bigint | 1515 // Note: A Mint cannot contain a value that would fit in Smi, a Bigint |
| 1064 // cannot contain a value that fits in Mint or Smi. | 1516 // cannot contain a value that fits in Mint or Smi. |
| 1065 void StubCode::GenerateIdenticalWithNumberCheckStub(Assembler* assembler) { | 1517 void StubCode::GenerateIdenticalWithNumberCheckStub(Assembler* assembler) { |
| 1518 __ Msg("IdenticalWithNumberCheckStub"); | |
| 1066 const Register ret = CMPRES; | 1519 const Register ret = CMPRES; |
| 1067 const Register temp1 = TMP1; | 1520 const Register temp1 = TMP1; |
| 1068 const Register temp2 = TMP2; | 1521 const Register temp2 = TMP2; |
| 1069 const Register left = T1; | 1522 const Register left = T1; |
| 1070 const Register right = T0; | 1523 const Register right = T0; |
| 1071 // Preserve left, right and temp. | 1524 // Preserve left, right. |
| 1072 __ addiu(SP, SP, Immediate(-2 * kWordSize)); | 1525 __ addiu(SP, SP, Immediate(-2 * kWordSize)); |
| 1073 __ sw(T1, Address(SP, 1 * kWordSize)); | 1526 __ sw(T1, Address(SP, 1 * kWordSize)); |
| 1074 __ sw(T0, Address(SP, 0 * kWordSize)); | 1527 __ sw(T0, Address(SP, 0 * kWordSize)); |
| 1075 // TOS + 4: left argument. | 1528 // TOS + 3: left argument. |
| 1076 // TOS + 3: right argument. | 1529 // TOS + 2: right argument. |
| 1077 // TOS + 1: saved left | 1530 // TOS + 1: saved left |
| 1078 // TOS + 0: saved right | 1531 // TOS + 0: saved right |
| 1079 __ lw(left, Address(SP, 3 * kWordSize)); | 1532 __ lw(left, Address(SP, 3 * kWordSize)); |
| 1080 __ lw(right, Address(SP, 2 * kWordSize)); | 1533 __ lw(right, Address(SP, 2 * kWordSize)); |
| 1081 Label reference_compare, done, check_mint, check_bigint; | 1534 Label reference_compare, done, check_mint, check_bigint; |
| 1082 // If any of the arguments is Smi do reference compare. | 1535 // If any of the arguments is Smi do reference compare. |
| 1083 __ andi(temp1, left, Immediate(kSmiTagMask)); | 1536 __ andi(temp1, left, Immediate(kSmiTagMask)); |
| 1084 __ beq(temp1, ZR, &reference_compare); | 1537 __ beq(temp1, ZR, &reference_compare); |
| 1085 __ andi(temp1, right, Immediate(kSmiTagMask)); | 1538 __ andi(temp1, right, Immediate(kSmiTagMask)); |
| 1086 __ beq(temp1, ZR, &reference_compare); | 1539 __ beq(temp1, ZR, &reference_compare); |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1123 __ Bind(&check_bigint); | 1576 __ Bind(&check_bigint); |
| 1124 __ LoadImmediate(temp1, kBigintCid); | 1577 __ LoadImmediate(temp1, kBigintCid); |
| 1125 __ LoadClassId(temp2, left); | 1578 __ LoadClassId(temp2, left); |
| 1126 __ bne(temp1, temp2, &reference_compare); | 1579 __ bne(temp1, temp2, &reference_compare); |
| 1127 __ LoadClassId(temp2, right); | 1580 __ LoadClassId(temp2, right); |
| 1128 __ subu(ret, temp1, temp2); | 1581 __ subu(ret, temp1, temp2); |
| 1129 __ bne(ret, ZR, &done); | 1582 __ bne(ret, ZR, &done); |
| 1130 | 1583 |
| 1131 __ EnterStubFrame(0); | 1584 __ EnterStubFrame(0); |
| 1132 __ ReserveAlignedFrameSpace(2 * kWordSize); | 1585 __ ReserveAlignedFrameSpace(2 * kWordSize); |
| 1133 __ addiu(SP, SP, Immediate(-2 * kWordSize)); | |
| 1134 __ sw(T1, Address(SP, 1 * kWordSize)); | 1586 __ sw(T1, Address(SP, 1 * kWordSize)); |
| 1135 __ sw(T0, Address(SP, 0 * kWordSize)); | 1587 __ sw(T0, Address(SP, 0 * kWordSize)); |
| 1136 __ CallRuntime(kBigintCompareRuntimeEntry); | 1588 __ CallRuntime(kBigintCompareRuntimeEntry); |
| 1589 __ Msg("IdenticalWithNumberCheckStub return"); | |
| 1137 // Result in V0, 0 means equal. | 1590 // Result in V0, 0 means equal. |
| 1138 __ LeaveStubFrame(); | 1591 __ LeaveStubFrame(); |
| 1139 __ b(&done); | 1592 __ b(&done); |
| 1140 __ delay_slot()->mov(CMPRES, V0); | 1593 __ delay_slot()->mov(CMPRES, V0); |
| 1141 | 1594 |
| 1142 __ Bind(&reference_compare); | 1595 __ Bind(&reference_compare); |
| 1143 __ subu(ret, left, right); | 1596 __ subu(ret, left, right); |
| 1144 __ Bind(&done); | 1597 __ Bind(&done); |
| 1145 __ lw(T0, Address(SP, 0 * kWordSize)); | 1598 __ lw(T0, Address(SP, 0 * kWordSize)); |
| 1146 __ lw(T1, Address(SP, 1 * kWordSize)); | 1599 __ lw(T1, Address(SP, 1 * kWordSize)); |
| 1147 __ Ret(); | 1600 __ Ret(); |
| 1148 __ delay_slot()->addiu(SP, SP, Immediate(2 * kWordSize)); | 1601 __ delay_slot()->addiu(SP, SP, Immediate(2 * kWordSize)); |
| 1149 } | 1602 } |
| 1150 | 1603 |
| 1151 } // namespace dart | 1604 } // namespace dart |
| 1152 | 1605 |
| 1153 #endif // defined TARGET_ARCH_MIPS | 1606 #endif // defined TARGET_ARCH_MIPS |
| OLD | NEW |