| 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/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."); |
| (...skipping 187 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 210 __ AddImmediate(R0, R0, Instructions::HeaderSize() - kHeapObjectTag); | 212 __ AddImmediate(R0, R0, Instructions::HeaderSize() - kHeapObjectTag); |
| 211 __ bx(R0); | 213 __ bx(R0); |
| 212 } | 214 } |
| 213 | 215 |
| 214 | 216 |
| 215 void StubCode::GenerateFixCallersTargetStub(Assembler* assembler) { | 217 void StubCode::GenerateFixCallersTargetStub(Assembler* assembler) { |
| 216 __ Unimplemented("FixCallersTarget stub"); | 218 __ Unimplemented("FixCallersTarget stub"); |
| 217 } | 219 } |
| 218 | 220 |
| 219 | 221 |
| 222 // Input parameters: |
| 223 // R2: Smi-tagged argument count, may be zero. |
| 224 // FP[kLastParamSlotIndex]: Last argument. |
| 225 static void PushArgumentsArray(Assembler* assembler) { |
| 226 // Allocate array to store arguments of caller. |
| 227 __ LoadImmediate(R1, reinterpret_cast<intptr_t>(Object::null())); |
| 228 // R1: Null element type for raw Array. |
| 229 // R2: Smi-tagged argument count, may be zero. |
| 230 __ BranchLink(&StubCode::AllocateArrayLabel()); |
| 231 // R0: newly allocated array. |
| 232 // R2: Smi-tagged argument count, may be zero (was preserved by the stub). |
| 233 __ Push(R0); // Array is in R0 and on top of stack. |
| 234 __ add(R1, FP, ShifterOperand(R2, LSL, 1)); |
| 235 __ AddImmediate(R1, (kLastParamSlotIndex - 1) * kWordSize); |
| 236 __ AddImmediate(R3, R0, Array::data_offset() - kHeapObjectTag); |
| 237 Label loop, loop_condition; |
| 238 __ b(&loop_condition); |
| 239 __ Bind(&loop); |
| 240 __ ldr(IP, Address(R1, 0)); |
| 241 __ str(IP, Address(R3, 0)); |
| 242 __ AddImmediate(R1, -kWordSize); |
| 243 __ AddImmediate(R3, kWordSize); |
| 244 __ Bind(&loop_condition); |
| 245 __ subs(R2, R2, ShifterOperand(Smi::RawValue(1))); // R2 is Smi. |
| 246 __ b(&loop, PL); |
| 247 } |
| 248 |
| 249 |
| 220 void StubCode::GenerateInstanceFunctionLookupStub(Assembler* assembler) { | 250 void StubCode::GenerateInstanceFunctionLookupStub(Assembler* assembler) { |
| 221 __ Unimplemented("InstanceFunctionLookup stub"); | 251 __ Unimplemented("InstanceFunctionLookup stub"); |
| 222 } | 252 } |
| 223 | 253 |
| 224 | 254 |
| 225 void StubCode::GenerateDeoptimizeLazyStub(Assembler* assembler) { | 255 void StubCode::GenerateDeoptimizeLazyStub(Assembler* assembler) { |
| 226 __ Unimplemented("DeoptimizeLazy stub"); | 256 __ Unimplemented("DeoptimizeLazy stub"); |
| 227 } | 257 } |
| 228 | 258 |
| 229 | 259 |
| 230 void StubCode::GenerateDeoptimizeStub(Assembler* assembler) { | 260 void StubCode::GenerateDeoptimizeStub(Assembler* assembler) { |
| 231 __ Unimplemented("Deoptimize stub"); | 261 __ Unimplemented("Deoptimize stub"); |
| 232 } | 262 } |
| 233 | 263 |
| 234 | 264 |
| 235 void StubCode::GenerateMegamorphicMissStub(Assembler* assembler) { | 265 void StubCode::GenerateMegamorphicMissStub(Assembler* assembler) { |
| 236 __ Unimplemented("MegamorphicMiss stub"); | 266 __ Unimplemented("MegamorphicMiss stub"); |
| 237 } | 267 } |
| 238 | 268 |
| 239 | 269 |
| 270 // Called for inline allocation of arrays. |
| 271 // Input parameters: |
| 272 // LR: return address. |
| 273 // R2: Array length as Smi. |
| 274 // R1: array element type (either NULL or an instantiated type). |
| 275 // NOTE: R2 cannot be clobbered here as the caller relies on it being saved. |
| 276 // The newly allocated object is returned in R0. |
| 240 void StubCode::GenerateAllocateArrayStub(Assembler* assembler) { | 277 void StubCode::GenerateAllocateArrayStub(Assembler* assembler) { |
| 241 __ Unimplemented("AllocateArray stub"); | 278 Label slow_case; |
| 279 if (FLAG_inline_alloc) { |
| 280 // Compute the size to be allocated, it is based on the array length |
| 281 // and is computed as: |
| 282 // RoundedAllocationSize((array_length * kwordSize) + sizeof(RawArray)). |
| 283 // Assert that length is a Smi. |
| 284 __ tst(R2, ShifterOperand(kSmiTagSize)); |
| 285 if (FLAG_use_slow_path) { |
| 286 __ b(&slow_case); |
| 287 } else { |
| 288 __ b(&slow_case, NE); |
| 289 } |
| 290 __ ldr(R8, FieldAddress(CTX, Context::isolate_offset())); |
| 291 __ LoadFromOffset(kLoadWord, R8, R8, Isolate::heap_offset()); |
| 292 __ LoadFromOffset(kLoadWord, R8, R8, Heap::new_space_offset()); |
| 293 |
| 294 // Calculate and align allocation size. |
| 295 // Load new object start and calculate next object start. |
| 296 // R1: array element type. |
| 297 // R2: Array length as Smi. |
| 298 // R8: Points to new space object. |
| 299 __ LoadFromOffset(kLoadWord, R0, R8, Scavenger::top_offset()); |
| 300 intptr_t fixed_size = sizeof(RawArray) + kObjectAlignment - 1; |
| 301 __ LoadImmediate(R7, fixed_size); |
| 302 __ add(R7, R7, ShifterOperand(R2, LSL, 1)); // R2 is Smi. |
| 303 ASSERT(kSmiTagShift == 1); |
| 304 __ bic(R7, R7, ShifterOperand(kObjectAlignment - 1)); |
| 305 __ add(R7, R7, ShifterOperand(R0)); |
| 306 |
| 307 // Check if the allocation fits into the remaining space. |
| 308 // R0: potential new object start. |
| 309 // R1: array element type. |
| 310 // R2: Array length as Smi. |
| 311 // R7: potential next object start. |
| 312 // R8: Points to new space object. |
| 313 __ LoadFromOffset(kLoadWord, IP, R8, Scavenger::end_offset()); |
| 314 __ cmp(R7, ShifterOperand(IP)); |
| 315 __ b(&slow_case, CS); // Branch if unsigned higher or equal. |
| 316 |
| 317 // Successfully allocated the object(s), now update top to point to |
| 318 // next object start and initialize the object. |
| 319 // R0: potential new object start. |
| 320 // R7: potential next object start. |
| 321 // R8: Points to new space object. |
| 322 __ StoreToOffset(kStoreWord, R7, R8, Scavenger::top_offset()); |
| 323 __ add(R0, R0, ShifterOperand(kHeapObjectTag)); |
| 324 |
| 325 // R0: new object start as a tagged pointer. |
| 326 // R1: array element type. |
| 327 // R2: Array length as Smi. |
| 328 // R7: new object end address. |
| 329 |
| 330 // Store the type argument field. |
| 331 __ StoreIntoObjectNoBarrier( |
| 332 R0, |
| 333 FieldAddress(R0, Array::type_arguments_offset()), |
| 334 R1); |
| 335 |
| 336 // Set the length field. |
| 337 __ StoreIntoObjectNoBarrier( |
| 338 R0, |
| 339 FieldAddress(R0, Array::length_offset()), |
| 340 R2); |
| 341 |
| 342 // Calculate the size tag. |
| 343 // R0: new object start as a tagged pointer. |
| 344 // R2: Array length as Smi. |
| 345 // R7: new object end address. |
| 346 __ LoadImmediate(R1, fixed_size); |
| 347 __ add(R1, R1, ShifterOperand(R2, LSL, 1)); // R2 is Smi. |
| 348 ASSERT(kSmiTagShift == 1); |
| 349 __ bic(R1, R1, ShifterOperand(kObjectAlignment - 1)); |
| 350 const intptr_t shift = RawObject::kSizeTagBit - kObjectAlignmentLog2; |
| 351 __ CompareImmediate(R1, RawObject::SizeTag::kMaxSizeTag); |
| 352 // If no size tag overflow, shift R1 left, else set R1 to zero. |
| 353 __ mov(R1, ShifterOperand(R1, LSL, shift), LS); |
| 354 __ mov(R1, ShifterOperand(0), HI); |
| 355 |
| 356 // Get the class index and insert it into the tags. |
| 357 __ LoadImmediate(IP, RawObject::ClassIdTag::encode(kArrayCid)); |
| 358 __ orr(R1, R1, ShifterOperand(IP)); |
| 359 __ str(R1, FieldAddress(R0, Array::tags_offset())); |
| 360 |
| 361 // Initialize all array elements to raw_null. |
| 362 // R0: new object start as a tagged pointer. |
| 363 // R7: new object end address. |
| 364 // R2: Array length as Smi. |
| 365 __ AddImmediate(R1, R0, Array::data_offset() - kHeapObjectTag); |
| 366 // R1: iterator which initially points to the start of the variable |
| 367 // data area to be initialized. |
| 368 __ LoadImmediate(IP, reinterpret_cast<intptr_t>(Object::null())); |
| 369 Label loop, test; |
| 370 __ b(&test); |
| 371 __ Bind(&loop); |
| 372 // TODO(cshapiro): StoreIntoObjectNoBarrier |
| 373 __ str(IP, Address(R1, 0)); |
| 374 __ AddImmediate(R1, kWordSize); |
| 375 __ Bind(&test); |
| 376 __ cmp(R1, ShifterOperand(R7)); |
| 377 __ b(&loop, NE); |
| 378 |
| 379 // Done allocating and initializing the array. |
| 380 // R0: new object. |
| 381 // R2: Array length as Smi (preserved for the caller.) |
| 382 __ Ret(); |
| 383 } |
| 384 |
| 385 // Unable to allocate the array using the fast inline code, just call |
| 386 // into the runtime. |
| 387 __ Bind(&slow_case); |
| 388 // Create a stub frame as we are pushing some objects on the stack before |
| 389 // calling into the runtime. |
| 390 __ EnterStubFrame(); |
| 391 __ LoadImmediate(IP, reinterpret_cast<intptr_t>(Object::null())); |
| 392 // Setup space on stack for return value. |
| 393 // Push array length as Smi and element type. |
| 394 __ PushList((1 << R1) | (1 << R2) | (1 << IP)); |
| 395 __ CallRuntime(kAllocateArrayRuntimeEntry); |
| 396 // Pop arguments; result is popped in IP. |
| 397 __ PopList((1 << R1) | (1 << R2) | (1 << IP)); // R2 is restored. |
| 398 __ mov(R0, ShifterOperand(IP)); |
| 399 __ LeaveStubFrame(); |
| 400 __ Ret(); |
| 242 } | 401 } |
| 243 | 402 |
| 244 | 403 |
| 404 // Input parameters: |
| 405 // LR: return address. |
| 406 // SP: address of last argument. |
| 407 // R4: Arguments descriptor array. |
| 408 // Note: The closure object is the first argument to the function being |
| 409 // called, the stub accesses the closure from this location directly |
| 410 // when trying to resolve the call. |
| 245 void StubCode::GenerateCallClosureFunctionStub(Assembler* assembler) { | 411 void StubCode::GenerateCallClosureFunctionStub(Assembler* assembler) { |
| 246 __ Unimplemented("CallClosureFunction stub"); | 412 // Load num_args. |
| 413 __ ldr(R0, FieldAddress(R4, ArgumentsDescriptor::count_offset())); |
| 414 __ sub(R0, R0, ShifterOperand(Smi::RawValue(1))); |
| 415 // Load closure object in R1. |
| 416 __ ldr(R1, Address(SP, R0, LSL, 1)); // R0 (num_args - 1) is a Smi. |
| 417 |
| 418 // Verify that R1 is a closure by checking its class. |
| 419 Label not_closure; |
| 420 __ LoadImmediate(R8, reinterpret_cast<intptr_t>(Object::null())); |
| 421 __ cmp(R1, ShifterOperand(R8)); |
| 422 // Not a closure, but null object. |
| 423 __ b(¬_closure, EQ); |
| 424 __ tst(R1, ShifterOperand(kSmiTagMask)); |
| 425 __ b(¬_closure, EQ); // Not a closure, but a smi. |
| 426 // Verify that the class of the object is a closure class by checking that |
| 427 // class.signature_function() is not null. |
| 428 __ LoadClass(R0, R1, R2); |
| 429 __ ldr(R0, FieldAddress(R0, Class::signature_function_offset())); |
| 430 __ cmp(R0, ShifterOperand(R8)); // R8 is raw null. |
| 431 // Actual class is not a closure class. |
| 432 __ b(¬_closure, EQ); |
| 433 |
| 434 // R0 is just the signature function. Load the actual closure function. |
| 435 __ ldr(R2, FieldAddress(R1, Closure::function_offset())); |
| 436 |
| 437 // Load closure context in CTX; note that CTX has already been preserved. |
| 438 __ ldr(CTX, FieldAddress(R1, Closure::context_offset())); |
| 439 |
| 440 // Load closure function code in R0. |
| 441 __ ldr(R0, FieldAddress(R2, Function::code_offset())); |
| 442 __ cmp(R0, ShifterOperand(R8)); // R8 is raw null. |
| 443 Label function_compiled; |
| 444 __ b(&function_compiled, NE); |
| 445 |
| 446 // Create a stub frame as we are pushing some objects on the stack before |
| 447 // calling into the runtime. |
| 448 __ EnterStubFrame(); |
| 449 |
| 450 // Preserve arguments descriptor array and read-only function object argument. |
| 451 __ PushList((1 << R2) | (1 << R4)); |
| 452 __ CallRuntime(kCompileFunctionRuntimeEntry); |
| 453 // Restore arguments descriptor array and read-only function object argument. |
| 454 __ PopList((1 << R2) | (1 << R4)); |
| 455 // Restore R0. |
| 456 __ ldr(R0, FieldAddress(R2, Function::code_offset())); |
| 457 |
| 458 // Remove the stub frame as we are about to jump to the closure function. |
| 459 __ LeaveStubFrame(); |
| 460 |
| 461 __ Bind(&function_compiled); |
| 462 // R0: Code. |
| 463 // R4: Arguments descriptor array. |
| 464 __ ldr(R0, FieldAddress(R0, Code::instructions_offset())); |
| 465 __ AddImmediate(R0, Instructions::HeaderSize() - kHeapObjectTag); |
| 466 __ bx(R0); |
| 467 |
| 468 __ Bind(¬_closure); |
| 469 // Call runtime to attempt to resolve and invoke a call method on a |
| 470 // non-closure object, passing the non-closure object and its arguments array, |
| 471 // returning here. |
| 472 // If no call method exists, throw a NoSuchMethodError. |
| 473 // R1: non-closure object. |
| 474 // R4: arguments descriptor array. |
| 475 |
| 476 // Create a stub frame as we are pushing some objects on the stack before |
| 477 // calling into the runtime. |
| 478 __ EnterStubFrame(); |
| 479 |
| 480 // Setup space on stack for result from error reporting. |
| 481 __ PushList((1 << R4) | (1 << R8)); // Arguments descriptor and raw null. |
| 482 |
| 483 // Load smi-tagged arguments array length, including the non-closure. |
| 484 __ ldr(R2, FieldAddress(R4, ArgumentsDescriptor::count_offset())); |
| 485 PushArgumentsArray(assembler); |
| 486 |
| 487 // Stack: |
| 488 // TOS + 0: Argument array. |
| 489 // TOS + 1: Arguments descriptor array. |
| 490 // TOS + 2: Place for result from the call. |
| 491 // TOS + 3: Saved FP of previous frame. |
| 492 // TOS + 4: Dart code return address |
| 493 // TOS + 5: PC marker (0 for stub). |
| 494 // TOS + 6: Last argument of caller. |
| 495 // .... |
| 496 __ CallRuntime(kInvokeNonClosureRuntimeEntry); |
| 497 // Remove arguments. |
| 498 __ Drop(2); |
| 499 __ Pop(R0); // Get result into R0. |
| 500 |
| 501 // Remove the stub frame as we are about to return. |
| 502 __ LeaveStubFrame(); |
| 503 __ Ret(); |
| 247 } | 504 } |
| 248 | 505 |
| 249 | 506 |
| 250 // Called when invoking Dart code from C++ (VM code). | 507 // Called when invoking Dart code from C++ (VM code). |
| 251 // Input parameters: | 508 // Input parameters: |
| 252 // LR : points to return address. | 509 // LR : points to return address. |
| 253 // R0 : entrypoint of the Dart function to call. | 510 // R0 : entrypoint of the Dart function to call. |
| 254 // R1 : arguments descriptor array. | 511 // R1 : arguments descriptor array. |
| 255 // R2 : arguments array. | 512 // R2 : arguments array. |
| 256 // R3 : new context containing the current isolate pointer. | 513 // R3 : new context containing the current isolate pointer. |
| (...skipping 178 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 435 // A new InstantiatedTypeArguments object only needs to be allocated if | 692 // A new InstantiatedTypeArguments object only needs to be allocated if |
| 436 // the instantiator is provided (not kNoInstantiator, but may be null). | 693 // the instantiator is provided (not kNoInstantiator, but may be null). |
| 437 __ CompareImmediate(R0, Smi::RawValue(StubCode::kNoInstantiator)); | 694 __ CompareImmediate(R0, Smi::RawValue(StubCode::kNoInstantiator)); |
| 438 __ AddImmediate(R3, type_args_size, NE); | 695 __ AddImmediate(R3, type_args_size, NE); |
| 439 // R4: potential new object end and, if R4 != R3, potential new | 696 // R4: potential new object end and, if R4 != R3, potential new |
| 440 // InstantiatedTypeArguments object start. | 697 // InstantiatedTypeArguments object start. |
| 441 } | 698 } |
| 442 // Check if the allocation fits into the remaining space. | 699 // Check if the allocation fits into the remaining space. |
| 443 // R2: potential new object start. | 700 // R2: potential new object start. |
| 444 // R3: potential next object start. | 701 // R3: potential next object start. |
| 702 __ LoadImmediate(IP, heap->EndAddress()); |
| 703 __ cmp(R3, ShifterOperand(IP)); |
| 445 if (FLAG_use_slow_path) { | 704 if (FLAG_use_slow_path) { |
| 446 __ b(&slow_case); | 705 __ b(&slow_case); |
| 447 } else { | 706 } else { |
| 448 __ LoadImmediate(IP, heap->EndAddress()); | |
| 449 __ cmp(R3, ShifterOperand(IP)); | |
| 450 __ b(&slow_case, CS); // Branch if unsigned higher or equal. | 707 __ b(&slow_case, CS); // Branch if unsigned higher or equal. |
| 451 } | 708 } |
| 452 | 709 |
| 453 // Successfully allocated the object(s), now update top to point to | 710 // Successfully allocated the object(s), now update top to point to |
| 454 // next object start and initialize the object. | 711 // next object start and initialize the object. |
| 455 __ str(R3, Address(R5, 0)); | 712 __ str(R3, Address(R5, 0)); |
| 456 | 713 |
| 457 if (is_cls_parameterized) { | 714 if (is_cls_parameterized) { |
| 458 // Initialize the type arguments field in the object. | 715 // Initialize the type arguments field in the object. |
| 459 // R2: new object start. | 716 // R2: new object start. |
| (...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 532 __ Bind(&done); | 789 __ Bind(&done); |
| 533 } | 790 } |
| 534 if (is_cls_parameterized) { | 791 if (is_cls_parameterized) { |
| 535 // R1: new object type arguments. | 792 // R1: new object type arguments. |
| 536 // Set the type arguments in the new object. | 793 // Set the type arguments in the new object. |
| 537 __ StoreToOffset(kStoreWord, R1, R2, cls.type_arguments_field_offset()); | 794 __ StoreToOffset(kStoreWord, R1, R2, cls.type_arguments_field_offset()); |
| 538 } | 795 } |
| 539 // Done allocating and initializing the instance. | 796 // Done allocating and initializing the instance. |
| 540 // R2: new object still missing its heap tag. | 797 // R2: new object still missing its heap tag. |
| 541 __ add(R0, R2, ShifterOperand(kHeapObjectTag)); | 798 __ add(R0, R2, ShifterOperand(kHeapObjectTag)); |
| 799 // R0: new object. |
| 542 __ Ret(); | 800 __ Ret(); |
| 543 | 801 |
| 544 __ Bind(&slow_case); | 802 __ Bind(&slow_case); |
| 545 } | 803 } |
| 546 if (is_cls_parameterized) { | 804 if (is_cls_parameterized) { |
| 547 __ ldm(IA, SP, (1 << R0) | (1 << R1)); | 805 __ ldm(IA, SP, (1 << R0) | (1 << R1)); |
| 548 } | 806 } |
| 549 // Create a stub frame as we are pushing some objects on the stack before | 807 // Create a stub frame as we are pushing some objects on the stack before |
| 550 // calling into the runtime. | 808 // calling into the runtime. |
| 551 __ EnterStubFrame(true); // Uses pool pointer to pass cls to runtime. | 809 __ EnterStubFrame(true); // Uses pool pointer to pass cls to runtime. |
| (...skipping 11 matching lines...) Expand all Loading... |
| 563 __ CallRuntime(kAllocateObjectRuntimeEntry); // Allocate object. | 821 __ CallRuntime(kAllocateObjectRuntimeEntry); // Allocate object. |
| 564 __ Drop(3); // Pop arguments. | 822 __ Drop(3); // Pop arguments. |
| 565 __ Pop(R0); // Pop result (newly allocated object). | 823 __ Pop(R0); // Pop result (newly allocated object). |
| 566 // R0: new object | 824 // R0: new object |
| 567 // Restore the frame pointer. | 825 // Restore the frame pointer. |
| 568 __ LeaveStubFrame(true); | 826 __ LeaveStubFrame(true); |
| 569 __ Ret(); | 827 __ Ret(); |
| 570 } | 828 } |
| 571 | 829 |
| 572 | 830 |
| 831 // Called for inline allocation of closures. |
| 832 // Input parameters: |
| 833 // LR : return address. |
| 834 // SP + 4 : receiver (null if not an implicit instance closure). |
| 835 // SP + 0 : type arguments object (null if class is no parameterized). |
| 573 void StubCode::GenerateAllocationStubForClosure(Assembler* assembler, | 836 void StubCode::GenerateAllocationStubForClosure(Assembler* assembler, |
| 574 const Function& func) { | 837 const Function& func) { |
| 575 __ Unimplemented("AllocateClosure stub"); | 838 ASSERT(func.IsClosureFunction()); |
| 839 const bool is_implicit_static_closure = |
| 840 func.IsImplicitStaticClosureFunction(); |
| 841 const bool is_implicit_instance_closure = |
| 842 func.IsImplicitInstanceClosureFunction(); |
| 843 const Class& cls = Class::ZoneHandle(func.signature_class()); |
| 844 const bool has_type_arguments = cls.HasTypeArguments(); |
| 845 |
| 846 __ EnterStubFrame(true); // Uses pool pointer to refer to function. |
| 847 const intptr_t kTypeArgumentsFPOffset = 3 * kWordSize; |
| 848 const intptr_t kReceiverFPOffset = 4 * kWordSize; |
| 849 const intptr_t closure_size = Closure::InstanceSize(); |
| 850 const intptr_t context_size = Context::InstanceSize(1); // Captured receiver. |
| 851 if (FLAG_inline_alloc && |
| 852 PageSpace::IsPageAllocatableSize(closure_size + context_size)) { |
| 853 Label slow_case; |
| 854 Heap* heap = Isolate::Current()->heap(); |
| 855 __ LoadImmediate(R5, heap->TopAddress()); |
| 856 __ ldr(R2, Address(R5, 0)); |
| 857 __ AddImmediate(R3, R2, closure_size); |
| 858 if (is_implicit_instance_closure) { |
| 859 __ mov(R4, ShifterOperand(R3)); // R4: new context address. |
| 860 __ AddImmediate(R3, context_size); |
| 861 } |
| 862 // Check if the allocation fits into the remaining space. |
| 863 // R2: potential new closure object. |
| 864 // R3: potential next object start. |
| 865 // R4: potential new context object (only if is_implicit_closure). |
| 866 __ LoadImmediate(IP, heap->EndAddress()); |
| 867 __ cmp(R3, ShifterOperand(IP)); |
| 868 if (FLAG_use_slow_path) { |
| 869 __ b(&slow_case); |
| 870 } else { |
| 871 __ b(&slow_case, CS); // Branch if unsigned higher or equal. |
| 872 } |
| 873 |
| 874 // Successfully allocated the object, now update top to point to |
| 875 // next object start and initialize the object. |
| 876 __ str(R3, Address(R5, 0)); |
| 877 |
| 878 // R2: new closure object. |
| 879 // R4: new context object (only if is_implicit_closure). |
| 880 // Set the tags. |
| 881 uword tags = 0; |
| 882 tags = RawObject::SizeTag::update(closure_size, tags); |
| 883 tags = RawObject::ClassIdTag::update(cls.id(), tags); |
| 884 __ LoadImmediate(R0, tags); |
| 885 __ str(R0, Address(R2, Instance::tags_offset())); |
| 886 |
| 887 // Initialize the function field in the object. |
| 888 // R2: new closure object. |
| 889 // R4: new context object (only if is_implicit_closure). |
| 890 __ LoadObject(R0, func); // Load function of closure to be allocated. |
| 891 __ str(R0, Address(R2, Closure::function_offset())); |
| 892 |
| 893 // Setup the context for this closure. |
| 894 if (is_implicit_static_closure) { |
| 895 ObjectStore* object_store = Isolate::Current()->object_store(); |
| 896 ASSERT(object_store != NULL); |
| 897 const Context& empty_context = |
| 898 Context::ZoneHandle(object_store->empty_context()); |
| 899 __ LoadObject(R0, empty_context); |
| 900 __ str(R0, Address(R2, Closure::context_offset())); |
| 901 } else if (is_implicit_instance_closure) { |
| 902 // Initialize the new context capturing the receiver. |
| 903 const Class& context_class = Class::ZoneHandle(Object::context_class()); |
| 904 // Set the tags. |
| 905 uword tags = 0; |
| 906 tags = RawObject::SizeTag::update(context_size, tags); |
| 907 tags = RawObject::ClassIdTag::update(context_class.id(), tags); |
| 908 __ LoadImmediate(R0, tags); |
| 909 __ str(R0, Address(R4, Context::tags_offset())); |
| 910 |
| 911 // Set number of variables field to 1 (for captured receiver). |
| 912 __ LoadImmediate(R0, 1); |
| 913 __ str(R0, Address(R4, Context::num_variables_offset())); |
| 914 |
| 915 // Set isolate field to isolate of current context. |
| 916 __ ldr(R0, FieldAddress(CTX, Context::isolate_offset())); |
| 917 __ str(R0, Address(R4, Context::isolate_offset())); |
| 918 |
| 919 // Set the parent to null. |
| 920 __ LoadImmediate(R0, reinterpret_cast<intptr_t>(Object::null())); |
| 921 __ str(R0, Address(R4, Context::parent_offset())); |
| 922 |
| 923 // Initialize the context variable to the receiver. |
| 924 __ ldr(R0, Address(FP, kReceiverFPOffset)); |
| 925 __ str(R0, Address(R4, Context::variable_offset(0))); |
| 926 |
| 927 // Set the newly allocated context in the newly allocated closure. |
| 928 __ add(R1, R4, ShifterOperand(kHeapObjectTag)); |
| 929 __ str(R1, Address(R2, Closure::context_offset())); |
| 930 } else { |
| 931 __ str(CTX, Address(R2, Closure::context_offset())); |
| 932 } |
| 933 |
| 934 // Set the type arguments field in the newly allocated closure. |
| 935 __ ldr(R0, Address(FP, kTypeArgumentsFPOffset)); |
| 936 __ str(R0, Address(R2, Closure::type_arguments_offset())); |
| 937 |
| 938 // Done allocating and initializing the instance. |
| 939 // R2: new object still missing its heap tag. |
| 940 __ add(R0, R2, ShifterOperand(kHeapObjectTag)); |
| 941 // R0: new object. |
| 942 __ LeaveStubFrame(true); |
| 943 __ Ret(); |
| 944 |
| 945 __ Bind(&slow_case); |
| 946 } |
| 947 __ LoadImmediate(R0, reinterpret_cast<intptr_t>(Object::null())); |
| 948 __ Push(R0); // Setup space on stack for return value. |
| 949 __ PushObject(func); |
| 950 if (is_implicit_static_closure) { |
| 951 __ CallRuntime(kAllocateImplicitStaticClosureRuntimeEntry); |
| 952 } else { |
| 953 if (is_implicit_instance_closure) { |
| 954 __ ldr(R1, Address(FP, kReceiverFPOffset)); |
| 955 __ Push(R1); // Receiver. |
| 956 } |
| 957 // R0: raw null. |
| 958 if (has_type_arguments) { |
| 959 __ ldr(R0, Address(FP, kTypeArgumentsFPOffset)); |
| 960 } |
| 961 __ Push(R0); // Push type arguments of closure to be allocated or null. |
| 962 |
| 963 if (is_implicit_instance_closure) { |
| 964 __ CallRuntime(kAllocateImplicitInstanceClosureRuntimeEntry); |
| 965 __ Drop(2); // Pop arguments (type arguments of object and receiver). |
| 966 } else { |
| 967 ASSERT(func.IsNonImplicitClosureFunction()); |
| 968 __ CallRuntime(kAllocateClosureRuntimeEntry); |
| 969 __ Drop(1); // Pop argument (type arguments of object). |
| 970 } |
| 971 } |
| 972 __ Drop(1); // Pop function object. |
| 973 __ Pop(R0); |
| 974 // R0: new object |
| 975 // Restore the frame pointer. |
| 976 __ LeaveStubFrame(true); |
| 977 __ Ret(); |
| 576 } | 978 } |
| 577 | 979 |
| 578 | 980 |
| 579 void StubCode::GenerateCallNoSuchMethodFunctionStub(Assembler* assembler) { | 981 void StubCode::GenerateCallNoSuchMethodFunctionStub(Assembler* assembler) { |
| 580 __ Unimplemented("CallNoSuchMethodFunction stub"); | 982 __ Unimplemented("CallNoSuchMethodFunction stub"); |
| 581 } | 983 } |
| 582 | 984 |
| 583 | 985 |
| 584 void StubCode::GenerateOptimizedUsageCounterIncrement(Assembler* assembler) { | 986 void StubCode::GenerateOptimizedUsageCounterIncrement(Assembler* assembler) { |
| 585 __ Unimplemented("OptimizedUsageCounterIncrement stub"); | 987 __ Unimplemented("OptimizedUsageCounterIncrement stub"); |
| (...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 690 __ ldr(R1, Address(R6, 0)); // Next class ID. | 1092 __ ldr(R1, Address(R6, 0)); // Next class ID. |
| 691 | 1093 |
| 692 __ Bind(&test); | 1094 __ Bind(&test); |
| 693 __ CompareImmediate(R1, Smi::RawValue(kIllegalCid)); // Done? | 1095 __ CompareImmediate(R1, Smi::RawValue(kIllegalCid)); // Done? |
| 694 __ b(&loop, NE); | 1096 __ b(&loop, NE); |
| 695 | 1097 |
| 696 // IC miss. | 1098 // IC miss. |
| 697 // Restore return address. | 1099 // Restore return address. |
| 698 __ mov(LR, ShifterOperand(R8)); | 1100 __ mov(LR, ShifterOperand(R8)); |
| 699 | 1101 |
| 700 // Compute address of arguments (first read number of arguments from | 1102 // Compute address of arguments. |
| 701 // arguments descriptor array and then compute address on the stack). | |
| 702 // R7: argument_count - 1 (smi). | 1103 // R7: argument_count - 1 (smi). |
| 703 __ add(R7, SP, ShifterOperand(R7, LSL, 1)); // R7 is Smi. | 1104 __ add(R7, SP, ShifterOperand(R7, LSL, 1)); // R7 is Smi. |
| 704 // R7: address of receiver. | 1105 // R7: address of receiver. |
| 705 // Create a stub frame as we are pushing some objects on the stack before | 1106 // Create a stub frame as we are pushing some objects on the stack before |
| 706 // calling into the runtime. | 1107 // calling into the runtime. |
| 707 __ EnterStubFrame(); | 1108 __ EnterStubFrame(); |
| 708 __ LoadImmediate(R0, reinterpret_cast<intptr_t>(Object::null())); | 1109 __ LoadImmediate(R0, reinterpret_cast<intptr_t>(Object::null())); |
| 709 // Preserve IC data object and arguments descriptor array and | 1110 // Preserve IC data object and arguments descriptor array and |
| 710 // setup space on stack for result (target code object). | 1111 // setup space on stack for result (target code object). |
| 711 __ PushList((1 << R0) | (1 << R4) | (1 << R5)); | 1112 __ PushList((1 << R0) | (1 << R4) | (1 << R5)); |
| (...skipping 371 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1083 __ Bind(&reference_compare); | 1484 __ Bind(&reference_compare); |
| 1084 __ cmp(left, ShifterOperand(right)); | 1485 __ cmp(left, ShifterOperand(right)); |
| 1085 __ Bind(&done); | 1486 __ Bind(&done); |
| 1086 __ PopList((1 << R0) | (1 << R1) | (1 << R2)); | 1487 __ PopList((1 << R0) | (1 << R1) | (1 << R2)); |
| 1087 __ Ret(); | 1488 __ Ret(); |
| 1088 } | 1489 } |
| 1089 | 1490 |
| 1090 } // namespace dart | 1491 } // namespace dart |
| 1091 | 1492 |
| 1092 #endif // defined TARGET_ARCH_ARM | 1493 #endif // defined TARGET_ARCH_ARM |
| OLD | NEW |