Skip to content
This repository was archived by the owner on Apr 30, 2025. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ jtranscVersion=0.8.0-SNAPSHOT
group=com.jtransc
file.encoding=UTF-8

kotlinVersion=1.4.31
kotlinVersion=1.5.10
bintrayVersion=1.7.3

mavenPluginAnnotationsVersion=3.4
Expand Down
105 changes: 92 additions & 13 deletions jtransc-core/src/com/jtransc/ast/ast.kt
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import com.jtransc.*
import com.jtransc.annotation.*
import com.jtransc.ast.dependency.AstDependencyAnalyzer
import com.jtransc.ast.optimize.AstOptimizer
import com.jtransc.backend.*
import com.jtransc.ds.cast
import com.jtransc.ds.clearFlags
import com.jtransc.ds.combinedWith
Expand All @@ -34,6 +35,7 @@ import com.jtransc.lang.Extra
import com.jtransc.lang.putIfAbsentJre7
import com.jtransc.maven.MavenLocalRepository
import com.jtransc.org.objectweb.asm.Type
import com.jtransc.org.objectweb.asm.tree.*
import com.jtransc.text.quote
import com.jtransc.text.substr
import com.jtransc.util.dependencySorter
Expand All @@ -42,6 +44,8 @@ import com.jtransc.vfs.UserData
import java.io.File
import java.io.IOException
import java.util.*
import kotlin.collections.ArrayDeque
import kotlin.collections.ArrayList
import kotlin.reflect.KMutableProperty1

data class ConfigCompile(val compile: Boolean = true)
Expand Down Expand Up @@ -110,17 +114,40 @@ data class AstBuildSettings(
}

interface AstClassGenerator {
fun getOrGenerateClass(program: AstProgram, fqname: FqName): AstClass {
return program.getOrNull(fqname) ?: generateClass(program, fqname)
}

fun generateClass(program: AstProgram, fqname: FqName): AstClass
fun generateAndAddMethod(program: AstProgram, ref: AstMethodRef): AstMethod {
val clazz = getOrGenerateClass(program, ref.classRef.name)
tryGenerateAndAddMethod(clazz, ref)?.let { return it }
TODO("Can't find $ref in any ancestor : ${clazz.thisAncestorsAndInterfaces.map { it.name }}")
}
fun tryGenerateAndAddMethod(clazz: AstClass, ref: AstMethodRef): AstMethod? {
val refWithoutClass = ref.withoutClass

val allClasses = clazz.thisAncestorsAndInterfaces + clazz.allInterfacesInAncestors.toSet()

for (subClass in allClasses) {
if (subClass.hasBasicMethod(refWithoutClass)) {
return generateAndAddMethod(subClass, refWithoutClass)
}
}
return null
}

fun generateAndAddMethod(clazz: AstClass, ref: AstMethodWithoutClassRef): AstMethod
}

interface AstResolver {
operator fun get(ref: AstMethodRef): AstMethod?
operator fun get(ref: AstFieldRef): AstField?
operator fun get(name: FqName): AstClass?
operator fun get(ref: AstMethodRef, reason: Any? = null): AstMethod?
operator fun get(ref: AstFieldRef, reason: Any? = null): AstField?
operator fun get(name: FqName, reason: Any? = null): AstClass?
operator fun contains(name: FqName): Boolean
}

operator fun AstResolver.get(ref: AstType.REF): AstClass? = this[ref.name]
operator fun AstResolver.get(ref: AstType.REF, reason: Any? = null): AstClass? = this.get(ref.name, reason)

fun AstResolver.get3(ref: AstType.REF): AstClass = this[ref.name]!!

Expand Down Expand Up @@ -192,11 +219,15 @@ class AstProgram(

val classes: List<AstClass> get() = _classes

private val classesToGenerate = LinkedList<AstType.REF>()
private val classesToGenerate = ArrayDeque<AstType.REF>()
private val referencedClasses = hashSetOf<AstType.REF>()
private val referencedClassBy = hashMapOf<AstType.REF, AstType.REF>()

private val methodsToGenerate = ArrayDeque<AstMethodRef>()
private val referencedMethods = hashSetOf<AstMethodRef>()

fun hasClassToGenerate() = classesToGenerate.isNotEmpty()
fun hasMethodToGenerate() = methodsToGenerate.isNotEmpty()

fun getClassBytes(clazz: FqName): ByteArray {
try {
Expand All @@ -206,7 +237,8 @@ class AstProgram(
}
}

fun readClassToGenerate(): AstType.REF = classesToGenerate.remove()
fun readClassToGenerate(): AstType.REF = classesToGenerate.removeFirst()
fun readMethodToGenerate(): AstMethodRef = methodsToGenerate.removeFirst()

fun addReference(clazz: AstType.REF, referencedBy: AstType.REF) {
if (clazz !in referencedClasses) {
Expand All @@ -216,20 +248,29 @@ class AstProgram(
}
}

fun addReference(methodRef: AstMethodRef, referencedBy: AstType.REF) {
if (methodRef !in referencedMethods) {
println("REFERENCED: $methodRef")
methodsToGenerate += methodRef
referencedMethods += methodRef
}
}

override operator fun contains(name: FqName) = name.fqname in _classesByFqname
//operator fun get(name: FqName) = classesByFqname[name.fqname] ?: throw RuntimeException("AstProgram. Can't find class '$name'")

fun getOrNull(name: FqName): AstClass? {
return _classesByFqname[name.fqname]
}

override operator fun get(name: FqName): AstClass {
override fun get(name: FqName, reason: Any?): AstClass {
val result = getOrNull(name)
if (result == null) {
val classFile = name.internalFqname + ".class"
println("AstProgram. Can't find class '$name'")
println("AstProgram. ClassFile: $classFile")
println("AstProgram. File exists: " + resourcesVfs[classFile].exists + " : " + resourcesVfs[classFile].realpathOS)
println("AstProgram. Reason: $reason")
println("ConfigClassPaths:")
for (classPath in injector.get<ConfigClassPaths>().classPaths) {
println(" - $classPath")
Expand Down Expand Up @@ -262,9 +303,9 @@ class AstProgram(

val allAnnotationsList by lazy { AstAnnotationList(AstProgramRef, allAnnotations) }

override operator fun get(ref: AstMethodRef): AstMethod? = this[ref.containingClass].getMethodInAncestorsAndInterfaces(ref.nameDesc)
override operator fun get(ref: AstMethodRef, reason: Any?): AstMethod? = this[ref.containingClass].getMethodInAncestorsAndInterfaces(ref.nameDesc)
//override operator fun get(ref: AstFieldRef): AstField = this[ref.containingClass][ref]
override operator fun get(ref: AstFieldRef): AstField = this[ref.containingClass].get(ref.withoutClass)
override operator fun get(ref: AstFieldRef, reason: Any?): AstField = this[ref.containingClass].get(ref.withoutClass)

operator fun get(ref: FieldRef): AstField = this[ref.ref.containingClass].get(ref.ref.withoutClass)

Expand Down Expand Up @@ -344,7 +385,7 @@ val AstAnnotated?.keepName: Boolean get() = this?.annotationsList?.contains<JTra

val Type.fqname get() = this.className.fqname

class AstClass(
class AstClass constructor(
val source: String,
program: AstProgram,
val name: FqName,
Expand All @@ -354,8 +395,22 @@ class AstClass(
annotations: List<AstAnnotation> = listOf(),
val classId: Int = program.lastClassId++
) : AstAnnotatedElement(program, name.ref, annotations), IUserData by UserData(), WithAstModifiersClass {
var classNode: ClassNode? = null
var classNodeMethods: Map<AstMethodWithoutClassRef, MethodNode>? = null
//var classNodeFields: Map<AstMethodRef, FieldNode>? = null

val types get() = program.types

fun hasBasicMethod(methodRef: AstMethodWithoutClassRef): Boolean {
return classNodeMethods?.contains(methodRef) == true
}

fun setAsmClassNode(classNode: ClassNode) {
this.classNode = classNode
classNodeMethods = classNode.methods.associateBy { it.astRef(this.ref, types).withoutClass }
//classNodeFields = classNode.fields.associateBy { AstFieldRef(name, it.name, AstType.) }
}

val implementingUnique by lazy { implementing.distinct() }
val THIS: AstExpr get() = AstExpr.THIS(name)
//var lastMethodId = 0
Expand Down Expand Up @@ -419,9 +474,28 @@ class AstClass(
}

//fun getDirectInterfaces(): List<AstClass> = implementing.map { program[it] }
val directInterfaces: List<AstClass> by lazy { implementing.map { program[it] } }
val directInterfaces: List<AstClass> by lazy {
implementing.mapNotNull { interfaceName ->
program.getOrNull(interfaceName).also {
if (it == null) {
println(interfaceName)
}
}
}
//implementing.map { program.get(it, this) }
}

val parentClass: AstClass? by lazy { if (extending != null) program[extending] else null }
val parentClass: AstClass? by lazy {
if (extending != null) {
program.getOrNull(extending).also {
if (it == null) {
System.err.println("AstClass.parentClass.extending can't find $extending")
}
} ?: program["java.lang.Object".fqname]
} else {
null
}
}

val parentClassList by lazy { listOf(parentClass).filterNotNull() }
//fun getParentClass(): AstClass? = if (extending != null) program[extending] else null
Expand Down Expand Up @@ -590,7 +664,12 @@ class AstClass(
if (extending == null) {
listOf(this)
} else {
listOf(this) + program[extending].thisAndAncestors
listOf(this) + program.getOrNull(extending)?.thisAndAncestors.let {
if (it == null) {
System.err.println("ERROR thisAndAncestors: extending=$extending")
}
it ?: listOf()
}
}
}

Expand Down
4 changes: 4 additions & 0 deletions jtransc-core/src/com/jtransc/ast/ast_ref.kt
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,10 @@ data class AstFieldWithoutClassRef(val name: String, val type: AstType)
data class AstFieldWithoutTypeRef(val containingClass: FqName, val name: String)

data class AstMethodWithoutClassRef(val name: String, val type: AstType.METHOD) {
companion object {
val CLINIT = AstMethodWithoutClassRef("<clinit>", AstType.METHOD(AstType.VOID, listOf()))
}

val fid2: String get() = "$name:${type.mangle()}"
val fid2Wildcard: String get() = "$name:*"
val desc = type.desc
Expand Down
13 changes: 13 additions & 0 deletions jtransc-core/src/com/jtransc/ast/ast_references.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ package com.jtransc.ast
import com.jtransc.annotation.JTranscAddFileList
import com.jtransc.annotation.JTranscAddMembersList
import com.jtransc.annotation.JTranscMethodBodyList
import com.jtransc.ast.References.getClassReferences
import com.jtransc.ast.References.getMethodReferences
import com.jtransc.ast.treeshaking.GetClassTemplateReferences
import com.jtransc.ast.treeshaking.TRefConfig
import com.jtransc.ast.treeshaking.TRefReason
Expand Down Expand Up @@ -48,6 +50,11 @@ object References {
return this.genericType.getRefClasses() + this.annotations.getClassReferences(targetName)
}

fun AstMethod.getMethodReferences(targetName: TargetName): List<AstMethodRef> {
val methodBodyList = this.annotationsList.getBodiesForTarget(targetName)
return if (methodBodyList.isEmpty()) this.body?.getMethodReferences() ?: listOf() else listOf()
}

fun AstMethod.getClassReferences(targetName: TargetName): List<AstType.REF> {
val clazzFqname = this.containingClass.name
val signatureRefs = this.genericMethodType.getRefClasses()
Expand Down Expand Up @@ -108,6 +115,12 @@ object References {
return locals + traps + stms
}

fun AstBody.getMethodReferences(): List<AstMethodRef> {
val refs = ReferencesVisitor()
refs.visit(this)
return refs.methodReferences.toList()
}

fun AstStm.getClassReferences(): List<AstType.REF> {
val refs = ReferencesVisitor()
refs.visit(this)
Expand Down
26 changes: 18 additions & 8 deletions jtransc-core/src/com/jtransc/ast/ast_type.kt
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,10 @@ open class AstType {
object DOUBLE : Primitive("java.lang.Double", 'D', "double", 8, priority = 0, subsets = setOf(BOOL, BYTE, CHAR, SHORT, INT))

data class REF(val name: FqName) : Reference(), AstRef {
constructor(name: String) : this(FqName(name))
//constructor(name: String) : this(FqName(name))
companion object {
operator fun invoke(name: String) = REF(FqName(name))
}

init {
if (fqname.contains(';') || fqname.contains(']')) {
Expand Down Expand Up @@ -345,7 +348,9 @@ fun _castLiteral(value: Int, to: AstType): Any = when (to) {
AstType.FLOAT -> value.toFloat()
AstType.DOUBLE -> value.toDouble()
//is AstType.Reference -> null
else -> invalidOp("Can't cast $value to $to")
else -> {
invalidOp("Can't cast $value to $to")
}
}

fun <T> Class<T>.ref() = AstType.REF(this.name)
Expand All @@ -370,9 +375,9 @@ fun _castLiteral(value: Long, to: AstType): Any = when (to) {

fun _castLiteral(value: Float, to: AstType): Any = when (to) {
AstType.BOOL -> value.toBool()
AstType.BYTE -> value.toByte()
AstType.BYTE -> value.toInt().toByte()
AstType.CHAR -> value.toChar()
AstType.SHORT -> value.toShort()
AstType.SHORT -> value.toInt().toShort()
AstType.INT -> value.toInt()
AstType.LONG -> value.toLong()
AstType.FLOAT -> value.toFloat()
Expand All @@ -382,9 +387,9 @@ fun _castLiteral(value: Float, to: AstType): Any = when (to) {

fun _castLiteral(value: Double, to: AstType): Any = when (to) {
AstType.BOOL -> value.toBool()
AstType.BYTE -> value.toByte()
AstType.BYTE -> value.toInt().toByte()
AstType.CHAR -> value.toChar()
AstType.SHORT -> value.toShort()
AstType.SHORT -> value.toInt().toShort()
AstType.INT -> value.toInt()
AstType.LONG -> value.toLong()
AstType.FLOAT -> value.toFloat()
Expand Down Expand Up @@ -436,6 +441,7 @@ data class AstArgument(val index: Int, val type: AstType, override val name: Str
}

data class FqName(val fqname: String) : Serializable {
//inline class FqName(val fqname: String) : Serializable {
constructor(packagePath: String, simpleName: String) : this("$packagePath.$simpleName".trim('.'))

constructor(packageParts: List<String>, simpleName: String) : this("${packageParts.joinToString(".")}.$simpleName".trim('.'))
Expand All @@ -449,7 +455,7 @@ data class FqName(val fqname: String) : Serializable {
}

init {
//if (fqname.isNullOrBlank()) invalidOp("Fqname is empty!")
if (fqname.isNullOrBlank()) invalidOp("Fqname is empty!")

if (!fqname.isEmpty()) {
val f = fqname.first()
Expand All @@ -468,14 +474,18 @@ data class FqName(val fqname: String) : Serializable {
val internalFqname by lazy { fqname.replace('.', '/') }
val pathToClass by lazy { "$internalFqname.class" }

//val packagePath get() = fqname.substringBeforeLast('.', "")
//val simpleName get() = fqname.substringAfterLast('.')
//val internalFqname get() = fqname.replace('.', '/')
//val pathToClass get() = "$internalFqname.class"

fun withPackagePath(packagePath: String) = FqName(packagePath, simpleName)
fun withPackageParts(packageParts: List<String>) = FqName(packageParts, simpleName)
fun withSimpleName(simpleName: String) = FqName(packagePath, simpleName)

override fun toString() = fqname

override fun hashCode(): Int = fqname.hashCode()

override fun equals(other: Any?): Boolean = this.fqname == (other as? FqName)?.fqname

fun append(s: String): FqName = FqName(this.fqname + s)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ fun genStaticInitOrder(program: AstProgram, plugins: JTranscPluginGroup) {
}

if (ref is AstType.REF) {
lockClass(program[ref]!!)
lockClass(program.get(ref, method)!!)
}

// First visit static constructor
Expand Down
12 changes: 11 additions & 1 deletion jtransc-core/src/com/jtransc/backend/AsmToAst.kt
Original file line number Diff line number Diff line change
Expand Up @@ -42,14 +42,24 @@ abstract class BaseAsmToAst(val types: AstTypes, val settings: AstBuildSettings)
extending = if (classNode.hasSuperclass() && !classNode.isInterface()) FqName.fromInternal(classNode.superName) else null,
implementing = classNode.getInterfaces().map { FqName.fromInternal(it) }
)

astClass.setAsmClassNode(classNode)
program.add(astClass)

classNode.getMethods().withIndex().forEach { astClass.add(generateMethod(astClass, it.value)) }
//classNode.getMethods().withIndex().forEach { astClass.add(generateMethod(astClass, it.value)) }
classNode.getFields().withIndex().forEach { astClass.add(generateField(astClass, it.value)) }

return astClass
}

override fun generateAndAddMethod(clazz: AstClass, ref: AstMethodWithoutClassRef): AstMethod {
val methodNode = clazz.classNodeMethods?.get(ref) ?: error("Can't find ref: $ref")
return clazz.methodsByNameDesc[ref] ?: generateMethod(clazz, methodNode).also {
clazz.add(it)
}
}


fun generateMethod(containingClass: AstClass, method: MethodNode): AstMethod {
val mods = AstModifiers(method.access)
val methodRef = method.astRef(containingClass.ref, types)
Expand Down
Loading