Skip to content

Commit eb626c2

Browse files
committed
ObjectOutliner: don't outline objects with tail allocations
An object with tail allocated elements is in risk of being passed to malloc_size, which does not work for non-heap allocated objects. Conservatively, disable objects with tail allocations. rdar://121886093
1 parent a52e96e commit eb626c2

File tree

2 files changed

+18
-4
lines changed

2 files changed

+18
-4
lines changed

SwiftCompilerSources/Sources/Optimizer/FunctionPasses/ObjectOutliner.swift

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,14 @@ private func optimizeObjectAllocation(allocRef: AllocRefInstBase, _ context: Fun
7676
return nil
7777
}
7878

79-
guard let endOfInitInst = findEndOfInitialization(of: allocRef) else {
79+
guard let endOfInitInst = findEndOfInitialization(
80+
of: allocRef,
81+
// An object with tail allocated elements is in risk of being passed to malloc_size, which does
82+
// not work for non-heap allocated objects. Conservatively, disable objects with tail allocations.
83+
// Note, that this does not affect Array because Array always has an end_cow_mutation at the end of
84+
// initialization.
85+
canStoreToGlobal: allocRef.tailAllocatedCounts.count == 0)
86+
else {
8087
return nil
8188
}
8289

@@ -98,15 +105,15 @@ private func optimizeObjectAllocation(allocRef: AllocRefInstBase, _ context: Fun
98105
// The end-of-initialization is either an end_cow_mutation, because it guarantees that the originally initialized
99106
// object is not mutated (it must be copied before mutation).
100107
// Or it is the store to a global let variable in the global's initializer function.
101-
private func findEndOfInitialization(of object: Value) -> Instruction? {
108+
private func findEndOfInitialization(of object: Value, canStoreToGlobal: Bool) -> Instruction? {
102109
for use in object.uses {
103110
let user = use.instruction
104111
switch user {
105112
case is UpcastInst,
106113
is UncheckedRefCastInst,
107114
is MoveValueInst,
108115
is EndInitLetRefInst:
109-
if let ecm = findEndOfInitialization(of: user as! SingleValueInstruction) {
116+
if let ecm = findEndOfInitialization(of: user as! SingleValueInstruction, canStoreToGlobal: canStoreToGlobal) {
110117
return ecm
111118
}
112119
case let ecm as EndCOWMutationInst:
@@ -115,7 +122,8 @@ private func findEndOfInitialization(of object: Value) -> Instruction? {
115122
}
116123
return ecm
117124
case let store as StoreInst:
118-
if let ga = store.destination as? GlobalAddrInst,
125+
if canStoreToGlobal,
126+
let ga = store.destination as? GlobalAddrInst,
119127
ga.global.isLet,
120128
ga.parentFunction.initializedGlobal == ga.global
121129
{

test/SILOptimizer/static_objects.swift

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,12 @@ public func testit() -> C {
4444
return c
4545
}
4646

47+
// Cannot allocate a ManagedBuffer in a data section, because it calls malloc_size on the class instance.
48+
// CHECK-LABEL: sil private [global_init_once_fn] @$s4test10managedBuf_WZ :
49+
// CHECK: alloc_ref [tail_elems $UInt8 * %{{[0-9]*}} : $Builtin.Word] $ManagedBuffer<(), UInt8>
50+
// CHECK: } // end sil function '$s4test10managedBuf_WZ'
51+
public let managedBuf = ManagedBuffer<Void, UInt8>.create(minimumCapacity: 0, makingHeaderWith: { _ in })
52+
4753
@main struct Main {
4854
static func main() {
4955
// CHECK-OUTPUT: c.x=27

0 commit comments

Comments
 (0)