
com.jtransc.ast.ast_body.kt Maven / Gradle / Ivy
The newest version!
package com.jtransc.ast
import com.jtransc.ds.cast
import com.jtransc.error.invalidOp
import com.jtransc.error.noImpl
data class AstBody(
val stm: AstStm,
var locals: List,
val traps: List,
val flags: AstBodyFlags
)
data class AstBodyFlags(val strictfp: Boolean)
enum class AstBinop(val symbol: String, val str: String) {
ADD("+", "add"), SUB("-", "sub"), MUL("*", "mul"), DIV("/", "div"), REM("%", "rem"),
AND("&", "and"), OR("|", "or"), XOR("^", "xor"),
SHL("<<", "shl"), SHR(">>", "shr"), USHR(">>>", "ushr"),
BAND("&&", "band"), BOR("||", "bor"),
EQ("==", "eq"), NE("!=", "ne"), GE(">=", "ge"), LE("<=", "le"), LT("<", "lt"), GT(">", "gt"),
LCMP("lcmp", "lcmp"), CMP("cmp", "cmp"), CMPL("cmpl", "cmpl"), CMPG("cmpg", "cmpg");
companion object {
val SHIFTS = setOf(SHL, SHR, USHR)
val COMPARISONS = setOf(EQ, NE, GE, LE, LT, GT)
//val operators = values.flatMap { listOf(Pair(it.symbol, it), Pair(it.str, it)) }.toMap()
}
}
enum class AstUnop(val symbol: String, val str: String) {
NEG("-", "neg"),
NOT("!", "not"),
INV("~", "inv");
companion object {
//val operators = values.flatMap { listOf(Pair(it.symbol, it), Pair(it.str, it)) }.toMap()
}
}
data class AstLocal(val index: Int, val name: String, val type: AstType) {
override fun toString() = "AstLocal:$name:$type(w:$writesCount,r:$readCount)"
val writes = arrayListOf()
val reads = arrayListOf()
val writesCount: Int get() = writes.size // @TODO: In SSA this should be one
val readCount: Int get() = reads.size
val isUsed: Boolean get() = (writesCount != 0) || (readCount != 0)
fun write(set: AstStm.SET_LOCAL) {
writes += set
}
fun read(ref: AstExpr.LOCAL) {
reads += ref
}
}
fun AstType.local(name: String, index: Int = 0) = AstExpr.LOCAL(AstLocal(index, name, this))
data class AstTrap(val start: AstLabel, val end: AstLabel, val handler: AstLabel, val exception: AstType.REF)
data class AstLabel(val name: String) {
}
interface AstElement
interface Cloneable {
fun clone(): T
}
open class AstStm() : AstElement, Cloneable {
class Box(_value: AstStm) {
var value: AstStm = _value
get() = field
set(value) {
field.box = AstStm.Box(field)
field = value
field.box = this
}
init {
_value.box = this
}
}
var box: AstStm.Box = AstStm.Box(this)
override fun clone(): AstStm = noImpl("AstStm.clone: $this")
class STMS(stms: List) : AstStm() {
constructor(vararg stms: AstStm) : this(stms.toList())
val stms = stms.map { it.box }
}
class NOP(val reason: String) : AstStm() {
override fun toString(): String = "NOP($reason)"
}
class LINE(val line: Int) : AstStm() {
override fun toString() = "AstStm.LINE($line)"
}
class STM_EXPR(expr: AstExpr) : AstStm() {
val expr = expr.box
}
class SET_LOCAL(val local: AstExpr.LOCAL, expr: AstExpr) : AstStm() {
val expr = expr.box
override fun toString(): String = "SET_LOCAL($local = $expr)"
}
class SET_ARRAY(array: AstExpr, index: AstExpr, expr: AstExpr) : AstStm() {
val array = array.box
val index = index.box
val expr = expr.box
}
class SET_FIELD_STATIC(val field: AstFieldRef, expr: AstExpr) : AstStm() {
val clazz = AstType.REF(field.classRef.fqname)
val expr = expr.box
}
class SET_FIELD_INSTANCE(val field: AstFieldRef, left: AstExpr, expr: AstExpr) : AstStm() {
val left = left.box
val expr = expr.box
}
class SET_NEW_WITH_CONSTRUCTOR(val local: AstExpr.LocalExpr, val target: AstType.REF, val method: AstMethodRef, args: List) : AstStm() {
val args = args.map { it.box }
}
class IF(cond: AstExpr, strue: AstStm) : AstStm() {
val cond = cond.box
val strue = strue.box
}
class IF_ELSE(cond: AstExpr, strue: AstStm, sfalse: AstStm) : AstStm() {
val cond = cond.box
val strue = strue.box
val sfalse = sfalse.box
}
class WHILE(cond: AstExpr, iter: AstStm) : AstStm() {
val cond = cond.box
val iter = iter.box
}
class RETURN(retval: AstExpr) : AstStm() {
val retval = retval.box
}
class RETURN_VOID() : AstStm() {
}
class THROW(value: AstExpr) : AstStm() {
val value = value.box
}
class RETHROW() : AstStm() {
}
//data class TRY_CATCH(val trystm: AstStm, val catches: List>) : AstStm
class TRY_CATCH(trystm: AstStm, catch: AstStm) : AstStm() {
val trystm = trystm.box
val catch = catch.box
}
class BREAK() : AstStm() {
}
class CONTINUE() : AstStm() {
}
// SwitchFeature
class SWITCH(subject: AstExpr, default: AstStm, cases: List>) : AstStm() {
val subject = subject.box
val default = default.box
val cases = cases.map { it.first to it.second.box }
}
// GotoFeature
class STM_LABEL(val label: AstLabel) : AstStm() {
}
class SWITCH_GOTO(subject: AstExpr, val default: AstLabel, val cases: List>) : AstStm() {
val subject = subject.box
}
class IF_GOTO(val label: AstLabel, cond: AstExpr) : AstStm() {
val cond = cond.box
}
class GOTO(val label: AstLabel) : AstStm() {
}
class MONITOR_ENTER(expr: AstExpr) : AstStm() {
val expr = expr.box
}
class MONITOR_EXIT(expr: AstExpr) : AstStm() {
val expr = expr.box
}
//class DEBUG() : AstStm() {
//}
//
//class NOT_IMPLEMENTED() : AstStm() {
//}
companion object {
fun build(build: AstBuilder.() -> AstStm): AstStm = AstBuilder().build()
}
}
abstract class AstExpr : AstElement, Cloneable {
class Box(_value: AstExpr) {
var value: AstExpr = _value
set(value) {
field.box = AstExpr.Box(field)
field = value
field.box = this
}
init {
_value.box = this
}
val type: AstType get() = value.type
override fun toString(): String = "BOX($value)"
}
var box: AstExpr.Box = AstExpr.Box(this)
var stm: AstStm? = null
abstract val type: AstType
override fun clone(): AstExpr = noImpl("AstExpr.clone: $this")
abstract class ImmutableRef : AstExpr()
abstract class LValueExpr : AstExpr() {
}
abstract class LocalExpr : LValueExpr() {
abstract val name: String
}
// Reference
class THIS(val ref: FqName) : LocalExpr() {
override val name: String get() = "this"
override val type: AstType = AstType.REF(ref)
override fun clone(): AstExpr.THIS = THIS(ref)
}
class LOCAL(val local: AstLocal) : LocalExpr() {
override val name: String get() = local.name
override val type = local.type
override fun clone(): AstExpr.LOCAL = LOCAL(local)
override fun toString(): String = "LOCAL($local)"
}
class PARAM(val argument: AstArgument) : LocalExpr() {
override val name: String get() = argument.name
override val type = argument.type
override fun clone(): AstExpr.PARAM = PARAM(argument)
}
abstract class LiteralExpr : AstExpr() {
abstract val value: Any?
}
/*
class METHODTYPE_CONSTANT(val methodType: AstType.METHOD) : LiteralExpr() {
override val value = methodType
override val type: AstType = methodType
}
class METHODREF_CONSTANT(val methodRef: AstMethodRef) : LiteralExpr() {
override val value = methodRef
override val type: AstType = AstType.UNKNOWN
}
class METHODHANDLE_CONSTANT(val methodHandle: AstMethodHandle) : LiteralExpr() {
override val value = methodHandle
override val type: AstType = AstType.UNKNOWN
}
*/
class LITERAL(override val value: Any?) : LiteralExpr() {
override val type = AstType.fromConstant(value)
}
class CAUGHT_EXCEPTION(override val type: AstType = AstType.OBJECT) : AstExpr() {
}
class BINOP(override val type: AstType, left: AstExpr, val op: AstBinop, right: AstExpr) : AstExpr() {
val left = left.box
val right = right.box
}
class UNOP(val op: AstUnop, right: AstExpr) : AstExpr() {
val right = right.box
override val type = right.type
}
abstract class CALL_BASE : AstExpr() {
//override val type = method.type.ret
abstract val method: AstMethodRef
abstract val args: List
abstract val isSpecial: Boolean
}
class CALL_INSTANCE(obj: AstExpr, override val method: AstMethodRef, args: List, override val isSpecial: Boolean = false) : CALL_BASE() {
val obj = obj.box
override val args = args.map { it.box }
override val type = method.type.ret
}
//class CALL_SPECIAL(obj: AstExpr, override val method: AstMethodRef, args: List, override val isSpecial: Boolean = false) : CALL_BASE() {
// val obj = obj.box
// override val args = args.map { it.box }
//
// override val type = method.type.ret
//}
class CALL_SUPER(obj: AstExpr, val target: FqName, override val method: AstMethodRef, args: List, override val isSpecial: Boolean = false) : CALL_BASE() {
val obj = obj.box
override val args = args.map { it.box }
override val type = method.type.ret
}
class CALL_STATIC(val clazz: AstType.REF, override val method: AstMethodRef, args: List, override val isSpecial: Boolean = false) : CALL_BASE() {
override val args = args.map { it.box }
//val clazz: AstType.REF = method.classRef.type
override val type = method.type.ret
}
class ARRAY_LENGTH(array: AstExpr) : AstExpr() {
val array = array.box
override val type = AstType.INT
}
class ARRAY_ACCESS(array: AstExpr, index: AstExpr) : LValueExpr() {
val array = array.box
val index = index.box
override val type = array.type.elementType
}
class FIELD_INSTANCE_ACCESS(val field: AstFieldRef, expr: AstExpr) : LValueExpr() {
val expr = expr.box
override val type: AstType = field.type
}
class FIELD_STATIC_ACCESS(val field: AstFieldRef) : LValueExpr() {
val clazzName = field.containingTypeRef
override val type: AstType = field.type
}
class INSTANCE_OF(expr: AstExpr, val checkType: AstType) : AstExpr() {
val expr = expr.box
override val type = AstType.BOOL
}
class CAST(expr: AstExpr, val to: AstType) : AstExpr() {
val expr = expr.box
val from: AstType get() = expr.type
override val type = to
override fun clone(): AstExpr = CAST(expr.value.clone(), to)
}
class NEW(val target: AstType.REF) : AstExpr() {
override val type = target
}
class NEW_WITH_CONSTRUCTOR(val target: AstType.REF, val method: AstMethodRef, args: List) : AstExpr() {
val args = args.map { it.box }
override val type = target
}
class NEW_ARRAY(val arrayType: AstType.ARRAY, counts: List) : AstExpr() {
val counts = counts.map { it.box }
override val type = arrayType
}
class METHOD_CLASS(
val methodInInterfaceRef: AstMethodRef,
val methodToConvertRef: AstMethodRef
) : AstExpr() {
override val type = AstType.REF(methodInInterfaceRef.containingClass)
}
infix fun ge(that: AstExpr) = AstExpr.BINOP(AstType.BOOL, this, AstBinop.GE, that)
infix fun le(that: AstExpr) = AstExpr.BINOP(AstType.BOOL, this, AstBinop.LE, that)
infix fun band(that: AstExpr) = AstExpr.BINOP(AstType.BOOL, this, AstBinop.BAND, that)
infix fun and(that: AstExpr) = AstExpr.BINOP(this.type, this, AstBinop.AND, that)
infix fun instanceof(that: AstType) = AstExpr.INSTANCE_OF(this, that)
companion object {
fun build(build: AstBuilder.() -> AstExpr): AstExpr = AstBuilder().build()
}
class TERNARY(val cond: AstExpr, val etrue: AstExpr, val efalse: AstExpr) : AstExpr() {
override val type: AstType = AstType.unify(etrue.type, efalse.type)
}
}
object AstStmUtils {
fun set(local: AstLocal, value: AstExpr): AstStm.SET_LOCAL {
val stm = AstStm.SET_LOCAL(AstExpr.LOCAL(local), AstExprUtils.fastcast(value, local.type))
local.write(stm)
return stm
}
fun stms(stms: List): AstStm = when (stms.size) {
0 -> AstStm.NOP("empty stm")
1 -> stms[0]
else -> AstStm.STMS(stms)
//else -> AstStm.STMS(stms.flatMap { if (it is AstStm.STMS) it.stms.map { it.value } else listOf(it) })
}
}
object AstExprUtils {
fun localRef(local: AstLocal): AstExpr.LOCAL {
val localExpr = AstExpr.LOCAL(local)
//val refExpr = AstExpr.REF(localExpr)
local.read(localExpr)
return localExpr
}
fun cast(expr: AstExpr, to: AstType): AstExpr {
if (expr is AstExpr.LITERAL) {
val value = expr.value
when (value) {
is Boolean -> castLiteral(value, to)
is Byte -> castLiteral(value, to)
is Char -> castLiteral(value, to)
is Short -> castLiteral(value, to)
is Int -> castLiteral(value, to)
is Long -> castLiteral(value, to)
is Float -> castLiteral(value, to)
is Double -> castLiteral(value, to)
}
//return AstExpr.LITERAL(expr.value)
}
if (expr.type != to) {
return AstExpr.CAST(expr, to)
} else {
return expr
}
}
// Can cast nulls
fun fastcast(expr: AstExpr, to: AstType): AstExpr {
// LITERAL + IMMEDIATE = IMMEDIATE casted
if (expr.type != to) {
return AstExpr.CAST(expr, to)
} else {
return expr
}
}
fun INVOKE_DYNAMIC(generatedMethodRef: AstMethodWithoutClassRef, bootstrapMethodRef: AstMethodRef, bootstrapArgs: List): AstExpr {
if (bootstrapMethodRef.containingClass.fqname == "java.lang.invoke.LambdaMetafactory" &&
bootstrapMethodRef.name == "metafactory"
) {
val literals = bootstrapArgs.cast()
val interfaceMethodType = literals[0].value as AstType.METHOD
val methodHandle = literals[1].value as AstMethodHandle
val methodType = literals[2].type
val interfaceToGenerate = generatedMethodRef.type.ret as AstType.REF
val methodToConvertRef = methodHandle.methodRef
return AstExpr.METHOD_CLASS(
AstMethodRef(interfaceToGenerate.name, generatedMethodRef.name, interfaceMethodType),
methodToConvertRef
)
} else {
noImpl("Not supported DynamicInvoke yet!")
}
}
fun INVOKE_SPECIAL(obj: AstExpr, method: AstMethodRef, args: List): AstExpr.CALL_BASE {
if (obj.type !is AstType.REF) {
invalidOp("Obj must be an object $obj, but was ${obj.type}")
}
//if (obj is AstExpr.THIS && ((obj.type as AstType.REF).name != method.containingClass)) {
if ((obj.type as AstType.REF).name != method.containingClass) {
//if (caller == "" && ((obj.type as AstType.REF).name != method.containingClass)) {
return AstExpr.CALL_SUPER(cast(obj, method.containingClassType), method.containingClass, method, args, isSpecial = true)
} else {
return AstExpr.CALL_INSTANCE(cast(obj, method.containingClassType), method, args, isSpecial = true)
}
}
fun BINOP(type: AstType, l: AstExpr, op: AstBinop, r: AstExpr): AstExpr.BINOP {
if (l.type == AstType.BOOL && r.type == AstType.BOOL) {
if (op == AstBinop.AND) return AstExpr.BINOP(AstType.BOOL, cast(l, AstType.BOOL), AstBinop.BAND, cast(r, AstType.BOOL))
if (op == AstBinop.OR) return AstExpr.BINOP(AstType.BOOL, cast(l, AstType.BOOL), AstBinop.BOR, cast(r, AstType.BOOL))
if (op == AstBinop.XOR) return AstExpr.BINOP(AstType.BOOL, cast(l, AstType.BOOL), AstBinop.NE, cast(r, AstType.BOOL))
} else if (l.type == AstType.BOOL) {
return AstExpr.BINOP(type, cast(l, r.type), op, r)
} else if (r.type == AstType.BOOL) {
return AstExpr.BINOP(type, l, op, cast(r, l.type))
}
return AstExpr.BINOP(type, l, op, r)
}
fun RESOLVE_SPECIAL(program: AstProgram, e: AstExpr.CALL_INSTANCE, context: AstGenContext): AstExpr.CALL_BASE {
val clazz = program.get3(e.method.classRef)
val refMethod = program.get(e.method) ?: invalidOp("Can't find method: ${e.method} while generating $context")
// https://docs.oracle.com/javase/specs/jvms/se7/html/jvms-6.html#jvms-6.5.invokespecial
return if (refMethod.modifiers.isPrivate || refMethod.isInstanceInit) {
// Call this!
AstExpr.CALL_INSTANCE(e.obj.value, e.method, e.args.map { it.value }, e.isSpecial)
} else {
// Call super!
if (context.method.ref != e.method) {
AstExpr.CALL_SUPER(e.obj.value, e.method.containingClass, e.method, e.args.map { it.value }, e.isSpecial)
} else {
AstExpr.CALL_INSTANCE(e.obj.value, e.method, e.args.map { it.value }, e.isSpecial)
}
}
}
}
operator fun AstExpr.plus(that: AstExpr) = AstExpr.BINOP(this.type, this, AstBinop.ADD, that)
operator fun AstExpr.minus(that: AstExpr) = AstExpr.BINOP(this.type, this, AstBinop.SUB, that)
class AstBuilder {
val BOOL = AstType.BOOL
val BYTE = AstType.BYTE
val SHORT = AstType.SHORT
val CHAR = AstType.CHAR
val INT = AstType.INT
val LONG = AstType.LONG
val FLOAT = AstType.FLOAT
val DOUBLE = AstType.DOUBLE
val OBJECT = AstType.OBJECT
val CLASS = AstType.CLASS
val STRING = AstType.STRING
fun AstExpr.not() = AstExpr.UNOP(AstUnop.NOT, this)
fun AstExpr.cast(type: AstType) = AstExpr.CAST(this, type)
val Any?.lit: AstExpr.LITERAL get() = AstExpr.LITERAL(this)
operator fun AstExpr.plus(that: AstExpr) = AstExpr.BINOP(this.type, this, AstBinop.ADD, that)
operator fun AstExpr.minus(that: AstExpr) = AstExpr.BINOP(this.type, this, AstBinop.SUB, that)
operator fun AstExpr.times(that: AstExpr) = AstExpr.BINOP(this.type, this, AstBinop.MUL, that)
infix fun AstExpr.eq(that: AstExpr) = AstExpr.BINOP(this.type, this, AstBinop.EQ, that)
infix fun AstExpr.ne(that: AstExpr) = AstExpr.BINOP(this.type, this, AstBinop.NE, that)
fun AstExpr.stm() = AstStm.STM_EXPR(this)
infix fun AstLocal.assignTo(that: AstExpr) = AstStm.SET_LOCAL(AstExpr.LOCAL(this), that)
infix fun AstExpr.LOCAL.assignTo(that: AstExpr) = AstStm.SET_LOCAL(this, that)
//fun FqName.get(name:String):AstExpr.STATIC_FIELD_ACCESS = AstExpr.STATIC_FIELD_ACCESS(AstFieldRef())
}
fun AstBuild(build: AstBuilder.() -> AstExpr): AstExpr {
return AstBuilder().build()
}
fun AstBuildStm(build: AstBuilder.() -> AstStm): AstStm {
return AstBuilder().build()
}
fun AstExpr.builder() {
}
class AstMethodHandle(val type: AstType.METHOD, val methodRef: AstMethodRef, val kind: Kind) {
enum class Kind(val id: Int) {
REF_getField(1),
REF_getStatic(2),
REF_putField(3),
REF_putStatic(4),
REF_invokeVirtual(5),
REF_invokeStatic(6),
REF_invokeSpecial(7),
REF_newInvokeSpecial(8),
REF_invokeInterface(9);
companion object {
private val table = values().map { it.id to it }.toMap()
fun fromId(id: Int) = table[id]!!
}
}
}
val Iterable.stms: AstStm get() = AstStm.STMS(this.toList())
val Any?.lit: AstExpr get() = AstExpr.LITERAL(this)
fun AstExpr.not() = AstExpr.UNOP(AstUnop.NOT, this)
© 2015 - 2025 Weber Informatics LLC | Privacy Policy