Move PromisedValue to a separate file
This commit is contained in:
-70
@@ -100,73 +100,6 @@ class BlockInfo private constructor(val parent: BlockInfo?) {
|
|||||||
|
|
||||||
class VariableInfo(val declaration: IrVariable, val index: Int, val type: Type, val startLabel: Label)
|
class VariableInfo(val declaration: IrVariable, val index: Int, val type: Type, val startLabel: Label)
|
||||||
|
|
||||||
// A value that may not have been fully constructed yet. The ability to "roll back" code generation
|
|
||||||
// is useful for certain optimizations.
|
|
||||||
abstract class PromisedValue(val codegen: ExpressionCodegen, val type: Type) {
|
|
||||||
// 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.
|
|
||||||
abstract fun materialize()
|
|
||||||
}
|
|
||||||
|
|
||||||
// A value that *has* been fully constructed.
|
|
||||||
class MaterialValue(codegen: ExpressionCodegen, type: Type) : PromisedValue(codegen, type) {
|
|
||||||
override fun materialize() {}
|
|
||||||
}
|
|
||||||
|
|
||||||
// A value that can be branched on. JVM has certain branching instructions which can be used
|
|
||||||
// to optimize these.
|
|
||||||
abstract class BooleanValue(codegen: ExpressionCodegen) : PromisedValue(codegen, Type.BOOLEAN_TYPE) {
|
|
||||||
abstract fun jumpIfFalse(target: Label)
|
|
||||||
abstract fun jumpIfTrue(target: Label)
|
|
||||||
|
|
||||||
override fun materialize() {
|
|
||||||
val const0 = Label()
|
|
||||||
val end = Label()
|
|
||||||
jumpIfFalse(const0)
|
|
||||||
codegen.mv.iconst(1)
|
|
||||||
codegen.mv.goTo(end)
|
|
||||||
codegen.mv.mark(const0)
|
|
||||||
codegen.mv.iconst(0)
|
|
||||||
codegen.mv.mark(end)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Same as materialize(), but return a representation of the result.
|
|
||||||
val PromisedValue.materialized: MaterialValue
|
|
||||||
get() {
|
|
||||||
materialize()
|
|
||||||
return MaterialValue(codegen, type)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Materialize and disregard this value. Materialization is forced because, presumably,
|
|
||||||
// we only wanted the side effects anyway.
|
|
||||||
fun PromisedValue.discard(): MaterialValue {
|
|
||||||
materialize()
|
|
||||||
if (type !== Type.VOID_TYPE)
|
|
||||||
AsmUtil.pop(codegen.mv, type)
|
|
||||||
return MaterialValue(codegen, Type.VOID_TYPE)
|
|
||||||
}
|
|
||||||
|
|
||||||
// On materialization, cast the value to a different type.
|
|
||||||
fun PromisedValue.coerce(target: Type) = when (target) {
|
|
||||||
Type.VOID_TYPE -> discard()
|
|
||||||
type -> this
|
|
||||||
else -> object : PromisedValue(codegen, target) {
|
|
||||||
// TODO remove dependency
|
|
||||||
override fun materialize() = StackValue.coerce(this@coerce.materialized.type, type, codegen.mv)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Same as above, but with a return type that allows conditional jumping.
|
|
||||||
fun PromisedValue.coerceToBoolean() = when (val coerced = coerce(Type.BOOLEAN_TYPE)) {
|
|
||||||
is BooleanValue -> coerced
|
|
||||||
else -> object : BooleanValue(codegen) {
|
|
||||||
override fun jumpIfFalse(target: Label) = coerced.materialize().also { codegen.mv.ifeq(target) }
|
|
||||||
override fun jumpIfTrue(target: Label) = coerced.materialize().also { codegen.mv.ifne(target) }
|
|
||||||
override fun materialize() = coerced.materialize()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class ExpressionCodegen(
|
class ExpressionCodegen(
|
||||||
val irFunction: IrFunction,
|
val irFunction: IrFunction,
|
||||||
val frame: IrFrameMap,
|
val frame: IrFrameMap,
|
||||||
@@ -212,9 +145,6 @@ class ExpressionCodegen(
|
|||||||
val IrExpression.onStack: MaterialValue
|
val IrExpression.onStack: MaterialValue
|
||||||
get() = MaterialValue(this@ExpressionCodegen, asmType)
|
get() = MaterialValue(this@ExpressionCodegen, asmType)
|
||||||
|
|
||||||
val voidValue: MaterialValue
|
|
||||||
get() = MaterialValue(this@ExpressionCodegen, Type.VOID_TYPE)
|
|
||||||
|
|
||||||
private fun markNewLabel() = Label().apply { mv.visitLabel(this) }
|
private fun markNewLabel() = Label().apply { mv.visitLabel(this) }
|
||||||
|
|
||||||
private fun IrElement.markLineNumber(startOffset: Boolean) {
|
private fun IrElement.markLineNumber(startOffset: Boolean) {
|
||||||
|
|||||||
@@ -0,0 +1,80 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
||||||
|
* that can be found in the license/LICENSE.txt file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jetbrains.kotlin.backend.jvm.codegen
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.codegen.AsmUtil
|
||||||
|
import org.jetbrains.kotlin.codegen.StackValue
|
||||||
|
import org.jetbrains.org.objectweb.asm.Label
|
||||||
|
import org.jetbrains.org.objectweb.asm.Type
|
||||||
|
|
||||||
|
// A value that may not have been fully constructed yet. The ability to "roll back" code generation
|
||||||
|
// is useful for certain optimizations.
|
||||||
|
abstract class PromisedValue(val codegen: ExpressionCodegen, val type: Type) {
|
||||||
|
// 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.
|
||||||
|
abstract fun materialize()
|
||||||
|
}
|
||||||
|
|
||||||
|
// A value that *has* been fully constructed.
|
||||||
|
class MaterialValue(codegen: ExpressionCodegen, type: Type) : PromisedValue(codegen, type) {
|
||||||
|
override fun materialize() {}
|
||||||
|
}
|
||||||
|
|
||||||
|
// A value that can be branched on. JVM has certain branching instructions which can be used
|
||||||
|
// to optimize these.
|
||||||
|
abstract class BooleanValue(codegen: ExpressionCodegen) : PromisedValue(codegen, Type.BOOLEAN_TYPE) {
|
||||||
|
abstract fun jumpIfFalse(target: Label)
|
||||||
|
abstract fun jumpIfTrue(target: Label)
|
||||||
|
|
||||||
|
override fun materialize() {
|
||||||
|
val const0 = Label()
|
||||||
|
val end = Label()
|
||||||
|
jumpIfFalse(const0)
|
||||||
|
codegen.mv.iconst(1)
|
||||||
|
codegen.mv.goTo(end)
|
||||||
|
codegen.mv.mark(const0)
|
||||||
|
codegen.mv.iconst(0)
|
||||||
|
codegen.mv.mark(end)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Same as materialize(), but return a representation of the result.
|
||||||
|
val PromisedValue.materialized: MaterialValue
|
||||||
|
get() {
|
||||||
|
materialize()
|
||||||
|
return MaterialValue(codegen, type)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Materialize and disregard this value. Materialization is forced because, presumably,
|
||||||
|
// we only wanted the side effects anyway.
|
||||||
|
fun PromisedValue.discard(): MaterialValue {
|
||||||
|
materialize()
|
||||||
|
if (type !== Type.VOID_TYPE)
|
||||||
|
AsmUtil.pop(codegen.mv, type)
|
||||||
|
return MaterialValue(codegen, Type.VOID_TYPE)
|
||||||
|
}
|
||||||
|
|
||||||
|
// On materialization, cast the value to a different type.
|
||||||
|
fun PromisedValue.coerce(target: Type) = when (target) {
|
||||||
|
type -> this
|
||||||
|
else -> object : PromisedValue(codegen, target) {
|
||||||
|
// TODO remove dependency
|
||||||
|
override fun materialize() = StackValue.coerce(this@coerce.materialized.type, type, codegen.mv)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Same as above, but with a return type that allows conditional jumping.
|
||||||
|
fun PromisedValue.coerceToBoolean() = when (val coerced = coerce(Type.BOOLEAN_TYPE)) {
|
||||||
|
is BooleanValue -> coerced
|
||||||
|
else -> object : BooleanValue(codegen) {
|
||||||
|
override fun jumpIfFalse(target: Label) = coerced.materialize().also { codegen.mv.ifeq(target) }
|
||||||
|
override fun jumpIfTrue(target: Label) = coerced.materialize().also { codegen.mv.ifne(target) }
|
||||||
|
override fun materialize() = coerced.materialize()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val ExpressionCodegen.voidValue: MaterialValue
|
||||||
|
get() = MaterialValue(this, Type.VOID_TYPE)
|
||||||
Reference in New Issue
Block a user