Native: allow subclassing FunctionGenerationContext
This allows one to have domain-specific generator without polluting the global namespace. Also introduce builders and do minor refactoring.
This commit is contained in:
committed by
Space
parent
be1acc8103
commit
e00fd6b9b3
+72
-23
@@ -121,11 +121,13 @@ val LLVMValueRef.isConst:Boolean
|
||||
get() = (LLVMIsConstant(this) == 1)
|
||||
|
||||
|
||||
internal inline fun<R> generateFunction(codegen: CodeGenerator,
|
||||
function: IrFunction,
|
||||
startLocation: LocationInfo?,
|
||||
endLocation: LocationInfo?,
|
||||
code: FunctionGenerationContext.(FunctionGenerationContext) -> R) {
|
||||
internal inline fun generateFunction(
|
||||
codegen: CodeGenerator,
|
||||
function: IrFunction,
|
||||
startLocation: LocationInfo?,
|
||||
endLocation: LocationInfo?,
|
||||
code: FunctionGenerationContext.() -> Unit
|
||||
) {
|
||||
val llvmFunction = codegen.llvmFunction(function)
|
||||
|
||||
val isCToKotlinBridge = function.origin == CBridgeOrigin.C_TO_KOTLIN_BRIDGE
|
||||
@@ -155,11 +157,24 @@ internal inline fun<R> generateFunction(codegen: CodeGenerator,
|
||||
LLVMVerifyFunction(llvmFunction, LLVMVerifierFailureAction.LLVMAbortProcessAction)
|
||||
}
|
||||
|
||||
internal inline fun <T : FunctionGenerationContext> FunctionGenerationContextBuilder<T>.generate(code: T.() -> Unit): LLVMValueRef {
|
||||
val functionGenerationContext = this.build()
|
||||
return try {
|
||||
generateFunctionBody(functionGenerationContext, code)
|
||||
functionGenerationContext.function
|
||||
} finally {
|
||||
functionGenerationContext.dispose()
|
||||
}
|
||||
}
|
||||
|
||||
internal inline fun<R> generateFunction(codegen: CodeGenerator, function: LLVMValueRef,
|
||||
startLocation: LocationInfo? = null, endLocation: LocationInfo? = null,
|
||||
switchToRunnable: Boolean = false,
|
||||
code:FunctionGenerationContext.(FunctionGenerationContext) -> R) {
|
||||
internal inline fun generateFunction(
|
||||
codegen: CodeGenerator,
|
||||
function: LLVMValueRef,
|
||||
startLocation: LocationInfo? = null,
|
||||
endLocation: LocationInfo? = null,
|
||||
switchToRunnable: Boolean = false,
|
||||
code: FunctionGenerationContext.() -> Unit
|
||||
) {
|
||||
val functionGenerationContext = FunctionGenerationContext(
|
||||
function,
|
||||
codegen,
|
||||
@@ -179,7 +194,7 @@ internal inline fun generateFunction(
|
||||
functionType: LLVMTypeRef,
|
||||
name: String,
|
||||
switchToRunnable: Boolean = false,
|
||||
block: FunctionGenerationContext.(FunctionGenerationContext) -> Unit
|
||||
block: FunctionGenerationContext.() -> Unit
|
||||
): LLVMValueRef {
|
||||
val function = addLlvmFunctionWithDefaultAttributes(
|
||||
codegen.context,
|
||||
@@ -192,10 +207,10 @@ internal inline fun generateFunction(
|
||||
}
|
||||
|
||||
// TODO: Consider using different abstraction than `FunctionGenerationContext` for `generateFunctionNoRuntime`.
|
||||
internal inline fun <R> generateFunctionNoRuntime(
|
||||
internal inline fun generateFunctionNoRuntime(
|
||||
codegen: CodeGenerator,
|
||||
function: LLVMValueRef,
|
||||
code: FunctionGenerationContext.(FunctionGenerationContext) -> R,
|
||||
code: FunctionGenerationContext.() -> Unit,
|
||||
) {
|
||||
val functionGenerationContext = FunctionGenerationContext(function, codegen, null, null, switchToRunnable = false)
|
||||
try {
|
||||
@@ -214,7 +229,7 @@ internal inline fun generateFunctionNoRuntime(
|
||||
codegen: CodeGenerator,
|
||||
functionType: LLVMTypeRef,
|
||||
name: String,
|
||||
code: FunctionGenerationContext.(FunctionGenerationContext) -> Unit,
|
||||
code: FunctionGenerationContext.() -> Unit,
|
||||
): LLVMValueRef {
|
||||
val function = addLlvmFunctionWithDefaultAttributes(
|
||||
codegen.context,
|
||||
@@ -226,11 +241,11 @@ internal inline fun generateFunctionNoRuntime(
|
||||
return function
|
||||
}
|
||||
|
||||
private inline fun <R> generateFunctionBody(
|
||||
functionGenerationContext: FunctionGenerationContext,
|
||||
code: FunctionGenerationContext.(FunctionGenerationContext) -> R) {
|
||||
private inline fun <T : FunctionGenerationContext> generateFunctionBody(
|
||||
functionGenerationContext: T,
|
||||
code: T.() -> Unit) {
|
||||
functionGenerationContext.prologue()
|
||||
functionGenerationContext.code(functionGenerationContext)
|
||||
functionGenerationContext.code()
|
||||
if (!functionGenerationContext.isAfterTerminator())
|
||||
functionGenerationContext.unreachable()
|
||||
functionGenerationContext.epilogue()
|
||||
@@ -387,12 +402,46 @@ internal class StackLocalsManagerImpl(
|
||||
}
|
||||
}
|
||||
|
||||
internal class FunctionGenerationContext(val function: LLVMValueRef,
|
||||
val codegen: CodeGenerator,
|
||||
private val startLocation: LocationInfo?,
|
||||
private val endLocation: LocationInfo?,
|
||||
private val switchToRunnable: Boolean,
|
||||
internal val irFunction: IrFunction? = null): ContextUtils {
|
||||
internal abstract class FunctionGenerationContextBuilder<T : FunctionGenerationContext>(
|
||||
val function: LLVMValueRef,
|
||||
val codegen: CodeGenerator
|
||||
) {
|
||||
constructor(functionType: LLVMTypeRef, functionName: String, codegen: CodeGenerator) :
|
||||
this(
|
||||
addLlvmFunctionWithDefaultAttributes(
|
||||
codegen.context,
|
||||
codegen.context.llvmModule!!,
|
||||
functionName,
|
||||
functionType
|
||||
),
|
||||
codegen
|
||||
)
|
||||
|
||||
var startLocation: LocationInfo? = null
|
||||
var endLocation: LocationInfo? = null
|
||||
var switchToRunnable = false
|
||||
var irFunction: IrFunction? = null
|
||||
|
||||
abstract fun build(): T
|
||||
}
|
||||
|
||||
internal open class FunctionGenerationContext(
|
||||
val function: LLVMValueRef,
|
||||
val codegen: CodeGenerator,
|
||||
private val startLocation: LocationInfo?,
|
||||
private val endLocation: LocationInfo?,
|
||||
private val switchToRunnable: Boolean,
|
||||
internal val irFunction: IrFunction? = null
|
||||
) : ContextUtils {
|
||||
|
||||
constructor(builder: FunctionGenerationContextBuilder<*>) : this(
|
||||
function = builder.function,
|
||||
codegen = builder.codegen,
|
||||
startLocation = builder.startLocation,
|
||||
endLocation = builder.endLocation,
|
||||
switchToRunnable = builder.switchToRunnable,
|
||||
irFunction = builder.irFunction
|
||||
)
|
||||
|
||||
override val context = codegen.context
|
||||
val vars = VariableManager(this)
|
||||
|
||||
+4
-4
@@ -371,7 +371,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
|
||||
|
||||
context.llvm.initializersGenerationState.globalInitFunction?.let { fileInitFunction ->
|
||||
generateFunction(codegen, fileInitFunction, fileInitFunction.location(start = true), fileInitFunction.location(start = false)) {
|
||||
using(FunctionScope(fileInitFunction, it)) {
|
||||
using(FunctionScope(fileInitFunction, this)) {
|
||||
val parameterScope = ParameterScope(fileInitFunction, functionGenerationContext)
|
||||
using(parameterScope) usingParameterScope@{
|
||||
using(VariableScope()) usingVariableScope@{
|
||||
@@ -388,7 +388,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
|
||||
|
||||
context.llvm.initializersGenerationState.threadLocalInitFunction?.let { fileInitFunction ->
|
||||
generateFunction(codegen, fileInitFunction, fileInitFunction.location(start = true), fileInitFunction.location(start = false)) {
|
||||
using(FunctionScope(fileInitFunction, it)) {
|
||||
using(FunctionScope(fileInitFunction, this)) {
|
||||
val parameterScope = ParameterScope(fileInitFunction, functionGenerationContext)
|
||||
using(parameterScope) usingParameterScope@{
|
||||
using(VariableScope()) usingVariableScope@{
|
||||
@@ -474,7 +474,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
|
||||
)
|
||||
LLVMSetLinkage(initFunction, LLVMLinkage.LLVMPrivateLinkage)
|
||||
generateFunction(codegen, initFunction) {
|
||||
using(FunctionScope(initFunction, it)) {
|
||||
using(FunctionScope(initFunction, this)) {
|
||||
val bbInit = basicBlock("init", null)
|
||||
val bbLocalInit = basicBlock("local_init", null)
|
||||
val bbLocalAlloc = basicBlock("local_alloc", null)
|
||||
@@ -831,7 +831,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
|
||||
generateFunction(codegen, declaration,
|
||||
declaration.location(start = true),
|
||||
declaration.location(start = false)) {
|
||||
using(FunctionScope(declaration, it)) {
|
||||
using(FunctionScope(declaration, this)) {
|
||||
val parameterScope = ParameterScope(declaration, functionGenerationContext)
|
||||
using(parameterScope) usingParameterScope@{
|
||||
using(VariableScope()) usingVariableScope@{
|
||||
|
||||
+9
-10
@@ -30,11 +30,10 @@ internal fun ObjCExportCodeGeneratorBase.generateBlockToKotlinFunctionConverter(
|
||||
structType(codegen.kObjHeader)
|
||||
}
|
||||
|
||||
val invokeImpl = generateFunction(
|
||||
codegen,
|
||||
val invokeImpl = functionGenerator(
|
||||
codegen.getLlvmFunctionType(invokeMethod),
|
||||
"invokeFunction${bridge.nameSuffix}"
|
||||
) {
|
||||
).generate {
|
||||
val args = (0 until bridge.numberOfParameters).map { index ->
|
||||
kotlinReferenceToObjC(param(index + 1))
|
||||
}
|
||||
@@ -71,11 +70,10 @@ internal fun ObjCExportCodeGeneratorBase.generateBlockToKotlinFunctionConverter(
|
||||
immutable = true
|
||||
)
|
||||
|
||||
return generateFunction(
|
||||
codegen,
|
||||
return functionGenerator(
|
||||
functionType(codegen.kObjHeaderPtr, false, int8TypePtr, codegen.kObjHeaderPtrPtr),
|
||||
"convertBlock${bridge.nameSuffix}"
|
||||
) {
|
||||
).generate {
|
||||
val blockPtr = param(0)
|
||||
ifThen(icmpEq(blockPtr, kNullInt8Ptr)) {
|
||||
ret(kNullObjHeaderPtr)
|
||||
@@ -235,7 +233,9 @@ internal class BlockGenerator(private val codegen: CodeGenerator) {
|
||||
invokeName: String,
|
||||
genBody: FunctionGenerationContext.(LLVMValueRef, List<LLVMValueRef>) -> Unit
|
||||
): ConstPointer {
|
||||
val result = generateFunction(codegen, blockType.blockInvokeLlvmType, invokeName, switchToRunnable = true) {
|
||||
val result = functionGenerator(blockType.blockInvokeLlvmType, invokeName) {
|
||||
switchToRunnable = true
|
||||
}.generate {
|
||||
val blockPtr = bitcast(pointerType(blockLiteralType), param(0))
|
||||
val kotlinObject = call(
|
||||
context.llvm.kRefSharedHolderRef,
|
||||
@@ -292,11 +292,10 @@ internal class BlockGenerator(private val codegen: CodeGenerator) {
|
||||
generateDescriptorForBlock(blockType)
|
||||
)
|
||||
|
||||
return generateFunction(
|
||||
codegen,
|
||||
return functionGenerator(
|
||||
functionType(int8TypePtr, false, codegen.kObjHeaderPtr),
|
||||
convertName
|
||||
) {
|
||||
).generate {
|
||||
val kotlinRef = param(0)
|
||||
ifThen(icmpEq(kotlinRef, kNullObjHeaderPtr)) {
|
||||
ret(kNullInt8Ptr)
|
||||
|
||||
+46
-16
@@ -47,6 +47,35 @@ internal fun TypeBridge.makeNothing() = when (this) {
|
||||
is ValueTypeBridge -> LLVMConstNull(this.objCValueType.llvmType)!!
|
||||
}
|
||||
|
||||
internal class ObjCExportFunctionGenerationContext(
|
||||
builder: ObjCExportFunctionGenerationContextBuilder
|
||||
) : FunctionGenerationContext(builder) {
|
||||
private val objCExportCodegen = builder.objCExportCodegen
|
||||
|
||||
}
|
||||
|
||||
internal class ObjCExportFunctionGenerationContextBuilder(
|
||||
functionType: LLVMTypeRef,
|
||||
functionName: String,
|
||||
val objCExportCodegen: ObjCExportCodeGeneratorBase
|
||||
) : FunctionGenerationContextBuilder<ObjCExportFunctionGenerationContext>(
|
||||
functionType,
|
||||
functionName,
|
||||
objCExportCodegen.codegen
|
||||
) {
|
||||
override fun build() = ObjCExportFunctionGenerationContext(this)
|
||||
}
|
||||
|
||||
internal inline fun ObjCExportCodeGeneratorBase.functionGenerator(
|
||||
functionType: LLVMTypeRef,
|
||||
functionName: String,
|
||||
configure: ObjCExportFunctionGenerationContextBuilder.() -> Unit = {}
|
||||
): ObjCExportFunctionGenerationContextBuilder = ObjCExportFunctionGenerationContextBuilder(
|
||||
functionType,
|
||||
functionName,
|
||||
this
|
||||
).apply(configure)
|
||||
|
||||
internal open class ObjCExportCodeGeneratorBase(codegen: CodeGenerator) : ObjCCodeGenerator(codegen) {
|
||||
val symbols get() = context.ir.symbols
|
||||
val runtime get() = codegen.runtime
|
||||
@@ -637,7 +666,7 @@ private fun ObjCExportCodeGenerator.emitBoxConverter(
|
||||
val boxClass = boxClassSymbol.owner
|
||||
val name = "${boxClass.name}ToNSNumber"
|
||||
|
||||
val converter = generateFunction(codegen, kotlinToObjCFunctionType, name) {
|
||||
val converter = functionGenerator(kotlinToObjCFunctionType, name).generate {
|
||||
val unboxFunction = context.getUnboxFunction(boxClass).llvmFunction
|
||||
val kotlinValue = callFromBridge(
|
||||
unboxFunction,
|
||||
@@ -760,25 +789,24 @@ private fun ObjCExportCodeGenerator.emitCollectionConverters() {
|
||||
)
|
||||
}
|
||||
|
||||
private fun ObjCExportFunctionGenerationContextBuilder.setupBridgeDebugInfo() {
|
||||
val location = setupBridgeDebugInfo(this.objCExportCodegen.context, function)
|
||||
startLocation = location
|
||||
endLocation = location
|
||||
}
|
||||
|
||||
private inline fun ObjCExportCodeGenerator.generateObjCImpBy(
|
||||
methodBridge: MethodBridge,
|
||||
debugInfo: Boolean = false,
|
||||
genBody: FunctionGenerationContext.() -> Unit
|
||||
): LLVMValueRef {
|
||||
val result = addLlvmFunctionWithDefaultAttributes(
|
||||
context,
|
||||
context.llvmModule!!,
|
||||
"objc2kotlin",
|
||||
objCFunctionType(context, methodBridge)
|
||||
)
|
||||
val result = functionGenerator(objCFunctionType(context, methodBridge), "objc2kotlin") {
|
||||
if (debugInfo) {
|
||||
this.setupBridgeDebugInfo()
|
||||
}
|
||||
|
||||
val location = if (debugInfo) {
|
||||
setupBridgeDebugInfo(context, result)
|
||||
} else {
|
||||
null
|
||||
}
|
||||
|
||||
generateFunction(codegen, result, startLocation = location, endLocation = location, switchToRunnable = true) {
|
||||
switchToRunnable = true
|
||||
}.generate {
|
||||
genBody()
|
||||
}
|
||||
|
||||
@@ -1019,7 +1047,7 @@ private fun ObjCExportCodeGenerator.generateKotlinToObjCBridge(
|
||||
|
||||
val functionType = codegen.getLlvmFunctionType(irFunction)
|
||||
|
||||
val result = generateFunction(codegen, functionType, "kotlin2objc") {
|
||||
val result = functionGenerator(functionType, "kotlin2objc").generate {
|
||||
var errorOutPtr: LLVMValueRef? = null
|
||||
|
||||
val parameters = irFunction.allParameters.mapIndexed { index, parameterDescriptor ->
|
||||
@@ -1526,7 +1554,9 @@ private inline fun ObjCExportCodeGenerator.generateObjCToKotlinSyntheticGetter(
|
||||
MethodBridgeReceiver.Static, valueParameters = emptyList()
|
||||
)
|
||||
|
||||
val imp = generateFunction(codegen, objCFunctionType(context, methodBridge), "objc2kotlin", switchToRunnable = true) {
|
||||
val imp = functionGenerator(objCFunctionType(context, methodBridge), "objc2kotlin") {
|
||||
switchToRunnable = true
|
||||
}.generate {
|
||||
block()
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user