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