From d54573695785c4a85b4ca9eda690e1aaec64987c Mon Sep 17 00:00:00 2001 From: Wagyourtail Date: Wed, 11 Sep 2024 21:10:27 -0500 Subject: [PATCH] work on inheritance tree. fields in signature reader --- build.gradle.kts | 37 +++----- cli/build.gradle.kts | 8 +- gradle.properties | 5 - gradle/libs.versions.toml | 38 ++++++++ .../formats/feather/SignatureReader.kt | 13 ++- .../mapping/propagator/InheritanceTree.kt | 94 +++++++++++++++---- .../mapping/tree/node/_class/ClassNode.kt | 34 +++++-- 7 files changed, 171 insertions(+), 58 deletions(-) create mode 100644 gradle/libs.versions.toml diff --git a/build.gradle.kts b/build.gradle.kts index ade63a3..e685109 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,13 +1,10 @@ -import org.jetbrains.kotlin.gradle.ExperimentalKotlinGradlePluginApi -import xyz.wagyourtail.commons.gradle.shadow.ShadowJar import java.net.URI plugins { - val kotlinVersion: String by System.getProperties() - kotlin("multiplatform") version kotlinVersion + kotlin("multiplatform") version libs.versions.kotlin.asProvider() + kotlin("plugin.serialization") version libs.versions.kotlin.asProvider() + id("xyz.wagyourtail.commons-gradle") version libs.versions.commons `maven-publish` - kotlin("plugin.serialization") version kotlinVersion - id("xyz.wagyourtail.commons-gradle") version "1.0.0-SNAPSHOT" } allprojects { @@ -26,9 +23,6 @@ allprojects { } } -val kotlinVersion: String by System.getProperties() -val javaVersion: String by System.getProperties() - kotlin { jvmToolchain(8) jvm { @@ -52,29 +46,26 @@ kotlin { sourceSets { val commonMain by getting { dependencies { - api("xyz.wagyourtail.commons:commons-kt:1.0.0-SNAPSHOT") - api("io.github.oshai:kotlin-logging:6.0.1") - api("com.squareup.okio:okio:3.7.0") - api("com.sschr15.annotations:jb-annotations-kmp:24.1.0") - api("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.8.0-RC2") - api("org.jetbrains.kotlinx:kotlinx-serialization-json:1.6.2") + api(libs.commons.kt) + api(libs.kotlin.logging) + api(libs.okio) + api(libs.jetbrains.annotations.kmp) + api(libs.kotlin.coroutines) + api(libs.kotlin.serialization.json) } } val commonTest by getting { dependencies { implementation(kotlin("test-common")) implementation(kotlin("test-annotations-common")) - implementation("org.jetbrains.kotlinx:kotlinx-coroutines-test:1.8.0-RC2") + implementation(libs.kotlin.coroutines.tests) } } val jvmMain by getting { dependencies { - // apache compress - api("org.apache.commons:commons-compress:1.26.1") - - // asm - api("org.ow2.asm:asm:9.6") - api("org.ow2.asm:asm-tree:9.6") + api(libs.appache.commons.compress) + api(libs.asm) + api(libs.asm.tree) } } val jvmTest by getting { @@ -85,7 +76,7 @@ kotlin { } val jsMain by getting { dependencies { - implementation(npm("jszip", "3.10.1")) + implementation(npm("jszip", libs.versions.jszip.get())) } } val jsTest by getting { diff --git a/cli/build.gradle.kts b/cli/build.gradle.kts index 60a3417..e19a5b0 100644 --- a/cli/build.gradle.kts +++ b/cli/build.gradle.kts @@ -4,15 +4,13 @@ plugins { kotlin("jvm") } -val cliktVersion: String by project.properties - dependencies { implementation(project(":")) - implementation("com.github.ajalt.clikt:clikt:$cliktVersion") + implementation(libs.clikt) - implementation("org.slf4j:slf4j-api:2.0.12") - implementation("org.slf4j:slf4j-simple:2.0.10") + implementation(libs.slf4j.api) + implementation(libs.slf4j.simple) } diff --git a/gradle.properties b/gradle.properties index bb9b29a..c85dba1 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,11 +1,6 @@ kotlin.code.style=official -javaVersion=8 -systemProp.kotlinVersion=2.0.20 - group=xyz.wagyourtail.unimined.mapping archives_base_name=unimined-mapping-library version=1.0.0 - -cliktVersion=4.2.1 \ No newline at end of file diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml new file mode 100644 index 0000000..b888417 --- /dev/null +++ b/gradle/libs.versions.toml @@ -0,0 +1,38 @@ +[versions] +asm = "9.7" +okio = "3.7.0" +kotlin = "2.0.20" +commons = "1.0.0-SNAPSHOT" +jb_annotations = "24.1.0" +apache_commons_compress = "1.26.2" +kotlin_serialization = "1.6.2" +kotlin_coroutines = "1.9.0-RC" +kotlin_logging = "6.0.1" +clikt = "4.3.0" +slf4j = "2.0.13" + +jszip = "3.10.1" + +[libraries] +asm = { module = "org.ow2.asm:asm", version.ref = "asm" } +asm_commons = { module = "org.ow2.asm:asm-commons", version.ref = "asm" } +asm_util = { module = "org.ow2.asm:asm-util", version.ref = "asm" } +asm_analysis = { module = "org.ow2.asm:asm-analysis", version.ref = "asm" } +asm_tree = { module = "org.ow2.asm:asm-tree", version.ref = "asm" } + +okio = { module = "com.squareup.okio:okio", version.ref = "okio" } + +commons_kt = { module = "xyz.wagyourtail.commons:commons-kt", version.ref = "commons" } + +jetbrains_annotations_kmp = { module = "com.sschr15.annotations:jb-annotations-kmp", version.ref = "jb_annotations" } +appache_commons_compress = { module = "org.apache.commons:commons-compress", version.ref = "apache_commons_compress" } + +kotlin_coroutines = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-core", version.ref = "kotlin_coroutines" } +kotlin_coroutines_tests = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-test", version.ref = "kotlin_coroutines" } +kotlin_serialization_json = { module = "org.jetbrains.kotlinx:kotlinx-serialization-json", version.ref = "kotlin_serialization" } +kotlin_logging = { module = "io.github.oshai:kotlin-logging", version.ref = "kotlin_logging" } + +clikt = { module = "com.github.ajalt.clikt:clikt", version.ref = "clikt" } + +slf4j_api = { module = "org.slf4j:slf4j-api", version.ref = "slf4j" } +slf4j_simple = { module = "org.slf4j:slf4j-simple", version.ref = "slf4j" } \ No newline at end of file diff --git a/src/commonMain/kotlin/xyz/wagyourtail/unimined/mapping/formats/feather/SignatureReader.kt b/src/commonMain/kotlin/xyz/wagyourtail/unimined/mapping/formats/feather/SignatureReader.kt index c4e6cdc..d30f4b1 100644 --- a/src/commonMain/kotlin/xyz/wagyourtail/unimined/mapping/formats/feather/SignatureReader.kt +++ b/src/commonMain/kotlin/xyz/wagyourtail/unimined/mapping/formats/feather/SignatureReader.kt @@ -6,6 +6,7 @@ import xyz.wagyourtail.commonskt.utils.translateEscapes import xyz.wagyourtail.unimined.mapping.EnvType import xyz.wagyourtail.unimined.mapping.Namespace import xyz.wagyourtail.unimined.mapping.formats.FormatReader +import xyz.wagyourtail.unimined.mapping.jvms.ext.FieldOrMethodDescriptor import xyz.wagyourtail.unimined.mapping.jvms.four.three.three.MethodDescriptor import xyz.wagyourtail.unimined.mapping.jvms.four.two.one.InternalName import xyz.wagyourtail.unimined.mapping.tree.AbstractMappingTree @@ -52,10 +53,16 @@ object SignatureReader : FormatReader { throw IllegalArgumentException("invalid line: $whitespace") } val mName = input.takeNextLiteral()!!.translateEscapes() - val desc = MethodDescriptor.read(input.takeNextLiteral()!!.translateEscapes()) + val desc = FieldOrMethodDescriptor.read(input.takeNextLiteral()!!.translateEscapes()) val sig = input.takeNextLiteral()!!.translateEscapes() - cls?.visitMethod(mapOf(ns to (mName to desc)))?.use { - visitSignature(sig, ns, emptySet()) + if (desc.isMethodDescriptor()) { + cls?.visitMethod(mapOf(ns to (mName to desc.getMethodDescriptor())))?.use { + visitSignature(sig, ns, emptySet()) + } + } else { + cls?.visitField(mapOf(ns to (mName to desc.getFieldDescriptor())))?.use { + visitSignature(sig, ns, emptySet()) + } } } diff --git a/src/commonMain/kotlin/xyz/wagyourtail/unimined/mapping/propagator/InheritanceTree.kt b/src/commonMain/kotlin/xyz/wagyourtail/unimined/mapping/propagator/InheritanceTree.kt index c5e4918..99ac949 100644 --- a/src/commonMain/kotlin/xyz/wagyourtail/unimined/mapping/propagator/InheritanceTree.kt +++ b/src/commonMain/kotlin/xyz/wagyourtail/unimined/mapping/propagator/InheritanceTree.kt @@ -14,8 +14,9 @@ import xyz.wagyourtail.unimined.mapping.jvms.four.two.one.InternalName import xyz.wagyourtail.unimined.mapping.tree.AbstractMappingTree import xyz.wagyourtail.commonskt.reader.CharReader import xyz.wagyourtail.commonskt.utils.coroutines.parallelMap +import xyz.wagyourtail.unimined.mapping.tree.node._class.ClassNode -open class InheritanceTree(val tree: AbstractMappingTree, val ns: Namespace) { +open class InheritanceTree(val tree: AbstractMappingTree, val fns: Namespace, val targets: Set) { val LOGGER = KotlinLogging.logger { } private val _classes = mutableMapOf() @@ -55,7 +56,7 @@ open class InheritanceTree(val tree: AbstractMappingTree, val ns: Namespace) { val desc = FieldOrMethodDescriptor.read(data.takeNext()!!) if (desc.isMethodDescriptor()) { - ci!!._methods.add( + ci!!.methods.add( MethodInfo( name, desc.getMethodDescriptor(), @@ -63,7 +64,7 @@ open class InheritanceTree(val tree: AbstractMappingTree, val ns: Namespace) { ) ) } else { - ci!!._fields.add( + ci!!.fields.add( FieldInfo( name, desc.getFieldDescriptor(), @@ -84,7 +85,7 @@ open class InheritanceTree(val tree: AbstractMappingTree, val ns: Namespace) { append(cls.interfaces.joinToString("\t") { it.toString() }) append("\n") - for (method in cls._methods) { + for (method in cls.methods) { append("\t") append(AccessFlag.of(ElementType.METHOD, method.access).joinToString("|") { it.toString() }) append("\t") @@ -102,45 +103,106 @@ open class InheritanceTree(val tree: AbstractMappingTree, val ns: Namespace) { val superType: InternalName?, val interfaces: List, ) { - val _methods = mutableListOf() - val methods: List get() = _methods + val methods = mutableListOf() - val _fields = mutableListOf() - val fields: List get() = _fields + val fields = mutableListOf() val superClass by lazy { this@InheritanceTree.classes[superType] } val interfaceClasses by lazy { - interfaces.map { this@InheritanceTree.classes[it] } + interfaces.mapNotNull { this@InheritanceTree.classes[it] } } val clsNode by lazy { - tree.getClass(ns, name) + tree.getClass(fns, name) } val propagateLock = Mutex() - lateinit var methodData: MutableMap, Map> + lateinit var methodData: MutableMap> - suspend fun propagate(): Map, Map> = coroutineScope { + suspend fun propagate(): Unit = coroutineScope { if (::methodData.isInitialized) methodData propagateLock.withLock { if (::methodData.isInitialized) methodData - methods.filter { md -> + + superClass?.propagate() + interfaceClasses.parallelMap { it.propagate() } + + for (method in methods) { + clsNode?.visitMethod(mapOf(fns to (method.name to method.descriptor))).visitEnd() + } + + val methods = methods.filter { md -> // modify access val acc = AccessFlag.of(ElementType.METHOD, md.access).toMutableSet() - val methods = clsNode?.getMethods(ns, md.name, md.descriptor) + val methods = clsNode?.getMethods(fns, md.name, md.descriptor) methods?.flatMap { it.access }?.forEach { it.apply(acc) } AccessFlag.isInheritable(acc) - }.parallelMap { + }.parallelMap { md -> + val names = (clsNode?.getMethods(fns, md.name, md.descriptor)?.firstOrNull()?.names?.filterKeys { it in targets } ?: emptyMap()).toMutableMap() // traverse parents, retrieve matching mappings + val superNames = superClass?.methodData?.get(md) + val interfaces = interfaceClasses.map { it to it.methodData[md] } + for (ns in targets) { + if (superNames != null) { + if (names[ns] != superNames[ns]) { + if (superNames[ns] == null) { + superClass!!.overwriteMethodName(md, ns, names[ns]!!) + } else { + names[ns] = superNames.getValue(ns) + } + } + } + for ((intf, intfNames) in interfaces) { + if (intfNames != null) { + if (names[ns] != intfNames[ns] && names[ns] != null) { + intf.overwriteMethodName(md, ns, names[ns]!!) + } + } + } + } + clsNode?.visitMethod( + mapOf(fns to (md.name to md.descriptor)) + + names.mapValues { it.value to null } + )?.visitEnd() + names[fns] = md.name + md to names + }.associate { it }.toMutableMap() + + for (method in superClass?.methodData ?: emptyMap()) { + if (method.key !in methods) { + methods[method.key] = method.value + } + } + + for (intf in interfaceClasses) { + for (method in intf.methodData) { + if (method.key !in methods) { + methods[method.key] = method.value + } + } + } + + methodData = methods + } + } + private fun overwriteMethodName(md: MethodInfo, namespace: Namespace, newName: String) { + if (md in methodData) { + methodData[md]!![namespace] = newName + clsNode?.visitMethod(mapOf( + fns to (md.name to md.descriptor), + namespace to (newName to null) + ))?.visitEnd() + superClass?.overwriteMethodName(md, namespace, newName) + for (interfaceClass in interfaceClasses) { + interfaceClass.overwriteMethodName(md, namespace, newName) } - methodData } } diff --git a/src/commonMain/kotlin/xyz/wagyourtail/unimined/mapping/tree/node/_class/ClassNode.kt b/src/commonMain/kotlin/xyz/wagyourtail/unimined/mapping/tree/node/_class/ClassNode.kt index 4069e35..6b5505a 100644 --- a/src/commonMain/kotlin/xyz/wagyourtail/unimined/mapping/tree/node/_class/ClassNode.kt +++ b/src/commonMain/kotlin/xyz/wagyourtail/unimined/mapping/tree/node/_class/ClassNode.kt @@ -54,24 +54,46 @@ class ClassNode(parent: AbstractMappingTree) : MemberNode { - val fields = mutableSetOf() + /** + * because of how resolve works, there should really be a max of 2 + * the one that matches best will be first. + * ie, if desc is not-null, it'll put the match with a not-null desc first. + * or vis-versa for null descs. + */ + fun getFields(namespace: Namespace, name: String, desc: FieldDescriptor?): List { + val fields = mutableListOf() for (field in this.fields.resolve()) { if (field.getName(namespace) == name) { if (desc == null || !field.hasDescriptor() || field.getFieldDesc(namespace) == desc) { - fields.add(field) + // ensure best match first + if ((desc == null) xor field.hasDescriptor()) { + fields.add(0, field) + } else { + fields.add(field) + } } } } return fields } - fun getMethods(namespace: Namespace, name: String, desc: MethodDescriptor?): Set { - val methods = mutableSetOf() + /** + * because of how resolve works, there should really be a max of 2 + * the one that matches best will be first. + * ie, if desc is not-null, it'll put the match with a not-null desc first. + * or vis-versa for null descs. + */ + fun getMethods(namespace: Namespace, name: String, desc: MethodDescriptor?): List { + val methods = mutableListOf() for (method in this.methods.resolve()) { if (method.getName(namespace) == name) { if (desc == null || !method.hasDescriptor() || method.getMethodDesc(namespace) == desc) { - methods.add(method) + // ensure best match first + if ((desc == null) xor method.hasDescriptor()) { + methods.add(0, method) + } else { + methods.add(method) + } } } }