Skip to content

Commit 62b898e

Browse files
committed
SourceGen: Handle init() of value types with indirect return
1 parent a7787f8 commit 62b898e

File tree

2 files changed

+153
-31
lines changed

2 files changed

+153
-31
lines changed

Sources/JExtractSwift/Swift2JavaTranslator+Printing.swift

Lines changed: 82 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,8 @@ extension Swift2JavaTranslator {
5353
if let outputFile = try printer.writeContents(
5454
outputDirectory: outputDirectory,
5555
javaPackagePath: javaPackagePath,
56-
filename: filename) {
56+
filename: filename)
57+
{
5758
print("[swift-java] Generated: \(self.swiftModuleName).java (at \(outputFile)")
5859
}
5960
}
@@ -76,7 +77,8 @@ extension Swift2JavaTranslator {
7677
if let outputFile = try printer.writeContents(
7778
outputDirectory: outputDirectory,
7879
javaPackagePath: nil,
79-
filename: moduleFilename) {
80+
filename: moduleFilename)
81+
{
8082
print("[swift-java] Generated: \(moduleFilenameBase.bold).swift (at \(outputFile)")
8183
}
8284
} catch {
@@ -95,7 +97,8 @@ extension Swift2JavaTranslator {
9597
if let outputFile = try printer.writeContents(
9698
outputDirectory: outputDirectory,
9799
javaPackagePath: nil,
98-
filename: filename) {
100+
filename: filename)
101+
{
99102
print("[swift-java] Generated: \(fileNameBase.bold).swift (at \(outputFile)")
100103
}
101104
} catch {
@@ -133,12 +136,12 @@ extension Swift2JavaTranslator {
133136
let stt = SwiftThunkTranslator(self)
134137

135138
printer.print(
136-
"""
137-
// Generated by swift-java
139+
"""
140+
// Generated by swift-java
138141
139-
import SwiftKitSwift
142+
import SwiftKitSwift
140143
141-
"""
144+
"""
142145
)
143146

144147
for thunk in stt.renderThunks(forType: ty) {
@@ -291,6 +294,7 @@ extension Swift2JavaTranslator {
291294
printer in
292295
// ==== Storage of the class
293296
printClassSelfProperty(&printer, decl)
297+
printStatusFlagsField(&printer, decl)
294298

295299
// Constants
296300
printClassConstants(printer: &printer)
@@ -412,6 +416,21 @@ extension Swift2JavaTranslator {
412416
)
413417
}
414418

419+
private func printStatusFlagsField(_ printer: inout CodePrinter, _ decl: ImportedNominalType) {
420+
printer.print(
421+
"""
422+
// TODO: make this a flagset integer and/or use a field updater
423+
/** Used to track additional state of the underlying object, e.g. if it was explicitly destroyed. */
424+
private final AtomicBoolean $state$destroyed = new AtomicBoolean(false);
425+
426+
@Override
427+
public final AtomicBoolean $statusDestroyedFlag() {
428+
return this.$state$destroyed;
429+
}
430+
"""
431+
)
432+
}
433+
415434
private func printClassMemoryLayout(_ printer: inout CodePrinter, _ decl: ImportedNominalType) {
416435
printer.print(
417436
"""
@@ -476,10 +495,10 @@ extension Swift2JavaTranslator {
476495
printMethodDowncallHandleForAddrDesc(&printer)
477496
}
478497

479-
printClassInitializerConstructors(&printer, decl, parentName: parentName)
498+
printNominalInitializerConstructors(&printer, decl, parentName: parentName)
480499
}
481500

482-
public func printClassInitializerConstructors(
501+
public func printNominalInitializerConstructors(
483502
_ printer: inout CodePrinter,
484503
_ decl: ImportedFunc,
485504
parentName: TranslatedType
@@ -499,6 +518,25 @@ extension Swift2JavaTranslator {
499518
"""
500519
)
501520

521+
let initializeMemorySegment =
522+
if let parent = decl.parent,
523+
parent.isReferenceType
524+
{
525+
"""
526+
this.selfMemorySegment = (MemorySegment) mh$.invokeExact(
527+
\(renderForwardJavaParams(decl, paramPassingStyle: nil))
528+
);
529+
"""
530+
} else {
531+
"""
532+
this.selfMemorySegment = arena.allocate($layout());
533+
mh$.invokeExact(
534+
\(renderForwardJavaParams(decl, paramPassingStyle: nil)),
535+
/* indirect return buffer */this.selfMemorySegment
536+
);
537+
"""
538+
}
539+
502540
printer.print(
503541
"""
504542
/**
@@ -514,7 +552,8 @@ extension Swift2JavaTranslator {
514552
SwiftKit.traceDowncall(\(renderForwardJavaParams(decl, paramPassingStyle: nil)));
515553
}
516554
517-
this.selfMemorySegment = (MemorySegment) mh$.invokeExact(\(renderForwardJavaParams(decl, paramPassingStyle: nil)), TYPE_METADATA.$memorySegment());
555+
\(initializeMemorySegment)
556+
518557
if (arena != null) {
519558
arena.register(this);
520559
}
@@ -666,9 +705,9 @@ extension Swift2JavaTranslator {
666705
_ printer: inout CodePrinter, _ decl: ImportedFunc,
667706
accessorKind: VariableAccessorKind? = nil
668707
) {
669-
// var thunkName = SwiftKitPrinting.Names.functionThunk(
670-
// thunkNameRegistry: &self.thunkNameRegistry,
671-
// module: self.swiftModuleName, function: decl)
708+
// var thunkName = SwiftKitPrinting.Names.functionThunk(
709+
// thunkNameRegistry: &self.thunkNameRegistry,
710+
// module: self.swiftModuleName, function: decl)
672711
let thunkName = thunkNameRegistry.functionThunkName(module: self.swiftModuleName, decl: decl)
673712
printer.print(
674713
"""
@@ -850,7 +889,9 @@ extension Swift2JavaTranslator {
850889
}
851890
}
852891

853-
public func renderJavaParamDecls(_ decl: ImportedFunc, paramPassingStyle: SelfParameterVariant?) -> String {
892+
public func renderJavaParamDecls(_ decl: ImportedFunc, paramPassingStyle: SelfParameterVariant?)
893+
-> String
894+
{
854895
var ps: [String] = []
855896
var pCounter = 0
856897

@@ -872,7 +913,8 @@ extension Swift2JavaTranslator {
872913
public func renderSwiftParamDecls(
873914
_ decl: ImportedFunc,
874915
paramPassingStyle: SelfParameterVariant?,
875-
style: ParameterVariant? = nil) -> String {
916+
style: ParameterVariant? = nil
917+
) -> String {
876918
var ps: [String] = []
877919
var pCounter = 0
878920

@@ -887,7 +929,7 @@ extension Swift2JavaTranslator {
887929

888930
let paramTy: String =
889931
if style == .cDeclThunk, p.type.javaType.isString {
890-
"UnsafeMutablePointer<CChar>" // TODO: is this ok?
932+
"UnsafeMutablePointer<CChar>" // TODO: is this ok?
891933
} else if paramPassingStyle == .swiftThunkSelf {
892934
"\(p.type.cCompatibleSwiftType)"
893935
} else {
@@ -906,7 +948,7 @@ extension Swift2JavaTranslator {
906948

907949
if paramPassingStyle == .swiftThunkSelf {
908950
ps.append("_self: UnsafeMutableRawPointer")
909-
// ps.append("_self: Any")
951+
// ps.append("_self: Any")
910952
}
911953

912954
let res = ps.joined(separator: ", ")
@@ -942,7 +984,9 @@ extension Swift2JavaTranslator {
942984
return printer.contents
943985
}
944986

945-
public func renderForwardJavaParams(_ decl: ImportedFunc, paramPassingStyle: SelfParameterVariant?) -> String {
987+
public func renderForwardJavaParams(
988+
_ decl: ImportedFunc, paramPassingStyle: SelfParameterVariant?
989+
) -> String {
946990
var ps: [String] = []
947991
var pCounter = 0
948992

@@ -980,20 +1024,16 @@ extension Swift2JavaTranslator {
9801024
}
9811025

9821026
// TODO: these are stateless, find new place for them?
983-
public func renderForwardSwiftParams(_ decl: ImportedFunc, paramPassingStyle: SelfParameterVariant?) -> String {
1027+
public func renderForwardSwiftParams(
1028+
_ decl: ImportedFunc, paramPassingStyle: SelfParameterVariant?
1029+
) -> String {
9841030
var ps: [String] = []
985-
var pCounter = 0
986-
987-
func nextUniqueParamName() -> String {
988-
pCounter += 1
989-
return "p\(pCounter)"
990-
}
9911031

9921032
for p in decl.effectiveParameters(paramPassingStyle: paramPassingStyle) {
9931033
if let firstName = p.firstName {
994-
ps.append("\(firstName): \(p.effectiveName ?? nextUniqueParamName())")
1034+
ps.append("\(firstName): \(p.effectiveValueName)")
9951035
} else {
996-
ps.append("\(p.effectiveName ?? nextUniqueParamName())")
1036+
ps.append("\(p.effectiveValueName)")
9971037
}
9981038
}
9991039

@@ -1008,12 +1048,20 @@ extension Swift2JavaTranslator {
10081048
let fieldName = accessorKind.renderDescFieldName
10091049
printer.start("public static final FunctionDescriptor \(fieldName) = ")
10101050

1011-
let parameterLayoutDescriptors = javaMemoryLayoutDescriptors(
1051+
let isIndirectReturn =
1052+
decl.returnType.isValueType || (decl.isInit && (decl.parent?.isValueType ?? false))
1053+
1054+
var parameterLayoutDescriptors: [ForeignValueLayout] = javaMemoryLayoutDescriptors(
10121055
forParametersOf: decl,
10131056
paramPassingStyle: .pointer
10141057
)
10151058

1016-
if decl.returnType.javaType == .void {
1059+
// Write indirect return buffer parameter after formal
1060+
// if isIndirectReturn || decl.isInit {
1061+
// parameterLayoutDescriptors.append(.SwiftPointer)
1062+
// }
1063+
1064+
if decl.returnType.javaType == .void || isIndirectReturn {
10171065
printer.print("FunctionDescriptor.ofVoid(")
10181066
printer.indent()
10191067
} else {
@@ -1040,6 +1088,11 @@ extension Swift2JavaTranslator {
10401088
printer.print(desc, .parameterNewlineSeparator(isLast))
10411089
}
10421090

1091+
// // Write indirect return buffer parameter after formal
1092+
// if isIndirectReturn {
1093+
// printer.print(", /* indirect return buffer */SWIFT_POINTER")
1094+
// }
1095+
10431096
printer.outdent()
10441097
printer.print(");")
10451098
}

Tests/JExtractSwiftTests/MethodImportTests.swift

Lines changed: 71 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,10 @@ final class MethodImportTests {
5353
5454
@objc deinit
5555
}
56+
57+
public struct MySwiftStruct {
58+
public init(len: Swift.Int, cap: Swift.Int) {}
59+
}
5660
"""
5761

5862
@Test("Import: public func helloWorld()")
@@ -397,7 +401,7 @@ final class MethodImportTests {
397401
}!
398402

399403
let output = CodePrinter.toString { printer in
400-
st.printClassInitializerConstructors(&printer, initDecl, parentName: initDecl.parent!)
404+
st.printNominalInitializerConstructors(&printer, initDecl, parentName: initDecl.parent!)
401405
}
402406

403407
assertOutput(
@@ -428,7 +432,72 @@ final class MethodImportTests {
428432
if (SwiftKit.TRACE_DOWNCALLS) {
429433
SwiftKit.traceDowncall(len, cap);
430434
}
431-
this.selfMemorySegment = (MemorySegment) mh$.invokeExact(len, cap, TYPE_METADATA.$memorySegment());
435+
this.selfMemorySegment = (MemorySegment) mh$.invokeExact(
436+
len, cap
437+
);
438+
if (arena != null) {
439+
arena.register(this);
440+
}
441+
} catch (Throwable ex$) {
442+
throw new AssertionError("should not reach here", ex$);
443+
}
444+
}
445+
"""
446+
)
447+
}
448+
449+
@Test
450+
func struct_constructor() throws {
451+
let st = Swift2JavaTranslator(
452+
javaPackage: "com.example.swift",
453+
swiftModuleName: "__FakeModule"
454+
)
455+
st.log.logLevel = .info
456+
457+
try st.analyze(file: "Fake.swift", text: class_interfaceFile)
458+
459+
let initDecl: ImportedFunc = st.importedTypes["MySwiftStruct"]!.initializers.first {
460+
$0.identifier == "init(len:cap:)"
461+
}!
462+
463+
let output = CodePrinter.toString { printer in
464+
st.printNominalInitializerConstructors(&printer, initDecl, parentName: initDecl.parent!)
465+
}
466+
467+
assertOutput(
468+
output,
469+
expected:
470+
"""
471+
/**
472+
* Create an instance of {@code MySwiftStruct}.
473+
*
474+
* {@snippet lang=swift :
475+
* public init(len: Swift.Int, cap: Swift.Int) {}
476+
* }
477+
*/
478+
public MySwiftStruct(long len, long cap) {
479+
this(/*arena=*/null, len, cap);
480+
}
481+
/**
482+
* Create an instance of {@code MySwiftStruct}.
483+
* This instance is managed by the passed in {@link SwiftArena} and may not outlive the arena's lifetime.
484+
*
485+
* {@snippet lang=swift :
486+
* public init(len: Swift.Int, cap: Swift.Int) {}
487+
* }
488+
*/
489+
490+
public MySwiftStruct(SwiftArena arena, long len, long cap) {
491+
var mh$ = init_len_cap.HANDLE;
492+
try {
493+
if (SwiftKit.TRACE_DOWNCALLS) {
494+
SwiftKit.traceDowncall(len, cap);
495+
}
496+
this.selfMemorySegment = arena.allocate($layout());
497+
mh$.invokeExact(
498+
len, cap,
499+
/* indirect return buffer */this.selfMemorySegment
500+
);
432501
if (arena != null) {
433502
arena.register(this);
434503
}

0 commit comments

Comments
 (0)