Skip to content

Commit 75b94d7

Browse files
authored
Merge pull request swiftlang#83921 from DougGregor/with-unsafe-temporary-alloc-typed-throws
Adopt typed throws in withUnsafeTemporaryAllocation
2 parents ff8058d + 3782db5 commit 75b94d7

File tree

3 files changed

+105
-77
lines changed

3 files changed

+105
-77
lines changed

stdlib/public/core/TemporaryAllocation.swift

Lines changed: 79 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -119,8 +119,6 @@ internal func _isStackAllocationSafe(byteCount: Int, alignment: Int) -> Bool {
119119
///
120120
/// - Returns: Whatever is returned by `body`.
121121
///
122-
/// - Throws: Whatever is thrown by `body`.
123-
///
124122
/// This function encapsulates the various calls to builtins required by
125123
/// `withUnsafeTemporaryAllocation()`.
126124
@_alwaysEmitIntoClient @_transparent
@@ -130,13 +128,13 @@ internal func _withUnsafeTemporaryAllocation<
130128
of type: T.Type,
131129
capacity: Int,
132130
alignment: Int,
133-
_ body: (Builtin.RawPointer) throws -> R
134-
) rethrows -> R {
131+
_ body: (Builtin.RawPointer) -> R
132+
) -> R {
135133
// How many bytes do we need to allocate?
136134
let byteCount = _byteCountForTemporaryAllocation(of: type, capacity: capacity)
137135

138136
guard _isStackAllocationSafe(byteCount: byteCount, alignment: alignment) else {
139-
return try _fallBackToHeapAllocation(byteCount: byteCount, alignment: alignment, body)
137+
return _fallBackToHeapAllocation(byteCount: byteCount, alignment: alignment, body)
140138
}
141139

142140
// This declaration must come BEFORE Builtin.stackAlloc() or
@@ -154,15 +152,9 @@ internal func _withUnsafeTemporaryAllocation<
154152
// The multiple calls to Builtin.stackDealloc() are because defer { } produces
155153
// a child function at the SIL layer and that conflicts with the verifier's
156154
// idea of a stack allocation's lifetime.
157-
do {
158-
result = try body(stackAddress)
159-
Builtin.stackDealloc(stackAddress)
160-
return result
161-
162-
} catch {
163-
Builtin.stackDealloc(stackAddress)
164-
throw error
165-
}
155+
result = body(stackAddress)
156+
Builtin.stackDealloc(stackAddress)
157+
return result
166158
#else
167159
fatalError("unsupported compiler")
168160
#endif
@@ -175,13 +167,13 @@ internal func _withUnprotectedUnsafeTemporaryAllocation<
175167
of type: T.Type,
176168
capacity: Int,
177169
alignment: Int,
178-
_ body: (Builtin.RawPointer) throws -> R
179-
) rethrows -> R {
170+
_ body: (Builtin.RawPointer) -> R
171+
) -> R {
180172
// How many bytes do we need to allocate?
181173
let byteCount = _byteCountForTemporaryAllocation(of: type, capacity: capacity)
182174

183175
guard _isStackAllocationSafe(byteCount: byteCount, alignment: alignment) else {
184-
return try _fallBackToHeapAllocation(byteCount: byteCount, alignment: alignment, body)
176+
return _fallBackToHeapAllocation(byteCount: byteCount, alignment: alignment, body)
185177
}
186178

187179
// This declaration must come BEFORE Builtin.unprotectedStackAlloc() or
@@ -198,23 +190,17 @@ internal func _withUnprotectedUnsafeTemporaryAllocation<
198190
// The multiple calls to Builtin.stackDealloc() are because defer { } produces
199191
// a child function at the SIL layer and that conflicts with the verifier's
200192
// idea of a stack allocation's lifetime.
201-
do {
202-
result = try body(stackAddress)
203-
Builtin.stackDealloc(stackAddress)
204-
return result
205-
206-
} catch {
207-
Builtin.stackDealloc(stackAddress)
208-
throw error
209-
}
193+
result = body(stackAddress)
194+
Builtin.stackDealloc(stackAddress)
195+
return result
210196
}
211197

212198
@_alwaysEmitIntoClient @_transparent
213-
internal func _fallBackToHeapAllocation<R: ~Copyable>(
199+
internal func _fallBackToHeapAllocation<R: ~Copyable, E: Error>(
214200
byteCount: Int,
215201
alignment: Int,
216-
_ body: (Builtin.RawPointer) throws -> R
217-
) rethrows -> R {
202+
_ body: (Builtin.RawPointer) throws(E) -> R
203+
) throws(E) -> R {
218204
let buffer = UnsafeMutableRawPointer.allocate(
219205
byteCount: byteCount,
220206
alignment: alignment
@@ -259,22 +245,28 @@ internal func _fallBackToHeapAllocation<R: ~Copyable>(
259245
/// the buffer) must not escape. It will be deallocated when `body` returns and
260246
/// cannot be used afterward.
261247
@_alwaysEmitIntoClient @_transparent
262-
public func withUnsafeTemporaryAllocation<R: ~Copyable>(
248+
public func withUnsafeTemporaryAllocation<R: ~Copyable, E: Error>(
263249
byteCount: Int,
264250
alignment: Int,
265-
_ body: (UnsafeMutableRawBufferPointer) throws -> R
266-
) rethrows -> R {
267-
return try _withUnsafeTemporaryAllocation(
251+
_ body: (UnsafeMutableRawBufferPointer) throws(E) -> R
252+
) throws(E) -> R {
253+
let result: Result<R, E> = _withUnsafeTemporaryAllocation(
268254
of: Int8.self,
269255
capacity: byteCount,
270256
alignment: alignment
271257
) { pointer in
272-
let buffer = unsafe UnsafeMutableRawBufferPointer(
273-
start: .init(pointer),
274-
count: byteCount
275-
)
276-
return try unsafe body(buffer)
258+
do throws(E) {
259+
let buffer = unsafe UnsafeMutableRawBufferPointer(
260+
start: .init(pointer),
261+
count: byteCount
262+
)
263+
return .success(try unsafe body(buffer))
264+
} catch {
265+
return .failure(error)
266+
}
277267
}
268+
269+
return try result.get()
278270
}
279271

280272
/// Provides scoped access to a raw buffer pointer with the specified byte count
@@ -283,22 +275,28 @@ public func withUnsafeTemporaryAllocation<R: ~Copyable>(
283275
/// This function is similar to `withUnsafeTemporaryAllocation`, except that it
284276
/// doesn't trigger stack protection for the stack allocated memory.
285277
@_alwaysEmitIntoClient @_transparent
286-
public func _withUnprotectedUnsafeTemporaryAllocation<R: ~Copyable>(
278+
public func _withUnprotectedUnsafeTemporaryAllocation<R: ~Copyable, E: Error>(
287279
byteCount: Int,
288280
alignment: Int,
289-
_ body: (UnsafeMutableRawBufferPointer) throws -> R
290-
) rethrows -> R {
291-
return try _withUnprotectedUnsafeTemporaryAllocation(
281+
_ body: (UnsafeMutableRawBufferPointer) throws(E) -> R
282+
) throws(E) -> R {
283+
let result: Result<R, E> = _withUnprotectedUnsafeTemporaryAllocation(
292284
of: Int8.self,
293285
capacity: byteCount,
294286
alignment: alignment
295287
) { pointer in
296-
let buffer = unsafe UnsafeMutableRawBufferPointer(
297-
start: .init(pointer),
298-
count: byteCount
299-
)
300-
return try unsafe body(buffer)
288+
do throws(E) {
289+
let buffer = unsafe UnsafeMutableRawBufferPointer(
290+
start: .init(pointer),
291+
count: byteCount
292+
)
293+
return try unsafe .success(body(buffer))
294+
} catch {
295+
return .failure(error)
296+
}
301297
}
298+
299+
return try result.get()
302300
}
303301

304302
/// Provides scoped access to a buffer pointer to memory of the specified type
@@ -334,24 +332,31 @@ public func _withUnprotectedUnsafeTemporaryAllocation<R: ~Copyable>(
334332
/// cannot be used afterward.
335333
@_alwaysEmitIntoClient @_transparent
336334
public func withUnsafeTemporaryAllocation<
337-
T: ~Copyable,R: ~Copyable
335+
T: ~Copyable,R: ~Copyable,
336+
E: Error
338337
>(
339338
of type: T.Type,
340339
capacity: Int,
341-
_ body: (UnsafeMutableBufferPointer<T>) throws -> R
342-
) rethrows -> R {
343-
return try _withUnsafeTemporaryAllocation(
340+
_ body: (UnsafeMutableBufferPointer<T>) throws(E) -> R
341+
) throws(E) -> R {
342+
let result: Result<R, E> = _withUnsafeTemporaryAllocation(
344343
of: type,
345344
capacity: capacity,
346345
alignment: MemoryLayout<T>.alignment
347346
) { pointer in
348-
Builtin.bindMemory(pointer, capacity._builtinWordValue, type)
349-
let buffer = unsafe UnsafeMutableBufferPointer<T>(
350-
start: .init(pointer),
351-
count: capacity
352-
)
353-
return try unsafe body(buffer)
347+
do throws(E) {
348+
Builtin.bindMemory(pointer, capacity._builtinWordValue, type)
349+
let buffer = unsafe UnsafeMutableBufferPointer<T>(
350+
start: .init(pointer),
351+
count: capacity
352+
)
353+
return try unsafe .success(body(buffer))
354+
} catch {
355+
return .failure(error)
356+
}
354357
}
358+
359+
return try result.get()
355360
}
356361

357362
/// Provides scoped access to a buffer pointer to memory of the specified type
@@ -361,22 +366,29 @@ public func withUnsafeTemporaryAllocation<
361366
/// doesn't trigger stack protection for the stack allocated memory.
362367
@_alwaysEmitIntoClient @_transparent
363368
public func _withUnprotectedUnsafeTemporaryAllocation<
364-
T: ~Copyable, R: ~Copyable
369+
T: ~Copyable, R: ~Copyable,
370+
E: Error
365371
>(
366372
of type: T.Type,
367373
capacity: Int,
368-
_ body: (UnsafeMutableBufferPointer<T>) throws -> R
369-
) rethrows -> R {
370-
return try _withUnprotectedUnsafeTemporaryAllocation(
374+
_ body: (UnsafeMutableBufferPointer<T>) throws(E) -> R
375+
) throws(E) -> R {
376+
let result: Result<R, E> = _withUnprotectedUnsafeTemporaryAllocation(
371377
of: type,
372378
capacity: capacity,
373379
alignment: MemoryLayout<T>.alignment
374380
) { pointer in
375-
Builtin.bindMemory(pointer, capacity._builtinWordValue, type)
376-
let buffer = unsafe UnsafeMutableBufferPointer<T>(
377-
start: .init(pointer),
378-
count: capacity
379-
)
380-
return try unsafe body(buffer)
381+
do throws(E) {
382+
Builtin.bindMemory(pointer, capacity._builtinWordValue, type)
383+
let buffer = unsafe UnsafeMutableBufferPointer<T>(
384+
start: .init(pointer),
385+
count: capacity
386+
)
387+
return try unsafe .success(body(buffer))
388+
} catch {
389+
return .failure(error)
390+
}
381391
}
392+
393+
return try result.get()
382394
}

test/IRGen/temporary_allocation/codegen.swift

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
// RUN: %target-swift-frontend -primary-file %s -O -emit-ir | %FileCheck %s
2-
// REQUIRES: swift_stdlib_no_asserts,optimized_stdlib
2+
// REQUIRES: optimized_stdlib
33

44
@_silgen_name("blackHole")
55
func blackHole(_ value: UnsafeMutableRawPointer?) -> Void
@@ -16,10 +16,10 @@ do {
1616
// CHECK: [[ONE_BYTE_PTR_RAW:%temp_alloc[0-9]*]] = alloca i8, align 1
1717
// CHECK: [[FIVE_BYTE_PTR_RAW:%temp_alloc[0-9]*]] = alloca [5 x i8], align 1
1818
// CHECK: [[ONE_KB_PTR_RAW:%temp_alloc[0-9]*]] = alloca [1024 x i8], align 8
19-
// CHECK: [[ONE_KB_RAND_PTR_RAW:%temp_alloc[0-9]*]] = alloca [1024 x i8], align 16
2019
// CHECK: [[INT_PTR_RAW:%temp_alloc[0-9]*]] = alloca [16 x i8], align 4
2120
// CHECK: [[INT_PTR_RAW2:%temp_alloc[0-9]*]] = alloca [16 x i8], align 4
2221
// CHECK: [[VOID_PTR_RAW:%temp_alloc[0-9]*]] = alloca [2 x i8], align 1
22+
// CHECK: [[ONE_KB_RAND_PTR_RAW:%temp_alloc[0-9]*]] = alloca [1024 x i8], align 16
2323

2424
// CHECK: ptrtoint ptr {{.*}} to [[WORD:i[0-9]+]]
2525

@@ -49,14 +49,6 @@ withUnsafeTemporaryAllocation(byteCount: 1024, alignment: 8) { buffer in
4949
// CHECK: [[ONE_KB_PTR:%[0-9]+]] = ptrtoint ptr [[ONE_KB_PTR_RAW]] to [[WORD]]
5050
// CHECK: call swiftcc void @blackHole([[WORD]] [[ONE_KB_PTR]])
5151

52-
// MARK: Alignment unknown at compile-time
53-
54-
withUnsafeTemporaryAllocation(byteCount: 1024, alignment: Int.random(in: 0 ..< 16)) { buffer in
55-
blackHole(buffer.baseAddress)
56-
}
57-
// CHECK: [[ONE_KB_RAND_PTR:%[0-9]+]] = ptrtoint ptr [[ONE_KB_RAND_PTR_RAW]] to [[WORD]]
58-
// CHECK: call swiftcc void @blackHole([[WORD]] [[ONE_KB_RAND_PTR]])
59-
6052
// MARK: Typed buffers
6153

6254
withUnsafeTemporaryAllocation(of: Int32.self, capacity: 4) { buffer in
@@ -77,3 +69,10 @@ withUnsafeTemporaryAllocation(of: Void.self, capacity: 2) { buffer in
7769
// CHECK: [[VOID_PTR:%[0-9]+]] = ptrtoint ptr [[VOID_PTR_RAW]] to [[WORD]]
7870
// CHECK: call swiftcc void @blackHole([[WORD]] [[VOID_PTR]])
7971

72+
// MARK: Alignment unknown at compile-time
73+
74+
withUnsafeTemporaryAllocation(byteCount: 1024, alignment: Int.random(in: 0 ..< 16)) { buffer in
75+
blackHole(buffer.baseAddress)
76+
}
77+
// CHECK: [[ONE_KB_RAND_PTR:%[0-9]+]] = ptrtoint ptr [[ONE_KB_RAND_PTR_RAW]] to [[WORD]]
78+
// CHECK: call swiftcc void @blackHole([[WORD]] [[ONE_KB_RAND_PTR]])

test/stdlib/TemporaryAllocation.swift

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,4 +155,21 @@ TemporaryAllocationTestSuite.test("typedAllocationIsAligned") {
155155
}
156156
}
157157

158+
// MARK: Typed throws
159+
enum HomeworkError: Error, Equatable {
160+
case dogAteIt
161+
case forgot
162+
}
163+
164+
TemporaryAllocationTestSuite.test("typedAllocationWithThrow") {
165+
do throws(HomeworkError) {
166+
try withUnsafeTemporaryAllocation(of: Int.self, capacity: 1) { (buffer) throws(HomeworkError) -> Void in
167+
throw HomeworkError.forgot
168+
}
169+
fatalError("did not throw!?!")
170+
} catch {
171+
expectEqual(error, .forgot)
172+
}
173+
}
174+
158175
runAllTests()

0 commit comments

Comments
 (0)