Store InstructionAdapter, not ExpressionCodegen, in PromisedValue

This commit is contained in:
pyos
2019-04-05 10:13:20 +02:00
committed by max-kammerer
parent 96e2eb6fa1
commit 73bd683af1
7 changed files with 41 additions and 40 deletions
@@ -143,7 +143,7 @@ class ExpressionCodegen(
// Assume this expression's result has already been materialized on the stack // Assume this expression's result has already been materialized on the stack
// with the correct type. // with the correct type.
val IrExpression.onStack: MaterialValue val IrExpression.onStack: MaterialValue
get() = MaterialValue(this@ExpressionCodegen, asmType) get() = MaterialValue(mv, asmType)
private fun markNewLabel() = Label().apply { mv.visitLabel(this) } private fun markNewLabel() = Label().apply { mv.visitLabel(this) }
@@ -392,9 +392,9 @@ class ExpressionCodegen(
return voidValue return voidValue
} else if (expression.type.isUnit()) { } else if (expression.type.isUnit()) {
// NewInference allows casting `() -> T` to `() -> Unit`. A CHECKCAST here will fail. // NewInference allows casting `() -> T` to `() -> Unit`. A CHECKCAST here will fail.
return MaterialValue(this, callable.returnType).discard().coerce(expression.asmType) return MaterialValue(mv, callable.returnType).discard().coerce(expression.asmType)
} }
return MaterialValue(this, callable.returnType).coerce(expression.asmType) return MaterialValue(mv, callable.returnType).coerce(expression.asmType)
} }
override fun visitVariable(declaration: IrVariable, data: BlockInfo): PromisedValue { override fun visitVariable(declaration: IrVariable, data: BlockInfo): PromisedValue {
@@ -442,7 +442,7 @@ class ExpressionCodegen(
isStatic -> mv.getstatic(ownerType, fieldName, fieldType.descriptor) isStatic -> mv.getstatic(ownerType, fieldName, fieldType.descriptor)
else -> mv.getfield(ownerType, fieldName, fieldType.descriptor) else -> mv.getfield(ownerType, fieldName, fieldType.descriptor)
} }
MaterialValue(this, fieldType).coerce(expression.asmType) MaterialValue(mv, fieldType).coerce(expression.asmType)
} }
} }
@@ -495,10 +495,10 @@ class ExpressionCodegen(
override fun <T> visitConst(expression: IrConst<T>, data: BlockInfo): PromisedValue { override fun <T> visitConst(expression: IrConst<T>, data: BlockInfo): PromisedValue {
expression.markLineNumber(startOffset = true) expression.markLineNumber(startOffset = true)
when (val value = expression.value) { when (val value = expression.value) {
is Boolean -> return object : BooleanValue(this) { is Boolean -> return object : BooleanValue(mv) {
override fun jumpIfFalse(target: Label) = if (value) Unit else codegen.mv.goTo(target) override fun jumpIfFalse(target: Label) = if (value) Unit else mv.goTo(target)
override fun jumpIfTrue(target: Label) = if (value) codegen.mv.goTo(target) else Unit override fun jumpIfTrue(target: Label) = if (value) mv.goTo(target) else Unit
override fun materialize() = codegen.mv.iconst(if (value) 1 else 0) override fun materialize() = mv.iconst(if (value) 1 else 0)
} }
is Char -> mv.iconst(value.toInt()) is Char -> mv.iconst(value.toInt())
is Long -> mv.lconst(value) is Long -> mv.lconst(value)
@@ -715,7 +715,7 @@ class ExpressionCodegen(
state.languageVersionSettings.isReleaseCoroutines() state.languageVersionSettings.isReleaseCoroutines()
) )
} }
MaterialValue(this, boxedType).coerce(expression.asmType) MaterialValue(mv, boxedType).coerce(expression.asmType)
} }
IrTypeOperator.INSTANCEOF, IrTypeOperator.NOT_INSTANCEOF -> { IrTypeOperator.INSTANCEOF, IrTypeOperator.NOT_INSTANCEOF -> {
@@ -9,23 +9,24 @@ import org.jetbrains.kotlin.codegen.AsmUtil
import org.jetbrains.kotlin.codegen.StackValue import org.jetbrains.kotlin.codegen.StackValue
import org.jetbrains.org.objectweb.asm.Label import org.jetbrains.org.objectweb.asm.Label
import org.jetbrains.org.objectweb.asm.Type import org.jetbrains.org.objectweb.asm.Type
import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter
// A value that may not have been fully constructed yet. The ability to "roll back" code generation // A value that may not have been fully constructed yet. The ability to "roll back" code generation
// is useful for certain optimizations. // is useful for certain optimizations.
abstract class PromisedValue(val codegen: ExpressionCodegen, val type: Type) { abstract class PromisedValue(val mv: InstructionAdapter, val type: Type) {
// If this value is immaterial, construct an object on the top of the stack. This // If this value is immaterial, construct an object on the top of the stack. This
// must always be done before generating other values or emitting raw bytecode. // must always be done before generating other values or emitting raw bytecode.
abstract fun materialize() abstract fun materialize()
} }
// A value that *has* been fully constructed. // A value that *has* been fully constructed.
class MaterialValue(codegen: ExpressionCodegen, type: Type) : PromisedValue(codegen, type) { class MaterialValue(mv: InstructionAdapter, type: Type) : PromisedValue(mv, type) {
override fun materialize() {} override fun materialize() {}
} }
// A value that can be branched on. JVM has certain branching instructions which can be used // A value that can be branched on. JVM has certain branching instructions which can be used
// to optimize these. // to optimize these.
abstract class BooleanValue(codegen: ExpressionCodegen) : PromisedValue(codegen, Type.BOOLEAN_TYPE) { abstract class BooleanValue(mv: InstructionAdapter) : PromisedValue(mv, Type.BOOLEAN_TYPE) {
abstract fun jumpIfFalse(target: Label) abstract fun jumpIfFalse(target: Label)
abstract fun jumpIfTrue(target: Label) abstract fun jumpIfTrue(target: Label)
@@ -33,11 +34,11 @@ abstract class BooleanValue(codegen: ExpressionCodegen) : PromisedValue(codegen,
val const0 = Label() val const0 = Label()
val end = Label() val end = Label()
jumpIfFalse(const0) jumpIfFalse(const0)
codegen.mv.iconst(1) mv.iconst(1)
codegen.mv.goTo(end) mv.goTo(end)
codegen.mv.mark(const0) mv.mark(const0)
codegen.mv.iconst(0) mv.iconst(0)
codegen.mv.mark(end) mv.mark(end)
} }
} }
@@ -45,7 +46,7 @@ abstract class BooleanValue(codegen: ExpressionCodegen) : PromisedValue(codegen,
val PromisedValue.materialized: MaterialValue val PromisedValue.materialized: MaterialValue
get() { get() {
materialize() materialize()
return MaterialValue(codegen, type) return MaterialValue(mv, type)
} }
// Materialize and disregard this value. Materialization is forced because, presumably, // Materialize and disregard this value. Materialization is forced because, presumably,
@@ -53,28 +54,28 @@ val PromisedValue.materialized: MaterialValue
fun PromisedValue.discard(): MaterialValue { fun PromisedValue.discard(): MaterialValue {
materialize() materialize()
if (type !== Type.VOID_TYPE) if (type !== Type.VOID_TYPE)
AsmUtil.pop(codegen.mv, type) AsmUtil.pop(mv, type)
return MaterialValue(codegen, Type.VOID_TYPE) return MaterialValue(mv, Type.VOID_TYPE)
} }
// On materialization, cast the value to a different type. // On materialization, cast the value to a different type.
fun PromisedValue.coerce(target: Type) = when (target) { fun PromisedValue.coerce(target: Type) = when (target) {
type -> this type -> this
else -> object : PromisedValue(codegen, target) { else -> object : PromisedValue(mv, target) {
// TODO remove dependency // TODO remove dependency
override fun materialize() = StackValue.coerce(this@coerce.materialized.type, type, codegen.mv) override fun materialize() = StackValue.coerce(this@coerce.materialized.type, type, mv)
} }
} }
// Same as above, but with a return type that allows conditional jumping. // Same as above, but with a return type that allows conditional jumping.
fun PromisedValue.coerceToBoolean() = when (val coerced = coerce(Type.BOOLEAN_TYPE)) { fun PromisedValue.coerceToBoolean() = when (val coerced = coerce(Type.BOOLEAN_TYPE)) {
is BooleanValue -> coerced is BooleanValue -> coerced
else -> object : BooleanValue(codegen) { else -> object : BooleanValue(mv) {
override fun jumpIfFalse(target: Label) = coerced.materialize().also { codegen.mv.ifeq(target) } override fun jumpIfFalse(target: Label) = coerced.materialize().also { mv.ifeq(target) }
override fun jumpIfTrue(target: Label) = coerced.materialize().also { codegen.mv.ifne(target) } override fun jumpIfTrue(target: Label) = coerced.materialize().also { mv.ifne(target) }
override fun materialize() = coerced.materialize() override fun materialize() = coerced.materialize()
} }
} }
val ExpressionCodegen.voidValue: MaterialValue val ExpressionCodegen.voidValue: MaterialValue
get() = MaterialValue(this, Type.VOID_TYPE) get() = MaterialValue(mv, Type.VOID_TYPE)
@@ -65,22 +65,22 @@ class CompareTo : IntrinsicMethod() {
} }
} }
class BooleanComparison(val op: IElementType, val a: MaterialValue, val b: MaterialValue) : BooleanValue(a.codegen) { class BooleanComparison(val op: IElementType, val a: MaterialValue, val b: MaterialValue) : BooleanValue(a.mv) {
override fun jumpIfFalse(target: Label) { override fun jumpIfFalse(target: Label) {
// TODO 1. get rid of the dependency; 2. take `b.type` into account. // TODO 1. get rid of the dependency; 2. take `b.type` into account.
val opcode = if (a.type.sort == Type.OBJECT) val opcode = if (a.type.sort == Type.OBJECT)
ObjectCompare.getObjectCompareOpcode(op) ObjectCompare.getObjectCompareOpcode(op)
else else
NumberCompare.patchOpcode(NumberCompare.getNumberCompareOpcode(op), codegen.mv, op, a.type) NumberCompare.patchOpcode(NumberCompare.getNumberCompareOpcode(op), mv, op, a.type)
codegen.mv.visitJumpInsn(opcode, target) mv.visitJumpInsn(opcode, target)
} }
override fun jumpIfTrue(target: Label) { override fun jumpIfTrue(target: Label) {
val opcode = if (a.type.sort == Type.OBJECT) val opcode = if (a.type.sort == Type.OBJECT)
BranchedValue.negatedOperations[ObjectCompare.getObjectCompareOpcode(op)]!! BranchedValue.negatedOperations[ObjectCompare.getObjectCompareOpcode(op)]!!
else else
NumberCompare.patchOpcode(BranchedValue.negatedOperations[NumberCompare.getNumberCompareOpcode(op)]!!, codegen.mv, op, a.type) NumberCompare.patchOpcode(BranchedValue.negatedOperations[NumberCompare.getNumberCompareOpcode(op)]!!, mv, op, a.type)
codegen.mv.visitJumpInsn(opcode, target) mv.visitJumpInsn(opcode, target)
} }
} }
@@ -27,9 +27,9 @@ import org.jetbrains.org.objectweb.asm.Type
import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter
class Equals(val operator: IElementType) : IntrinsicMethod() { class Equals(val operator: IElementType) : IntrinsicMethod() {
private class BooleanNullCheck(val value: PromisedValue) : BooleanValue(value.codegen) { private class BooleanNullCheck(val value: PromisedValue) : BooleanValue(value.mv) {
override fun jumpIfFalse(target: Label) = value.materialize().also { codegen.mv.ifnonnull(target) } override fun jumpIfFalse(target: Label) = value.materialize().also { mv.ifnonnull(target) }
override fun jumpIfTrue(target: Label) = value.materialize().also { codegen.mv.ifnull(target) } override fun jumpIfTrue(target: Label) = value.materialize().also { mv.ifnull(target) }
} }
override fun invoke(expression: IrFunctionAccessExpression, codegen: ExpressionCodegen, data: BlockInfo): PromisedValue? { override fun invoke(expression: IrFunctionAccessExpression, codegen: ExpressionCodegen, data: BlockInfo): PromisedValue? {
@@ -50,7 +50,7 @@ class Equals(val operator: IElementType) : IntrinsicMethod() {
val bValue = b.accept(codegen, data).coerce(operandType).materialized val bValue = b.accept(codegen, data).coerce(operandType).materialized
if (useEquals) { if (useEquals) {
AsmUtil.genAreEqualCall(codegen.mv) AsmUtil.genAreEqualCall(codegen.mv)
return MaterialValue(codegen, Type.BOOLEAN_TYPE) return MaterialValue(codegen.mv, Type.BOOLEAN_TYPE)
} }
return BooleanComparison(operator, aValue, bValue) return BooleanComparison(operator, aValue, bValue)
} }
@@ -28,8 +28,8 @@ abstract class IntrinsicMethod {
with(codegen) { with(codegen) {
val descriptor = typeMapper.mapSignatureSkipGeneric(expression.descriptor) val descriptor = typeMapper.mapSignatureSkipGeneric(expression.descriptor)
val stackValue = toCallable(expression, descriptor, context).invoke(mv, codegen, data) val stackValue = toCallable(expression, descriptor, context).invoke(mv, codegen, data)
return object : PromisedValue(codegen, stackValue.type) { return object : PromisedValue(mv, stackValue.type) {
override fun materialize() = stackValue.put(codegen.mv) override fun materialize() = stackValue.put(mv)
} }
} }
@@ -30,10 +30,10 @@ object JavaClassProperty : IntrinsicMethod() {
} }
if (isPrimitive(value.type)) { if (isPrimitive(value.type)) {
value.discard() value.discard()
value.codegen.mv.getstatic(boxType(value.type).internalName, "TYPE", "Ljava/lang/Class;") value.mv.getstatic(boxType(value.type).internalName, "TYPE", "Ljava/lang/Class;")
} else { } else {
value.materialize() value.materialize()
value.codegen.mv.invokevirtual("java/lang/Object", "getClass", "()Ljava/lang/Class;", false) value.mv.invokevirtual("java/lang/Object", "getClass", "()Ljava/lang/Class;", false)
} }
} }
@@ -24,7 +24,7 @@ import org.jetbrains.kotlin.ir.expressions.IrFunctionAccessExpression
import org.jetbrains.org.objectweb.asm.Label import org.jetbrains.org.objectweb.asm.Label
class Not : IntrinsicMethod() { class Not : IntrinsicMethod() {
class BooleanNegation(val value: BooleanValue) : BooleanValue(value.codegen) { class BooleanNegation(val value: BooleanValue) : BooleanValue(value.mv) {
override fun jumpIfFalse(target: Label) = value.jumpIfTrue(target) override fun jumpIfFalse(target: Label) = value.jumpIfTrue(target)
override fun jumpIfTrue(target: Label) = value.jumpIfFalse(target) override fun jumpIfTrue(target: Label) = value.jumpIfFalse(target)
} }