Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 37 additions & 2 deletions Sources/JExtractSwiftLib/JNI/JNIJavaTypeTranslator.swift
Original file line number Diff line number Diff line change
Expand Up @@ -39,20 +39,55 @@ enum JNIJavaTypeTranslator {

case .int64: return .long
case .uint64: return .long

case .int, .uint: return .long

case .float: return .float
case .double: return .double
case .void: return .void

case .string: return .javaLangString

case .int, .uint, // FIXME: why not supported int/uint?
.unsafeRawPointer, .unsafeMutableRawPointer,
case .unsafeRawPointer, .unsafeMutableRawPointer,
.unsafePointer, .unsafeMutablePointer,
.unsafeRawBufferPointer, .unsafeMutableRawBufferPointer,
.unsafeBufferPointer, .unsafeMutableBufferPointer,
.optional, .foundationData, .foundationDataProtocol, .essentialsData, .essentialsDataProtocol, .array:
return nil
}
}

static func indirectConversionSetepSwiftType(for knownKind: SwiftKnownTypeDeclKind, from knownTypes: SwiftKnownTypes) -> SwiftType? {
switch knownKind {
case .int: knownTypes.int64
case .uint: knownTypes.uint64

case .bool, .int8, .uint8, .int16, .uint16, .int32, .uint32, .int64, .uint64,
.float, .double, .void, .string,
.unsafeRawPointer, .unsafeMutableRawPointer,
.unsafePointer, .unsafeMutablePointer,
.unsafeRawBufferPointer, .unsafeMutableRawBufferPointer,
.unsafeBufferPointer, .unsafeMutableBufferPointer,
.optional, .foundationData, .foundationDataProtocol, .essentialsData, .essentialsDataProtocol,
.array:
nil
}
}

static func checkStep(for knownKind: SwiftKnownTypeDeclKind, from knownTypes: SwiftKnownTypes) -> JNISwift2JavaGenerator.NativeSwiftConversionCheck? {
switch knownKind {
case .int: .check32BitIntOverflow(typeWithMinAndMax: knownTypes.int32)
case .uint: .check32BitIntOverflow(typeWithMinAndMax: knownTypes.uint32)

case .bool, .int8, .uint8, .int16, .uint16, .int32, .uint32, .int64, .uint64,
.float, .double, .void, .string,
.unsafeRawPointer, .unsafeMutableRawPointer,
.unsafePointer, .unsafeMutablePointer,
.unsafeRawBufferPointer, .unsafeMutableRawBufferPointer,
.unsafeBufferPointer, .unsafeMutableBufferPointer,
.optional, .foundationData, .foundationDataProtocol, .essentialsData, .essentialsDataProtocol,
.array:
nil
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -445,7 +445,7 @@ extension JNISwift2JavaGenerator {
let translatedSignature = translatedDecl.translatedFunctionSignature
let resultType = translatedSignature.resultType.javaType
var parameters = translatedDecl.translatedFunctionSignature.parameters.map { $0.parameter.renderParameter() }
let throwsClause = translatedDecl.isThrowing && !translatedDecl.isAsync ? " throws Exception" : ""
let throwsClause = translatedDecl.throwsClause()

let generics = translatedDecl.translatedFunctionSignature.parameters.reduce(into: [(String, [JavaType])]()) { generics, parameter in
guard case .generic(let name, let extends) = parameter.parameter.type else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,12 @@ extension JNISwift2JavaGenerator {
.class(package: nil,name: caseName)
)
])
var exceptions: [JavaException] = []

if enumCase.parameters.contains(where: \.type.isArchDependingInteger) {
exceptions.append(.integerOverflow)
}

let getAsCaseFunction = TranslatedFunctionDecl(
name: getAsCaseName,
isStatic: false,
Expand All @@ -137,12 +143,15 @@ extension JNISwift2JavaGenerator {
javaType: .class(package: nil, name: "Optional<\(caseName)>"),
outParameters: conversions.flatMap(\.translated.outParameters),
conversion: enumCase.parameters.isEmpty ? constructRecordConversion : .aggregate(variable: ("$nativeParameters", nativeParametersType), [constructRecordConversion])
)
),
exceptions: exceptions
),
nativeFunctionSignature: NativeFunctionSignature(
selfParameter: NativeParameter(
parameters: [JavaParameter(name: "self", type: .long)],
conversion: .extractSwiftValue(.placeholder, swiftType: .nominal(enumCase.enumType), allowNil: false)
conversion: .extractSwiftValue(.placeholder, swiftType: .nominal(enumCase.enumType), allowNil: false),
indirectConversion: nil,
conversionCheck: nil
),
parameters: [],
result: NativeResult(
Expand Down Expand Up @@ -291,12 +300,19 @@ extension JNISwift2JavaGenerator {
genericRequirements: functionSignature.genericRequirements
)

var exceptions: [JavaException] = []

if functionSignature.parameters.contains(where: \.type.isArchDependingInteger) {
exceptions.append(.integerOverflow)
}

let resultType = try translate(swiftResult: functionSignature.result)

return TranslatedFunctionSignature(
selfParameter: selfParameter,
parameters: parameters,
resultType: resultType
resultType: resultType,
exceptions: exceptions
)
}

Expand Down Expand Up @@ -955,12 +971,22 @@ extension JNISwift2JavaGenerator {
var annotations: [JavaAnnotation] {
self.translatedFunctionSignature.annotations
}

func throwsClause() -> String {
guard !translatedFunctionSignature.exceptions.isEmpty else {
return isThrowing && !isAsync ? " throws Exception" : ""
}

let signatureExceptions = translatedFunctionSignature.exceptions.compactMap(\.type.className).joined(separator: ", ")
return " throws \(signatureExceptions)\(isThrowing ? ", Exception" : "")"
}
}

struct TranslatedFunctionSignature {
var selfParameter: TranslatedParameter?
var parameters: [TranslatedParameter]
var resultType: TranslatedResult
var exceptions: [JavaException]

// if the result type implied any annotations,
// propagate them onto the function the result is returned from
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -103,11 +103,16 @@ extension JNISwift2JavaGenerator {
throw JavaTranslationError.unsupportedSwiftType(type)
}

let indirectStepType = JNIJavaTypeTranslator.indirectConversionSetepSwiftType(for: knownType, from: knownTypes)
let indirectCheck = JNIJavaTypeTranslator.checkStep(for: knownType, from: knownTypes)

return NativeParameter(
parameters: [
JavaParameter(name: parameterName, type: javaType)
],
conversion: .initFromJNI(.placeholder, swiftType: type)
conversion: indirectStepType != nil ? .labelessAssignmentOfVariable(.placeholder, swiftType: type) : .initFromJNI(.placeholder, swiftType: type),
indirectConversion: indirectStepType.flatMap { .initFromJNI(.placeholder, swiftType: $0) },
conversionCheck: indirectCheck
)

}
Expand All @@ -129,7 +134,9 @@ extension JNISwift2JavaGenerator {
fatalErrorMessage: "\(parameterName) was null in call to \\(#function), but Swift requires non-optional!"
),
wrapperName: nominalTypeName
)
),
indirectConversion: nil,
conversionCheck: nil
)
}

Expand All @@ -138,15 +145,19 @@ extension JNISwift2JavaGenerator {
parameters: [
JavaParameter(name: parameterName, type: .long)
],
conversion: .pointee(.extractSwiftValue(.placeholder, swiftType: type))
conversion: .pointee(.extractSwiftValue(.placeholder, swiftType: type)),
indirectConversion: nil,
conversionCheck: nil
)

case .tuple([]):
return NativeParameter(
parameters: [
JavaParameter(name: parameterName, type: .void)
],
conversion: .placeholder
conversion: .placeholder,
indirectConversion: nil,
conversionCheck: nil
)

case .function(let fn):
Expand All @@ -169,7 +180,9 @@ extension JNISwift2JavaGenerator {
conversion: .closureLowering(
parameters: parameters,
result: result
)
),
indirectConversion: nil,
conversionCheck: nil
)

case .optional(let wrapped):
Expand Down Expand Up @@ -242,7 +255,9 @@ extension JNISwift2JavaGenerator {
.placeholder,
typeMetadataVariableName: .combinedName(component: "typeMetadataAddress"),
protocolNames: protocolNames
)
),
indirectConversion: nil,
conversionCheck: nil
)
}

Expand Down Expand Up @@ -272,7 +287,9 @@ extension JNISwift2JavaGenerator {
.initFromJNI(.placeholder, swiftType: swiftType),
discriminatorName: discriminatorName,
valueName: valueName
)
),
indirectConversion: nil,
conversionCheck: nil
)
}

Expand All @@ -285,7 +302,9 @@ extension JNISwift2JavaGenerator {
parameters: [
JavaParameter(name: parameterName, type: javaType)
],
conversion: .optionalMap(.initializeJavaKitWrapper(.placeholder, wrapperName: nominalTypeName))
conversion: .optionalMap(.initializeJavaKitWrapper(.placeholder, wrapperName: nominalTypeName)),
indirectConversion: nil,
conversionCheck: nil
)
}

Expand All @@ -300,7 +319,9 @@ extension JNISwift2JavaGenerator {
allowNil: true
)
)
)
),
indirectConversion: nil,
conversionCheck: nil
)

default:
Expand Down Expand Up @@ -434,7 +455,9 @@ extension JNISwift2JavaGenerator {
parameters: [
JavaParameter(name: parameterName, type: javaType)
],
conversion: .getJValue(.placeholder)
conversion: .getJValue(.placeholder),
indirectConversion: nil,
conversionCheck: nil
)
}

Expand Down Expand Up @@ -570,7 +593,9 @@ extension JNISwift2JavaGenerator {
parameters: [
JavaParameter(name: parameterName, type: .array(javaType)),
],
conversion: .initFromJNI(.placeholder, swiftType: .array(elementType))
conversion: .initFromJNI(.placeholder, swiftType: .array(elementType)),
indirectConversion: nil,
conversionCheck: nil
)
}

Expand All @@ -594,7 +619,9 @@ extension JNISwift2JavaGenerator {
convertLongFromJNI: false
))))
]
)
),
indirectConversion: nil,
conversionCheck: nil
)

default:
Expand All @@ -616,6 +643,12 @@ extension JNISwift2JavaGenerator {

/// Represents how to convert the JNI parameter to a Swift parameter
let conversion: NativeSwiftConversionStep

/// Represents swift type for indirect variable used in required checks, e.g Int64 for Int overflow check on 32-bit platforms
let indirectConversion: NativeSwiftConversionStep?

/// Represents check operations executed in if/guard conditional block for check during conversion
let conversionCheck: NativeSwiftConversionCheck?
}

struct NativeResult {
Expand Down Expand Up @@ -695,6 +728,8 @@ extension JNISwift2JavaGenerator {
/// `{ (args) -> return body }`
indirect case closure(args: [String] = [], body: NativeSwiftConversionStep)

indirect case labelessAssignmentOfVariable(NativeSwiftConversionStep, swiftType: SwiftType)

/// Returns the conversion string applied to the placeholder.
func render(_ printer: inout CodePrinter, _ placeholder: String) -> String {
// NOTE: 'printer' is used if the conversion wants to cause side-effects.
Expand Down Expand Up @@ -1025,6 +1060,20 @@ extension JNISwift2JavaGenerator {
}
}
return printer.finalize()
case .labelessAssignmentOfVariable(let name, let swiftType):
return "\(swiftType)(indirect_\(name.render(&printer, placeholder)))"
}
}
}

enum NativeSwiftConversionCheck {
case check32BitIntOverflow(typeWithMinAndMax: SwiftType)

// Returns the check string
func render(_ printer: inout CodePrinter, _ placeholder: String) -> String {
switch self {
case .check32BitIntOverflow(let minMaxSource):
return "\(placeholder) >= \(minMaxSource).min && \(placeholder) <= \(minMaxSource).max"
}
}
}
Expand Down
Loading