Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2014, 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" // NOLINT | 5 #include "vm/globals.h" // NOLINT |
| 6 #if defined(TARGET_ARCH_ARM64) | 6 #if defined(TARGET_ARCH_ARM64) |
| 7 | 7 |
| 8 #include "vm/assembler.h" | 8 #include "vm/assembler.h" |
| 9 #include "vm/cpu.h" | 9 #include "vm/cpu.h" |
| 10 #include "vm/longjump.h" | 10 #include "vm/longjump.h" |
| 11 #include "vm/runtime_entry.h" | 11 #include "vm/runtime_entry.h" |
| 12 #include "vm/simulator.h" | 12 #include "vm/simulator.h" |
| 13 #include "vm/stack_frame.h" | 13 #include "vm/stack_frame.h" |
| 14 #include "vm/stub_code.h" | 14 #include "vm/stub_code.h" |
| 15 | 15 |
| 16 // An extra check since we are assuming the existence of /proc/cpuinfo below. | 16 // An extra check since we are assuming the existence of /proc/cpuinfo below. |
| 17 #if !defined(USING_SIMULATOR) && !defined(__linux__) && !defined(ANDROID) | 17 #if !defined(USING_SIMULATOR) && !defined(__linux__) && !defined(ANDROID) |
| 18 #error ARM64 cross-compile only supported on Linux | 18 #error ARM64 cross-compile only supported on Linux |
| 19 #endif | 19 #endif |
| 20 | 20 |
| 21 namespace dart { | 21 namespace dart { |
| 22 | 22 |
| 23 DEFINE_FLAG(bool, use_far_branches, false, "Always use far branches"); | 23 DEFINE_FLAG(bool, use_far_branches, false, "Always use far branches"); |
| 24 DEFINE_FLAG(bool, print_stop_message, false, "Print stop message."); | 24 DEFINE_FLAG(bool, print_stop_message, false, "Print stop message."); |
| 25 DECLARE_FLAG(bool, inline_alloc); | 25 DECLARE_FLAG(bool, inline_alloc); |
| 26 | 26 |
| 27 | 27 |
| 28 Assembler::Assembler(bool use_far_branches) | 28 Assembler::Assembler(bool use_far_branches) |
| 29 : buffer_(), | 29 : buffer_(), |
| 30 object_pool_(GrowableObjectArray::Handle()), | |
| 31 patchable_pool_entries_(), | |
| 32 prologue_offset_(-1), | 30 prologue_offset_(-1), |
| 33 use_far_branches_(use_far_branches), | 31 use_far_branches_(use_far_branches), |
| 34 comments_(), | 32 comments_(), |
| 35 allow_constant_pool_(true) { | 33 allow_constant_pool_(true) { |
| 36 if (Isolate::Current() != Dart::vm_isolate()) { | 34 if (Isolate::Current() != Dart::vm_isolate()) { |
| 37 object_pool_ = GrowableObjectArray::New(Heap::kOld); | |
| 38 | |
| 39 // These objects and labels need to be accessible through every pool-pointer | 35 // These objects and labels need to be accessible through every pool-pointer |
| 40 // at the same index. | 36 // at the same index. |
| 41 object_pool_.Add(Object::null_object(), Heap::kOld); | 37 intptr_t index = |
|
Vyacheslav Egorov (Google)
2015/02/06 15:55:18
I wonder if this should be moved to the generic ob
Florian Schneider
2015/02/09 10:25:36
Yes, possibly. Although the patching code in the d
| |
| 42 patchable_pool_entries_.Add(kNotPatchable); | 38 object_pool_.AddObject(Object::null_object(), kNotPatchable); |
| 43 object_pool_index_table_.Insert(ObjIndexPair(&Object::null_object(), 0)); | 39 ASSERT(index == 0); |
| 44 | 40 |
| 45 object_pool_.Add(Bool::True(), Heap::kOld); | 41 index = object_pool_.AddObject(Bool::True(), kNotPatchable); |
| 46 patchable_pool_entries_.Add(kNotPatchable); | 42 ASSERT(index == 1); |
| 47 object_pool_index_table_.Insert(ObjIndexPair(&Bool::True(), 1)); | |
| 48 | 43 |
| 49 object_pool_.Add(Bool::False(), Heap::kOld); | 44 index = object_pool_.AddObject(Bool::False(), kNotPatchable); |
| 50 patchable_pool_entries_.Add(kNotPatchable); | 45 ASSERT(index == 2); |
| 51 object_pool_index_table_.Insert(ObjIndexPair(&Bool::False(), 2)); | |
| 52 | 46 |
| 53 const Smi& vacant = Smi::Handle(Smi::New(0xfa >> kSmiTagShift)); | 47 const Smi& vacant = Smi::Handle(Smi::New(0xfa >> kSmiTagShift)); |
| 54 StubCode* stub_code = Isolate::Current()->stub_code(); | 48 StubCode* stub_code = Isolate::Current()->stub_code(); |
| 55 | |
| 56 if (stub_code->UpdateStoreBuffer_entry() != NULL) { | 49 if (stub_code->UpdateStoreBuffer_entry() != NULL) { |
| 57 FindExternalLabel(&stub_code->UpdateStoreBufferLabel(), kNotPatchable); | 50 object_pool_.AddExternalLabel( |
| 51 &stub_code->UpdateStoreBufferLabel(), kNotPatchable); | |
| 58 } else { | 52 } else { |
| 59 object_pool_.Add(vacant, Heap::kOld); | 53 object_pool_.AddObject(vacant, kNotPatchable); |
| 60 patchable_pool_entries_.Add(kNotPatchable); | |
| 61 } | 54 } |
| 62 | 55 |
| 63 if (stub_code->CallToRuntime_entry() != NULL) { | 56 if (stub_code->CallToRuntime_entry() != NULL) { |
| 64 FindExternalLabel(&stub_code->CallToRuntimeLabel(), kNotPatchable); | 57 object_pool_.AddExternalLabel( |
| 58 &stub_code->CallToRuntimeLabel(), kNotPatchable); | |
| 65 } else { | 59 } else { |
| 66 object_pool_.Add(vacant, Heap::kOld); | 60 object_pool_.AddObject(vacant, kNotPatchable); |
| 67 patchable_pool_entries_.Add(kNotPatchable); | |
| 68 } | 61 } |
| 69 | 62 |
| 70 // Create fixed object pool entries for debugger stubs. | 63 // Create fixed object pool entries for debugger stubs. |
| 71 if (stub_code->ICCallBreakpoint_entry() != NULL) { | 64 if (stub_code->ICCallBreakpoint_entry() != NULL) { |
| 72 intptr_t index = | 65 intptr_t index = |
| 73 FindExternalLabel(&stub_code->ICCallBreakpointLabel(), | 66 object_pool_.AddExternalLabel(&stub_code->ICCallBreakpointLabel(), |
| 74 kNotPatchable); | 67 kNotPatchable); |
| 75 ASSERT(index == kICCallBreakpointCPIndex); | 68 ASSERT(index == kICCallBreakpointCPIndex); |
| 76 } else { | 69 } else { |
| 77 object_pool_.Add(vacant, Heap::kOld); | 70 object_pool_.AddObject(vacant, kNotPatchable); |
| 78 patchable_pool_entries_.Add(kNotPatchable); | |
| 79 } | 71 } |
| 80 if (stub_code->ClosureCallBreakpoint_entry() != NULL) { | 72 if (stub_code->ClosureCallBreakpoint_entry() != NULL) { |
| 81 intptr_t index = | 73 intptr_t index = object_pool_.AddExternalLabel( |
| 82 FindExternalLabel(&stub_code->ClosureCallBreakpointLabel(), | 74 &stub_code->ClosureCallBreakpointLabel(), kNotPatchable); |
| 83 kNotPatchable); | |
| 84 ASSERT(index == kClosureCallBreakpointCPIndex); | 75 ASSERT(index == kClosureCallBreakpointCPIndex); |
| 85 } else { | 76 } else { |
| 86 object_pool_.Add(vacant, Heap::kOld); | 77 object_pool_.AddObject(vacant, kNotPatchable); |
| 87 patchable_pool_entries_.Add(kNotPatchable); | |
| 88 } | 78 } |
| 89 if (stub_code->RuntimeCallBreakpoint_entry() != NULL) { | 79 if (stub_code->RuntimeCallBreakpoint_entry() != NULL) { |
| 90 intptr_t index = | 80 intptr_t index = object_pool_.AddExternalLabel( |
| 91 FindExternalLabel(&stub_code->RuntimeCallBreakpointLabel(), | 81 &stub_code->RuntimeCallBreakpointLabel(), kNotPatchable); |
| 92 kNotPatchable); | |
| 93 ASSERT(index == kRuntimeCallBreakpointCPIndex); | 82 ASSERT(index == kRuntimeCallBreakpointCPIndex); |
| 94 } else { | 83 } else { |
| 95 object_pool_.Add(vacant, Heap::kOld); | 84 object_pool_.AddObject(vacant, kNotPatchable); |
| 96 patchable_pool_entries_.Add(kNotPatchable); | |
| 97 } | 85 } |
| 98 } | 86 } |
| 99 } | 87 } |
| 100 | 88 |
| 101 | 89 |
| 102 void Assembler::InitializeMemoryWithBreakpoints(uword data, intptr_t length) { | 90 void Assembler::InitializeMemoryWithBreakpoints(uword data, intptr_t length) { |
| 103 ASSERT(Utils::IsAligned(data, 4)); | 91 ASSERT(Utils::IsAligned(data, 4)); |
| 104 ASSERT(Utils::IsAligned(length, 4)); | 92 ASSERT(Utils::IsAligned(length, 4)); |
| 105 const uword end = data + length; | 93 const uword end = data + length; |
| 106 while (data < end) { | 94 while (data < end) { |
| (...skipping 310 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 417 const uint32_t lower12 = offset & 0x00000fff; | 405 const uint32_t lower12 = offset & 0x00000fff; |
| 418 const Operand::OperandType ot = | 406 const Operand::OperandType ot = |
| 419 Operand::CanHold(upper20, kXRegSizeInBits, &op); | 407 Operand::CanHold(upper20, kXRegSizeInBits, &op); |
| 420 ASSERT(ot == Operand::Immediate); | 408 ASSERT(ot == Operand::Immediate); |
| 421 ASSERT(Address::CanHoldOffset(lower12)); | 409 ASSERT(Address::CanHoldOffset(lower12)); |
| 422 add(dst, pp, op); | 410 add(dst, pp, op); |
| 423 ldr(dst, Address(dst, lower12)); | 411 ldr(dst, Address(dst, lower12)); |
| 424 } | 412 } |
| 425 | 413 |
| 426 | 414 |
| 427 intptr_t Assembler::FindExternalLabel(const ExternalLabel* label, | |
| 428 Patchability patchable) { | |
| 429 // The object pool cannot be used in the vm isolate. | |
| 430 ASSERT(Isolate::Current() != Dart::vm_isolate()); | |
| 431 ASSERT(!object_pool_.IsNull()); | |
| 432 const uword address = label->address(); | |
| 433 ASSERT(Utils::IsAligned(address, 4)); | |
| 434 // The address is stored in the object array as a RawSmi. | |
| 435 const Smi& smi = Smi::Handle(reinterpret_cast<RawSmi*>(address)); | |
| 436 if (patchable == kNotPatchable) { | |
| 437 // If the call site is not patchable, we can try to re-use an existing | |
| 438 // entry. | |
| 439 return FindObject(smi, kNotPatchable); | |
| 440 } | |
| 441 // If the call is patchable, do not reuse an existing entry since each | |
| 442 // reference may be patched independently. | |
| 443 object_pool_.Add(smi, Heap::kOld); | |
| 444 patchable_pool_entries_.Add(patchable); | |
| 445 return object_pool_.Length() - 1; | |
| 446 } | |
| 447 | |
| 448 | |
| 449 intptr_t Assembler::FindObject(const Object& obj, Patchability patchable) { | |
| 450 // The object pool cannot be used in the vm isolate. | |
| 451 ASSERT(Isolate::Current() != Dart::vm_isolate()); | |
| 452 ASSERT(!object_pool_.IsNull()); | |
| 453 | |
| 454 // If the object is not patchable, check if we've already got it in the | |
| 455 // object pool. | |
| 456 if (patchable == kNotPatchable) { | |
| 457 intptr_t idx = object_pool_index_table_.Lookup(&obj); | |
| 458 if (idx != ObjIndexPair::kNoIndex) { | |
| 459 ASSERT(patchable_pool_entries_[idx] == kNotPatchable); | |
| 460 return idx; | |
| 461 } | |
| 462 } | |
| 463 | |
| 464 object_pool_.Add(obj, Heap::kOld); | |
| 465 patchable_pool_entries_.Add(patchable); | |
| 466 if (patchable == kNotPatchable) { | |
| 467 // The object isn't patchable. Record the index for fast lookup. | |
| 468 object_pool_index_table_.Insert( | |
| 469 ObjIndexPair(&obj, object_pool_.Length() - 1)); | |
| 470 } | |
| 471 return object_pool_.Length() - 1; | |
| 472 } | |
| 473 | |
| 474 | |
| 475 intptr_t Assembler::FindImmediate(int64_t imm) { | 415 intptr_t Assembler::FindImmediate(int64_t imm) { |
| 476 ASSERT(Isolate::Current() != Dart::vm_isolate()); | 416 ASSERT(Isolate::Current() != Dart::vm_isolate()); |
| 477 ASSERT(!object_pool_.IsNull()); | |
| 478 const Smi& smi = Smi::Handle(reinterpret_cast<RawSmi*>(imm)); | 417 const Smi& smi = Smi::Handle(reinterpret_cast<RawSmi*>(imm)); |
| 479 return FindObject(smi, kNotPatchable); | 418 return object_pool_.FindObject(smi, kNotPatchable); |
| 480 } | 419 } |
| 481 | 420 |
| 482 | 421 |
| 483 // A set of VM objects that are present in every constant pool. | 422 // A set of VM objects that are present in every constant pool. |
| 484 static bool IsAlwaysInConstantPool(const Object& object) { | 423 static bool IsAlwaysInConstantPool(const Object& object) { |
| 485 // TODO(zra): Evaluate putting all VM heap objects into the pool. | 424 // TODO(zra): Evaluate putting all VM heap objects into the pool. |
| 486 return (object.raw() == Object::null()) | 425 return (object.raw() == Object::null()) |
| 487 || (object.raw() == Bool::True().raw()) | 426 || (object.raw() == Bool::True().raw()) |
| 488 || (object.raw() == Bool::False().raw()); | 427 || (object.raw() == Bool::False().raw()); |
| 489 } | 428 } |
| (...skipping 30 matching lines...) Expand all Loading... | |
| 520 } | 459 } |
| 521 | 460 |
| 522 | 461 |
| 523 void Assembler::LoadExternalLabel(Register dst, | 462 void Assembler::LoadExternalLabel(Register dst, |
| 524 const ExternalLabel* label, | 463 const ExternalLabel* label, |
| 525 Patchability patchable, | 464 Patchability patchable, |
| 526 Register pp) { | 465 Register pp) { |
| 527 const int64_t target = static_cast<int64_t>(label->address()); | 466 const int64_t target = static_cast<int64_t>(label->address()); |
| 528 if (CanLoadImmediateFromPool(target, pp)) { | 467 if (CanLoadImmediateFromPool(target, pp)) { |
| 529 const int32_t offset = | 468 const int32_t offset = |
| 530 Array::element_offset(FindExternalLabel(label, patchable)); | 469 Array::element_offset(object_pool_.FindExternalLabel(label, patchable)); |
| 531 LoadWordFromPoolOffset(dst, pp, offset); | 470 LoadWordFromPoolOffset(dst, pp, offset); |
| 532 } else { | 471 } else { |
| 533 LoadImmediate(dst, target, kNoPP); | 472 LoadImmediate(dst, target, kNoPP); |
| 534 } | 473 } |
| 535 } | 474 } |
| 536 | 475 |
| 537 | 476 |
| 538 void Assembler::LoadExternalLabelFixed(Register dst, | 477 void Assembler::LoadExternalLabelFixed(Register dst, |
| 539 const ExternalLabel* label, | 478 const ExternalLabel* label, |
| 540 Patchability patchable, | 479 Patchability patchable, |
| 541 Register pp) { | 480 Register pp) { |
| 542 const int32_t offset = | 481 const int32_t offset = |
| 543 Array::element_offset(FindExternalLabel(label, patchable)); | 482 Array::element_offset(object_pool_.FindExternalLabel(label, patchable)); |
| 544 LoadWordFromPoolOffsetFixed(dst, pp, offset); | 483 LoadWordFromPoolOffsetFixed(dst, pp, offset); |
| 545 } | 484 } |
| 546 | 485 |
| 547 | 486 |
| 548 void Assembler::LoadIsolate(Register dst, Register pp) { | 487 void Assembler::LoadIsolate(Register dst, Register pp) { |
| 549 LoadImmediate(dst, reinterpret_cast<uword>(Isolate::Current()), pp); | 488 LoadImmediate(dst, reinterpret_cast<uword>(Isolate::Current()), pp); |
| 550 } | 489 } |
| 551 | 490 |
| 552 | 491 |
| 553 void Assembler::LoadObject(Register dst, const Object& object, Register pp) { | 492 void Assembler::LoadObject(Register dst, const Object& object, Register pp) { |
| 554 if (CanLoadObjectFromPool(object)) { | 493 if (CanLoadObjectFromPool(object)) { |
| 555 const int32_t offset = | 494 const int32_t offset = |
| 556 Array::element_offset(FindObject(object, kNotPatchable)); | 495 Array::element_offset(object_pool_.FindObject(object, kNotPatchable)); |
| 557 LoadWordFromPoolOffset(dst, pp, offset); | 496 LoadWordFromPoolOffset(dst, pp, offset); |
| 558 } else { | 497 } else { |
| 559 ASSERT((Isolate::Current() == Dart::vm_isolate()) || | 498 ASSERT((Isolate::Current() == Dart::vm_isolate()) || |
| 560 object.IsSmi() || | 499 object.IsSmi() || |
| 561 object.InVMHeap()); | 500 object.InVMHeap()); |
| 562 LoadDecodableImmediate(dst, reinterpret_cast<int64_t>(object.raw()), pp); | 501 LoadDecodableImmediate(dst, reinterpret_cast<int64_t>(object.raw()), pp); |
| 563 } | 502 } |
| 564 } | 503 } |
| 565 | 504 |
| 566 | 505 |
| (...skipping 979 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1546 add(base, array, Operand(index, LSL, shift)); | 1485 add(base, array, Operand(index, LSL, shift)); |
| 1547 } | 1486 } |
| 1548 const OperandSize size = Address::OperandSizeFor(cid); | 1487 const OperandSize size = Address::OperandSizeFor(cid); |
| 1549 ASSERT(Address::CanHoldOffset(offset, Address::Offset, size)); | 1488 ASSERT(Address::CanHoldOffset(offset, Address::Offset, size)); |
| 1550 return Address(base, offset, Address::Offset, size); | 1489 return Address(base, offset, Address::Offset, size); |
| 1551 } | 1490 } |
| 1552 | 1491 |
| 1553 } // namespace dart | 1492 } // namespace dart |
| 1554 | 1493 |
| 1555 #endif // defined TARGET_ARCH_ARM64 | 1494 #endif // defined TARGET_ARCH_ARM64 |
| OLD | NEW |