moved initilizers lowering from code generation to lowering phase (#219)

* moved initilizers lowering from code generation to lowering phase

* bug fix

* bug fix

* permuted phases

* supported KFunction
This commit is contained in:
Igor Chevdar
2017-02-07 15:00:12 +05:00
committed by GitHub
parent 80587b65ee
commit a127f0f1ef
6 changed files with 146 additions and 106 deletions
@@ -49,6 +49,9 @@ internal class KonanLower(val context: Context) {
phaser.phase(KonanPhase.LOWER_INNER_CLASSES) {
InnerClassLowering(context).runOnFilePostfix(irFile)
}
phaser.phase(KonanPhase.LOWER_INITIALIZERS) {
InitializersLowering(context).runOnFilePostfix(irFile)
}
phaser.phase(KonanPhase.LOWER_CALLABLES) {
CallableReferenceLowering(context).runOnFilePostfix(irFile)
}
@@ -23,6 +23,7 @@ enum class KonanPhase(val description: String,
/* ... ... */ LOWER_ENUMS("Enum classes lowering"),
/* ... ... */ LOWER_INNER_CLASSES("Inner classes lowering"),
/* ... ... */ LOWER_STRING_CONCAT("String concatenation lowering"),
/* ... ... */ LOWER_INITIALIZERS("Initializers lowering"),
/* ... */ BITCODE("LLVM BitCode Generation"),
/* ... ... */ RTTI("RTTI Generation"),
/* ... ... */ CODEGEN("Code Generation"),
@@ -5,6 +5,8 @@ import org.jetbrains.kotlin.backend.konan.ValueType
import org.jetbrains.kotlin.backend.konan.isRepresentedAs
import org.jetbrains.kotlin.backend.konan.llvm.functionName
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.builtins.functions.FunctionClassDescriptor
import org.jetbrains.kotlin.builtins.getFunctionalClassKind
import org.jetbrains.kotlin.builtins.isFunctionType
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.annotations.Annotations
@@ -140,9 +142,22 @@ internal val CallableDescriptor.allValueParameters: List<ParameterDescriptor>
return receivers + this.valueParameters
}
internal val KotlinType.isFunctionOrKFunctionType: Boolean
get() {
val kind = constructor.declarationDescriptor?.getFunctionalClassKind()
return kind == FunctionClassDescriptor.Kind.Function || kind == FunctionClassDescriptor.Kind.KFunction
}
internal val KotlinType.isKFunctionType: Boolean
get() {
val kind = constructor.declarationDescriptor?.getFunctionalClassKind()
return kind == FunctionClassDescriptor.Kind.KFunction
}
internal val FunctionDescriptor.isFunctionInvoke: Boolean
get() {
val dispatchReceiver = dispatchReceiverParameter ?: return false
assert (!dispatchReceiver.type.isKFunctionType)
return dispatchReceiver.type.isFunctionType &&
this.isOperator && this.name == OperatorNameConventions.INVOKE
@@ -352,78 +352,25 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
//-------------------------------------------------------------------------//
override fun visitConstructor(constructorDeclaration: IrConstructor) {
context.log("visitConstructor : ${ir2string(constructorDeclaration)}")
if (constructorDeclaration.descriptor.containingDeclaration.isIntrinsic) {
// Do not generate any ctors for intrinsic classes.
return
}
codegen.prologue(constructorDeclaration.descriptor)
val constructorDescriptor = constructorDeclaration.descriptor
val classDescriptor = constructorDescriptor.constructedClass
if (constructorDescriptor.isPrimary) {
if (DescriptorUtils.isObject(classDescriptor)) {
if (!classDescriptor.isUnit()) {
val objectPtr = objectPtrByName(classDescriptor)
using(FunctionScope(constructorDeclaration)) {
val thisPtr = currentCodeContext.genGetValue(classDescriptor.thisAsReceiverParameter)
/**
* IR for kotlin.Any is:
* BLOCK_BODY
* DELEGATING_CONSTRUCTOR_CALL 'constructor Any()'
* INSTANCE_INITIALIZER_CALL classDescriptor='Any'
*
* to avoid possible recursion we manually reject body generation for Any.
*/
if (!skipConstructorBodyGeneration(constructorDeclaration)) {
constructorDeclaration.body?.let {
generateBody(it)
LLVMSetInitializer(objectPtr, codegen.kNullObjHeaderPtr)
}
}
if (constructorDescriptor.isPrimary) {
if (DescriptorUtils.isObject(classDescriptor)) {
if (!classDescriptor.isUnit()) {
val objectPtr = objectPtrByName(classDescriptor)
LLVMSetInitializer(objectPtr, codegen.kNullObjHeaderPtr)
}
}
val irOfCurrentClass = context.ir.moduleIndexForCodegen.classes[classDescriptor]
irOfCurrentClass!!.acceptChildrenVoid(object : IrElementVisitorVoid {
override fun visitElement(element: IrElement) {
element.acceptChildrenVoid(this)
}
override fun visitField(fieldDeclaration: IrField) {
val fieldDescriptor = fieldDeclaration.descriptor
fieldDeclaration.initializer?.let {
val value = evaluateExpression(it.expression)
val fieldPtr = fieldPtrOfClass(thisPtr, fieldDescriptor)
codegen.storeAnyGlobal(value, fieldPtr)
}
}
override fun visitAnonymousInitializer(declaration: IrAnonymousInitializer) {
generateBlockBody(declaration.body)
}
override fun visitClass(declaration: IrClass) {
return
}
override fun visitConstructor(declaration: IrConstructor) {
return
}
})
}
}
codegen.ret(null)
codegen.epilogue()
context.log("visitConstructor : ${ir2string(constructorDeclaration)}")
visitFunction(constructorDeclaration)
}
//-------------------------------------------------------------------------//
@@ -434,25 +381,6 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
//-------------------------------------------------------------------------//
private fun generateBlockBody(body: IrBlockBody) {
using(VariableScope()) {
body.statements.forEach {
generateStatement(it)
}
// TODO: write it properly!
if (codegen.constructedClass == null && !codegen.isAfterTerminator()) {
if (codegen.returnType == voidType) {
codegen.ret(null)
} else {
codegen.unreachable()
}
}
}
context.log("generateBlockBody : ${ir2string(body)}")
}
//-------------------------------------------------------------------------//
/**
* The scope of variable visibility.
*/
@@ -559,14 +487,29 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
override fun visitFunction(declaration: IrFunction) {
context.log("visitFunction : ${ir2string(declaration)}")
val body = declaration.body
if (declaration.descriptor.modality == Modality.ABSTRACT || body == null)
return
if (declaration.descriptor.modality == Modality.ABSTRACT || declaration.descriptor.isExternal || body == null)
return
codegen.prologue(declaration.descriptor)
using(FunctionScope(declaration)) {
generateBody(body)
using(VariableScope()) {
context.log("generateBlockBody : ${ir2string(body)}")
when (body) {
is IrBlockBody -> body.statements.forEach { generateStatement(it) }
is IrExpressionBody -> generateStatement(body.expression)
is IrSyntheticBody -> throw AssertionError("Synthetic body ${body.kind} has not been lowered")
else -> TODO(ir2string(body))
}
}
}
if (!codegen.isAfterTerminator()) {
if (codegen.returnType == voidType)
codegen.ret(null)
else
codegen.unreachable()
}
codegen.epilogue()
@@ -665,13 +608,6 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
private fun IrStatement.generate() = generateStatement(this)
private fun generateBody(body: IrBody) {
when (body) {
is IrBlockBody -> generateBlockBody(body)
else -> TODO(ir2string(body))
}
}
//-------------------------------------------------------------------------//
private fun evaluateGetObjectValue(value: IrGetObjectValue): LLVMValueRef {
@@ -1895,22 +1831,6 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
//-------------------------------------------------------------------------//
private fun skipConstructorBodyGeneration(declaration: IrConstructor): Boolean {
var skipBody = false
declaration.acceptChildrenVoid(object : IrElementVisitorVoid {
override fun visitElement(element: IrElement) {
element.acceptChildrenVoid(this)
}
override fun visitDelegatingConstructorCall(expression: IrDelegatingConstructorCall) {
skipBody = expression.descriptor == declaration.descriptor
}
})
return skipBody
}
//-------------------------------------------------------------------------//
fun appendLlvmUsed(args: List<LLVMValueRef>) {
if (args.isEmpty()) return
@@ -5,6 +5,7 @@ import org.jetbrains.kotlin.backend.common.lower.createIrBuilder
import org.jetbrains.kotlin.backend.konan.*
import org.jetbrains.kotlin.backend.konan.descriptors.*
import org.jetbrains.kotlin.backend.konan.ir.*
import org.jetbrains.kotlin.builtins.getFunctionalClassKind
import org.jetbrains.kotlin.builtins.isFunctionType
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.annotations.Annotations
@@ -86,7 +87,7 @@ private class CallableReferencesUnbinder(val lower: CallableReferenceLowering,
}
override fun visitCallableReference(expression: IrCallableReference): IrExpression {
assert (expression.type.isFunctionType)
assert (expression.type.isFunctionOrKFunctionType)
val descriptor = expression.descriptor
val boundArgs = expression.getArguments()
@@ -0,0 +1,100 @@
package org.jetbrains.kotlin.backend.konan.lower
import org.jetbrains.kotlin.backend.common.ClassLoweringPass
import org.jetbrains.kotlin.backend.konan.Context
import org.jetbrains.kotlin.ir.IrStatement
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.declarations.impl.IrFieldImpl
import org.jetbrains.kotlin.ir.expressions.IrBlockBody
import org.jetbrains.kotlin.ir.expressions.IrDelegatingConstructorCall
import org.jetbrains.kotlin.ir.expressions.IrInstanceInitializerCall
import org.jetbrains.kotlin.ir.expressions.IrStatementOriginImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrBlockImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrGetValueImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrSetFieldImpl
import org.jetbrains.kotlin.ir.util.transformFlat
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
internal class InitializersLowering(val context: Context) : ClassLoweringPass {
override fun lower(irClass: IrClass) {
InitializersTransformer(irClass).lowerInitializers()
}
private inner class InitializersTransformer(val irClass: IrClass) {
val fieldInitializers = mutableListOf<IrStatement>()
val initializers = mutableListOf<IrStatement>()
fun lowerInitializers() {
collectAndRemoveInitializers()
lowerConstructors()
}
object STATEMENT_ORIGIN_ANONYMOUS_INITIALIZER :
IrStatementOriginImpl("ANONYMOUS_INITIALIZER")
private fun collectAndRemoveInitializers() {
irClass.transformChildrenVoid(object : IrElementTransformerVoid() {
override fun visitClass(declaration: IrClass): IrStatement {
// Skip nested.
return declaration
}
override fun visitField(declaration: IrField): IrStatement {
val initializer = declaration.initializer ?: return declaration
val propertyDescriptor = declaration.descriptor
val startOffset = initializer.startOffset
val endOffset = initializer.endOffset
fieldInitializers.add(IrBlockImpl(startOffset, endOffset, context.builtIns.unitType, STATEMENT_ORIGIN_ANONYMOUS_INITIALIZER,
listOf(
IrSetFieldImpl(startOffset, endOffset, propertyDescriptor,
IrGetValueImpl(startOffset, endOffset, irClass.descriptor.thisAsReceiverParameter),
initializer.expression, STATEMENT_ORIGIN_ANONYMOUS_INITIALIZER))))
return IrFieldImpl(declaration.startOffset, declaration.endOffset, declaration.origin, propertyDescriptor)
}
})
irClass.declarations.transformFlat {
if (it !is IrAnonymousInitializer)
null
else {
initializers.add(IrBlockImpl(it.startOffset, it.endOffset,
context.builtIns.unitType, STATEMENT_ORIGIN_ANONYMOUS_INITIALIZER, it.body.statements))
listOf()
}
}
}
private fun lowerConstructors() {
irClass.transformChildrenVoid(object : IrElementTransformerVoid() {
override fun visitClass(declaration: IrClass): IrStatement {
// Skip nested.
return declaration
}
override fun visitConstructor(declaration: IrConstructor): IrStatement {
val blockBody = declaration.body as? IrBlockBody ?: throw AssertionError("Unexpected constructor body: ${declaration.body}")
blockBody.statements.transformFlat {
when {
it is IrInstanceInitializerCall -> fieldInitializers + initializers
/**
* IR for kotlin.Any is:
* BLOCK_BODY
* DELEGATING_CONSTRUCTOR_CALL 'constructor Any()'
* INSTANCE_INITIALIZER_CALL classDescriptor='Any'
*
* to avoid possible recursion we manually reject body generation for Any.
*/
it is IrDelegatingConstructorCall && irClass.descriptor == context.builtIns.any
&& it.descriptor == declaration.descriptor -> listOf()
else -> null
}
}
return declaration
}
})
}
}
}