Skip to content

Commit 02a8dd9

Browse files
sstricklcommit-bot@chromium.org
authored andcommitted
[vm] Add a bare-bones AllocateClosure stub.
Also create a subclass of AllocationInstr, AllocateClosureInstr, which is used when allocating closures. Followup CLs add inputs to this instruction and to the AllocateClosure stub, starting with the closure function. Adding these inputs allows the related field to be set within the stub, instead of using StoreInstanceField manually at each closure allocation point. Since this CL only adds the initial stub/instruction implementation, the overhead on snapshots is minimal: just the addition of the new stub to each isolate. ----- This CL also adds virtual and non-virtual methods to assembler_base.h revolving around field loads and stores and attempted inline object allocation, to ensure all architectures have these methods. It also adds LoadFromSlot/StoreToSlot/StoreToSlotNoBarrier, which appropriately calls one of the other methods based on whether the slot is compressed or not and whether it is a boxed or unboxed field. With these additions, the AllocateClosure stub generator can be defined in an architecture-independent way. TEST=Basically a refactoring, so check using current test suites. Cq-Include-Trybots: luci.dart.try:vm-kernel-precomp-linux-debug-simarm64c-try,vm-kernel-precomp-linux-debug-simarm_x64-try,vm-kernel-precomp-linux-debug-x64-try,vm-kernel-precomp-linux-debug-x64c-try,vm-kernel-precomp-linux-product-x64-try,vm-kernel-precomp-linux-release-x64-try,vm-kernel-precomp-linux-release-simarm64-try,vm-kernel-precomp-linux-release-simarm-try,vm-kernel-linux-debug-ia32-try,vm-kernel-linux-debug-x64-try,vm-kernel-linux-product-x64-try,vm-kernel-linux-release-simarm64-try,vm-kernel-linux-release-simarm-try,vm-kernel-linux-release-x64-try,vm-kernel-linux-debug-x64c-try Change-Id: I71f5691307679f8d5e3604007699de4706f86eb8 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/198284 Commit-Queue: Tess Strickland <sstrickl@google.com> Reviewed-by: Alexander Markov <alexmarkov@google.com> Reviewed-by: Martin Kustermann <kustermann@google.com>
1 parent 010523e commit 02a8dd9

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

42 files changed

+902
-574
lines changed

runtime/vm/compiler/assembler/assembler_arm.cc

Lines changed: 20 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -3421,28 +3421,31 @@ void Assembler::LoadAllocationStatsAddress(Register dest, intptr_t cid) {
34213421
}
34223422
#endif // !PRODUCT
34233423

3424-
void Assembler::TryAllocate(const Class& cls,
3425-
Label* failure,
3426-
JumpDistance distance,
3427-
Register instance_reg,
3428-
Register temp_reg) {
3424+
void Assembler::TryAllocateObject(intptr_t cid,
3425+
intptr_t instance_size,
3426+
Label* failure,
3427+
JumpDistance distance,
3428+
Register instance_reg,
3429+
Register temp_reg) {
34293430
ASSERT(failure != NULL);
3430-
const intptr_t instance_size = target::Class::GetInstanceSize(cls);
3431+
ASSERT(instance_reg != kNoRegister);
3432+
ASSERT(instance_reg != temp_reg);
3433+
ASSERT(instance_reg != IP);
3434+
ASSERT(temp_reg != kNoRegister);
3435+
ASSERT(temp_reg != IP);
3436+
ASSERT(instance_size != 0);
3437+
ASSERT(Utils::IsAligned(instance_size,
3438+
target::ObjectAlignment::kObjectAlignment));
34313439
if (FLAG_inline_alloc &&
34323440
target::Heap::IsAllocatableInNewSpace(instance_size)) {
3433-
const classid_t cid = target::Class::GetId(cls);
3434-
ASSERT(instance_reg != temp_reg);
3435-
ASSERT(temp_reg != IP);
3436-
ASSERT(instance_size != 0);
34373441
NOT_IN_PRODUCT(LoadAllocationStatsAddress(temp_reg, cid));
34383442
ldr(instance_reg, Address(THR, target::Thread::top_offset()));
34393443
// TODO(koda): Protect against unsigned overflow here.
3440-
AddImmediateSetFlags(instance_reg, instance_reg, instance_size);
3441-
3442-
// instance_reg: potential next object start.
3444+
AddImmediate(instance_reg, instance_size);
3445+
// instance_reg: potential top (next object start).
34433446
ldr(IP, Address(THR, target::Thread::end_offset()));
34443447
cmp(IP, Operand(instance_reg));
3445-
// fail if heap end unsigned less than or equal to instance_reg.
3448+
// fail if heap end unsigned less than or equal to new heap top.
34463449
b(failure, LS);
34473450

34483451
// If this allocation is traced, program will jump to failure path
@@ -3453,13 +3456,12 @@ void Assembler::TryAllocate(const Class& cls,
34533456
// Successfully allocated the object, now update top to point to
34543457
// next object start and store the class in the class field of object.
34553458
str(instance_reg, Address(THR, target::Thread::top_offset()));
3456-
3457-
ASSERT(instance_size >= kHeapObjectTag);
3459+
// Move instance_reg back to the start of the object and tag it.
34583460
AddImmediate(instance_reg, -instance_size + kHeapObjectTag);
34593461

34603462
const uword tags = target::MakeTagWordForNewSpaceObject(cid, instance_size);
3461-
LoadImmediate(IP, tags);
3462-
str(IP, FieldAddress(instance_reg, target::Object::tags_offset()));
3463+
LoadImmediate(temp_reg, tags);
3464+
str(temp_reg, FieldAddress(instance_reg, target::Object::tags_offset()));
34633465
} else {
34643466
b(failure);
34653467
}

runtime/vm/compiler/assembler/assembler_arm.h

Lines changed: 10 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -388,9 +388,8 @@ class Assembler : public AssemblerBase {
388388
// Unconditional jump to a given address in memory.
389389
void Jump(const Address& address) { Branch(address); }
390390

391-
void LoadField(Register dst, FieldAddress address) { ldr(dst, address); }
392-
void LoadCompressedField(Register dst, FieldAddress address) {
393-
LoadField(dst, address);
391+
void LoadField(Register dst, const FieldAddress& address) override {
392+
ldr(dst, address);
394393
}
395394
void LoadMemoryValue(Register dst, Register base, int32_t offset) {
396395
LoadFromOffset(dst, base, offset);
@@ -854,11 +853,6 @@ class Assembler : public AssemblerBase {
854853
}
855854
void CompareObject(Register rn, const Object& object);
856855

857-
enum CanBeSmi {
858-
kValueIsNotSmi,
859-
kValueCanBeSmi,
860-
};
861-
862856
// Store into a heap object and apply the generational and incremental write
863857
// barriers. All stores into heap objects must pass through this function or,
864858
// if the value can be proven either Smi or old-and-premarked, its NoBarrier
@@ -867,7 +861,7 @@ class Assembler : public AssemblerBase {
867861
void StoreIntoObject(Register object, // Object we are storing into.
868862
const Address& dest, // Where we are storing into.
869863
Register value, // Value we are storing.
870-
CanBeSmi can_value_be_smi = kValueCanBeSmi);
864+
CanBeSmi can_value_be_smi = kValueCanBeSmi) override;
871865
void StoreIntoArray(Register object,
872866
Register slot,
873867
Register value,
@@ -879,7 +873,7 @@ class Assembler : public AssemblerBase {
879873

880874
void StoreIntoObjectNoBarrier(Register object,
881875
const Address& dest,
882-
Register value);
876+
Register value) override;
883877
void StoreIntoObjectNoBarrier(Register object,
884878
const Address& dest,
885879
const Object& value);
@@ -1274,15 +1268,12 @@ class Assembler : public AssemblerBase {
12741268
// which will allocate in the runtime where tracing occurs.
12751269
void MaybeTraceAllocation(Register stats_addr_reg, Label* trace);
12761270

1277-
// Inlined allocation of an instance of class 'cls', code has no runtime
1278-
// calls. Jump to 'failure' if the instance cannot be allocated here.
1279-
// Allocated instance is returned in 'instance_reg'.
1280-
// Only the tags field of the object is initialized.
1281-
void TryAllocate(const Class& cls,
1282-
Label* failure,
1283-
JumpDistance distance,
1284-
Register instance_reg,
1285-
Register temp_reg);
1271+
void TryAllocateObject(intptr_t cid,
1272+
intptr_t instance_size,
1273+
Label* failure,
1274+
JumpDistance distance,
1275+
Register instance_reg,
1276+
Register temp_reg) override;
12861277

12871278
void TryAllocateArray(intptr_t cid,
12881279
intptr_t instance_size,

runtime/vm/compiler/assembler/assembler_arm64.cc

Lines changed: 27 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1841,46 +1841,48 @@ void Assembler::MaybeTraceAllocation(intptr_t cid,
18411841
}
18421842
#endif // !PRODUCT
18431843

1844-
void Assembler::TryAllocate(const Class& cls,
1845-
Label* failure,
1846-
JumpDistance distance,
1847-
Register instance_reg,
1848-
Register top_reg,
1849-
bool tag_result) {
1844+
void Assembler::TryAllocateObject(intptr_t cid,
1845+
intptr_t instance_size,
1846+
Label* failure,
1847+
JumpDistance distance,
1848+
Register instance_reg,
1849+
Register temp_reg) {
18501850
ASSERT(failure != NULL);
1851-
const intptr_t instance_size = target::Class::GetInstanceSize(cls);
1851+
ASSERT(instance_size != 0);
1852+
ASSERT(instance_reg != temp_reg);
1853+
ASSERT(temp_reg != kNoRegister);
1854+
ASSERT(Utils::IsAligned(instance_size,
1855+
target::ObjectAlignment::kObjectAlignment));
18521856
if (FLAG_inline_alloc &&
18531857
target::Heap::IsAllocatableInNewSpace(instance_size)) {
18541858
// If this allocation is traced, program will jump to failure path
18551859
// (i.e. the allocation stub) which will allocate the object and trace the
18561860
// allocation call site.
1857-
const classid_t cid = target::Class::GetId(cls);
1858-
NOT_IN_PRODUCT(MaybeTraceAllocation(cid, /*temp_reg=*/top_reg, failure));
1859-
1860-
const Register kEndReg = TMP;
1861-
1862-
// instance_reg: potential next object start.
1861+
NOT_IN_PRODUCT(MaybeTraceAllocation(cid, temp_reg, failure));
18631862
RELEASE_ASSERT((target::Thread::top_offset() + target::kWordSize) ==
18641863
target::Thread::end_offset());
1865-
ldp(instance_reg, kEndReg,
1864+
ldp(instance_reg, temp_reg,
18661865
Address(THR, target::Thread::top_offset(), Address::PairOffset));
1866+
// instance_reg: current top (next object start).
1867+
// temp_reg: heap end
18671868

18681869
// TODO(koda): Protect against unsigned overflow here.
1869-
AddImmediate(top_reg, instance_reg, instance_size);
1870-
cmp(kEndReg, Operand(top_reg));
1871-
b(failure, LS); // Unsigned lower or equal.
1870+
AddImmediate(instance_reg, instance_size);
1871+
// instance_reg: potential top (next object start).
1872+
// fail if heap end unsigned less than or equal to new heap top.
1873+
cmp(temp_reg, Operand(instance_reg));
1874+
b(failure, LS);
18721875

1873-
// Successfully allocated the object, now update top to point to
1876+
// Successfully allocated the object, now update temp to point to
18741877
// next object start and store the class in the class field of object.
1875-
str(top_reg, Address(THR, target::Thread::top_offset()));
1878+
str(instance_reg, Address(THR, target::Thread::top_offset()));
1879+
// Move instance_reg back to the start of the object and tag it.
1880+
AddImmediate(instance_reg, -instance_size + kHeapObjectTag);
18761881

18771882
const uword tags = target::MakeTagWordForNewSpaceObject(cid, instance_size);
1878-
LoadImmediate(TMP, tags);
1879-
StoreToOffset(TMP, instance_reg, target::Object::tags_offset());
1880-
1881-
if (tag_result) {
1882-
AddImmediate(instance_reg, kHeapObjectTag);
1883-
}
1883+
LoadImmediate(temp_reg, tags);
1884+
StoreToOffset(temp_reg,
1885+
FieldAddress(instance_reg, target::Object::tags_offset()));
18841886
} else {
18851887
b(failure);
18861888
}

runtime/vm/compiler/assembler/assembler_arm64.h

Lines changed: 18 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -547,8 +547,10 @@ class Assembler : public AssemblerBase {
547547
br(TMP);
548548
}
549549

550-
void LoadField(Register dst, FieldAddress address) { ldr(dst, address); }
551-
void LoadCompressedField(Register dst, FieldAddress address) {
550+
void LoadField(Register dst, const FieldAddress& address) override {
551+
ldr(dst, address);
552+
}
553+
void LoadCompressedField(Register dst, const FieldAddress& address) override {
552554
LoadCompressed(dst, address);
553555
}
554556
void LoadMemoryValue(Register dst, Register base, int32_t offset) {
@@ -1762,11 +1764,6 @@ class Assembler : public AssemblerBase {
17621764
StoreQToOffset(src, base, offset - kHeapObjectTag);
17631765
}
17641766

1765-
enum CanBeSmi {
1766-
kValueIsNotSmi,
1767-
kValueCanBeSmi,
1768-
};
1769-
17701767
void LoadCompressed(Register dest, const Address& slot);
17711768
void LoadCompressedSmi(Register dest, const Address& slot);
17721769

@@ -1778,11 +1775,12 @@ class Assembler : public AssemblerBase {
17781775
void StoreIntoObject(Register object,
17791776
const Address& dest,
17801777
Register value,
1781-
CanBeSmi can_value_be_smi = kValueCanBeSmi);
1782-
void StoreCompressedIntoObject(Register object,
1783-
const Address& dest,
1784-
Register value,
1785-
CanBeSmi can_value_be_smi = kValueCanBeSmi);
1778+
CanBeSmi can_value_be_smi = kValueCanBeSmi) override;
1779+
void StoreCompressedIntoObject(
1780+
Register object,
1781+
const Address& dest,
1782+
Register value,
1783+
CanBeSmi can_value_be_smi = kValueCanBeSmi) override;
17861784
void StoreBarrier(Register object, Register value, CanBeSmi can_value_be_smi);
17871785
void StoreIntoArray(Register object,
17881786
Register slot,
@@ -1800,10 +1798,10 @@ class Assembler : public AssemblerBase {
18001798
CanBeSmi can_value_be_smi = kValueCanBeSmi);
18011799
void StoreIntoObjectNoBarrier(Register object,
18021800
const Address& dest,
1803-
Register value);
1801+
Register value) override;
18041802
void StoreCompressedIntoObjectNoBarrier(Register object,
18051803
const Address& dest,
1806-
Register value);
1804+
Register value) override;
18071805
void StoreIntoObjectOffsetNoBarrier(Register object,
18081806
int32_t offset,
18091807
Register value);
@@ -1990,19 +1988,12 @@ class Assembler : public AssemblerBase {
19901988
// which will allocate in the runtime where tracing occurs.
19911989
void MaybeTraceAllocation(intptr_t cid, Register temp_reg, Label* trace);
19921990

1993-
// Inlined allocation of an instance of class 'cls', code has no runtime
1994-
// calls. Jump to 'failure' if the instance cannot be allocated here.
1995-
// Allocated instance is returned in 'instance_reg'.
1996-
// Only the tags field of the object is initialized.
1997-
// Result:
1998-
// * [instance_reg] will contain allocated new-space object
1999-
// * [top_reg] will contain Thread::top_offset()
2000-
void TryAllocate(const Class& cls,
2001-
Label* failure,
2002-
JumpDistance distance,
2003-
Register instance_reg,
2004-
Register top_reg,
2005-
bool tag_result = true);
1991+
void TryAllocateObject(intptr_t cid,
1992+
intptr_t instance_size,
1993+
Label* failure,
1994+
JumpDistance distance,
1995+
Register instance_reg,
1996+
Register top_reg) override;
20061997

20071998
void TryAllocateArray(intptr_t cid,
20081999
intptr_t instance_size,

runtime/vm/compiler/assembler/assembler_base.cc

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
#include "vm/compiler/assembler/assembler_base.h"
66

77
#include "platform/utils.h"
8+
#include "vm/compiler/backend/slot.h"
89
#include "vm/cpu.h"
910
#include "vm/heap/heap.h"
1011
#include "vm/memory_region.h"
@@ -26,6 +27,53 @@ namespace compiler {
2627

2728
AssemblerBase::~AssemblerBase() {}
2829

30+
void AssemblerBase::LoadFromSlot(Register dst,
31+
Register base,
32+
const Slot& slot) {
33+
auto const rep = slot.representation();
34+
const FieldAddress address(base, slot.offset_in_bytes());
35+
if (rep != kTagged) {
36+
auto const sz = RepresentationUtils::OperandSize(rep);
37+
return LoadFromOffset(dst, address, sz);
38+
}
39+
if (slot.is_compressed()) {
40+
return LoadCompressedField(dst, address);
41+
}
42+
return LoadField(dst, address);
43+
}
44+
45+
void AssemblerBase::StoreToSlot(Register src, Register base, const Slot& slot) {
46+
auto const rep = slot.representation();
47+
const FieldAddress address(base, slot.offset_in_bytes());
48+
if (rep != kTagged) {
49+
auto const sz = RepresentationUtils::OperandSize(rep);
50+
return StoreToOffset(src, address, sz);
51+
}
52+
if (slot.is_compressed()) {
53+
return StoreCompressedIntoObject(
54+
base, address, src,
55+
slot.ComputeCompileType().CanBeSmi() ? kValueCanBeSmi : kValueIsNotSmi);
56+
}
57+
return StoreIntoObject(
58+
base, address, src,
59+
slot.ComputeCompileType().CanBeSmi() ? kValueCanBeSmi : kValueIsNotSmi);
60+
}
61+
62+
void AssemblerBase::StoreToSlotNoBarrier(Register src,
63+
Register base,
64+
const Slot& slot) {
65+
auto const rep = slot.representation();
66+
const FieldAddress address(base, slot.offset_in_bytes());
67+
if (rep != kTagged) {
68+
auto const sz = RepresentationUtils::OperandSize(rep);
69+
return StoreToOffset(src, address, sz);
70+
}
71+
if (slot.is_compressed()) {
72+
return StoreCompressedIntoObjectNoBarrier(base, address, src);
73+
}
74+
return StoreIntoObjectNoBarrier(base, address, src);
75+
}
76+
2977
intptr_t AssemblerBase::InsertAlignedRelocation(BSS::Relocation reloc) {
3078
// We cannot put a relocation at the very start (it's not a valid
3179
// instruction)!

0 commit comments

Comments
 (0)