Skip to content

Commit

Permalink
Reincarnated devirtualization
Browse files Browse the repository at this point in the history
  • Loading branch information
homuroll committed Mar 21, 2019
1 parent 553e2fd commit 7c0225b
Show file tree
Hide file tree
Showing 13 changed files with 175 additions and 335 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ import org.jetbrains.kotlin.backend.konan.library.KonanLibraryWriter
import org.jetbrains.kotlin.backend.konan.library.LinkData
import org.jetbrains.kotlin.backend.konan.llvm.*
import org.jetbrains.kotlin.backend.konan.lower.DECLARATION_ORIGIN_BRIDGE_METHOD
import org.jetbrains.kotlin.backend.konan.optimizations.DataFlowIR
import org.jetbrains.kotlin.backend.konan.optimizations.Devirtualization
import org.jetbrains.kotlin.backend.konan.optimizations.ExternalModulesDFG
import org.jetbrains.kotlin.backend.konan.optimizations.ModuleDFG
Expand Down Expand Up @@ -321,9 +320,6 @@ internal class Context(config: KonanConfig) : KonanBackendContext(config) {

val coverage = CoverageManager(this)

lateinit var privateFunctions: List<Pair<IrFunction, DataFlowIR.FunctionSymbol.Declared>>
lateinit var privateClasses: List<Pair<IrClass, DataFlowIR.Type.Declared>>

// Cache used for source offset->(line,column) mapping.
val fileEntryCache = mutableMapOf<String, SourceManager.FileEntry>()

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -268,6 +268,8 @@ internal val bitcodePhase = namedIrModulePhase(
lower = contextLLVMSetupPhase then
RTTIPhase then
generateDebugInfoHeaderPhase then
buildDFGPhase then
serializeDFGPhase then
deserializeDFGPhase then
devirtualizationPhase then
escapeAnalysisPhase then
Expand Down Expand Up @@ -295,8 +297,6 @@ internal val toplevelPhase = namedUnitPhase(
dependenciesLowerPhase then // Then lower all libraries in topological order.
// With that we guarantee that inline functions are unlowered while being inlined.
moduleIndexForCodegenPhase then
buildDFGPhase then
serializeDFGPhase then
bitcodePhase then
produceOutputPhase then
verifyBitcodePhase then
Expand All @@ -309,9 +309,7 @@ internal val toplevelPhase = namedUnitPhase(
internal fun PhaseConfig.konanPhasesConfig(config: KonanConfig) {
with(config.configuration) {
disable(compileTimeEvaluatePhase)
disable(buildDFGPhase)
disable(deserializeDFGPhase)
disable(devirtualizationPhase)
disable(escapeAnalysisPhase)
disable(serializeDFGPhase)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -384,6 +384,8 @@ internal class KonanSymbols(context: Context, val symbolTable: SymbolTable, val

val returnIfSuspended = internalFunction("returnIfSuspended")

val coroutineLaunchpad = internalFunction("coroutineLaunchpad")

val konanSuspendCoroutineUninterceptedOrReturn = internalFunction("suspendCoroutineUninterceptedOrReturn")

val konanCoroutineContextGetter = internalFunction("getCoroutineContext")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,8 @@
package org.jetbrains.kotlin.backend.konan.ir

import org.jetbrains.kotlin.backend.konan.SYNTHETIC_OFFSET
import org.jetbrains.kotlin.backend.konan.optimizations.DataFlowIR
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor
import org.jetbrains.kotlin.ir.IrStatement
import org.jetbrains.kotlin.ir.SourceManager
import org.jetbrains.kotlin.ir.SourceManager.FileEntry
import org.jetbrains.kotlin.ir.SourceRangeInfo
Expand All @@ -18,14 +16,7 @@ import org.jetbrains.kotlin.ir.declarations.IrDeclaration
import org.jetbrains.kotlin.ir.declarations.IrFile
import org.jetbrains.kotlin.ir.declarations.MetadataSource
import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.expressions.impl.IrContainerExpressionBase
import org.jetbrains.kotlin.ir.expressions.impl.IrExpressionBase
import org.jetbrains.kotlin.ir.expressions.impl.IrTerminalDeclarationReferenceBase
import org.jetbrains.kotlin.ir.symbols.IrClassifierSymbol
import org.jetbrains.kotlin.ir.symbols.IrFileSymbol
import org.jetbrains.kotlin.ir.symbols.IrReturnableBlockSymbol
import org.jetbrains.kotlin.ir.symbols.impl.IrReturnableBlockSymbolImpl
import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.ir.symbols.*
import org.jetbrains.kotlin.ir.visitors.IrElementTransformer
import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
import org.jetbrains.kotlin.konan.file.File
Expand Down Expand Up @@ -131,91 +122,4 @@ class IrFileImpl(entry: SourceManager.FileEntry) : IrFile {
override fun <R, D> accept(visitor: IrElementVisitor<R, D>, data: D): R {
TODO("not implemented")
}
}

//-----------------------------------------------------------------------------//

internal interface IrPrivateFunctionCall : IrExpression {
val valueArgumentsCount: Int
fun getValueArgument(index: Int): IrExpression?
fun putValueArgument(index: Int, valueArgument: IrExpression?)
fun removeValueArgument(index: Int)

val virtualCallee: IrCall?
val dfgSymbol: DataFlowIR.FunctionSymbol.Declared
val moduleDescriptor: ModuleDescriptor
val totalFunctions: Int
val functionIndex: Int
}

internal class IrPrivateFunctionCallImpl(startOffset: Int,
endOffset: Int,
type: IrType,
override val valueArgumentsCount: Int,
override val virtualCallee: IrCall?,
override val dfgSymbol: DataFlowIR.FunctionSymbol.Declared,
override val moduleDescriptor: ModuleDescriptor,
override val totalFunctions: Int,
override val functionIndex: Int
) : IrPrivateFunctionCall, IrExpressionBase(startOffset, endOffset, type) {

override fun <R, D> accept(visitor: IrElementVisitor<R, D>, data: D): R {
return visitor.visitExpression(this, data)
}

private val argumentsByParameterIndex: Array<IrExpression?> = arrayOfNulls(valueArgumentsCount)

override fun getValueArgument(index: Int): IrExpression? {
if (index >= valueArgumentsCount) {
throw AssertionError("$this: No such value argument slot: $index")
}
return argumentsByParameterIndex[index]
}

override fun putValueArgument(index: Int, valueArgument: IrExpression?) {
if (index >= valueArgumentsCount) {
throw AssertionError("$this: No such value argument slot: $index")
}
argumentsByParameterIndex[index] = valueArgument
}

override fun removeValueArgument(index: Int) {
argumentsByParameterIndex[index] = null
}

override fun <D> acceptChildren(visitor: IrElementVisitor<Unit, D>, data: D) {
argumentsByParameterIndex.forEach { it?.accept(visitor, data) }
}

override fun <D> transformChildren(transformer: IrElementTransformer<D>, data: D) {
argumentsByParameterIndex.forEachIndexed { i, irExpression ->
argumentsByParameterIndex[i] = irExpression?.transform(transformer, data)
}
}
}

internal interface IrPrivateClassReference : IrClassReference {
val moduleDescriptor: ModuleDescriptor
val totalClasses: Int
val classIndex: Int
val dfgSymbol: DataFlowIR.Type.Declared
}

internal class IrPrivateClassReferenceImpl(startOffset: Int,
endOffset: Int,
type: IrType,
symbol: IrClassifierSymbol,
override val classType: IrType,
override val moduleDescriptor: ModuleDescriptor,
override val totalClasses: Int,
override val classIndex: Int,
override val dfgSymbol: DataFlowIR.Type.Declared
) : IrPrivateClassReference,
IrTerminalDeclarationReferenceBase<IrClassifierSymbol, ClassifierDescriptor>(
startOffset, endOffset, type,
symbol, symbol.descriptor
)
{
override fun <R, D> accept(visitor: IrElementVisitor<R, D>, data: D): R =
visitor.visitClassReference(this, data)
}
Original file line number Diff line number Diff line change
Expand Up @@ -63,38 +63,11 @@ internal val deserializeDFGPhase = makeKonanModuleOpPhase(
internal val devirtualizationPhase = makeKonanModuleOpPhase(
name = "Devirtualization",
description = "Devirtualization",
prerequisite = setOf(buildDFGPhase, deserializeDFGPhase),
prerequisite = setOf(buildDFGPhase),
op = { context, irModule ->
context.externalModulesDFG?.let { externalModulesDFG ->
context.devirtualizationAnalysisResult = Devirtualization.run(
irModule, context, context.moduleDFG!!, externalModulesDFG
)

val privateFunctions = context.moduleDFG!!.symbolTable.getPrivateFunctionsTableForExport()
privateFunctions.forEachIndexed { index, it ->
val function = context.codegenVisitor.codegen.llvmFunction(it.first)
LLVMAddAlias(
context.llvmModule,
function.type,
function,
irModule.descriptor.privateFunctionSymbolName(index, it.second.name)
)!!
}
context.privateFunctions = privateFunctions

val privateClasses = context.moduleDFG!!.symbolTable.getPrivateClassesTableForExport()

privateClasses.forEachIndexed { index, it ->
val typeInfoPtr = context.codegenVisitor.codegen.typeInfoValue(it.first)
LLVMAddAlias(
context.llvmModule,
typeInfoPtr.type,
typeInfoPtr,
irModule.descriptor.privateClassSymbolName(index, it.second.name)
)!!
}
context.privateClasses = privateClasses
}
context.devirtualizationAnalysisResult = Devirtualization.run(
irModule, context, context.moduleDFG!!, ExternalModulesDFG(emptyList(), emptyMap(), emptyMap(), emptyMap())
)
}
)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,15 @@ import llvm.*
import org.jetbrains.kotlin.backend.konan.descriptors.TypedIntrinsic
import org.jetbrains.kotlin.backend.konan.descriptors.isTypedIntrinsic
import org.jetbrains.kotlin.backend.konan.llvm.objc.genObjCSelector
import org.jetbrains.kotlin.backend.konan.ir.isSuspend
import org.jetbrains.kotlin.backend.konan.reportCompilationError
import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.declarations.IrClass
import org.jetbrains.kotlin.ir.declarations.IrConstructor
import org.jetbrains.kotlin.ir.declarations.IrFunction
import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.types.getClass
import org.jetbrains.kotlin.ir.util.dump
import org.jetbrains.kotlin.name.Name

internal enum class IntrinsicType {
Expand Down Expand Up @@ -64,6 +67,7 @@ internal enum class IntrinsicType {
// Coroutines
GET_CONTINUATION,
RETURN_IF_SUSPEND,
COROUTINE_LAUNCHPAD,
// Interop
INTEROP_READ_BITS,
INTEROP_WRITE_BITS,
Expand Down Expand Up @@ -98,7 +102,7 @@ internal interface IntrinsicGeneratorEnvironment {

fun calculateLifetime(element: IrElement): Lifetime

fun evaluateCall(function: IrFunction, args: List<LLVMValueRef>, resultLifetime: Lifetime): LLVMValueRef
fun evaluateCall(function: IrFunction, args: List<LLVMValueRef>, resultLifetime: Lifetime, superClass: IrClass? = null): LLVMValueRef

fun evaluateExplicitArgs(expression: IrMemberAccessExpression): List<LLVMValueRef>

Expand Down Expand Up @@ -155,16 +159,26 @@ internal class IntrinsicGenerator(private val environment: IntrinsicGeneratorEnv
environment.functionGenerationContext.genObjCSelector(selector)
}
IntrinsicType.INIT_INSTANCE -> {
val callee = callSite as IrCall
val initializer = callee.getValueArgument(1) as IrCall
val thiz = environment.evaluateExpression(callee.getValueArgument(0)!!)
val initializer = callSite.getValueArgument(1) as IrCall
val thiz = environment.evaluateExpression(callSite.getValueArgument(0)!!)
environment.evaluateCall(
initializer.symbol.owner,
listOf(thiz) + environment.evaluateExplicitArgs(initializer),
environment.calculateLifetime(initializer)
)
codegen.theUnitInstanceRef.llvm
}
IntrinsicType.COROUTINE_LAUNCHPAD -> {
val suspendFunctionCall = callSite.getValueArgument(0) as IrCall
val continuation = environment.evaluateExpression(callSite.getValueArgument(1)!!)
val suspendFunction = suspendFunctionCall.symbol.owner
assert(suspendFunction.isSuspend) { "Call to a suspend function expected but was ${suspendFunction.dump()}" }
environment.evaluateCall(suspendFunction,
environment.evaluateExplicitArgs(suspendFunctionCall) + listOf(continuation),
environment.calculateLifetime(suspendFunctionCall),
suspendFunction.parent as? IrClass // Call non-virtually.
)
}
else -> null
}
}
Expand Down Expand Up @@ -238,6 +252,7 @@ internal class IntrinsicGenerator(private val environment: IntrinsicGeneratorEnv
reportNonLoweredIntrinsic(intrinsicType)
IntrinsicType.INIT_INSTANCE,
IntrinsicType.OBJC_INIT_BY,
IntrinsicType.COROUTINE_LAUNCHPAD,
IntrinsicType.OBJC_GET_SELECTOR,
IntrinsicType.IMMUTABLE_BLOB ->
reportSpecialIntrinsic(intrinsicType)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ import org.jetbrains.kotlin.backend.konan.*
import org.jetbrains.kotlin.backend.konan.descriptors.*
import org.jetbrains.kotlin.backend.konan.ir.*
import org.jetbrains.kotlin.backend.konan.llvm.coverage.*
import org.jetbrains.kotlin.backend.konan.objcexport.ObjCExport
import org.jetbrains.kotlin.backend.konan.optimizations.*
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.builtins.UnsignedType
Expand Down Expand Up @@ -220,8 +219,8 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
override val exceptionHandler: ExceptionHandler
get() = currentCodeContext.exceptionHandler

override fun evaluateCall(function: IrFunction, args: List<LLVMValueRef>, resultLifetime: Lifetime): LLVMValueRef =
evaluateSimpleFunctionCall(function, args, resultLifetime)
override fun evaluateCall(function: IrFunction, args: List<LLVMValueRef>, resultLifetime: Lifetime, superClass: IrClass?) =
evaluateSimpleFunctionCall(function, args, resultLifetime, superClass)

override fun evaluateExplicitArgs(expression: IrMemberAccessExpression): List<LLVMValueRef> =
this@CodeGeneratorVisitor.evaluateExplicitArgs(expression)
Expand Down Expand Up @@ -794,9 +793,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
is IrSuspendableExpression ->
return evaluateSuspendableExpression (value)
is IrSuspensionPoint -> return evaluateSuspensionPoint (value)
is IrPrivateFunctionCall -> return evaluatePrivateFunctionCall (value)
is IrPrivateClassReference ->
return evaluatePrivateClassReference (value)
is IrClassReference -> return evaluateClassReference (value)
else -> {
TODO(ir2string(value))
}
Expand Down Expand Up @@ -2017,42 +2014,8 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE

//-------------------------------------------------------------------------//

private fun evaluatePrivateFunctionCall(callee: IrPrivateFunctionCall): LLVMValueRef {
val args = (0 until callee.valueArgumentsCount).map { index ->
callee.getValueArgument(index)?.let { evaluateExpression(it) }
?: run {
assert(index == callee.valueArgumentsCount - 1) { "Only last argument may be null - for suspend functions" }
getContinuation()
}
}
val dfgSymbol = callee.dfgSymbol
val functionIndex = callee.functionIndex
val function = if (callee.moduleDescriptor == context.irModule!!.descriptor) {
codegen.llvmFunction(context.privateFunctions[functionIndex].first)
} else {
context.llvm.externalFunction(
callee.moduleDescriptor.privateFunctionSymbolName(functionIndex, callee.dfgSymbol.name),
codegen.getLlvmFunctionType(dfgSymbol),
callee.moduleDescriptor.llvmSymbolOrigin

)
}
return call(dfgSymbol, function, args, resultLifetime = Lifetime.GLOBAL)
}

//-------------------------------------------------------------------------//

private fun evaluatePrivateClassReference(classReference: IrPrivateClassReference): LLVMValueRef {
val classIndex = classReference.classIndex
val typeInfoPtr = if (classReference.moduleDescriptor == context.irModule!!.descriptor) {
codegen.typeInfoValue(context.privateClasses[classIndex].first)
} else {
codegen.importGlobal(
classReference.moduleDescriptor.privateClassSymbolName(classIndex, classReference.dfgSymbol.name),
codegen.kTypeInfo,
classReference.moduleDescriptor.llvmSymbolOrigin
)
}
private fun evaluateClassReference(classReference: IrClassReference): LLVMValueRef {
val typeInfoPtr = codegen.typeInfoValue(classReference.symbol.owner as IrClass)
return functionGenerationContext.bitcast(int8TypePtr, typeInfoPtr)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -479,11 +479,32 @@ internal class ModuleDFGBuilder(val context: Context, val irModule: IrModuleFrag
)
}

private fun IrType.erasure(): IrType {
if (this !is IrSimpleType) return this

val classifier = this.classifier
return when (classifier) {
is IrClassSymbol -> this
is IrTypeParameterSymbol -> {
val upperBound = classifier.owner.superTypes.singleOrNull() ?:
TODO("${classifier.descriptor} : ${classifier.descriptor.upperBounds}")

if (this.hasQuestionMark) {
// `T?`
upperBound.erasure().makeNullable()
} else {
upperBound.erasure()
}
}
else -> TODO(classifier.toString())
}
}

private fun expressionToEdge(expression: IrExpression) =
if (expression is IrTypeOperatorCall && expression.operator.isCast())
DataFlowIR.Edge(
getNode(expression.argument),
symbolTable.mapClassReferenceType(expression.typeOperand.getClass()!!)
symbolTable.mapClassReferenceType(expression.typeOperand.erasure().getClass()!!)
)
else DataFlowIR.Edge(getNode(expression), null)

Expand Down
Loading

0 comments on commit 7c0225b

Please sign in to comment.