Split voidValue into immaterialUnitValue and defaultValue
This commit is contained in:
committed by
Alexander Udalov
parent
27a850be92
commit
ea3bae5fc9
+26
-22
@@ -34,6 +34,7 @@ import org.jetbrains.kotlin.ir.types.*
|
|||||||
import org.jetbrains.kotlin.ir.util.*
|
import org.jetbrains.kotlin.ir.util.*
|
||||||
import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
|
import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
|
||||||
import org.jetbrains.kotlin.resolve.jvm.AsmTypes
|
import org.jetbrains.kotlin.resolve.jvm.AsmTypes
|
||||||
|
import org.jetbrains.kotlin.resolve.jvm.AsmTypes.DEFAULT_CONSTRUCTOR_MARKER
|
||||||
import org.jetbrains.kotlin.resolve.jvm.AsmTypes.OBJECT_TYPE
|
import org.jetbrains.kotlin.resolve.jvm.AsmTypes.OBJECT_TYPE
|
||||||
import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull
|
import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull
|
||||||
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
||||||
@@ -169,7 +170,8 @@ class ExpressionCodegen(
|
|||||||
irFunction.markLineNumber(startOffset = irFunction is IrConstructor && irFunction.isPrimary)
|
irFunction.markLineNumber(startOffset = irFunction is IrConstructor && irFunction.isPrimary)
|
||||||
}
|
}
|
||||||
val returnType = typeMapper.mapReturnType(irFunction)
|
val returnType = typeMapper.mapReturnType(irFunction)
|
||||||
result.coerce(returnType, if (irFunction !is IrConstructor) irFunction.returnType else null).materialize()
|
val returnIrType = if (irFunction !is IrConstructor) irFunction.returnType else context.irBuiltIns.unitType
|
||||||
|
result.coerce(returnType, returnIrType).materialize()
|
||||||
mv.areturn(returnType)
|
mv.areturn(returnType)
|
||||||
}
|
}
|
||||||
val endLabel = markNewLabel()
|
val endLabel = markNewLabel()
|
||||||
@@ -278,7 +280,7 @@ class ExpressionCodegen(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun visitStatementContainer(container: IrStatementContainer, data: BlockInfo) =
|
private fun visitStatementContainer(container: IrStatementContainer, data: BlockInfo) =
|
||||||
container.statements.fold(voidValue as PromisedValue) { prev, exp ->
|
container.statements.fold(immaterialUnitValue as PromisedValue) { prev, exp ->
|
||||||
prev.discard()
|
prev.discard()
|
||||||
exp.accept(this, data).also { (exp as? IrExpression)?.markEndOfStatementIfNeeded() }
|
exp.accept(this, data).also { (exp as? IrExpression)?.markEndOfStatementIfNeeded() }
|
||||||
}
|
}
|
||||||
@@ -396,12 +398,12 @@ class ExpressionCodegen(
|
|||||||
returnType.substitute(typeSubstitutionMap).isNothing() -> {
|
returnType.substitute(typeSubstitutionMap).isNothing() -> {
|
||||||
mv.aconst(null)
|
mv.aconst(null)
|
||||||
mv.athrow()
|
mv.athrow()
|
||||||
voidValue
|
immaterialUnitValue
|
||||||
}
|
}
|
||||||
expression is IrConstructorCall ->
|
expression is IrConstructorCall ->
|
||||||
MaterialValue(this, asmType, expression.type)
|
MaterialValue(this, asmType, expression.type)
|
||||||
expression is IrDelegatingConstructorCall ->
|
expression is IrDelegatingConstructorCall ->
|
||||||
voidValue
|
immaterialUnitValue
|
||||||
expression.type.isUnit() ->
|
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.
|
||||||
MaterialValue(this, callable.returnType, returnType).discard().coerce(expression.type)
|
MaterialValue(this, callable.returnType, returnType).discard().coerce(expression.type)
|
||||||
@@ -423,7 +425,7 @@ class ExpressionCodegen(
|
|||||||
}
|
}
|
||||||
|
|
||||||
data.variables.add(VariableInfo(declaration, index, varType, markNewLabel()))
|
data.variables.add(VariableInfo(declaration, index, varType, markNewLabel()))
|
||||||
return voidValue
|
return immaterialUnitValue
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun visitGetValue(expression: IrGetValue, data: BlockInfo): PromisedValue {
|
override fun visitGetValue(expression: IrGetValue, data: BlockInfo): PromisedValue {
|
||||||
@@ -442,7 +444,7 @@ class ExpressionCodegen(
|
|||||||
assert(expression is IrSetField) { "read of const val ${expression.symbol.owner.name} not inlined by ConstLowering" }
|
assert(expression is IrSetField) { "read of const val ${expression.symbol.owner.name} not inlined by ConstLowering" }
|
||||||
// This can only be the field's initializer; JVM implementations are required
|
// This can only be the field's initializer; JVM implementations are required
|
||||||
// to generate those for ConstantValue-marked fields automatically, so this is redundant.
|
// to generate those for ConstantValue-marked fields automatically, so this is redundant.
|
||||||
return voidValue.coerce(expression.type)
|
return defaultValue(expression.type)
|
||||||
}
|
}
|
||||||
|
|
||||||
val realField = expression.symbol.owner.resolveFakeOverride()!!
|
val realField = expression.symbol.owner.resolveFakeOverride()!!
|
||||||
@@ -458,7 +460,7 @@ class ExpressionCodegen(
|
|||||||
isStatic -> mv.putstatic(ownerType, fieldName, fieldType.descriptor)
|
isStatic -> mv.putstatic(ownerType, fieldName, fieldType.descriptor)
|
||||||
else -> mv.putfield(ownerType, fieldName, fieldType.descriptor)
|
else -> mv.putfield(ownerType, fieldName, fieldType.descriptor)
|
||||||
}
|
}
|
||||||
voidValue.coerce(expression.type)
|
defaultValue(expression.type)
|
||||||
} else {
|
} else {
|
||||||
when {
|
when {
|
||||||
isStatic ->
|
isStatic ->
|
||||||
@@ -480,7 +482,7 @@ class ExpressionCodegen(
|
|||||||
val isFieldInitializer = expression.origin == null
|
val isFieldInitializer = expression.origin == null
|
||||||
val skip = (inPrimaryConstructor || inClassInit) && isFieldInitializer && expressionValue is IrConst<*> &&
|
val skip = (inPrimaryConstructor || inClassInit) && isFieldInitializer && expressionValue is IrConst<*> &&
|
||||||
isDefaultValueForType(expression.symbol.owner.type.asmType, expressionValue.value)
|
isDefaultValueForType(expression.symbol.owner.type.asmType, expressionValue.value)
|
||||||
return if (skip) voidValue.coerce(expression.type) else super.visitSetField(expression, data)
|
return if (skip) defaultValue(expression.type) else super.visitSetField(expression, data)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -511,7 +513,7 @@ class ExpressionCodegen(
|
|||||||
expression.value.markLineNumber(startOffset = true)
|
expression.value.markLineNumber(startOffset = true)
|
||||||
expression.value.accept(this, data).coerce(expression.symbol.owner.type).materialize()
|
expression.value.accept(this, data).coerce(expression.symbol.owner.type).materialize()
|
||||||
mv.store(findLocalIndex(expression.symbol), expression.symbol.owner.asmType)
|
mv.store(findLocalIndex(expression.symbol), expression.symbol.owner.asmType)
|
||||||
return voidValue.coerce(expression.type)
|
return defaultValue(expression.type)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun <T> visitConst(expression: IrConst<T>, data: BlockInfo): PromisedValue {
|
override fun <T> visitConst(expression: IrConst<T>, data: BlockInfo): PromisedValue {
|
||||||
@@ -544,7 +546,7 @@ class ExpressionCodegen(
|
|||||||
// TODO maybe remove?
|
// TODO maybe remove?
|
||||||
override fun visitClass(declaration: IrClass, data: BlockInfo): PromisedValue {
|
override fun visitClass(declaration: IrClass, data: BlockInfo): PromisedValue {
|
||||||
classCodegen.generateLocalClass(declaration)
|
classCodegen.generateLocalClass(declaration)
|
||||||
return voidValue
|
return immaterialUnitValue
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun visitVararg(expression: IrVararg, data: BlockInfo): PromisedValue {
|
override fun visitVararg(expression: IrVararg, data: BlockInfo): PromisedValue {
|
||||||
@@ -662,7 +664,7 @@ class ExpressionCodegen(
|
|||||||
mv, "java/lang/UnsupportedOperationException",
|
mv, "java/lang/UnsupportedOperationException",
|
||||||
"Non-local returns are not allowed with inlining disabled"
|
"Non-local returns are not allowed with inlining disabled"
|
||||||
)
|
)
|
||||||
return voidValue
|
return immaterialUnitValue
|
||||||
}
|
}
|
||||||
|
|
||||||
val target = data.findBlock<ReturnableBlockInfo> { it.returnSymbol == expression.returnTargetSymbol }
|
val target = data.findBlock<ReturnableBlockInfo> { it.returnSymbol == expression.returnTargetSymbol }
|
||||||
@@ -682,7 +684,7 @@ class ExpressionCodegen(
|
|||||||
}
|
}
|
||||||
mv.mark(afterReturnLabel)
|
mv.mark(afterReturnLabel)
|
||||||
mv.nop()/*TODO check RESTORE_STACK_IN_TRY_CATCH processor*/
|
mv.nop()/*TODO check RESTORE_STACK_IN_TRY_CATCH processor*/
|
||||||
return voidValue
|
return immaterialUnitValue
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun visitWhen(expression: IrWhen, data: BlockInfo): PromisedValue {
|
override fun visitWhen(expression: IrWhen, data: BlockInfo): PromisedValue {
|
||||||
@@ -715,7 +717,7 @@ class ExpressionCodegen(
|
|||||||
}
|
}
|
||||||
// Produce the default value for the type. Doesn't really matter right now, as non-exhaustive
|
// Produce the default value for the type. Doesn't really matter right now, as non-exhaustive
|
||||||
// conditionals cannot be used as expressions.
|
// conditionals cannot be used as expressions.
|
||||||
val result = voidValue.coerce(expression.type).materialized
|
val result = defaultValue(expression.type).materialized
|
||||||
mv.mark(endLabel)
|
mv.mark(endLabel)
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
@@ -727,7 +729,7 @@ class ExpressionCodegen(
|
|||||||
IrTypeOperator.IMPLICIT_COERCION_TO_UNIT -> {
|
IrTypeOperator.IMPLICIT_COERCION_TO_UNIT -> {
|
||||||
expression.argument.accept(this, data).discard()
|
expression.argument.accept(this, data).discard()
|
||||||
expression.argument.markEndOfStatementIfNeeded()
|
expression.argument.markEndOfStatementIfNeeded()
|
||||||
voidValue.coerce(expression.asmType)
|
defaultValue(expression.type)
|
||||||
}
|
}
|
||||||
|
|
||||||
IrTypeOperator.IMPLICIT_CAST, IrTypeOperator.IMPLICIT_INTEGER_COERCION -> {
|
IrTypeOperator.IMPLICIT_CAST, IrTypeOperator.IMPLICIT_INTEGER_COERCION -> {
|
||||||
@@ -736,7 +738,7 @@ class ExpressionCodegen(
|
|||||||
|
|
||||||
IrTypeOperator.CAST, IrTypeOperator.SAFE_CAST -> {
|
IrTypeOperator.CAST, IrTypeOperator.SAFE_CAST -> {
|
||||||
val result = expression.argument.accept(this, data)
|
val result = expression.argument.accept(this, data)
|
||||||
val boxedLeftType = result.irType?.let { typeMapper.boxType(it) } ?: OBJECT_TYPE
|
val boxedLeftType = typeMapper.boxType(result.irType)
|
||||||
result.coerce(boxedLeftType, expression.argument.type).materialize()
|
result.coerce(boxedLeftType, expression.argument.type).materialize()
|
||||||
val boxedRightType = typeMapper.boxType(typeOperand)
|
val boxedRightType = typeMapper.boxType(typeOperand)
|
||||||
|
|
||||||
@@ -851,7 +853,7 @@ class ExpressionCodegen(
|
|||||||
}
|
}
|
||||||
mv.goTo(continueLabel)
|
mv.goTo(continueLabel)
|
||||||
mv.mark(endLabel)
|
mv.mark(endLabel)
|
||||||
return voidValue
|
return immaterialUnitValue
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun visitDoWhileLoop(loop: IrDoWhileLoop, data: BlockInfo): PromisedValue {
|
override fun visitDoWhileLoop(loop: IrDoWhileLoop, data: BlockInfo): PromisedValue {
|
||||||
@@ -868,7 +870,7 @@ class ExpressionCodegen(
|
|||||||
loop.condition.markLineNumber(true)
|
loop.condition.markLineNumber(true)
|
||||||
loop.condition.accept(this, data).coerceToBoolean().jumpIfTrue(entry)
|
loop.condition.accept(this, data).coerceToBoolean().jumpIfTrue(entry)
|
||||||
mv.mark(endLabel)
|
mv.mark(endLabel)
|
||||||
return voidValue
|
return immaterialUnitValue
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun unwindBlockStack(endLabel: Label, data: BlockInfo, stop: (ExpressionInfo) -> Boolean): ExpressionInfo? {
|
private fun unwindBlockStack(endLabel: Label, data: BlockInfo, stop: (ExpressionInfo) -> Boolean): ExpressionInfo? {
|
||||||
@@ -886,7 +888,7 @@ class ExpressionCodegen(
|
|||||||
?: throw AssertionError("Target label for break/continue not found")
|
?: throw AssertionError("Target label for break/continue not found")
|
||||||
mv.fixStackAndJump(if (jump is IrBreak) stackElement.breakLabel else stackElement.continueLabel)
|
mv.fixStackAndJump(if (jump is IrBreak) stackElement.breakLabel else stackElement.continueLabel)
|
||||||
mv.mark(endLabel)
|
mv.mark(endLabel)
|
||||||
return voidValue
|
return immaterialUnitValue
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun visitTry(aTry: IrTry, data: BlockInfo): PromisedValue {
|
override fun visitTry(aTry: IrTry, data: BlockInfo): PromisedValue {
|
||||||
@@ -985,7 +987,7 @@ class ExpressionCodegen(
|
|||||||
frameMap.leaveTemp(tryAsmType)
|
frameMap.leaveTemp(tryAsmType)
|
||||||
return aTry.onStack
|
return aTry.onStack
|
||||||
}
|
}
|
||||||
return voidValue
|
return immaterialUnitValue
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun genTryCatchCover(catchStart: Label, tryStart: Label, tryEnd: Label, tryGaps: List<Pair<Label, Label>>, type: String?) {
|
private fun genTryCatchCover(catchStart: Label, tryStart: Label, tryEnd: Label, tryGaps: List<Pair<Label, Label>>, type: String?) {
|
||||||
@@ -1030,9 +1032,11 @@ class ExpressionCodegen(
|
|||||||
|
|
||||||
override fun visitThrow(expression: IrThrow, data: BlockInfo): PromisedValue {
|
override fun visitThrow(expression: IrThrow, data: BlockInfo): PromisedValue {
|
||||||
expression.markLineNumber(startOffset = true)
|
expression.markLineNumber(startOffset = true)
|
||||||
expression.value.accept(this, data).coerce(AsmTypes.JAVA_THROWABLE_TYPE).materialize()
|
expression.value.accept(this, data)
|
||||||
|
.coerce(AsmTypes.JAVA_THROWABLE_TYPE, context.irBuiltIns.throwableType)
|
||||||
|
.materialize()
|
||||||
mv.athrow()
|
mv.athrow()
|
||||||
return voidValue
|
return immaterialUnitValue
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun visitGetClass(expression: IrGetClass, data: BlockInfo) =
|
override fun visitGetClass(expression: IrGetClass, data: BlockInfo) =
|
||||||
@@ -1213,7 +1217,7 @@ fun DefaultCallArgs.generateOnStackIfNeeded(callGenerator: IrCallGenerator, isCo
|
|||||||
callGenerator.putValueIfNeeded(Type.INT_TYPE, StackValue.constant(mask, Type.INT_TYPE), ValueKind.DEFAULT_MASK, -1, codegen)
|
callGenerator.putValueIfNeeded(Type.INT_TYPE, StackValue.constant(mask, Type.INT_TYPE), ValueKind.DEFAULT_MASK, -1, codegen)
|
||||||
}
|
}
|
||||||
|
|
||||||
val parameterType = if (isConstructor) AsmTypes.DEFAULT_CONSTRUCTOR_MARKER else OBJECT_TYPE
|
val parameterType = if (isConstructor) DEFAULT_CONSTRUCTOR_MARKER else OBJECT_TYPE
|
||||||
callGenerator.putValueIfNeeded(
|
callGenerator.putValueIfNeeded(
|
||||||
parameterType,
|
parameterType,
|
||||||
StackValue.constant(null, parameterType),
|
StackValue.constant(null, parameterType),
|
||||||
|
|||||||
+34
-18
@@ -19,7 +19,7 @@ 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, val irType: IrType?) {
|
abstract class PromisedValue(val codegen: ExpressionCodegen, val type: Type, val irType: IrType) {
|
||||||
// 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()
|
||||||
@@ -30,12 +30,17 @@ abstract class PromisedValue(val codegen: ExpressionCodegen, val type: Type, val
|
|||||||
val typeMapper: IrTypeMapper
|
val typeMapper: IrTypeMapper
|
||||||
get() = codegen.typeMapper
|
get() = codegen.typeMapper
|
||||||
|
|
||||||
val kotlinType: KotlinType?
|
val kotlinType: KotlinType
|
||||||
get() = irType?.toKotlinType()
|
get() = irType.toKotlinType()
|
||||||
}
|
}
|
||||||
|
|
||||||
// A value that *has* been fully constructed.
|
// A value that *has* been fully constructed.
|
||||||
class MaterialValue(codegen: ExpressionCodegen, type: Type, irType: IrType?) : PromisedValue(codegen, type, irType) {
|
class MaterialValue(codegen: ExpressionCodegen, type: Type, irType: IrType) : PromisedValue(codegen, type, irType) {
|
||||||
|
override fun materialize() {}
|
||||||
|
}
|
||||||
|
|
||||||
|
// A value that is only materialized through coercion.
|
||||||
|
class ImmaterialValue(codegen: ExpressionCodegen, type: Type, irType: IrType) : PromisedValue(codegen, type, irType) {
|
||||||
override fun materialize() {}
|
override fun materialize() {}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -66,11 +71,11 @@ val PromisedValue.materialized: MaterialValue
|
|||||||
|
|
||||||
// Materialize and disregard this value. Materialization is forced because, presumably,
|
// Materialize and disregard this value. Materialization is forced because, presumably,
|
||||||
// we only wanted the side effects anyway.
|
// we only wanted the side effects anyway.
|
||||||
fun PromisedValue.discard(): MaterialValue {
|
fun PromisedValue.discard(): PromisedValue {
|
||||||
materialize()
|
materialize()
|
||||||
if (type !== Type.VOID_TYPE)
|
if (type !== Type.VOID_TYPE)
|
||||||
AsmUtil.pop(mv, type)
|
AsmUtil.pop(mv, type)
|
||||||
return codegen.voidValue
|
return codegen.immaterialUnitValue
|
||||||
}
|
}
|
||||||
|
|
||||||
private val IrType.unboxed: IrType
|
private val IrType.unboxed: IrType
|
||||||
@@ -103,9 +108,8 @@ fun PromisedValue.coerceInlineClasses(type: Type, irType: IrType, target: Type,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// On materialization, cast the value to a different type.
|
// On materialization, cast the value to a different type.
|
||||||
fun PromisedValue.coerce(target: Type, irTarget: IrType? = null): PromisedValue {
|
fun PromisedValue.coerce(target: Type, irTarget: IrType): PromisedValue {
|
||||||
if (irType != null && irTarget != null)
|
coerceInlineClasses(type, irType, target, irTarget)?.let { return it }
|
||||||
coerceInlineClasses(type, irType, target, irTarget)?.let { return it }
|
|
||||||
return when (type) {
|
return when (type) {
|
||||||
// All unsafe coercions between irTypes should use the UnsafeCoerce intrinsic
|
// All unsafe coercions between irTypes should use the UnsafeCoerce intrinsic
|
||||||
target -> this
|
target -> this
|
||||||
@@ -129,14 +133,26 @@ fun PromisedValue.boxInlineClasses(irTarget: IrType) =
|
|||||||
coerceToBoxed(irTarget) else this
|
coerceToBoxed(irTarget) else this
|
||||||
|
|
||||||
// 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() =
|
||||||
is BooleanValue -> coerced
|
when (val coerced = coerce(Type.BOOLEAN_TYPE, codegen.context.irBuiltIns.booleanType)) {
|
||||||
else -> object : BooleanValue(codegen) {
|
is BooleanValue -> coerced
|
||||||
override fun jumpIfFalse(target: Label) = coerced.materialize().also { mv.ifeq(target) }
|
else -> object : BooleanValue(codegen) {
|
||||||
override fun jumpIfTrue(target: Label) = coerced.materialize().also { mv.ifne(target) }
|
override fun jumpIfFalse(target: Label) = coerced.materialize().also { mv.ifeq(target) }
|
||||||
override fun materialize() = coerced.materialize()
|
override fun jumpIfTrue(target: Label) = coerced.materialize().also { mv.ifne(target) }
|
||||||
|
override fun materialize() = coerced.materialize()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
val ExpressionCodegen.voidValue: MaterialValue
|
// Non-materialized value of Unit type
|
||||||
get() = MaterialValue(this, Type.VOID_TYPE, null)
|
// This value is only materialized when calling coerce, which is why it is represented
|
||||||
|
// as a MaterialValue even though there is nothing on the stack.
|
||||||
|
val ExpressionCodegen.immaterialUnitValue: ImmaterialValue
|
||||||
|
get() = ImmaterialValue(this, Type.VOID_TYPE, context.irBuiltIns.unitType)
|
||||||
|
|
||||||
|
// Non-materialized default value for the given type
|
||||||
|
fun ExpressionCodegen.defaultValue(irType: IrType): PromisedValue =
|
||||||
|
object : PromisedValue(this, typeMapper.mapType(irType), irType) {
|
||||||
|
override fun materialize() {
|
||||||
|
StackValue.coerce(Type.VOID_TYPE, type, codegen.mv)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
+3
-3
@@ -217,7 +217,7 @@ class SwitchGenerator(private val expression: IrWhen, private val data: BlockInf
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected fun genBranchTargets(): PromisedValue {
|
private fun genBranchTargets(): PromisedValue {
|
||||||
with(codegen) {
|
with(codegen) {
|
||||||
val endLabel = Label()
|
val endLabel = Label()
|
||||||
for ((thenExpression, label) in expressionToLabels) {
|
for ((thenExpression, label) in expressionToLabels) {
|
||||||
@@ -226,8 +226,8 @@ class SwitchGenerator(private val expression: IrWhen, private val data: BlockInf
|
|||||||
mv.goTo(endLabel)
|
mv.goTo(endLabel)
|
||||||
}
|
}
|
||||||
mv.visitLabel(defaultLabel)
|
mv.visitLabel(defaultLabel)
|
||||||
val stackValue = elseExpression?.accept(codegen, data) ?: voidValue
|
val stackValue = elseExpression?.accept(codegen, data)?.coerce(expression.type) ?: defaultValue(expression.type)
|
||||||
val result = stackValue.coerce(expression.type).materialized
|
val result = stackValue.materialized
|
||||||
mv.mark(endLabel)
|
mv.mark(endLabel)
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-2
@@ -33,8 +33,8 @@ object JavaClassProperty : IntrinsicMethod() {
|
|||||||
fun invokeWith(value: PromisedValue) =
|
fun invokeWith(value: PromisedValue) =
|
||||||
when {
|
when {
|
||||||
value.type == Type.VOID_TYPE ->
|
value.type == Type.VOID_TYPE ->
|
||||||
invokeGetClass(value.coerce(AsmTypes.UNIT_TYPE))
|
invokeGetClass(value.coerce(AsmTypes.UNIT_TYPE, value.codegen.context.irBuiltIns.unitType))
|
||||||
value.irType?.isInlined() == true ->
|
value.irType.isInlined() ->
|
||||||
invokeGetClass(value.coerceToBoxed(value.irType))
|
invokeGetClass(value.coerceToBoxed(value.irType))
|
||||||
isPrimitive(value.type) -> {
|
isPrimitive(value.type) -> {
|
||||||
value.discard()
|
value.discard()
|
||||||
|
|||||||
Reference in New Issue
Block a user