Skip to content

Commit 1873da5

Browse files
committed
Factor out the lowering step as a more general "ConversionStep"
1 parent aff35dd commit 1873da5

File tree

2 files changed

+121
-105
lines changed

2 files changed

+121
-105
lines changed
Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2025 Apple Inc. and the Swift.org project authors
6+
// Licensed under Apache License v2.0
7+
//
8+
// See LICENSE.txt for license information
9+
// See CONTRIBUTORS.txt for the list of Swift.org project authors
10+
//
11+
// SPDX-License-Identifier: Apache-2.0
12+
//
13+
//===----------------------------------------------------------------------===//
14+
15+
import SwiftSyntax
16+
17+
/// Describes the transformation needed to take the parameters of a thunk
18+
/// and map them to the corresponding parameter (or result value) of the
19+
/// original function.
20+
enum ConversionStep: Equatable {
21+
/// The value being lowered.
22+
case placeholder
23+
24+
/// A reference to a component in a value that has been exploded, such as
25+
/// a tuple element or part of a buffer pointer.
26+
indirect case explodedComponent(ConversionStep, component: String)
27+
28+
/// Cast the pointer described by the lowering step to the given
29+
/// Swift type using `unsafeBitCast(_:to:)`.
30+
indirect case unsafeCastPointer(ConversionStep, swiftType: SwiftType)
31+
32+
/// Assume at the untyped pointer described by the lowering step to the
33+
/// given type, using `assumingMemoryBound(to:).`
34+
indirect case typedPointer(ConversionStep, swiftType: SwiftType)
35+
36+
/// The thing to which the pointer typed, which is the `pointee` property
37+
/// of the `Unsafe(Mutable)Pointer` types in Swift.
38+
indirect case pointee(ConversionStep)
39+
40+
/// Pass this value indirectly, via & for explicit `inout` parameters.
41+
indirect case passIndirectly(ConversionStep)
42+
43+
/// Initialize a value of the given Swift type with the set of labeled
44+
/// arguments.
45+
case initialize(SwiftType, arguments: [LabeledArgument<ConversionStep>])
46+
47+
/// Produce a tuple with the given elements.
48+
///
49+
/// This is used for exploding Swift tuple arguments into multiple
50+
/// elements, recursively. Note that this always produces unlabeled
51+
/// tuples, which Swift will convert to the labeled tuple form.
52+
case tuplify([ConversionStep])
53+
54+
/// Convert the conversion step into an expression with the given
55+
/// value as the placeholder value in the expression.
56+
func asExprSyntax(isSelf: Bool, placeholder: String) -> ExprSyntax {
57+
switch self {
58+
case .placeholder:
59+
return "\(raw: placeholder)"
60+
61+
case .explodedComponent(let step, component: let component):
62+
return step.asExprSyntax(isSelf: false, placeholder: "\(placeholder)_\(component)")
63+
64+
case .unsafeCastPointer(let step, swiftType: let swiftType):
65+
let untypedExpr = step.asExprSyntax(isSelf: false, placeholder: placeholder)
66+
return "unsafeBitCast(\(untypedExpr), to: \(swiftType.metatypeReferenceExprSyntax))"
67+
68+
case .typedPointer(let step, swiftType: let type):
69+
let untypedExpr = step.asExprSyntax(isSelf: isSelf, placeholder: placeholder)
70+
return "\(untypedExpr).assumingMemoryBound(to: \(type.metatypeReferenceExprSyntax))"
71+
72+
case .pointee(let step):
73+
let untypedExpr = step.asExprSyntax(isSelf: isSelf, placeholder: placeholder)
74+
return "\(untypedExpr).pointee"
75+
76+
case .passIndirectly(let step):
77+
let innerExpr = step.asExprSyntax(isSelf: false, placeholder: placeholder)
78+
return isSelf ? innerExpr : "&\(innerExpr)"
79+
80+
case .initialize(let type, arguments: let arguments):
81+
let renderedArguments: [String] = arguments.map { labeledArgument in
82+
let renderedArg = labeledArgument.argument.asExprSyntax(isSelf: false, placeholder: placeholder)
83+
if let argmentLabel = labeledArgument.label {
84+
return "\(argmentLabel): \(renderedArg.description)"
85+
} else {
86+
return renderedArg.description
87+
}
88+
}
89+
90+
// FIXME: Should be able to use structured initializers here instead
91+
// of splatting out text.
92+
let renderedArgumentList = renderedArguments.joined(separator: ", ")
93+
return "\(raw: type.description)(\(raw: renderedArgumentList))"
94+
95+
case .tuplify(let elements):
96+
let renderedElements: [String] = elements.enumerated().map { (index, element) in
97+
element.asExprSyntax(isSelf: false, placeholder: "\(placeholder)_\(index)").description
98+
}
99+
100+
// FIXME: Should be able to use structured initializers here instead
101+
// of splatting out text.
102+
let renderedElementList = renderedElements.joined(separator: ", ")
103+
return "(\(raw: renderedElementList))"
104+
}
105+
}
106+
}

Sources/JExtractSwift/Swift2JavaTranslator+FunctionLowering.swift

Lines changed: 15 additions & 105 deletions
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,7 @@ extension Swift2JavaTranslator {
138138
case .metatype(let instanceType):
139139
return LoweredParameters(
140140
cdeclToOriginal: .unsafeCastPointer(
141-
.value,
141+
.placeholder,
142142
swiftType: instanceType
143143
),
144144
cdeclParameters: [
@@ -170,14 +170,14 @@ extension Swift2JavaTranslator {
170170
}
171171

172172
let mutable = (convention == .inout)
173-
let loweringStep: LoweringStep
173+
let loweringStep: ConversionStep
174174
switch nominal.nominalTypeDecl.kind {
175175
case .actor, .class:
176176
loweringStep =
177-
.unsafeCastPointer(.value, swiftType: type)
177+
.unsafeCastPointer(.placeholder, swiftType: type)
178178
case .enum, .struct, .protocol:
179179
loweringStep =
180-
.passIndirectly(.pointee(.typedPointer(.value, swiftType: type)))
180+
.passIndirectly(.pointee(.typedPointer(.placeholder, swiftType: type)))
181181
}
182182

183183
return LoweredParameters(
@@ -228,7 +228,7 @@ extension Swift2JavaTranslator {
228228
}
229229

230230
return LoweredParameters(
231-
cdeclToOriginal: .value,
231+
cdeclToOriginal: .placeholder,
232232
cdeclParameters: [
233233
SwiftParameter(
234234
convention: convention,
@@ -249,7 +249,7 @@ extension Swift2JavaTranslator {
249249
}
250250

251251
return LoweredParameters(
252-
cdeclToOriginal: .value,
252+
cdeclToOriginal: .placeholder,
253253
cdeclParameters: [
254254
SwiftParameter(
255255
convention: convention,
@@ -280,21 +280,21 @@ extension Swift2JavaTranslator {
280280
let cdeclPointerType = mutable
281281
? swiftStdlibTypes[.unsafeMutableRawPointer]
282282
: swiftStdlibTypes[.unsafeRawPointer]
283-
var cdeclToOriginal: LoweringStep
283+
var cdeclToOriginal: ConversionStep
284284
switch (requiresArgument, hasCount) {
285285
case (false, false):
286-
cdeclToOriginal = .value
286+
cdeclToOriginal = .placeholder
287287

288288
case (true, false):
289289
cdeclToOriginal = .typedPointer(
290-
.explodedComponent(.value, component: "pointer"),
290+
.explodedComponent(.placeholder, component: "pointer"),
291291
swiftType: nominal.genericArguments![0]
292292
)
293293

294294
case (false, true):
295295
cdeclToOriginal = .initialize(type, arguments: [
296-
LabeledArgument(label: "start", argument: .explodedComponent(.value, component: "pointer")),
297-
LabeledArgument(label: "count", argument: .explodedComponent(.value, component: "count"))
296+
LabeledArgument(label: "start", argument: .explodedComponent(.placeholder, component: "pointer")),
297+
LabeledArgument(label: "count", argument: .explodedComponent(.placeholder, component: "count"))
298298
])
299299

300300
case (true, true):
@@ -304,12 +304,12 @@ extension Swift2JavaTranslator {
304304
LabeledArgument(
305305
label: "start",
306306
argument: .typedPointer(
307-
.explodedComponent(.value, component: "pointer"),
307+
.explodedComponent(.placeholder, component: "pointer"),
308308
swiftType: nominal.genericArguments![0])
309309
),
310310
LabeledArgument(
311311
label: "count",
312-
argument: .explodedComponent(.value, component: "count")
312+
argument: .explodedComponent(.placeholder, component: "count")
313313
)
314314
]
315315
)
@@ -395,48 +395,11 @@ struct LabeledArgument<Element> {
395395

396396
extension LabeledArgument: Equatable where Element: Equatable { }
397397

398-
/// Describes the transformation needed to take the parameters of a thunk
399-
/// and map them to the corresponding parameter (or result value) of the
400-
/// original function.
401-
enum LoweringStep: Equatable {
402-
/// The value being lowered.
403-
case value
404-
405-
/// A reference to a component in a value that has been exploded, such as
406-
/// a tuple element or part of a buffer pointer.
407-
indirect case explodedComponent(LoweringStep, component: String)
408-
409-
/// Cast the pointer described by the lowering step to the given
410-
/// Swift type using `unsafeBitCast(_:to:)`.
411-
indirect case unsafeCastPointer(LoweringStep, swiftType: SwiftType)
412-
413-
/// Assume at the untyped pointer described by the lowering step to the
414-
/// given type, using `assumingMemoryBound(to:).`
415-
indirect case typedPointer(LoweringStep, swiftType: SwiftType)
416-
417-
/// The thing to which the pointer typed, which is the `pointee` property
418-
/// of the `Unsafe(Mutable)Pointer` types in Swift.
419-
indirect case pointee(LoweringStep)
420-
421-
/// Pass this value indirectly, via & for explicit `inout` parameters.
422-
indirect case passIndirectly(LoweringStep)
423-
424-
/// Initialize a value of the given Swift type with the set of labeled
425-
/// arguments.
426-
case initialize(SwiftType, arguments: [LabeledArgument<LoweringStep>])
427-
428-
/// Produce a tuple with the given elements.
429-
///
430-
/// This is used for exploding Swift tuple arguments into multiple
431-
/// elements, recursively. Note that this always produces unlabeled
432-
/// tuples, which Swift will convert to the labeled tuple form.
433-
case tuplify([LoweringStep])
434-
}
435398

436399
struct LoweredParameters: Equatable {
437400
/// The steps needed to get from the @_cdecl parameters to the original function
438401
/// parameter.
439-
var cdeclToOriginal: LoweringStep
402+
var cdeclToOriginal: ConversionStep
440403

441404
/// The lowering of the parameters at the C level in Swift.
442405
var cdeclParameters: [SwiftParameter]
@@ -446,60 +409,7 @@ extension LoweredParameters {
446409
/// Produce an expression that computes the argument for this parameter
447410
/// when calling the original function from the cdecl entrypoint.
448411
func cdeclToOriginalArgumentExpr(isSelf: Bool, value: String)-> ExprSyntax {
449-
cdeclToOriginal.asExprSyntax(isSelf: isSelf, value: value)
450-
}
451-
}
452-
453-
extension LoweringStep {
454-
func asExprSyntax(isSelf: Bool, value: String) -> ExprSyntax {
455-
switch self {
456-
case .value:
457-
return "\(raw: value)"
458-
459-
case .explodedComponent(let step, component: let component):
460-
return step.asExprSyntax(isSelf: false, value: "\(value)_\(component)")
461-
462-
case .unsafeCastPointer(let step, swiftType: let swiftType):
463-
let untypedExpr = step.asExprSyntax(isSelf: false, value: value)
464-
return "unsafeBitCast(\(untypedExpr), to: \(swiftType.metatypeReferenceExprSyntax))"
465-
466-
case .typedPointer(let step, swiftType: let type):
467-
let untypedExpr = step.asExprSyntax(isSelf: isSelf, value: value)
468-
return "\(untypedExpr).assumingMemoryBound(to: \(type.metatypeReferenceExprSyntax))"
469-
470-
case .pointee(let step):
471-
let untypedExpr = step.asExprSyntax(isSelf: isSelf, value: value)
472-
return "\(untypedExpr).pointee"
473-
474-
case .passIndirectly(let step):
475-
let innerExpr = step.asExprSyntax(isSelf: false, value: value)
476-
return isSelf ? innerExpr : "&\(innerExpr)"
477-
478-
case .initialize(let type, arguments: let arguments):
479-
let renderedArguments: [String] = arguments.map { labeledArgument in
480-
let renderedArg = labeledArgument.argument.asExprSyntax(isSelf: false, value: value)
481-
if let argmentLabel = labeledArgument.label {
482-
return "\(argmentLabel): \(renderedArg.description)"
483-
} else {
484-
return renderedArg.description
485-
}
486-
}
487-
488-
// FIXME: Should be able to use structured initializers here instead
489-
// of splatting out text.
490-
let renderedArgumentList = renderedArguments.joined(separator: ", ")
491-
return "\(raw: type.description)(\(raw: renderedArgumentList))"
492-
493-
case .tuplify(let elements):
494-
let renderedElements: [String] = elements.enumerated().map { (index, element) in
495-
element.asExprSyntax(isSelf: false, value: "\(value)_\(index)").description
496-
}
497-
498-
// FIXME: Should be able to use structured initializers here instead
499-
// of splatting out text.
500-
let renderedElementList = renderedElements.joined(separator: ", ")
501-
return "(\(raw: renderedElementList))"
502-
}
412+
cdeclToOriginal.asExprSyntax(isSelf: isSelf, placeholder: value)
503413
}
504414
}
505415

0 commit comments

Comments
 (0)