|
2 | 2 | // |
3 | 3 | // This source file is part of the Swift.org open source project |
4 | 4 | // |
5 | | -// Copyright (c) 2024 Apple Inc. and the Swift.org project authors |
| 5 | +// Copyright (c) 2024-2025 Apple Inc. and the Swift.org project authors |
6 | 6 | // Licensed under Apache License v2.0 |
7 | 7 | // |
8 | 8 | // See LICENSE.txt for license information |
|
13 | 13 | //===----------------------------------------------------------------------===// |
14 | 14 |
|
15 | 15 | import JavaTypes |
16 | | -import SwiftSyntax |
17 | | -import SwiftSyntaxBuilder |
18 | | - |
19 | | -// ==== --------------------------------------------------------------------------------------------------------------- |
20 | | -// MARK: File writing |
21 | | - |
22 | | -let PATH_SEPARATOR = "/" // TODO: Windows |
23 | | - |
24 | | -extension Swift2JavaTranslator { |
25 | | - |
26 | | - /// Every imported public type becomes a public class in its own file in Java. |
27 | | - public func writeJavaBindingsSources(outputDirectory: String) throws { |
28 | | - var printer = CodePrinter() |
29 | | - try writeJavaBindingsSources(outputDirectory: outputDirectory, printer: &printer) |
30 | | - } |
31 | | - |
32 | | - public func writeJavaBindingsSources(outputDirectory: String, printer: inout CodePrinter) throws { |
33 | | - for (_, ty) in importedTypes.sorted(by: { (lhs, rhs) in lhs.key < rhs.key }) { |
34 | | - let filename = "\(ty.swiftNominal.name).java" |
35 | | - log.info("Printing contents: \(filename)") |
36 | | - printImportedNominal(&printer, ty) |
37 | | - |
38 | | - if let outputFile = try printer.writeContents( |
39 | | - outputDirectory: outputDirectory, |
40 | | - javaPackagePath: javaPackagePath, |
41 | | - filename: filename |
42 | | - ) { |
43 | | - print("[swift-java] Generated: \(ty.swiftNominal.name.bold).java (at \(outputFile))") |
44 | | - } |
45 | | - } |
46 | | - |
47 | | - do { |
48 | | - let filename = "\(self.swiftModuleName).java" |
49 | | - log.info("Printing contents: \(filename)") |
50 | | - printModule(&printer) |
51 | | - |
52 | | - if let outputFile = try printer.writeContents( |
53 | | - outputDirectory: outputDirectory, |
54 | | - javaPackagePath: javaPackagePath, |
55 | | - filename: filename) |
56 | | - { |
57 | | - print("[swift-java] Generated: \(self.swiftModuleName).java (at \(outputFile))") |
58 | | - } |
59 | | - } |
60 | | - } |
61 | | -} |
62 | | - |
63 | | -// ==== --------------------------------------------------------------------------------------------------------------- |
64 | | -// MARK: Java/text printing |
65 | 16 |
|
66 | 17 | extension Swift2JavaTranslator { |
67 | | - |
68 | | - /// Render the Java file contents for an imported Swift module. |
69 | | - /// |
70 | | - /// This includes any Swift global functions in that module, and some general type information and helpers. |
71 | | - public func printModule(_ printer: inout CodePrinter) { |
72 | | - printHeader(&printer) |
73 | | - printPackage(&printer) |
74 | | - printImports(&printer) |
75 | | - |
76 | | - printModuleClass(&printer) { printer in |
77 | | - // TODO: print all "static" methods |
78 | | - for decl in importedGlobalFuncs { |
79 | | - self.log.trace("Print imported decl: \(decl)") |
80 | | - printFunctionDowncallMethods(&printer, decl) |
81 | | - } |
82 | | - } |
83 | | - } |
84 | | - |
85 | | - package func printImportedNominal(_ printer: inout CodePrinter, _ decl: ImportedNominalType) { |
86 | | - printHeader(&printer) |
87 | | - printPackage(&printer) |
88 | | - printImports(&printer) |
89 | | - |
90 | | - printNominal(&printer, decl) { printer in |
91 | | - // Prepare type metadata, we're going to need these when invoking e.g. initializers so cache them in a static. |
92 | | - // We call into source swift-java source generated accessors which give us the type of the Swift object: |
93 | | - // TODO: seems we no longer need the mangled name per se, so avoiding such constant and downcall |
94 | | - // printer.printParts( |
95 | | - // "public static final String TYPE_MANGLED_NAME = ", |
96 | | - // SwiftKitPrinting.renderCallGetSwiftTypeMangledName(module: self.swiftModuleName, nominal: decl), |
97 | | - // ";" |
98 | | - // ) |
99 | | - |
100 | | - // We use a static field to abuse the initialization order such that by the time we get type metadata, |
101 | | - // we already have loaded the library where it will be obtained from. |
102 | | - printer.printParts( |
103 | | - """ |
104 | | - @SuppressWarnings("unused") |
105 | | - private static final boolean INITIALIZED_LIBS = initializeLibs(); |
106 | | - static boolean initializeLibs() { |
107 | | - System.loadLibrary(SwiftKit.STDLIB_DYLIB_NAME); |
108 | | - System.loadLibrary("SwiftKitSwift"); |
109 | | - System.loadLibrary(LIB_NAME); |
110 | | - return true; |
111 | | - } |
112 | | -
|
113 | | - public static final SwiftAnyType TYPE_METADATA = |
114 | | - new SwiftAnyType(\(SwiftKitPrinting.renderCallGetSwiftType(module: self.swiftModuleName, nominal: decl))); |
115 | | - public final SwiftAnyType $swiftType() { |
116 | | - return TYPE_METADATA; |
117 | | - } |
118 | | - """ |
119 | | - ) |
120 | | - printer.println() |
121 | | - |
122 | | - // Layout of the class |
123 | | - printClassMemoryLayout(&printer, decl) |
124 | | - |
125 | | - printer.println() |
126 | | - |
127 | | - printer.print( |
128 | | - """ |
129 | | - public \(decl.swiftNominal.name)(MemorySegment segment, SwiftArena arena) { |
130 | | - super(segment, arena); |
131 | | - } |
132 | | - """ |
133 | | - ) |
134 | | - |
135 | | - // Initializers |
136 | | - for initDecl in decl.initializers { |
137 | | - printInitializerDowncallConstructors(&printer, initDecl) |
138 | | - } |
139 | | - |
140 | | - // Properties |
141 | | - for accessorDecl in decl.variables { |
142 | | - printFunctionDowncallMethods(&printer, accessorDecl) |
143 | | - } |
144 | | - |
145 | | - // Methods |
146 | | - for funcDecl in decl.methods { |
147 | | - printFunctionDowncallMethods(&printer, funcDecl) |
148 | | - } |
149 | | - |
150 | | - // Helper methods and default implementations |
151 | | - printToStringMethod(&printer, decl) |
152 | | - } |
153 | | - } |
154 | | - |
155 | | - public func printHeader(_ printer: inout CodePrinter) { |
156 | | - printer.print( |
157 | | - """ |
158 | | - // Generated by jextract-swift |
159 | | - // Swift module: \(swiftModuleName) |
160 | | -
|
161 | | - """ |
162 | | - ) |
163 | | - } |
164 | | - |
165 | | - public func printPackage(_ printer: inout CodePrinter) { |
166 | | - printer.print( |
167 | | - """ |
168 | | - package \(javaPackage); |
169 | | -
|
170 | | - """ |
171 | | - ) |
172 | | - } |
173 | | - |
174 | | - public func printImports(_ printer: inout CodePrinter) { |
175 | | - for i in Swift2JavaTranslator.defaultJavaImports { |
176 | | - printer.print("import \(i);") |
177 | | - } |
178 | | - printer.print("") |
179 | | - } |
180 | | - |
181 | | - package func printNominal( |
182 | | - _ printer: inout CodePrinter, _ decl: ImportedNominalType, body: (inout CodePrinter) -> Void |
183 | | - ) { |
184 | | - let baseProtocol = decl.swiftNominal.isReferenceType ? "SwiftHeapObject" : "SwiftValue" |
185 | | - |
186 | | - printer.printBraceBlock("public final class \(decl.swiftNominal.name) extends SwiftInstance implements \(baseProtocol)") { printer in |
187 | | - // Constants |
188 | | - printClassConstants(printer: &printer) |
189 | | - |
190 | | - body(&printer) |
191 | | - } |
192 | | - } |
193 | | - |
194 | | - public func printModuleClass(_ printer: inout CodePrinter, body: (inout CodePrinter) -> Void) { |
195 | | - printer.printBraceBlock("public final class \(swiftModuleName)") { printer in |
196 | | - printPrivateConstructor(&printer, swiftModuleName) |
197 | | - |
198 | | - // Constants |
199 | | - printClassConstants(printer: &printer) |
200 | | - |
201 | | - printer.print( |
202 | | - """ |
203 | | - static MemorySegment findOrThrow(String symbol) { |
204 | | - return SYMBOL_LOOKUP.find(symbol) |
205 | | - .orElseThrow(() -> new UnsatisfiedLinkError("unresolved symbol: %s".formatted(symbol))); |
206 | | - } |
207 | | - """ |
208 | | - ) |
209 | | - |
210 | | - printer.print( |
211 | | - """ |
212 | | - static MethodHandle upcallHandle(Class<?> fi, String name, FunctionDescriptor fdesc) { |
213 | | - try { |
214 | | - return MethodHandles.lookup().findVirtual(fi, name, fdesc.toMethodType()); |
215 | | - } catch (ReflectiveOperationException ex) { |
216 | | - throw new AssertionError(ex); |
217 | | - } |
218 | | - } |
219 | | - """ |
220 | | - ) |
221 | | - |
222 | | - printer.print( |
223 | | - """ |
224 | | - static MemoryLayout align(MemoryLayout layout, long align) { |
225 | | - return switch (layout) { |
226 | | - case PaddingLayout p -> p; |
227 | | - case ValueLayout v -> v.withByteAlignment(align); |
228 | | - case GroupLayout g -> { |
229 | | - MemoryLayout[] alignedMembers = g.memberLayouts().stream() |
230 | | - .map(m -> align(m, align)).toArray(MemoryLayout[]::new); |
231 | | - yield g instanceof StructLayout ? |
232 | | - MemoryLayout.structLayout(alignedMembers) : MemoryLayout.unionLayout(alignedMembers); |
233 | | - } |
234 | | - case SequenceLayout s -> MemoryLayout.sequenceLayout(s.elementCount(), align(s.elementLayout(), align)); |
235 | | - }; |
236 | | - } |
237 | | - """ |
238 | | - ) |
239 | | - |
240 | | - // SymbolLookup.libraryLookup is platform dependent and does not take into account java.library.path |
241 | | - // https://bugs.openjdk.org/browse/JDK-8311090 |
242 | | - printer.print( |
243 | | - """ |
244 | | - static final SymbolLookup SYMBOL_LOOKUP = getSymbolLookup(); |
245 | | - private static SymbolLookup getSymbolLookup() { |
246 | | - // Ensure Swift and our Lib are loaded during static initialization of the class. |
247 | | - SwiftKit.loadLibrary("swiftCore"); |
248 | | - SwiftKit.loadLibrary("SwiftKitSwift"); |
249 | | - SwiftKit.loadLibrary(LIB_NAME); |
250 | | -
|
251 | | - if (PlatformUtils.isMacOS()) { |
252 | | - return SymbolLookup.libraryLookup(System.mapLibraryName(LIB_NAME), LIBRARY_ARENA) |
253 | | - .or(SymbolLookup.loaderLookup()) |
254 | | - .or(Linker.nativeLinker().defaultLookup()); |
255 | | - } else { |
256 | | - return SymbolLookup.loaderLookup() |
257 | | - .or(Linker.nativeLinker().defaultLookup()); |
258 | | - } |
259 | | - } |
260 | | - """ |
261 | | - ) |
262 | | - |
263 | | - body(&printer) |
264 | | - } |
265 | | - } |
266 | | - |
267 | | - private func printClassConstants(printer: inout CodePrinter) { |
268 | | - printer.print( |
269 | | - """ |
270 | | - static final String LIB_NAME = "\(swiftModuleName)"; |
271 | | - static final Arena LIBRARY_ARENA = Arena.ofAuto(); |
272 | | - """ |
273 | | - ) |
274 | | - } |
275 | | - |
276 | | - private func printPrivateConstructor(_ printer: inout CodePrinter, _ typeName: String) { |
277 | | - printer.print( |
278 | | - """ |
279 | | - private \(typeName)() { |
280 | | - // Should not be called directly |
281 | | - } |
282 | | -
|
283 | | - // Static enum to force initialization |
284 | | - private static enum Initializer { |
285 | | - FORCE; // Refer to this to force outer Class initialization (and static{} blocks to trigger) |
286 | | - } |
287 | | - """ |
288 | | - ) |
289 | | - } |
290 | | - |
291 | | - private func printClassMemoryLayout(_ printer: inout CodePrinter, _ decl: ImportedNominalType) { |
292 | | - printer.print( |
293 | | - """ |
294 | | - private static final GroupLayout $LAYOUT = (GroupLayout) SwiftValueWitnessTable.layoutOfSwiftType(TYPE_METADATA.$memorySegment()); |
295 | | - public static final GroupLayout $LAYOUT() { |
296 | | - return $LAYOUT; |
297 | | - } |
298 | | - public final GroupLayout $layout() { |
299 | | - return $LAYOUT; |
300 | | - } |
301 | | - """ |
302 | | - ) |
303 | | - } |
304 | | - |
305 | 18 | public func printInitializerDowncallConstructors( |
306 | 19 | _ printer: inout CodePrinter, |
307 | 20 | _ decl: ImportedFunc |
@@ -582,23 +295,6 @@ extension Swift2JavaTranslator { |
582 | 295 | fatalError("renderMemoryLayoutValue not supported for \(javaType)") |
583 | 296 | } |
584 | 297 | } |
585 | | - |
586 | | - package func printToStringMethod( |
587 | | - _ printer: inout CodePrinter, _ decl: ImportedNominalType |
588 | | - ) { |
589 | | - printer.print( |
590 | | - """ |
591 | | - @Override |
592 | | - public String toString() { |
593 | | - return getClass().getSimpleName() |
594 | | - + "(" |
595 | | - + SwiftKit.nameOfSwiftType($swiftType().$memorySegment(), true) |
596 | | - + ")@" |
597 | | - + $memorySegment(); |
598 | | - } |
599 | | - """) |
600 | | - } |
601 | | - |
602 | 298 | } |
603 | 299 |
|
604 | 300 | extension JavaConversionStep { |
|
0 commit comments