Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1)

Side by Side Diff: runtime/vm/stub_code_arm.cc

Issue 13502002: Support FrameLookup vm test on ARM, requiring among other things: (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: Created 7 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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/dart_entry.h" 10 #include "vm/dart_entry.h"
11 #include "vm/flow_graph_compiler.h"
11 #include "vm/instructions.h" 12 #include "vm/instructions.h"
12 #include "vm/stack_frame.h" 13 #include "vm/stack_frame.h"
13 #include "vm/stub_code.h" 14 #include "vm/stub_code.h"
14 15
15 #define __ assembler-> 16 #define __ assembler->
16 17
17 namespace dart { 18 namespace dart {
18 19
20 DEFINE_FLAG(bool, inline_alloc, true, "Inline allocation of objects.");
21 DEFINE_FLAG(bool, use_slow_path, false,
22 "Set to true for debugging & verifying the slow paths.");
23 DECLARE_FLAG(int, optimization_counter_threshold);
24 DECLARE_FLAG(bool, trace_optimized_ic_calls);
25
26
19 // Input parameters: 27 // Input parameters:
20 // LR : return address. 28 // LR : return address.
21 // SP : address of last argument in argument array. 29 // SP : address of last argument in argument array.
22 // SP + 4*R4 - 4 : address of first argument in argument array. 30 // SP + 4*R4 - 4 : address of first argument in argument array.
23 // SP + 4*R4 : address of return value. 31 // SP + 4*R4 : address of return value.
24 // R5 : address of the runtime function to call. 32 // R5 : address of the runtime function to call.
25 // R4 : number of arguments to the call. 33 // R4 : number of arguments to the call.
26 void StubCode::GenerateCallToRuntimeStub(Assembler* assembler) { 34 void StubCode::GenerateCallToRuntimeStub(Assembler* assembler) {
27 const intptr_t isolate_offset = NativeArguments::isolate_offset(); 35 const intptr_t isolate_offset = NativeArguments::isolate_offset();
28 const intptr_t argc_tag_offset = NativeArguments::argc_tag_offset(); 36 const intptr_t argc_tag_offset = NativeArguments::argc_tag_offset();
(...skipping 317 matching lines...) Expand 10 before | Expand all | Expand 10 after
346 void StubCode::GenerateAllocateContextStub(Assembler* assembler) { 354 void StubCode::GenerateAllocateContextStub(Assembler* assembler) {
347 __ Unimplemented("AllocateContext stub"); 355 __ Unimplemented("AllocateContext stub");
348 } 356 }
349 357
350 358
351 void StubCode::GenerateUpdateStoreBufferStub(Assembler* assembler) { 359 void StubCode::GenerateUpdateStoreBufferStub(Assembler* assembler) {
352 __ Unimplemented("UpdateStoreBuffer stub"); 360 __ Unimplemented("UpdateStoreBuffer stub");
353 } 361 }
354 362
355 363
364 // Called for inline allocation of objects.
365 // Input parameters:
366 // LR : return address.
367 // SP + 4 : type arguments object (only if class is parameterized).
368 // SP + 0 : type arguments of instantiator (only if class is parameterized).
356 void StubCode::GenerateAllocationStubForClass(Assembler* assembler, 369 void StubCode::GenerateAllocationStubForClass(Assembler* assembler,
357 const Class& cls) { 370 const Class& cls) {
358 __ Unimplemented("AllocateObject stub"); 371 // The generated code is different if the class is parameterized.
372 const bool is_cls_parameterized =
373 cls.type_arguments_field_offset() != Class::kNoTypeArguments;
374 // kInlineInstanceSize is a constant used as a threshold for determining
375 // when the object initialization should be done as a loop or as
376 // straight line code.
377 const int kInlineInstanceSize = 12;
zra 2013/04/03 17:39:47 Why 12? Should this be a flag?
regis 2013/04/03 20:06:07 The flag would only be useful until the value is t
378 const intptr_t instance_size = cls.instance_size();
379 ASSERT(instance_size > 0);
380 const intptr_t type_args_size = InstantiatedTypeArguments::InstanceSize();
381 if (FLAG_inline_alloc &&
382 PageSpace::IsPageAllocatableSize(instance_size + type_args_size)) {
383 Label slow_case;
384 Heap* heap = Isolate::Current()->heap();
385 __ LoadImmediate(R5, heap->TopAddress());
386 __ ldr(R2, Address(R5, 0));
387 __ AddImmediate(R3, R2, instance_size);
388 if (is_cls_parameterized) {
389 __ ldm(IA, SP, (1 << R0) | (1 << R1));
390 __ mov(R4, ShifterOperand(R3));
391 // A new InstantiatedTypeArguments object only needs to be allocated if
392 // the instantiator is provided (not kNoInstantiator, but may be null).
393 __ CompareImmediate(R0, Smi::RawValue(StubCode::kNoInstantiator));
394 __ AddImmediate(R3, type_args_size, NE);
395 // R4: potential new object end and, if R4 != R3, potential new
396 // InstantiatedTypeArguments object start.
397 }
398 // Check if the allocation fits into the remaining space.
399 // R2: potential new object start.
400 // R3: potential next object start.
401 if (FLAG_use_slow_path) {
402 __ b(&slow_case);
403 } else {
404 __ LoadImmediate(IP, heap->EndAddress());
405 __ cmp(R3, ShifterOperand(IP));
406 __ b(&slow_case, CS); // Branch if unsigned higher or equal.
407 }
408
409 // Successfully allocated the object(s), now update top to point to
410 // next object start and initialize the object.
411 __ str(R3, Address(R5, 0));
412
413 if (is_cls_parameterized) {
414 // Initialize the type arguments field in the object.
415 // R2: new object start.
416 // R4: potential new object end and, if R4 != R3, potential new
417 // InstantiatedTypeArguments object start.
418 // R3: next object start.
419 Label type_arguments_ready;
420 __ cmp(R4, ShifterOperand(R3));
421 __ b(&type_arguments_ready, EQ);
422 // Initialize InstantiatedTypeArguments object at R4.
423 __ str(R1, Address(R4,
424 InstantiatedTypeArguments::uninstantiated_type_arguments_offset()));
425 __ str(R0, Address(R4,
426 InstantiatedTypeArguments::instantiator_type_arguments_offset()));
427 const Class& ita_cls =
428 Class::ZoneHandle(Object::instantiated_type_arguments_class());
429 // Set the tags.
430 uword tags = 0;
431 tags = RawObject::SizeTag::update(type_args_size, tags);
432 tags = RawObject::ClassIdTag::update(ita_cls.id(), tags);
433 __ LoadImmediate(R0, tags);
434 __ str(R0, Address(R4, Instance::tags_offset()));
435 // Set the new InstantiatedTypeArguments object (R4) as the type
436 // arguments (R1) of the new object (R2).
437 __ add(R1, R4, ShifterOperand(kHeapObjectTag));
438 // Set R3 to new object end.
439 __ mov(R3, ShifterOperand(R4));
440 __ Bind(&type_arguments_ready);
441 // R2: new object.
442 // R1: new object type arguments.
443 }
444
445 // R2: new object start.
446 // R3: next object start.
447 // R1: new object type arguments (if is_cls_parameterized).
448 // Set the tags.
449 uword tags = 0;
450 tags = RawObject::SizeTag::update(instance_size, tags);
451 ASSERT(cls.id() != kIllegalCid);
452 tags = RawObject::ClassIdTag::update(cls.id(), tags);
453 __ LoadImmediate(R0, tags);
454 __ str(R0, Address(R2, Instance::tags_offset()));
455
456 // Initialize the remaining words of the object.
457 __ LoadImmediate(R0, reinterpret_cast<intptr_t>(Object::null()));
458
459 // R0: raw null.
460 // R2: new object start.
461 // R3: next object start.
462 // R1: new object type arguments (if is_cls_parameterized).
463 // First try inlining the initialization without a loop.
464 if (instance_size < (kInlineInstanceSize * kWordSize)) {
465 // Check if the object contains any non-header fields.
466 // Small objects are initialized using a consecutive set of writes.
467 for (intptr_t current_offset = sizeof(RawObject);
468 current_offset < instance_size;
469 current_offset += kWordSize) {
470 __ StoreToOffset(kStoreWord, R0, R2, current_offset);
471 }
472 } else {
473 __ add(R4, R2, ShifterOperand(sizeof(RawObject)));
474 // Loop until the whole object is initialized.
475 // R0: raw null.
476 // R2: new object.
477 // R3: next object start.
478 // R4: next word to be initialized.
479 // R1: new object type arguments (if is_cls_parameterized).
480 Label init_loop;
481 Label done;
482 __ Bind(&init_loop);
483 __ cmp(R4, ShifterOperand(R3));
484 __ b(&done, CS);
485 __ str(R0, Address(R4, 0));
486 __ AddImmediate(R4, kWordSize);
487 __ b(&init_loop);
488 __ Bind(&done);
489 }
490 if (is_cls_parameterized) {
491 // R1: new object type arguments.
492 // Set the type arguments in the new object.
493 __ StoreToOffset(kStoreWord, R1, R2, cls.type_arguments_field_offset());
494 }
495 // Done allocating and initializing the instance.
496 // R2: new object still missing its heap tag.
497 __ add(R0, R2, ShifterOperand(kHeapObjectTag));
498 __ Ret();
499
500 __ Bind(&slow_case);
501 }
502 if (is_cls_parameterized) {
503 __ ldm(IA, SP, (1 << R0) | (1 << R1));
504 }
505 // Create a stub frame as we are pushing some objects on the stack before
506 // calling into the runtime.
507 __ EnterStubFrame(true); // Uses pool pointer to pass cls to runtime.
508 __ LoadImmediate(R2, reinterpret_cast<intptr_t>(Object::null()));
509 __ Push(R2); // Setup space on stack for return value.
510 __ PushObject(cls); // Push class of object to be allocated.
511 if (is_cls_parameterized) {
512 // Push type arguments of object to be allocated and of instantiator.
513 __ PushList((1 << R0) | (1 << R1));
514 } else {
515 // Push null type arguments and kNoInstantiator.
516 __ LoadImmediate(R1, Smi::RawValue(StubCode::kNoInstantiator));
517 __ PushList((1 << R1) | (1 << R2));
518 }
519 __ CallRuntime(kAllocateObjectRuntimeEntry); // Allocate object.
520 __ Drop(3); // Pop arguments.
521 __ Pop(R0); // Pop result (newly allocated object).
522 // R0: new object
523 // Restore the frame pointer.
524 __ LeaveStubFrame(true);
525 __ Ret();
359 } 526 }
360 527
361 528
362 void StubCode::GenerateAllocationStubForClosure(Assembler* assembler, 529 void StubCode::GenerateAllocationStubForClosure(Assembler* assembler,
363 const Function& func) { 530 const Function& func) {
364 __ Unimplemented("AllocateClosure stub"); 531 __ Unimplemented("AllocateClosure stub");
365 } 532 }
366 533
367 534
368 void StubCode::GenerateCallNoSuchMethodFunctionStub(Assembler* assembler) { 535 void StubCode::GenerateCallNoSuchMethodFunctionStub(Assembler* assembler) {
369 __ Unimplemented("CallNoSuchMethodFunction stub"); 536 __ Unimplemented("CallNoSuchMethodFunction stub");
370 } 537 }
371 538
372 539
373 void StubCode::GenerateOptimizedUsageCounterIncrement(Assembler* assembler) { 540 void StubCode::GenerateOptimizedUsageCounterIncrement(Assembler* assembler) {
374 __ Unimplemented("OptimizedUsageCounterIncrement stub"); 541 __ Unimplemented("OptimizedUsageCounterIncrement stub");
375 } 542 }
376 543
377 544
545 // Loads function into 'temp_reg'.
378 void StubCode::GenerateUsageCounterIncrement(Assembler* assembler, 546 void StubCode::GenerateUsageCounterIncrement(Assembler* assembler,
379 Register temp_reg) { 547 Register temp_reg) {
380 __ Unimplemented("UsageCounterIncrement stub"); 548 Register ic_reg = R5;
381 } 549 Register func_reg = temp_reg;
382 550 ASSERT(temp_reg == R6);
383 551 __ ldr(func_reg, FieldAddress(ic_reg, ICData::function_offset()));
552 __ ldr(R7, FieldAddress(func_reg, Function::usage_counter_offset()));
553 Label is_hot;
554 if (FlowGraphCompiler::CanOptimize()) {
555 ASSERT(FLAG_optimization_counter_threshold > 1);
556 // The usage_counter is always less than FLAG_optimization_counter_threshold
557 // except when the function gets optimized.
558 __ CompareImmediate(R7, FLAG_optimization_counter_threshold);
559 __ b(&is_hot, EQ);
560 // As long as VM has no OSR do not optimize in the middle of the function
561 // but only at exit so that we have collected all type feedback before
562 // optimizing.
563 }
564 __ add(R7, R7, ShifterOperand(1));
565 __ str(R7, FieldAddress(func_reg, Function::usage_counter_offset()));
566 __ Bind(&is_hot);
567 }
568
569
570 // Generate inline cache check for 'num_args'.
571 // LR: return address
572 // R5: Inline cache data object.
573 // R4: Arguments descriptor array.
574 // Control flow:
575 // - If receiver is null -> jump to IC miss.
576 // - If receiver is Smi -> load Smi class.
577 // - If receiver is not-Smi -> load receiver's class.
578 // - Check if 'num_args' (including receiver) match any IC data group.
579 // - Match found -> jump to target.
580 // - Match not found -> jump to IC miss.
384 void StubCode::GenerateNArgsCheckInlineCacheStub(Assembler* assembler, 581 void StubCode::GenerateNArgsCheckInlineCacheStub(Assembler* assembler,
385 intptr_t num_args) { 582 intptr_t num_args) {
386 __ Unimplemented("NArgsCheckInlineCache stub"); 583 ASSERT(num_args > 0);
387 } 584 #if defined(DEBUG)
388 585 { Label ok;
389 586 // Check that the IC data array has NumberOfArgumentsChecked() == num_args.
587 // 'num_args_tested' is stored as an untagged int.
588 __ ldr(R6, FieldAddress(R5, ICData::num_args_tested_offset()));
589 __ CompareImmediate(R6, num_args);
590 __ b(&ok, EQ);
591 __ Stop("Incorrect stub for IC data");
592 __ Bind(&ok);
593 }
594 #endif // DEBUG
595
596 // Preserve return address, since LR is needed for subroutine call.
597 __ mov(R8, ShifterOperand(LR));
598 // Loop that checks if there is an IC data match.
599 Label loop, update, test, found, get_class_id_as_smi;
600 // R5: IC data object (preserved).
601 __ ldr(R6, FieldAddress(R5, ICData::ic_data_offset()));
602 // R6: ic_data_array with check entries: classes and target functions.
603 __ AddImmediate(R6, R6, Array::data_offset() - kHeapObjectTag);
604 // R6: points directly to the first ic data array element.
605
606 // Get the receiver's class ID (first read number of arguments from
607 // arguments descriptor array and then access the receiver from the stack).
608 __ ldr(R7, FieldAddress(R4, ArgumentsDescriptor::count_offset()));
609 __ sub(R7, R7, ShifterOperand(Smi::RawValue(1)));
610 __ ldr(R0, Address(SP, R7, LSL, 1)); // R7 (argument_count - 1) is smi.
611 __ bl(&get_class_id_as_smi);
612 // R7: argument_count - 1 (smi).
613 // R0: receiver's class ID (smi).
614 __ ldr(R1, Address(R6, 0)); // First class id (smi) to check.
615 __ b(&test);
616
617 __ Bind(&loop);
618 for (int i = 0; i < num_args; i++) {
619 if (i > 0) {
620 // If not the first, load the next argument's class ID.
621 __ AddImmediate(R0, R7, Smi::RawValue(-i));
622 __ ldr(R0, Address(SP, R0, LSL, 1));
623 __ bl(&get_class_id_as_smi);
624 // R0: next argument class ID (smi).
625 __ LoadFromOffset(kLoadWord, R1, R6, i * kWordSize);
626 // R1: next class ID to check (smi).
627 }
628 __ cmp(R0, ShifterOperand(R1)); // Class id match?
629 if (i < (num_args - 1)) {
630 __ b(&update, NE); // Continue.
631 } else {
632 // Last check, all checks before matched.
633 __ mov(LR, ShifterOperand(R8), EQ); // Restore return address if found.
634 __ b(&found, EQ); // Break.
635 }
636 }
637 __ Bind(&update);
638 // Reload receiver class ID. It has not been destroyed when num_args == 1.
639 if (num_args > 1) {
640 __ ldr(R0, Address(SP, R7, LSL, 1));
641 __ bl(&get_class_id_as_smi);
642 }
643
644 const intptr_t entry_size = ICData::TestEntryLengthFor(num_args) * kWordSize;
645 __ AddImmediate(R6, entry_size); // Next entry.
646 __ ldr(R1, Address(R6, 0)); // Next class ID.
647
648 __ Bind(&test);
649 __ CompareImmediate(R1, Smi::RawValue(kIllegalCid)); // Done?
650 __ b(&loop, NE);
651
652 // IC miss.
653 // Restore return address.
654 __ mov(LR, ShifterOperand(R8));
655
656 // Compute address of arguments (first read number of arguments from
657 // arguments descriptor array and then compute address on the stack).
658 // R7: argument_count - 1 (smi).
659 __ add(R7, SP, ShifterOperand(R7, LSL, 1)); // R7 is Smi.
660 // R7: address of receiver.
661 // Create a stub frame as we are pushing some objects on the stack before
662 // calling into the runtime.
663 __ EnterStubFrame();
664 __ LoadImmediate(R0, reinterpret_cast<intptr_t>(Object::null()));
665 // Preserve IC data object and arguments descriptor array and
666 // setup space on stack for result (target code object).
667 __ PushList((1 << R0) | (1 << R4) | (1 << R5));
668 // Push call arguments.
669 for (intptr_t i = 0; i < num_args; i++) {
670 __ LoadFromOffset(kLoadWord, IP, R7, -i * kWordSize);
671 __ Push(IP);
672 }
673 // Pass IC data object and arguments descriptor array.
674 __ PushList((1 << R4) | (1 << R5));
675
676 if (num_args == 1) {
677 __ CallRuntime(kInlineCacheMissHandlerOneArgRuntimeEntry);
678 } else if (num_args == 2) {
679 __ CallRuntime(kInlineCacheMissHandlerTwoArgsRuntimeEntry);
680 } else if (num_args == 3) {
681 __ CallRuntime(kInlineCacheMissHandlerThreeArgsRuntimeEntry);
682 } else {
683 UNIMPLEMENTED();
684 }
685 // Remove the call arguments pushed earlier, including the IC data object
686 // and the arguments descriptor array.
687 __ Drop(num_args + 2);
688 // Pop returned code object into R0 (null if not found).
689 // Restore arguments descriptor array and IC data array.
690 __ PopList((1 << R0) | (1 << R4) | (1 << R5));
691 __ LeaveStubFrame();
692 Label call_target_function;
693 __ CompareImmediate(R0, reinterpret_cast<intptr_t>(Object::null()));
694 __ b(&call_target_function, NE);
695 // NoSuchMethod or closure.
696 // Mark IC call that it may be a closure call that does not collect
697 // type feedback.
698 __ mov(IP, ShifterOperand(1));
699 __ strb(IP, FieldAddress(R5, ICData::is_closure_call_offset()));
700 __ Branch(&StubCode::InstanceFunctionLookupLabel());
701
702 __ Bind(&found);
703 // R6: Pointer to an IC data check group.
704 const intptr_t target_offset = ICData::TargetIndexFor(num_args) * kWordSize;
705 const intptr_t count_offset = ICData::CountIndexFor(num_args) * kWordSize;
706 __ LoadFromOffset(kLoadWord, R0, R6, target_offset);
707 __ LoadFromOffset(kLoadWord, R1, R6, count_offset);
708 __ adds(R1, R1, ShifterOperand(Smi::RawValue(1)));
709 __ StoreToOffset(kStoreWord, R1, R6, count_offset);
710 __ b(&call_target_function, VC); // No overflow.
711 __ LoadImmediate(R1, Smi::RawValue(Smi::kMaxValue));
712 __ StoreToOffset(kStoreWord, R1, R6, count_offset);
713
714 __ Bind(&call_target_function);
715 // R0: Target function.
716 __ ldr(R0, FieldAddress(R0, Function::code_offset()));
717 __ ldr(R0, FieldAddress(R0, Code::instructions_offset()));
718 __ AddImmediate(R0, Instructions::HeaderSize() - kHeapObjectTag);
719 __ bx(R0);
720
721 // Instance in R0, return its class-id in R0 as Smi.
722 __ Bind(&get_class_id_as_smi);
723 Label not_smi;
724 // Test if Smi -> load Smi class for comparison.
725 __ tst(R0, ShifterOperand(kSmiTagMask));
726 __ mov(R0, ShifterOperand(Smi::RawValue(kSmiCid)), EQ);
727 __ bx(LR, EQ);
728 __ LoadClassId(R0, R0);
729 __ SmiTag(R0);
730 __ bx(LR);
731 }
732
733
734 // Use inline cache data array to invoke the target or continue in inline
735 // cache miss handler. Stub for 1-argument check (receiver class).
736 // LR: Return address.
737 // R5: Inline cache data object.
738 // R4: Arguments descriptor array.
739 // Inline cache data object structure:
740 // 0: function-name
741 // 1: N, number of arguments checked.
742 // 2 .. (length - 1): group of checks, each check containing:
743 // - N classes.
744 // - 1 target function.
390 void StubCode::GenerateOneArgCheckInlineCacheStub(Assembler* assembler) { 745 void StubCode::GenerateOneArgCheckInlineCacheStub(Assembler* assembler) {
391 __ Unimplemented("GenerateOneArgCheckInlineCacheStub stub"); 746 GenerateUsageCounterIncrement(assembler, R6);
747 GenerateNArgsCheckInlineCacheStub(assembler, 1);
392 } 748 }
393 749
394 750
395 void StubCode::GenerateTwoArgsCheckInlineCacheStub(Assembler* assembler) { 751 void StubCode::GenerateTwoArgsCheckInlineCacheStub(Assembler* assembler) {
396 __ Unimplemented("GenerateTwoArgsCheckInlineCacheStub stub"); 752 GenerateUsageCounterIncrement(assembler, R6);
753 GenerateNArgsCheckInlineCacheStub(assembler, 2);
397 } 754 }
398 755
399 756
400 void StubCode::GenerateThreeArgsCheckInlineCacheStub(Assembler* assembler) { 757 void StubCode::GenerateThreeArgsCheckInlineCacheStub(Assembler* assembler) {
401 __ Unimplemented("GenerateThreeArgsCheckInlineCacheStub stub"); 758 GenerateUsageCounterIncrement(assembler, R6);
402 } 759 GenerateNArgsCheckInlineCacheStub(assembler, 3);
403 760 }
404 761
762
405 void StubCode::GenerateOneArgOptimizedCheckInlineCacheStub( 763 void StubCode::GenerateOneArgOptimizedCheckInlineCacheStub(
406 Assembler* assembler) { 764 Assembler* assembler) {
407 GenerateOptimizedUsageCounterIncrement(assembler); 765 GenerateOptimizedUsageCounterIncrement(assembler);
408 GenerateNArgsCheckInlineCacheStub(assembler, 1); 766 GenerateNArgsCheckInlineCacheStub(assembler, 1);
409 } 767 }
410 768
411 769
412 void StubCode::GenerateTwoArgsOptimizedCheckInlineCacheStub( 770 void StubCode::GenerateTwoArgsOptimizedCheckInlineCacheStub(
413 Assembler* assembler) { 771 Assembler* assembler) {
414 GenerateOptimizedUsageCounterIncrement(assembler); 772 GenerateOptimizedUsageCounterIncrement(assembler);
(...skipping 26 matching lines...) Expand all
441 void StubCode::GenerateBreakpointReturnStub(Assembler* assembler) { 799 void StubCode::GenerateBreakpointReturnStub(Assembler* assembler) {
442 __ Unimplemented("BreakpointReturn stub"); 800 __ Unimplemented("BreakpointReturn stub");
443 } 801 }
444 802
445 803
446 void StubCode::GenerateBreakpointDynamicStub(Assembler* assembler) { 804 void StubCode::GenerateBreakpointDynamicStub(Assembler* assembler) {
447 __ Unimplemented("BreakpointDynamic stub"); 805 __ Unimplemented("BreakpointDynamic stub");
448 } 806 }
449 807
450 808
451 void StubCode::GenerateSubtype1TestCacheStub(Assembler* assembler) { 809 // Used to check class and type arguments. Arguments passed in registers:
452 __ Unimplemented("Subtype1TestCache Stub"); 810 // LR: return address.
811 // R0: instance (must be preserved).
812 // R1: instantiator type arguments or NULL.
813 // R2: cache array.
814 // Result in R1: null -> not found, otherwise result (true or false).
815 static void GenerateSubtypeNTestCacheStub(Assembler* assembler, int n) {
816 ASSERT((1 <= n) && (n <= 3));
817 if (n > 1) {
818 // Get instance type arguments.
819 __ LoadClass(R3, R0, R4);
820 // Compute instance type arguments into R4.
821 Label has_no_type_arguments;
822 __ LoadImmediate(R4, reinterpret_cast<intptr_t>(Object::null()));
823 __ ldr(R5, FieldAddress(R3,
824 Class::type_arguments_field_offset_in_words_offset()));
825 __ CompareImmediate(R5, Class::kNoTypeArguments);
826 __ b(&has_no_type_arguments, EQ);
827 __ add(R5, R0, ShifterOperand(R5, LSL, 2));
828 __ ldr(R4, FieldAddress(R5, 0));
829 __ Bind(&has_no_type_arguments);
830 }
831 __ LoadClassId(R3, R0);
832 // R0: instance.
833 // R1: instantiator type arguments or NULL.
834 // R2: SubtypeTestCache.
835 // R3: instance class id.
836 // R4: instance type arguments (null if none), used only if n > 1.
837 __ ldr(R2, FieldAddress(R2, SubtypeTestCache::cache_offset()));
838 __ AddImmediate(R2, Array::data_offset() - kHeapObjectTag);
839
840 Label loop, found, not_found, next_iteration;
841 // R2: Entry start.
842 // R3: instance class id.
843 // R4: instance type arguments.
844 __ SmiTag(R3);
845 __ Bind(&loop);
846 __ ldr(R5, Address(R2, kWordSize * SubtypeTestCache::kInstanceClassId));
847 __ CompareImmediate(R5, reinterpret_cast<intptr_t>(Object::null()));
848 __ b(&not_found, EQ);
849 __ cmp(R5, ShifterOperand(R3));
850 if (n == 1) {
851 __ b(&found, EQ);
852 } else {
853 __ b(&next_iteration, NE);
854 __ ldr(R5,
855 Address(R2, kWordSize * SubtypeTestCache::kInstanceTypeArguments));
856 __ cmp(R5, ShifterOperand(R4));
857 if (n == 2) {
858 __ b(&found, EQ);
859 } else {
860 __ b(&next_iteration, NE);
861 __ ldr(R5, Address(R2, kWordSize *
862 SubtypeTestCache::kInstantiatorTypeArguments));
863 __ cmp(R5, ShifterOperand(R1));
864 __ b(&found, EQ);
865 }
866 }
867 __ Bind(&next_iteration);
868 __ AddImmediate(R2, kWordSize * SubtypeTestCache::kTestEntryLength);
869 __ b(&loop);
870 // Fall through to not found.
871 __ Bind(&not_found);
872 __ LoadImmediate(R1, reinterpret_cast<intptr_t>(Object::null()));
873 __ Ret();
874
875 __ Bind(&found);
876 __ ldr(R1, Address(R2, kWordSize * SubtypeTestCache::kTestResult));
877 __ Ret();
453 } 878 }
454 879
455 880
456 void StubCode::GenerateSubtype2TestCacheStub(Assembler* assembler) { 881 // Used to check class and type arguments. Arguments passed in registers:
457 __ Unimplemented("Subtype2TestCache Stub"); 882 // LR: return address.
883 // R0: instance (must be preserved).
884 // R1: instantiator type arguments or NULL.
885 // R2: cache array.
886 // Result in R1: null -> not found, otherwise result (true or false).
887 void StubCode::GenerateSubtype1TestCacheStub(Assembler* assembler) {
888 GenerateSubtypeNTestCacheStub(assembler, 1);
458 } 889 }
459 890
460 891
461 void StubCode::GenerateSubtype3TestCacheStub(Assembler* assembler) { 892 // Used to check class and type arguments. Arguments passed in registers:
462 __ Unimplemented("Subtype3TestCache Stub"); 893 // LR: return address.
894 // R0: instance (must be preserved).
895 // R1: instantiator type arguments or NULL.
896 // R2: cache array.
897 // Result in R1: null -> not found, otherwise result (true or false).
898 void StubCode::GenerateSubtype2TestCacheStub(Assembler* assembler) {
899 GenerateSubtypeNTestCacheStub(assembler, 2);
463 } 900 }
464 901
465 902
903 // Used to check class and type arguments. Arguments passed in registers:
904 // LR: return address.
905 // R0: instance (must be preserved).
906 // R1: instantiator type arguments or NULL.
907 // R2: cache array.
908 // Result in R1: null -> not found, otherwise result (true or false).
909 void StubCode::GenerateSubtype3TestCacheStub(Assembler* assembler) {
910 GenerateSubtypeNTestCacheStub(assembler, 3);
911 }
912
913
466 // Return the current stack pointer address, used to stack alignment 914 // Return the current stack pointer address, used to stack alignment
467 // checks. 915 // checks.
468 void StubCode::GenerateGetStackPointerStub(Assembler* assembler) { 916 void StubCode::GenerateGetStackPointerStub(Assembler* assembler) {
469 __ Unimplemented("GetStackPointer Stub"); 917 __ Unimplemented("GetStackPointer Stub");
470 } 918 }
471 919
472 920
473 // Jump to the exception handler. 921 // Jump to the exception handler.
474 // No Result. 922 // No Result.
475 void StubCode::GenerateJumpToExceptionHandlerStub(Assembler* assembler) { 923 void StubCode::GenerateJumpToExceptionHandlerStub(Assembler* assembler) {
476 __ Unimplemented("JumpToExceptionHandler Stub"); 924 __ Unimplemented("JumpToExceptionHandler Stub");
477 } 925 }
478 926
479 927
480 // Jump to the error handler. 928 // Jump to the error handler.
481 // No Result. 929 // No Result.
482 void StubCode::GenerateJumpToErrorHandlerStub(Assembler* assembler) { 930 void StubCode::GenerateJumpToErrorHandlerStub(Assembler* assembler) {
483 __ Unimplemented("JumpToErrorHandler Stub"); 931 __ Unimplemented("JumpToErrorHandler Stub");
484 } 932 }
485 933
486 934
935 // Implements equality operator when one of the arguments is null
936 // (identity check) and updates ICData if necessary.
937 // LR: return address.
938 // R6: ICData.
zra 2013/04/03 17:39:47 R5?
regis 2013/04/03 20:06:07 Since the stub is unimplemented, the comment is me
939 // R1: left operand.
940 // R0: right operand.
941 // Return result in R0.
942 // TODO(srdjan): Move to VM stubs once Boolean objects become VM objects.
487 void StubCode::GenerateEqualityWithNullArgStub(Assembler* assembler) { 943 void StubCode::GenerateEqualityWithNullArgStub(Assembler* assembler) {
488 __ Unimplemented("EqualityWithNullArg stub"); 944 __ Unimplemented("EqualityWithNullArg Stub");
945 #if 0
zra 2013/04/03 17:39:47 Maybe rm from the CL?
regis 2013/04/03 20:06:07 Oops. Removed.
946 static const intptr_t kNumArgsTested = 2;
947 #if defined(DEBUG)
948 { Label ok;
949 __ movl(EAX, FieldAddress(ECX, ICData::num_args_tested_offset()));
950 __ cmpl(EAX, Immediate(kNumArgsTested));
951 __ j(EQUAL, &ok, Assembler::kNearJump);
952 __ Stop("Incorrect ICData for equality");
953 __ Bind(&ok);
954 }
955 #endif // DEBUG
956 // Check IC data, update if needed.
957 // EBX: IC data object (preserved).
958 __ movl(EBX, FieldAddress(ECX, ICData::ic_data_offset()));
959 // EBX: ic_data_array with check entries: classes and target functions.
960 __ leal(EBX, FieldAddress(EBX, Array::data_offset()));
961 // EBX: points directly to the first ic data array element.
962
963 Label get_class_id_as_smi, no_match, loop, compute_result, found;
964 __ Bind(&loop);
965 // Check left.
966 __ movl(EAX, Address(ESP, 2 * kWordSize));
967 __ call(&get_class_id_as_smi);
968 __ movl(EDI, Address(EBX, 0 * kWordSize));
969 __ cmpl(EAX, EDI); // Class id match?
970 __ j(NOT_EQUAL, &no_match, Assembler::kNearJump);
971 // Check right.
972 __ movl(EAX, Address(ESP, 1 * kWordSize));
973 __ call(&get_class_id_as_smi);
974 __ movl(EDI, Address(EBX, 1 * kWordSize));
975 __ cmpl(EAX, EDI); // Class id match?
976 __ j(EQUAL, &found, Assembler::kNearJump);
977 __ Bind(&no_match);
978 // Next check group.
979 __ addl(EBX, Immediate(
980 kWordSize * ICData::TestEntryLengthFor(kNumArgsTested)));
981 __ cmpl(EDI, Immediate(Smi::RawValue(kIllegalCid))); // Done?
982 __ j(NOT_EQUAL, &loop, Assembler::kNearJump);
983 Label update_ic_data;
984 __ jmp(&update_ic_data);
985
986 __ Bind(&found);
987 const intptr_t count_offset =
988 ICData::CountIndexFor(kNumArgsTested) * kWordSize;
989 __ addl(Address(EBX, count_offset), Immediate(Smi::RawValue(1)));
990 __ j(NO_OVERFLOW, &compute_result);
991 __ movl(Address(EBX, count_offset),
992 Immediate(Smi::RawValue(Smi::kMaxValue)));
993
994 __ Bind(&compute_result);
995 Label true_label;
996 __ movl(EAX, Address(ESP, 1 * kWordSize));
997 __ cmpl(EAX, Address(ESP, 2 * kWordSize));
998 __ j(EQUAL, &true_label, Assembler::kNearJump);
999 __ LoadObject(EAX, Bool::False());
1000 __ ret();
1001 __ Bind(&true_label);
1002 __ LoadObject(EAX, Bool::True());
1003 __ ret();
1004
1005 __ Bind(&get_class_id_as_smi);
1006 Label not_smi;
1007 // Test if Smi -> load Smi class for comparison.
1008 __ testl(EAX, Immediate(kSmiTagMask));
1009 __ j(NOT_ZERO, &not_smi, Assembler::kNearJump);
1010 __ movl(EAX, Immediate(Smi::RawValue(kSmiCid)));
1011 __ ret();
1012
1013 __ Bind(&not_smi);
1014 __ LoadClassId(EAX, EAX);
1015 __ SmiTag(EAX);
1016 __ ret();
1017
1018 __ Bind(&update_ic_data);
1019
1020 // ECX: ICData
1021 __ movl(EAX, Address(ESP, 1 * kWordSize));
1022 __ movl(EDI, Address(ESP, 2 * kWordSize));
1023 __ EnterStubFrame();
1024 __ pushl(EDI); // arg 0
1025 __ pushl(EAX); // arg 1
1026 __ PushObject(Symbols::EqualOperator()); // Target's name.
1027 __ pushl(ECX); // ICData
1028 __ CallRuntime(kUpdateICDataTwoArgsRuntimeEntry);
1029 __ Drop(4);
1030 __ LeaveFrame();
1031
1032 __ jmp(&compute_result, Assembler::kNearJump);
1033 #endif
489 } 1034 }
490 1035
491 1036
492 void StubCode::GenerateOptimizeFunctionStub(Assembler* assembler) { 1037 void StubCode::GenerateOptimizeFunctionStub(Assembler* assembler) {
493 __ Unimplemented("OptimizeFunction stub"); 1038 __ Unimplemented("OptimizeFunction stub");
494 } 1039 }
495 1040
496 1041
1042 DECLARE_LEAF_RUNTIME_ENTRY(intptr_t,
1043 BigintCompare,
1044 RawBigint* left,
1045 RawBigint* right);
1046
1047
1048 // Does identical check (object references are equal or not equal) with special
1049 // checks for boxed numbers.
1050 // LR: return address.
1051 // SP + 4: left operand.
1052 // SP + 0: right operand.
1053 // Return Zero condition flag set if equal.
1054 // Note: A Mint cannot contain a value that would fit in Smi, a Bigint
1055 // cannot contain a value that fits in Mint or Smi.
497 void StubCode::GenerateIdenticalWithNumberCheckStub(Assembler* assembler) { 1056 void StubCode::GenerateIdenticalWithNumberCheckStub(Assembler* assembler) {
498 __ Unimplemented("IdenticalWithNumberCheck stub"); 1057 const Register temp = R2;
1058 const Register left = R1;
1059 const Register right = R0;
1060 // Preserve left, right and temp.
1061 __ PushList((1 << R0) | (1 << R1) | (1 << R2));
1062 // TOS + 4: left argument.
1063 // TOS + 3: right argument.
1064 // TOS + 2: saved temp
1065 // TOS + 1: saved left
1066 // TOS + 0: saved right
1067 __ ldr(left, Address(SP, 4 * kWordSize));
1068 __ ldr(right, Address(SP, 3 * kWordSize));
1069 Label reference_compare, done, check_mint, check_bigint;
1070 // If any of the arguments is Smi do reference compare.
1071 __ tst(left, ShifterOperand(kSmiTagMask));
1072 __ b(&reference_compare, EQ);
1073 __ tst(right, ShifterOperand(kSmiTagMask));
1074 __ b(&reference_compare, EQ);
1075
1076 // Value compare for two doubles.
1077 __ CompareClassId(left, kDoubleCid, temp);
1078 __ b(&check_mint, NE);
1079 __ CompareClassId(right, kDoubleCid, temp);
1080 __ b(&done, NE);
1081
1082 // Double values bitwise compare.
1083 __ ldr(temp, FieldAddress(left, Double::value_offset() + 0 * kWordSize));
1084 __ ldr(IP, FieldAddress(right, Double::value_offset() + 0 * kWordSize));
1085 __ cmp(temp, ShifterOperand(IP));
1086 __ b(&done, NE);
1087 __ ldr(temp, FieldAddress(left, Double::value_offset() + 1 * kWordSize));
1088 __ ldr(IP, FieldAddress(right, Double::value_offset() + 1 * kWordSize));
1089 __ cmp(temp, ShifterOperand(IP));
1090 __ b(&done);
1091
1092 __ Bind(&check_mint);
1093 __ CompareClassId(left, kMintCid, temp);
1094 __ b(&check_bigint, NE);
1095 __ CompareClassId(right, kMintCid, temp);
1096 __ b(&done, NE);
1097 __ ldr(temp, FieldAddress(left, Mint::value_offset() + 0 * kWordSize));
1098 __ ldr(IP, FieldAddress(right, Mint::value_offset() + 0 * kWordSize));
1099 __ cmp(temp, ShifterOperand(IP));
1100 __ b(&done, NE);
1101 __ ldr(temp, FieldAddress(left, Mint::value_offset() + 1 * kWordSize));
1102 __ ldr(IP, FieldAddress(right, Mint::value_offset() + 1 * kWordSize));
1103 __ cmp(temp, ShifterOperand(IP));
1104 __ b(&done);
1105
1106 __ Bind(&check_bigint);
1107 __ CompareClassId(left, kBigintCid, temp);
1108 __ b(&reference_compare, NE);
1109 __ CompareClassId(right, kBigintCid, temp);
1110 __ b(&done, NE);
1111 __ EnterStubFrame(0);
1112 __ ReserveAlignedFrameSpace(2 * kWordSize);
1113 __ stm(IA, SP, (1 << R0) | (1 << R1));
1114 __ CallRuntime(kBigintCompareRuntimeEntry);
1115 // Result in R0, 0 means equal.
1116 __ LeaveStubFrame();
1117 __ cmp(R0, ShifterOperand(0));
1118 __ b(&done);
1119
1120 __ Bind(&reference_compare);
1121 __ cmp(left, ShifterOperand(right));
1122 __ Bind(&done);
1123 __ PopList((1 << R0) | (1 << R1) | (1 << R2));
1124 __ Ret();
499 } 1125 }
500 1126
501 } // namespace dart 1127 } // namespace dart
502 1128
503 #endif // defined TARGET_ARCH_ARM 1129 #endif // defined TARGET_ARCH_ARM
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698