Make ExpressionCodegen a bit shorter in general

This commit is contained in:
pyos
2019-03-27 17:26:32 +01:00
committed by max-kammerer
parent 89cb31c387
commit 2356f72fd4
@@ -58,7 +58,7 @@ import org.jetbrains.org.objectweb.asm.Type
import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter
import java.util.*
sealed class ExpressionInfo()
sealed class ExpressionInfo
class LoopInfo(val loop: IrLoop, val continueLabel: Label, val breakLabel: Label) : ExpressionInfo()
@@ -106,7 +106,6 @@ class BlockInfo private constructor(val parent: BlockInfo?) {
class VariableInfo(val declaration: IrVariable, val index: Int, val type: Type, val startLabel: Label)
@Suppress("IMPLICIT_CAST_TO_ANY")
class ExpressionCodegen(
val irFunction: IrFunction,
val frame: IrFrameMap,
@@ -119,13 +118,19 @@ class ExpressionCodegen(
val typeMapper = classCodegen.typeMapper
val returnType = typeMapper.mapReturnType(irFunction.descriptor)
private val state = classCodegen.state
val state = classCodegen.state
private val fileEntry = classCodegen.context.psiSourceManager.getFileEntry(irFunction.fileParent)
private val sourceManager = classCodegen.context.psiSourceManager
override val frameMap: IrFrameMap
get() = frame
private val fileEntry = sourceManager.getFileEntry(irFunction.fileParent)
override val visitor: InstructionAdapter
get() = mv
override val inlineNameGenerator: NameGenerator = NameGenerator("${classCodegen.type.internalName}\$todo") // TODO
override var lastLineNumber: Int = -1
private val KotlinType.asmType: Type
get() = typeMapper.mapType(this)
@@ -174,6 +179,15 @@ class ExpressionCodegen(
}
}
fun gen(expression: IrElement, type: Type, data: BlockInfo): StackValue {
gen(expression, data).put(type, mv)
return onStack(type)
}
fun gen(expression: IrElement, data: BlockInfo): StackValue {
return expression.accept(this, data)
}
fun generate() {
mv.visitCode()
val startLabel = markNewLabel()
@@ -306,9 +320,7 @@ class ExpressionCodegen(
return expression.onStack
}
fun generateNewArray(
expression: IrCall, data: BlockInfo
): StackValue {
private fun generateNewArray(expression: IrCall, data: BlockInfo): StackValue {
val args = expression.descriptor.valueParameters
assert(args.size == 1 || args.size == 2) { "Unknown constructor called: " + args.size + " arguments" }
@@ -412,10 +424,6 @@ class ExpressionCodegen(
return coerceNotToUnit(callable.returnType, returnType, expression.type.toKotlinType())
}
override fun visitInstanceInitializerCall(expression: IrInstanceInitializerCall, data: BlockInfo): StackValue {
throw AssertionError("Instruction should've been lowered before code generation: ${expression.render()}")
}
override fun visitDelegatingConstructorCall(expression: IrDelegatingConstructorCall, data: BlockInfo): StackValue {
//HACK
StackValue.local(0, OBJECT_TYPE).put(OBJECT_TYPE, mv)
@@ -433,26 +441,10 @@ class ExpressionCodegen(
this.markLineNumber(startOffset = true)
}
val info = VariableInfo(
declaration,
index,
varType,
markNewLabel()
)
data.variables.add(info)
data.variables.add(VariableInfo(declaration, index, varType, markNewLabel()))
return none()
}
fun gen(expression: IrElement, type: Type, data: BlockInfo): StackValue {
gen(expression, data).put(type, mv)
return onStack(type)
}
fun gen(expression: IrElement, data: BlockInfo): StackValue {
return expression.accept(this, data)
}
override fun visitGetValue(expression: IrGetValue, data: BlockInfo): StackValue {
// Do not generate line number information for loads from compiler-generated
// temporary variables. They do not correspond to variable loads in user code.
@@ -501,7 +493,6 @@ class ExpressionCodegen(
return onStack(AsmTypes.UNIT_TYPE)
}
/**
* Returns true if the given constant value is the JVM's default value for the given type.
* See: https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-2.html#jvms-2.3
@@ -524,17 +515,15 @@ class ExpressionCodegen(
}
private fun findLocalIndex(irSymbol: IrSymbol): Int {
return frame.getIndex(irSymbol).apply {
if (this < 0) {
if (irFunction.dispatchReceiverParameter != null) {
(irFunction.parent as? IrClass)?.takeIf { it.thisReceiver?.symbol == irSymbol }?.let { return 0 }
}
throw AssertionError(
"Non-mapped local declaration: " +
"${if (irSymbol.isBound) irSymbol.owner.dump() else irSymbol.descriptor} \n in ${irFunction.dump()}"
)
}
val index = frame.getIndex(irSymbol)
if (index >= 0) {
return index
}
if (irFunction.dispatchReceiverParameter != null && (irFunction.parent as? IrClass)?.thisReceiver?.symbol == irSymbol) {
return 0
}
val dump = if (irSymbol.isBound) irSymbol.owner.dump() else irSymbol.descriptor.toString()
throw AssertionError("Non-mapped local declaration: $dump\n in ${irFunction.dump()}")
}
override fun visitSetVariable(expression: IrSetVariable, data: BlockInfo): StackValue {
@@ -550,9 +539,7 @@ class ExpressionCodegen(
override fun <T> visitConst(expression: IrConst<T>, data: BlockInfo): StackValue {
expression.markLineNumber(startOffset = true)
val value = expression.value
val type = expression.asmType
StackValue.constant(value, type).put(mv)
StackValue.constant(expression.value, expression.asmType).put(mv)
return expression.onStack
}
@@ -692,29 +679,15 @@ class ExpressionCodegen(
return none()
}
val actualReturn =
if (isNonLocalReturn) {
typeMapper.mapReturnType(owner.descriptor)
} else {
returnType
}
expression.value.apply {
gen(this, actualReturn, data)
}
val returnType = typeMapper.mapReturnType(owner.descriptor)
val afterReturnLabel = Label()
generateFinallyBlocksIfNeeded(actualReturn, afterReturnLabel, data)
gen(expression.value, returnType, data)
generateFinallyBlocksIfNeeded(returnType, afterReturnLabel, data)
expression.markLineNumber(startOffset = true)
if (isNonLocalReturn) {
val nonLocalReturnType = typeMapper.mapReturnType(owner.descriptor)
val labelName = (owner as IrFunction).name.asString()
generateGlobalReturnFlag(mv, labelName)
mv.areturn(nonLocalReturnType)
} else {
mv.areturn(actualReturn)
generateGlobalReturnFlag(mv, (owner as IrFunction).name.asString())
}
mv.areturn(returnType)
mv.mark(afterReturnLabel)
mv.nop()/*TODO check RESTORE_STACK_IN_TRY_CATCH processor*/
return expression.onStack
@@ -726,12 +699,11 @@ class ExpressionCodegen(
val type = expression.type.toKotlinType()
val endLabel = Label()
var exhaustive = false
for (branch in expression.branches) {
val elseLabel = Label()
if (branch.condition.isFalseConst() || branch.condition.isTrueConst()) {
// True or false conditions known at compile time need not be generated. A linenumber and nop are still required
// for a debugger to break on the line of the condition.
// True or false conditions known at compile time need not be generated. A linenumber and nop
// are still required for a debugger to break on the line of the condition.
if (branch !is IrElseBranch) {
branch.condition.markLineNumber(startOffset = true)
mv.nop()
@@ -741,27 +713,20 @@ class ExpressionCodegen(
} else {
genConditionalJumpWithOptimizationsIfPossible(branch.condition, data, elseLabel)
}
gen(branch.result, data).let {
coerceNotToUnit(it.type, it.kotlinType, type)
}
val result = gen(branch.result, data).coerce(type)
if (branch.condition.isTrueConst()) {
exhaustive = true
break // The rest of the expression is dead code.
// The rest of the expression is dead code.
mv.mark(endLabel)
return result
}
mv.goTo(endLabel)
mv.mark(elseLabel)
}
if (!exhaustive) {
// TODO: make all non-exhaustive `if`/`when` return Nothing.
if (type.isUnit())
putUnitInstance(mv)
else if (!type.isNothing())
throw AssertionError("non-exhaustive `if`/`when` wants to return $type")
}
// Produce the default value for the type. Doesn't really matter right now, as non-exhaustive
// conditionals cannot be used as expressions.
val result = none().coerce(type)
mv.mark(endLabel)
return if (type.isNothing()) none() else expression.onStack
return result
}
private fun genConditionalJumpWithOptimizationsIfPossible(
@@ -783,12 +748,13 @@ class ExpressionCodegen(
// Do not materialize null constants to check for null. Instead use the JVM bytecode
// ifnull and ifnonnull instructions.
if (isNullCheck(condition)) {
val call = condition as IrCall
val left = call.getValueArgument(0)!!
val right = call.getValueArgument(1)!!
val other = if (left.isNullConst()) right else left
gen(other, data).put(other.asmType, mv)
if (condition is IrCall
&& condition.symbol == classCodegen.context.irBuiltIns.eqeqSymbol
&& (condition.getValueArgument(0)!!.isNullConst() || condition.getValueArgument(1)!!.isNullConst())
) {
val left = condition.getValueArgument(0)!!
val right = condition.getValueArgument(1)!!
gen(if (left.isNullConst()) right else left, data)
if (jumpIfFalse) {
mv.ifnonnull(jumpToLabel)
} else {
@@ -819,23 +785,14 @@ class ExpressionCodegen(
gen(condition.argument, OBJECT_TYPE, data)
val type = boxType(asmType)
generateIsCheck(mv, condition.typeOperand.toKotlinType(), type, state.languageVersionSettings.isReleaseCoroutines())
val stackValue =
if (condition.operator == IrTypeOperator.INSTANCEOF)
onStack(Type.BOOLEAN_TYPE)
else
StackValue.not(onStack(Type.BOOLEAN_TYPE))
BranchedValue.condJump(stackValue, jumpToLabel, jumpIfFalse, mv)
if (condition.operator == IrTypeOperator.NOT_INSTANCEOF) {
jumpIfFalse = !jumpIfFalse
}
BranchedValue.condJump(onStack(Type.BOOLEAN_TYPE), jumpToLabel, jumpIfFalse, mv)
return
}
gen(condition, data).put(condition.asmType, mv)
BranchedValue.condJump(onStack(condition.asmType), jumpToLabel, jumpIfFalse, mv)
}
private fun isNullCheck(expression: IrExpression): Boolean {
return expression is IrCall
&& expression.symbol == classCodegen.context.irBuiltIns.eqeqSymbol
&& (expression.getValueArgument(0)!!.isNullConst() || expression.getValueArgument(1)!!.isNullConst())
BranchedValue.condJump(gen(condition, data), jumpToLabel, jumpIfFalse, mv)
}
override fun visitTypeOperator(expression: IrTypeOperatorCall, data: BlockInfo): StackValue {
@@ -1253,7 +1210,7 @@ class ExpressionCodegen(
}
}
internal fun getOrCreateCallGenerator(
private fun getOrCreateCallGenerator(
memberAccessExpression: IrMemberAccessExpression,
descriptor: CallableDescriptor,
data: BlockInfo
@@ -1293,14 +1250,6 @@ class ExpressionCodegen(
return getOrCreateCallGenerator(descriptor, memberAccessExpression, mappings, false, data)
}
override val frameMap: IrFrameMap
get() = frame
override val visitor: InstructionAdapter
get() = mv
override val inlineNameGenerator: NameGenerator = NameGenerator("${classCodegen.type.internalName}\$todo")
override var lastLineNumber: Int = -1
override fun consumeReifiedOperationMarker(typeParameterDescriptor: TypeParameterDescriptor) {
//TODO
}