Skip to content

Commit c9dc9b6

Browse files
authored
[JExtract] Bridge UnsafeRawBufferPointer (#279)
1 parent 649140b commit c9dc9b6

15 files changed

+314
-57
lines changed

Samples/SwiftKitSampleApp/Sources/MySwiftLibrary/MySwiftLibrary.swift

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,12 @@ public func globalCallMeRunnable(run: () -> ()) {
4747
run()
4848
}
4949

50+
public func globalReceiveRawBuffer(buf: UnsafeRawBufferPointer) -> Int {
51+
return buf.count
52+
}
53+
54+
public var globalBuffer: UnsafeRawBufferPointer = UnsafeRawBufferPointer(UnsafeMutableRawBufferPointer.allocate(byteCount: 124, alignment: 1))
55+
5056
// ==== Internal helpers
5157

5258
func p(_ msg: String, file: String = #fileID, line: UInt = #line, function: String = #function) {

Samples/SwiftKitSampleApp/src/main/java/com/example/swift/HelloJava2Swift.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,8 @@ static void examples() {
4545
SwiftKit.trace("running runnable");
4646
});
4747

48+
SwiftKit.trace("getGlobalBuffer().byteSize()=" + MySwiftLibrary.getGlobalBuffer().byteSize());
49+
4850
// Example of using an arena; MyClass.deinit is run at end of scope
4951
try (var arena = SwiftArena.ofConfined()) {
5052
MySwiftClass obj = MySwiftClass.init(2222, 7777, arena);

Sources/ExampleSwiftLibrary/MySwiftLibrary.swift

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,10 @@ public func globalCallMeRunnable(run: () -> ()) {
4141
run()
4242
}
4343

44+
public func globalReceiveRawBuffer(buf: UnsafeRawBufferPointer) -> Int {
45+
return buf.count
46+
}
47+
4448
public class MySwiftClass {
4549

4650
public var len: Int

Sources/JExtractSwiftLib/FFM/CDeclLowering/CRepresentation.swift

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,9 @@ extension CType {
6565
case .tuple([]):
6666
self = .void
6767

68+
case .optional(let wrapped) where wrapped.isPointer:
69+
try self.init(cdeclType: wrapped)
70+
6871
case .metatype, .optional, .tuple:
6972
throw CDeclToCLoweringError.invalidCDeclType(cdeclType)
7073
}
@@ -122,7 +125,7 @@ extension SwiftStandardLibraryTypeKind {
122125
.qualified(const: true, volatile: false, type: .void)
123126
)
124127
case .void: .void
125-
case .unsafePointer, .unsafeMutablePointer, .unsafeBufferPointer, .unsafeMutableBufferPointer, .string:
128+
case .unsafePointer, .unsafeMutablePointer, .unsafeRawBufferPointer, .unsafeMutableRawBufferPointer, .unsafeBufferPointer, .unsafeMutableBufferPointer, .string:
126129
nil
127130
}
128131
}

Sources/JExtractSwiftLib/FFM/CDeclLowering/FFMSwift2JavaGenerator+FunctionLowering.swift

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -220,6 +220,35 @@ struct CdeclLowering {
220220
)
221221
)
222222

223+
case .unsafeRawBufferPointer, .unsafeMutableRawBufferPointer:
224+
// pointer buffers are lowered to (raw-pointer, count) pair.
225+
let isMutable = knownType == .unsafeMutableRawBufferPointer
226+
return LoweredParameter(
227+
cdeclParameters: [
228+
SwiftParameter(
229+
convention: .byValue,
230+
parameterName: "\(parameterName)_pointer",
231+
type: .optional(isMutable ? knownTypes.unsafeMutableRawPointer : knownTypes.unsafeRawPointer)
232+
),
233+
SwiftParameter(
234+
convention: .byValue, parameterName: "\(parameterName)_count",
235+
type: knownTypes.int
236+
)
237+
],
238+
conversion: .initialize(
239+
type,
240+
arguments: [
241+
LabeledArgument(
242+
label: "start",
243+
argument: .explodedComponent(.placeholder, component: "pointer")
244+
),
245+
LabeledArgument(
246+
label: "count",
247+
argument: .explodedComponent(.placeholder, component: "count")
248+
)
249+
]
250+
))
251+
223252
case .string:
224253
// 'String' is passed in by C string. i.e. 'UnsafePointer<Int8>' ('const uint8_t *')
225254
if knownType == .string {
@@ -382,6 +411,37 @@ struct CdeclLowering {
382411
outParameterName: outParameterName
383412
)
384413

414+
case .unsafeRawBufferPointer, .unsafeMutableRawBufferPointer:
415+
// pointer buffers are lowered to (raw-pointer, count) pair.
416+
let isMutable = knownType == .unsafeMutableRawBufferPointer
417+
return LoweredResult(
418+
cdeclResultType: .void,
419+
cdeclOutParameters: [
420+
SwiftParameter(
421+
convention: .byValue,
422+
parameterName: "\(outParameterName)_pointer",
423+
type: knownTypes.unsafeMutablePointer(
424+
.optional(isMutable ? knownTypes.unsafeMutableRawPointer : knownTypes.unsafeRawPointer)
425+
)
426+
),
427+
SwiftParameter(
428+
convention: .byValue,
429+
parameterName: "\(outParameterName)_count",
430+
type: knownTypes.unsafeMutablePointer(knownTypes.int)
431+
),
432+
],
433+
conversion: .aggregate([
434+
.populatePointer(
435+
name: "\(outParameterName)_pointer",
436+
to: .member(.placeholder, member: "baseAddress")
437+
),
438+
.populatePointer(
439+
name: "\(outParameterName)_count",
440+
to: .member(.placeholder, member: "count")
441+
)
442+
], name: outParameterName)
443+
)
444+
385445
case .void:
386446
return LoweredResult(cdeclResultType: .void, cdeclOutParameters: [], conversion: .placeholder)
387447

Sources/JExtractSwiftLib/FFM/ConversionStep.swift

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -52,9 +52,14 @@ enum ConversionStep: Equatable {
5252
/// Initialize mutable raw pointer with a typed value.
5353
indirect case populatePointer(name: String, assumingType: SwiftType? = nil, to: ConversionStep)
5454

55-
/// Perform multiple conversions, but discard the result.
55+
/// Perform multiple conversions for each tuple input elements, but discard the result.
5656
case tupleExplode([ConversionStep], name: String?)
5757

58+
/// Perform multiple conversions using the same input.
59+
case aggregate([ConversionStep], name: String?)
60+
61+
indirect case member(ConversionStep, member: String)
62+
5863
/// Count the number of times that the placeholder occurs within this
5964
/// conversion step.
6065
var placeholderCount: Int {
@@ -63,13 +68,14 @@ enum ConversionStep: Equatable {
6368
.pointee(let inner),
6469
.typedPointer(let inner, swiftType: _),
6570
.unsafeCastPointer(let inner, swiftType: _),
66-
.populatePointer(name: _, assumingType: _, to: let inner):
71+
.populatePointer(name: _, assumingType: _, to: let inner),
72+
.member(let inner, member: _):
6773
inner.placeholderCount
6874
case .initialize(_, arguments: let arguments):
6975
arguments.reduce(0) { $0 + $1.argument.placeholderCount }
7076
case .placeholder, .tupleExplode:
7177
1
72-
case .tuplify(let elements):
78+
case .tuplify(let elements), .aggregate(let elements, _):
7379
elements.reduce(0) { $0 + $1.placeholderCount }
7480
}
7581
}
@@ -140,6 +146,25 @@ enum ConversionStep: Equatable {
140146
}
141147
}
142148
return nil
149+
150+
case .member(let step, let member):
151+
let inner = step.asExprSyntax(placeholder: placeholder, bodyItems: &bodyItems)
152+
return "\(inner).\(raw: member)"
153+
154+
case .aggregate(let steps, let name):
155+
let toExplode: String
156+
if let name {
157+
bodyItems.append("let \(raw: name) = \(raw: placeholder)")
158+
toExplode = name
159+
} else {
160+
toExplode = placeholder
161+
}
162+
for step in steps {
163+
if let result = step.asExprSyntax(placeholder: toExplode, bodyItems: &bodyItems) {
164+
bodyItems.append(CodeBlockItemSyntax(item: .expr(result)))
165+
}
166+
}
167+
return nil
143168
}
144169
}
145170
}

Sources/JExtractSwiftLib/FFM/FFMSwift2JavaGenerator+JavaBindingsPrinting.swift

Lines changed: 46 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -365,7 +365,7 @@ extension FFMSwift2JavaGenerator {
365365
"arena$"
366366
}
367367

368-
let varName = "_result" + outParameter.name
368+
let varName = outParameter.name.isEmpty ? "_result" : "_result_" + outParameter.name
369369

370370
printer.print(
371371
"MemorySegment \(varName) = \(arena).allocate(\(memoryLayout));"
@@ -419,32 +419,35 @@ extension JavaConversionStep {
419419
/// Whether the conversion uses SwiftArena.
420420
var requiresSwiftArena: Bool {
421421
switch self {
422-
case .pass, .swiftValueSelfSegment, .construct, .cast, .call, .method:
422+
case .placeholder, .constant, .readOutParameter:
423423
return false
424424
case .constructSwiftValue:
425425
return true
426+
427+
case .call(let inner, _, _), .cast(let inner, _), .construct(let inner, _),
428+
.method(let inner, _, _, _), .swiftValueSelfSegment(let inner):
429+
return inner.requiresSwiftArena
430+
431+
case .commaSeparated(let list):
432+
return list.contains(where: { $0.requiresSwiftArena })
426433
}
427434
}
428435

429436
/// Whether the conversion uses temporary Arena.
430437
var requiresTemporaryArena: Bool {
431438
switch self {
432-
case .pass, .swiftValueSelfSegment, .construct, .constructSwiftValue, .cast:
439+
case .placeholder, .constant:
433440
return false
434-
case .call(_, let withArena), .method(_, _, let withArena):
435-
return withArena
436-
}
437-
}
438-
439-
/// Whether if the result evaluation is trivial.
440-
///
441-
/// If this is false, it's advised to store it to a variable if it's used multiple times
442-
var isTrivial: Bool {
443-
switch self {
444-
case .pass, .swiftValueSelfSegment:
441+
case .readOutParameter:
445442
return true
446-
case .cast, .construct, .constructSwiftValue, .call, .method:
447-
return false
443+
case .cast(let inner, _), .construct(let inner, _), .constructSwiftValue(let inner, _), .swiftValueSelfSegment(let inner):
444+
return inner.requiresSwiftArena
445+
case .call(let inner, _, let withArena):
446+
return withArena || inner.requiresTemporaryArena
447+
case .method(let inner, _, let args, let withArena):
448+
return withArena || inner.requiresTemporaryArena || args.contains(where: { $0.requiresTemporaryArena })
449+
case .commaSeparated(let list):
450+
return list.contains(where: { $0.requiresTemporaryArena })
448451
}
449452
}
450453

@@ -453,28 +456,43 @@ extension JavaConversionStep {
453456
// NOTE: 'printer' is used if the conversion wants to cause side-effects.
454457
// E.g. storing a temporary values into a variable.
455458
switch self {
456-
case .pass:
459+
case .placeholder:
457460
return placeholder
458461

459462
case .swiftValueSelfSegment:
460463
return "\(placeholder).$memorySegment()"
461464

462-
case .call(let function, let withArena):
465+
case .call(let inner, let function, let withArena):
466+
let inner = inner.render(&printer, placeholder)
463467
let arenaArg = withArena ? ", arena$" : ""
464-
return "\(function)(\(placeholder)\(arenaArg))"
468+
return "\(function)(\(inner)\(arenaArg))"
469+
470+
case .method(let inner, let methodName, let arguments, let withArena):
471+
let inner = inner.render(&printer, placeholder)
472+
let args = arguments.map { $0.render(&printer, placeholder) }
473+
let argsStr = (args + (withArena ? ["arena$"] : [])).joined(separator: " ,")
474+
return "\(inner).\(methodName)(\(argsStr))"
475+
476+
case .constructSwiftValue(let inner, let javaType):
477+
let inner = inner.render(&printer, placeholder)
478+
return "new \(javaType.className!)(\(inner), swiftArena$)"
479+
480+
case .construct(let inner, let javaType):
481+
let inner = inner.render(&printer, placeholder)
482+
return "new \(javaType)(\(inner))"
465483

466-
case .method(let methodName, let arguments, let withArena):
467-
let argsStr = (arguments + (withArena ? ["arena$"] : [])).joined(separator: " ,")
468-
return "\(placeholder).\(methodName)(\(argsStr))"
484+
case .cast(let inner, let javaType):
485+
let inner = inner.render(&printer, placeholder)
486+
return "(\(javaType)) \(inner)"
469487

470-
case .constructSwiftValue(let javaType):
471-
return "new \(javaType.className!)(\(placeholder), swiftArena$)"
488+
case .commaSeparated(let list):
489+
return list.map({ $0.render(&printer, placeholder)}).joined(separator: ", ")
472490

473-
case .construct(let javaType):
474-
return "new \(javaType)(\(placeholder))"
491+
case .constant(let value):
492+
return value
475493

476-
case .cast(let javaType):
477-
return "(\(javaType)) \(placeholder)"
494+
case .readOutParameter(let javaType, let name):
495+
return "\(placeholder)_\(name).get(\(ForeignValueLayout(javaType: javaType)!), 0)"
478496
}
479497
}
480498
}

0 commit comments

Comments
 (0)