| 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_IA32) | 6 #if defined(TARGET_ARCH_IA32) |
| 7 | 7 |
| 8 #include "vm/assembler.h" | 8 #include "vm/assembler.h" |
| 9 #include "vm/compiler.h" | 9 #include "vm/compiler.h" |
| 10 #include "vm/dart_entry.h" | 10 #include "vm/dart_entry.h" |
| (...skipping 303 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 314 __ CallRuntime(kFixAllocationStubTargetRuntimeEntry, 0); | 314 __ CallRuntime(kFixAllocationStubTargetRuntimeEntry, 0); |
| 315 __ popl(EAX); // Get Code object. | 315 __ popl(EAX); // Get Code object. |
| 316 __ movl(EAX, FieldAddress(EAX, Code::instructions_offset())); | 316 __ movl(EAX, FieldAddress(EAX, Code::instructions_offset())); |
| 317 __ addl(EAX, Immediate(Instructions::HeaderSize() - kHeapObjectTag)); | 317 __ addl(EAX, Immediate(Instructions::HeaderSize() - kHeapObjectTag)); |
| 318 __ LeaveFrame(); | 318 __ LeaveFrame(); |
| 319 __ jmp(EAX); | 319 __ jmp(EAX); |
| 320 __ int3(); | 320 __ int3(); |
| 321 } | 321 } |
| 322 | 322 |
| 323 | 323 |
| 324 // Called from array allocate instruction when the allocation stub has been | |
| 325 // disabled. | |
| 326 // EDX: length (preserved). | |
| 327 // ECX: element type (preserved). | |
| 328 void StubCode::GenerateFixAllocateArrayStubTargetStub(Assembler* assembler) { | |
| 329 const Immediate& raw_null = | |
| 330 Immediate(reinterpret_cast<intptr_t>(Object::null())); | |
| 331 __ EnterStubFrame(); | |
| 332 __ pushl(EDX); // Preserve length. | |
| 333 __ pushl(ECX); // Preserve element type. | |
| 334 __ pushl(raw_null); // Setup space on stack for return value. | |
| 335 __ CallRuntime(kFixAllocationStubTargetRuntimeEntry, 0); | |
| 336 __ popl(EAX); // Get Code object. | |
| 337 __ popl(ECX); // Restore element type. | |
| 338 __ popl(EDX); // Restore length. | |
| 339 __ movl(EAX, FieldAddress(EAX, Code::instructions_offset())); | |
| 340 __ addl(EAX, Immediate(Instructions::HeaderSize() - kHeapObjectTag)); | |
| 341 __ LeaveFrame(); | |
| 342 __ jmp(EAX); | |
| 343 __ int3(); | |
| 344 } | |
| 345 | |
| 346 | |
| 347 // Input parameters: | 324 // Input parameters: |
| 348 // EDX: smi-tagged argument count, may be zero. | 325 // EDX: smi-tagged argument count, may be zero. |
| 349 // EBP[kParamEndSlotFromFp + 1]: last argument. | 326 // EBP[kParamEndSlotFromFp + 1]: last argument. |
| 350 // Uses EAX, EBX, ECX, EDX, EDI. | 327 // Uses EAX, EBX, ECX, EDX, EDI. |
| 351 static void PushArgumentsArray(Assembler* assembler) { | 328 static void PushArgumentsArray(Assembler* assembler) { |
| 329 // Allocate array to store arguments of caller. |
| 352 const Immediate& raw_null = | 330 const Immediate& raw_null = |
| 353 Immediate(reinterpret_cast<intptr_t>(Object::null())); | 331 Immediate(reinterpret_cast<intptr_t>(Object::null())); |
| 354 StubCode* stub_code = Isolate::Current()->stub_code(); | |
| 355 | |
| 356 // Allocate array to store arguments of caller. | |
| 357 __ movl(ECX, raw_null); // Null element type for raw Array. | 332 __ movl(ECX, raw_null); // Null element type for raw Array. |
| 358 const Code& array_stub = Code::Handle(stub_code->GetAllocateArrayStub()); | 333 const ExternalLabel array_label(StubCode::AllocateArrayEntryPoint()); |
| 359 const ExternalLabel array_label(array_stub.EntryPoint()); | |
| 360 __ call(&array_label); | 334 __ call(&array_label); |
| 361 __ SmiUntag(EDX); | 335 __ SmiUntag(EDX); |
| 362 // EAX: newly allocated array. | 336 // EAX: newly allocated array. |
| 363 // EDX: length of the array (was preserved by the stub). | 337 // EDX: length of the array (was preserved by the stub). |
| 364 __ pushl(EAX); // Array is in EAX and on top of stack. | 338 __ pushl(EAX); // Array is in EAX and on top of stack. |
| 365 __ leal(EBX, Address(EBP, EDX, TIMES_4, kParamEndSlotFromFp * kWordSize)); | 339 __ leal(EBX, Address(EBP, EDX, TIMES_4, kParamEndSlotFromFp * kWordSize)); |
| 366 __ leal(ECX, FieldAddress(EAX, Array::data_offset())); | 340 __ leal(ECX, FieldAddress(EAX, Array::data_offset())); |
| 367 // EBX: address of first argument on stack. | 341 // EBX: address of first argument on stack. |
| 368 // ECX: address of first argument in array. | 342 // ECX: address of first argument in array. |
| 369 Label loop, loop_condition; | 343 Label loop, loop_condition; |
| (...skipping 205 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 575 __ jmp(EBX); | 549 __ jmp(EBX); |
| 576 } | 550 } |
| 577 | 551 |
| 578 | 552 |
| 579 // Called for inline allocation of arrays. | 553 // Called for inline allocation of arrays. |
| 580 // Input parameters: | 554 // Input parameters: |
| 581 // EDX : Array length as Smi (must be preserved). | 555 // EDX : Array length as Smi (must be preserved). |
| 582 // ECX : array element type (either NULL or an instantiated type). | 556 // ECX : array element type (either NULL or an instantiated type). |
| 583 // Uses EAX, EBX, ECX, EDI as temporary registers. | 557 // Uses EAX, EBX, ECX, EDI as temporary registers. |
| 584 // The newly allocated object is returned in EAX. | 558 // The newly allocated object is returned in EAX. |
| 585 void StubCode::GeneratePatchableAllocateArrayStub(Assembler* assembler, | 559 void StubCode::GenerateAllocateArrayStub(Assembler* assembler) { |
| 586 uword* entry_patch_offset, uword* patch_code_pc_offset) { | |
| 587 *entry_patch_offset = assembler->CodeSize(); | |
| 588 Label slow_case; | 560 Label slow_case; |
| 589 const Immediate& raw_null = | 561 const Immediate& raw_null = |
| 590 Immediate(reinterpret_cast<intptr_t>(Object::null())); | 562 Immediate(reinterpret_cast<intptr_t>(Object::null())); |
| 591 | |
| 592 Isolate* isolate = Isolate::Current(); | |
| 593 const Class& cls = Class::Handle(isolate->object_store()->array_class()); | |
| 594 ASSERT(!cls.IsNull()); | |
| 595 // Compute the size to be allocated, it is based on the array length | 563 // Compute the size to be allocated, it is based on the array length |
| 596 // and is computed as: | 564 // and is computed as: |
| 597 // RoundedAllocationSize((array_length * kwordSize) + sizeof(RawArray)). | 565 // RoundedAllocationSize((array_length * kwordSize) + sizeof(RawArray)). |
| 598 // Assert that length is a Smi. | 566 // Assert that length is a Smi. |
| 599 __ testl(EDX, Immediate(kSmiTagMask)); | 567 __ testl(EDX, Immediate(kSmiTagMask)); |
| 600 | 568 |
| 601 if (FLAG_use_slow_path || cls.trace_allocation()) { | 569 if (FLAG_use_slow_path) { |
| 602 __ jmp(&slow_case); | 570 __ jmp(&slow_case); |
| 603 } else { | 571 } else { |
| 604 __ j(NOT_ZERO, &slow_case); | 572 __ j(NOT_ZERO, &slow_case); |
| 605 } | 573 } |
| 606 __ cmpl(EDX, Immediate(0)); | 574 __ cmpl(EDX, Immediate(0)); |
| 607 __ j(LESS, &slow_case); | 575 __ j(LESS, &slow_case); |
| 608 | 576 |
| 609 // Check for maximum allowed length. | 577 // Check for maximum allowed length. |
| 610 const Immediate& max_len = | 578 const Immediate& max_len = |
| 611 Immediate(reinterpret_cast<int32_t>(Smi::New(Array::kMaxElements))); | 579 Immediate(reinterpret_cast<int32_t>(Smi::New(Array::kMaxElements))); |
| 612 __ cmpl(EDX, max_len); | 580 __ cmpl(EDX, max_len); |
| 613 __ j(GREATER, &slow_case); | 581 __ j(GREATER, &slow_case); |
| 614 | 582 |
| 583 __ MaybeTraceAllocation(kArrayCid, |
| 584 EAX, |
| 585 &slow_case, |
| 586 /* near_jump = */ false, |
| 587 /* inline_isolate = */ false); |
| 588 |
| 615 const intptr_t fixed_size = sizeof(RawArray) + kObjectAlignment - 1; | 589 const intptr_t fixed_size = sizeof(RawArray) + kObjectAlignment - 1; |
| 616 __ leal(EDI, Address(EDX, TIMES_2, fixed_size)); // EDX is Smi. | 590 __ leal(EBX, Address(EDX, TIMES_2, fixed_size)); // EDX is Smi. |
| 617 ASSERT(kSmiTagShift == 1); | 591 ASSERT(kSmiTagShift == 1); |
| 618 __ andl(EDI, Immediate(-kObjectAlignment)); | 592 __ andl(EBX, Immediate(-kObjectAlignment)); |
| 619 | 593 |
| 620 // ECX: array element type. | 594 // ECX: array element type. |
| 621 // EDX: array length as Smi. | 595 // EDX: array length as Smi. |
| 622 // EDI: allocation size. | 596 // EBX: allocation size. |
| 623 | 597 |
| 624 Heap* heap = isolate->heap(); | |
| 625 const intptr_t cid = kArrayCid; | 598 const intptr_t cid = kArrayCid; |
| 626 Heap::Space space = Heap::SpaceForAllocation(cid); | 599 Heap::Space space = Heap::SpaceForAllocation(cid); |
| 627 __ movl(EAX, Address::Absolute(heap->TopAddress(space))); | 600 __ LoadIsolate(EDI); |
| 628 __ movl(EBX, EAX); | 601 __ movl(EDI, Address(EDI, Isolate::heap_offset())); |
| 629 | 602 __ movl(EAX, Address(EDI, Heap::TopOffset(space))); |
| 630 // EDI: allocation size. | 603 __ addl(EBX, EAX); |
| 631 __ addl(EBX, EDI); | |
| 632 __ j(CARRY, &slow_case); | 604 __ j(CARRY, &slow_case); |
| 633 | 605 |
| 634 // Check if the allocation fits into the remaining space. | 606 // Check if the allocation fits into the remaining space. |
| 635 // EAX: potential new object start. | 607 // EAX: potential new object start. |
| 636 // EBX: potential next object start. | 608 // EBX: potential next object start. |
| 637 // EDI: allocation size. | 609 // EDI: heap. |
| 638 // ECX: array element type. | 610 // ECX: array element type. |
| 639 // EDX: array length as Smi). | 611 // EDX: array length as Smi). |
| 640 __ cmpl(EBX, Address::Absolute(heap->EndAddress(space))); | 612 __ cmpl(EBX, Address(EDI, Heap::EndOffset(space))); |
| 641 __ j(ABOVE_EQUAL, &slow_case); | 613 __ j(ABOVE_EQUAL, &slow_case); |
| 642 | 614 |
| 643 // Successfully allocated the object(s), now update top to point to | 615 // Successfully allocated the object(s), now update top to point to |
| 644 // next object start and initialize the object. | 616 // next object start and initialize the object. |
| 645 __ movl(Address::Absolute(heap->TopAddress(space)), EBX); | 617 __ movl(Address(EDI, Heap::TopOffset(space)), EBX); |
| 618 __ subl(EBX, EAX); |
| 646 __ addl(EAX, Immediate(kHeapObjectTag)); | 619 __ addl(EAX, Immediate(kHeapObjectTag)); |
| 647 __ UpdateAllocationStatsWithSize(cid, EDI, kNoRegister, space); | 620 __ UpdateAllocationStatsWithSize(cid, EBX, EDI, space, |
| 621 /* inline_isolate = */ false); |
| 648 | 622 |
| 649 // Initialize the tags. | 623 // Initialize the tags. |
| 650 // EAX: new object start as a tagged pointer. | 624 // EAX: new object start as a tagged pointer. |
| 651 // EBX: new object end address. | 625 // EBX: allocation size. |
| 652 // EDI: allocation size. | |
| 653 // ECX: array element type. | 626 // ECX: array element type. |
| 654 // EDX: array length as Smi. | 627 // EDX: array length as Smi. |
| 655 { | 628 { |
| 656 Label size_tag_overflow, done; | 629 Label size_tag_overflow, done; |
| 630 __ movl(EDI, EBX); |
| 657 __ cmpl(EDI, Immediate(RawObject::SizeTag::kMaxSizeTag)); | 631 __ cmpl(EDI, Immediate(RawObject::SizeTag::kMaxSizeTag)); |
| 658 __ j(ABOVE, &size_tag_overflow, Assembler::kNearJump); | 632 __ j(ABOVE, &size_tag_overflow, Assembler::kNearJump); |
| 659 __ shll(EDI, Immediate(RawObject::kSizeTagPos - kObjectAlignmentLog2)); | 633 __ shll(EDI, Immediate(RawObject::kSizeTagPos - kObjectAlignmentLog2)); |
| 660 __ jmp(&done, Assembler::kNearJump); | 634 __ jmp(&done, Assembler::kNearJump); |
| 661 | 635 |
| 662 __ Bind(&size_tag_overflow); | 636 __ Bind(&size_tag_overflow); |
| 663 __ movl(EDI, Immediate(0)); | 637 __ movl(EDI, Immediate(0)); |
| 664 __ Bind(&done); | 638 __ Bind(&done); |
| 665 | 639 |
| 666 // Get the class index and insert it into the tags. | 640 // Get the class index and insert it into the tags. |
| 667 __ orl(EDI, Immediate(RawObject::ClassIdTag::encode(cid))); | 641 __ orl(EDI, Immediate(RawObject::ClassIdTag::encode(cid))); |
| 668 __ movl(FieldAddress(EAX, Array::tags_offset()), EDI); // Tags. | 642 __ movl(FieldAddress(EAX, Array::tags_offset()), EDI); // Tags. |
| 669 } | 643 } |
| 670 // EAX: new object start as a tagged pointer. | 644 // EAX: new object start as a tagged pointer. |
| 671 // EBX: new object end address. | 645 // EBX: allocation size. |
| 672 // ECX: array element type. | 646 // ECX: array element type. |
| 673 // EDX: Array length as Smi (preserved). | 647 // EDX: Array length as Smi (preserved). |
| 674 // Store the type argument field. | 648 // Store the type argument field. |
| 675 __ InitializeFieldNoBarrier(EAX, | 649 __ InitializeFieldNoBarrier(EAX, |
| 676 FieldAddress(EAX, Array::type_arguments_offset()), | 650 FieldAddress(EAX, Array::type_arguments_offset()), |
| 677 ECX); | 651 ECX); |
| 678 | 652 |
| 679 // Set the length field. | 653 // Set the length field. |
| 680 __ InitializeFieldNoBarrier(EAX, | 654 __ InitializeFieldNoBarrier(EAX, |
| 681 FieldAddress(EAX, Array::length_offset()), | 655 FieldAddress(EAX, Array::length_offset()), |
| 682 EDX); | 656 EDX); |
| 683 | 657 |
| 684 // Initialize all array elements to raw_null. | 658 // Initialize all array elements to raw_null. |
| 685 // EAX: new object start as a tagged pointer. | 659 // EAX: new object start as a tagged pointer. |
| 686 // EBX: new object end address. | 660 // EBX: allocation size. |
| 687 // EDI: iterator which initially points to the start of the variable | 661 // EDI: iterator which initially points to the start of the variable |
| 688 // data area to be initialized. | 662 // data area to be initialized. |
| 689 // ECX: array element type. | 663 // ECX: array element type. |
| 690 // EDX: array length as Smi. | 664 // EDX: array length as Smi. |
| 665 __ leal(EBX, FieldAddress(EAX, EBX, TIMES_1, 0)); |
| 691 __ leal(EDI, FieldAddress(EAX, sizeof(RawArray))); | 666 __ leal(EDI, FieldAddress(EAX, sizeof(RawArray))); |
| 692 Label done; | 667 Label done; |
| 693 Label init_loop; | 668 Label init_loop; |
| 694 __ Bind(&init_loop); | 669 __ Bind(&init_loop); |
| 695 __ cmpl(EDI, EBX); | 670 __ cmpl(EDI, EBX); |
| 696 __ j(ABOVE_EQUAL, &done, Assembler::kNearJump); | 671 __ j(ABOVE_EQUAL, &done, Assembler::kNearJump); |
| 697 // No generational barrier needed, since we are storing null. | 672 // No generational barrier needed, since we are storing null. |
| 698 __ InitializeFieldNoBarrier(EAX, Address(EDI, 0), Object::null_object()); | 673 __ InitializeFieldNoBarrier(EAX, Address(EDI, 0), Object::null_object()); |
| 699 __ addl(EDI, Immediate(kWordSize)); | 674 __ addl(EDI, Immediate(kWordSize)); |
| 700 __ jmp(&init_loop, Assembler::kNearJump); | 675 __ jmp(&init_loop, Assembler::kNearJump); |
| 701 __ Bind(&done); | 676 __ Bind(&done); |
| 702 __ ret(); // returns the newly allocated object in EAX. | 677 __ ret(); // returns the newly allocated object in EAX. |
| 703 | 678 |
| 704 // Unable to allocate the array using the fast inline code, just call | 679 // Unable to allocate the array using the fast inline code, just call |
| 705 // into the runtime. | 680 // into the runtime. |
| 706 __ Bind(&slow_case); | 681 __ Bind(&slow_case); |
| 707 // Create a stub frame as we are pushing some objects on the stack before | 682 // Create a stub frame as we are pushing some objects on the stack before |
| 708 // calling into the runtime. | 683 // calling into the runtime. |
| 709 __ EnterStubFrame(); | 684 __ EnterStubFrame(); |
| 710 __ pushl(raw_null); // Setup space on stack for return value. | 685 __ pushl(raw_null); // Setup space on stack for return value. |
| 711 __ pushl(EDX); // Array length as Smi. | 686 __ pushl(EDX); // Array length as Smi. |
| 712 __ pushl(ECX); // Element type. | 687 __ pushl(ECX); // Element type. |
| 713 __ CallRuntime(kAllocateArrayRuntimeEntry, 2); | 688 __ CallRuntime(kAllocateArrayRuntimeEntry, 2); |
| 714 __ popl(EAX); // Pop element type argument. | 689 __ popl(EAX); // Pop element type argument. |
| 715 __ popl(EDX); // Pop array length argument (preserved). | 690 __ popl(EDX); // Pop array length argument (preserved). |
| 716 __ popl(EAX); // Pop return value from return slot. | 691 __ popl(EAX); // Pop return value from return slot. |
| 717 __ LeaveFrame(); | 692 __ LeaveFrame(); |
| 718 __ ret(); | 693 __ ret(); |
| 719 // Emit function patching code. This will be swapped with the first 5 bytes | |
| 720 // at entry point. | |
| 721 *patch_code_pc_offset = assembler->CodeSize(); | |
| 722 StubCode* stub_code = Isolate::Current()->stub_code(); | |
| 723 __ jmp(&stub_code->FixAllocateArrayStubTargetLabel()); | |
| 724 } | 694 } |
| 725 | 695 |
| 726 | 696 |
| 727 // Called when invoking dart code from C++ (VM code). | 697 // Called when invoking dart code from C++ (VM code). |
| 728 // Input parameters: | 698 // Input parameters: |
| 729 // ESP : points to return address. | 699 // ESP : points to return address. |
| 730 // ESP + 4 : entrypoint of the dart function to call. | 700 // ESP + 4 : entrypoint of the dart function to call. |
| 731 // ESP + 8 : arguments descriptor array. | 701 // ESP + 8 : arguments descriptor array. |
| 732 // ESP + 12 : arguments array. | 702 // ESP + 12 : arguments array. |
| 733 // ESP + 16 : current thread. | 703 // ESP + 16 : current thread. |
| (...skipping 423 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1157 __ popl(EAX); // Pop argument (type arguments of object). | 1127 __ popl(EAX); // Pop argument (type arguments of object). |
| 1158 __ popl(EAX); // Pop argument (class of object). | 1128 __ popl(EAX); // Pop argument (class of object). |
| 1159 __ popl(EAX); // Pop result (newly allocated object). | 1129 __ popl(EAX); // Pop result (newly allocated object). |
| 1160 // EAX: new object | 1130 // EAX: new object |
| 1161 // Restore the frame pointer. | 1131 // Restore the frame pointer. |
| 1162 __ LeaveFrame(); | 1132 __ LeaveFrame(); |
| 1163 __ ret(); | 1133 __ ret(); |
| 1164 // Emit function patching code. This will be swapped with the first 5 bytes | 1134 // Emit function patching code. This will be swapped with the first 5 bytes |
| 1165 // at entry point. | 1135 // at entry point. |
| 1166 *patch_code_pc_offset = assembler->CodeSize(); | 1136 *patch_code_pc_offset = assembler->CodeSize(); |
| 1167 StubCode* stub_code = Isolate::Current()->stub_code(); | 1137 __ jmp(&StubCode::FixAllocationStubTargetLabel()); |
| 1168 __ jmp(&stub_code->FixAllocationStubTargetLabel()); | |
| 1169 } | 1138 } |
| 1170 | 1139 |
| 1171 | 1140 |
| 1172 // Called for invoking "dynamic noSuchMethod(Invocation invocation)" function | 1141 // Called for invoking "dynamic noSuchMethod(Invocation invocation)" function |
| 1173 // from the entry code of a dart function after an error in passed argument | 1142 // from the entry code of a dart function after an error in passed argument |
| 1174 // name or number is detected. | 1143 // name or number is detected. |
| 1175 // Input parameters: | 1144 // Input parameters: |
| 1176 // ESP : points to return address. | 1145 // ESP : points to return address. |
| 1177 // ESP + 4 : address of last argument. | 1146 // ESP + 4 : address of last argument. |
| 1178 // EDX : arguments descriptor array. | 1147 // EDX : arguments descriptor array. |
| (...skipping 948 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2127 // EBX: entry point. | 2096 // EBX: entry point. |
| 2128 void StubCode::GenerateMegamorphicLookupStub(Assembler* assembler) { | 2097 void StubCode::GenerateMegamorphicLookupStub(Assembler* assembler) { |
| 2129 EmitMegamorphicLookup(assembler, EDI, EBX, EBX); | 2098 EmitMegamorphicLookup(assembler, EDI, EBX, EBX); |
| 2130 __ ret(); | 2099 __ ret(); |
| 2131 } | 2100 } |
| 2132 | 2101 |
| 2133 | 2102 |
| 2134 } // namespace dart | 2103 } // namespace dart |
| 2135 | 2104 |
| 2136 #endif // defined TARGET_ARCH_IA32 | 2105 #endif // defined TARGET_ARCH_IA32 |
| OLD | NEW |