Add arch/OS enums to avoid hard-coding the platform detection patch

Signed-off-by: Graham <gpe@openrs2.org>
pull/132/head
Graham 3 years ago
parent 80957aeca0
commit 3091409f82
  1. 10
      patcher/src/main/kotlin/org/openrs2/patcher/Architecture.kt
  2. 17
      patcher/src/main/kotlin/org/openrs2/patcher/OperatingSystem.kt
  3. 76
      patcher/src/main/kotlin/org/openrs2/patcher/Resource.kt
  4. 164
      patcher/src/main/kotlin/org/openrs2/patcher/transform/PlatformDetectionTransformer.kt

@ -0,0 +1,10 @@
package org.openrs2.patcher
public enum class Architecture(
public val needles: List<String>
) {
I386(listOf("i386", "x86")),
AMD64(listOf("amd64", "x86_64"));
public val id: String = name.toLowerCase()
}

@ -0,0 +1,17 @@
package org.openrs2.patcher
import org.openrs2.patcher.Architecture.AMD64
import org.openrs2.patcher.Architecture.I386
public enum class OperatingSystem(
public val needle: String,
public val architectures: List<Architecture>,
public val glLibraries: List<String>
) {
// AMD64 must be before I386 as x86 is a substring of x86_64
WINDOWS("win", listOf(AMD64, I386), listOf("jaggl.dll")),
MAC("mac", listOf(AMD64, I386), listOf("libjaggl.dylib")),
LINUX("linux", listOf(AMD64, I386), listOf("libjaggl.so", "libjaggl_dri.so"));
public val id: String = name.toLowerCase()
}

@ -85,43 +85,43 @@ public class Resource(
return compress(source, destination, uncompressed) return compress(source, destination, uncompressed)
} }
public fun compressGlNatives(): List<List<Resource>> = listOf( public fun compressGlNatives(): List<List<Resource>> {
// Windows i386 val platforms = mutableListOf<List<Resource>>()
listOf( var i = 0
compressNative("jaggl_0_0.lib", "jaggl.dll", "windows-i386/jaggl.dll")
), for (os in OperatingSystem.values()) {
for (arch in os.architectures) {
// Windows amd64 val resources = mutableListOf<Resource>()
listOf(
compressNative("jaggl_1_0.lib", "jaggl.dll", "windows-amd64/jaggl.dll") for ((j, library) in os.glLibraries.withIndex()) {
), resources += compressNative(
source = "jaggl_${i}_$j.lib",
// macOS i386 destination = library,
listOf( resource = "${os.id}-${arch.id}/$library"
compressNative("jaggl_2_0.lib", "libjaggl.dylib", "mac-i386/libjaggl.dylib") )
), }
// macOS amd64 platforms += resources
listOf( i++
compressNative("jaggl_3_0.lib", "libjaggl.dylib", "mac-amd64/libjaggl.dylib") }
), }
// Linux i386 return platforms
listOf( }
compressNative("jaggl_4_0.lib", "libjaggl.so", "linux-i386/libjaggl.so"),
compressNative("jaggl_4_1.lib", "libjaggl_dri.so", "linux-i386/libjaggl_dri.so") public fun compressMiscNatives(): List<Resource> {
), val os = OperatingSystem.WINDOWS
val resources = mutableListOf<Resource>()
// Linux amd64
listOf( for ((i, arch) in os.architectures.withIndex()) {
compressNative("jaggl_5_0.lib", "libjaggl.so", "linux-amd64/libjaggl.so"), resources += compressNative(
compressNative("jaggl_5_1.lib", "libjaggl_dri.so", "linux-amd64/libjaggl_dri.so") source = "jagmisc_$i.lib",
) destination = "jagmisc.dll",
) resource = "${os.id}-${arch.id}/jagmisc.dll"
)
public fun compressMiscNatives(): List<Resource> = listOf( }
compressNative("jagmisc_0.lib", "jagmisc.dll", "windows-i386/jagmisc.dll"),
compressNative("jagmisc_1.lib", "jagmisc.dll", "windows-amd64/jagmisc.dll") return resources
) }
} }
} }

@ -5,7 +5,6 @@ import org.objectweb.asm.Opcodes
import org.objectweb.asm.tree.AbstractInsnNode import org.objectweb.asm.tree.AbstractInsnNode
import org.objectweb.asm.tree.ClassNode import org.objectweb.asm.tree.ClassNode
import org.objectweb.asm.tree.InsnList import org.objectweb.asm.tree.InsnList
import org.objectweb.asm.tree.InsnNode
import org.objectweb.asm.tree.JumpInsnNode import org.objectweb.asm.tree.JumpInsnNode
import org.objectweb.asm.tree.LabelNode import org.objectweb.asm.tree.LabelNode
import org.objectweb.asm.tree.LdcInsnNode import org.objectweb.asm.tree.LdcInsnNode
@ -16,9 +15,9 @@ import org.openrs2.asm.InsnMatcher
import org.openrs2.asm.MemberRef import org.openrs2.asm.MemberRef
import org.openrs2.asm.classpath.ClassPath import org.openrs2.asm.classpath.ClassPath
import org.openrs2.asm.classpath.Library import org.openrs2.asm.classpath.Library
import org.openrs2.asm.intConstant
import org.openrs2.asm.toAbstractInsnNode import org.openrs2.asm.toAbstractInsnNode
import org.openrs2.asm.transform.Transformer import org.openrs2.asm.transform.Transformer
import org.openrs2.patcher.OperatingSystem
import javax.inject.Singleton import javax.inject.Singleton
@Singleton @Singleton
@ -32,7 +31,7 @@ public class PlatformDetectionTransformer : Transformer() {
} }
override fun transformCode(classPath: ClassPath, library: Library, clazz: ClassNode, method: MethodNode): Boolean { override fun transformCode(classPath: ClassPath, library: Library, clazz: ClassNode, method: MethodNode): Boolean {
val match = GL_PLATFORM_DETECTION_MATCHER.match(method).singleOrNull() var match = GL_PLATFORM_DETECTION_MATCHER.match(method).singleOrNull()
if (match != null) { if (match != null) {
// find os.name, os.arch and platform ID variables // find os.name, os.arch and platform ID variables
val nameStore = match[3] as VarInsnNode val nameStore = match[3] as VarInsnNode
@ -50,14 +49,13 @@ public class PlatformDetectionTransformer : Transformer() {
// generate our own platform detection code // generate our own platform detection code
val list = InsnList() val list = InsnList()
val end = LabelNode() val end = LabelNode()
var platform = 0
for ((index, os) in OS_NAMES.withIndex()) { for (os in OperatingSystem.values()) {
val next = LabelNode() val nextOs = LabelNode()
val amd64 = LabelNode()
val i386 = LabelNode()
list.add(VarInsnNode(Opcodes.ALOAD, nameVar)) list.add(VarInsnNode(Opcodes.ALOAD, nameVar))
list.add(LdcInsnNode(os)) list.add(LdcInsnNode(os.needle))
list.add( list.add(
MethodInsnNode( MethodInsnNode(
Opcodes.INVOKEVIRTUAL, Opcodes.INVOKEVIRTUAL,
@ -66,43 +64,42 @@ public class PlatformDetectionTransformer : Transformer() {
STARTS_WITH.desc STARTS_WITH.desc
) )
) )
list.add(JumpInsnNode(Opcodes.IFEQ, next)) list.add(JumpInsnNode(Opcodes.IFEQ, nextOs))
list.add(VarInsnNode(Opcodes.ALOAD, archVar)) for ((i, arch) in os.architectures.withIndex()) {
list.add(LdcInsnNode("amd64")) val matchingArch = LabelNode()
list.add( val nextArch = LabelNode()
MethodInsnNode(
Opcodes.INVOKEVIRTUAL, if (i != os.architectures.size - 1) {
STARTS_WITH.owner, for ((j, needle) in arch.needles.withIndex()) {
STARTS_WITH.name, list.add(VarInsnNode(Opcodes.ALOAD, archVar))
STARTS_WITH.desc list.add(LdcInsnNode(needle))
) list.add(
) MethodInsnNode(
list.add(JumpInsnNode(Opcodes.IFNE, amd64)) Opcodes.INVOKEVIRTUAL,
STARTS_WITH.owner,
list.add(VarInsnNode(Opcodes.ALOAD, archVar)) STARTS_WITH.name,
list.add(LdcInsnNode("x86_64")) STARTS_WITH.desc
list.add( )
MethodInsnNode( )
Opcodes.INVOKEVIRTUAL,
STARTS_WITH.owner, if (j != arch.needles.size - 1) {
STARTS_WITH.name, list.add(JumpInsnNode(Opcodes.IFNE, matchingArch))
STARTS_WITH.desc } else {
) list.add(JumpInsnNode(Opcodes.IFEQ, nextArch))
) }
list.add(JumpInsnNode(Opcodes.IFEQ, i386)) }
}
list.add(amd64)
list.add((index * 2 + 1).toAbstractInsnNode()) list.add(matchingArch)
list.add(VarInsnNode(Opcodes.ISTORE, platformVar)) list.add((platform++).toAbstractInsnNode())
list.add(JumpInsnNode(Opcodes.GOTO, end)) list.add(VarInsnNode(Opcodes.ISTORE, platformVar))
list.add(JumpInsnNode(Opcodes.GOTO, end))
list.add(i386)
list.add((index * 2).toAbstractInsnNode()) list.add(nextArch)
list.add(VarInsnNode(Opcodes.ISTORE, platformVar)) }
list.add(JumpInsnNode(Opcodes.GOTO, end))
list.add(next) list.add(nextOs)
} }
list.add(unknownOs) list.add(unknownOs)
@ -119,28 +116,62 @@ public class PlatformDetectionTransformer : Transformer() {
} }
// adjust jagmisc platform IDs to account for the removal of MSJVM support // adjust jagmisc platform IDs to account for the removal of MSJVM support
val miscMatch = MISC_PLATFORM_DETECTION_MATCHER.match(method).filter { match = MISC_PLATFORM_DETECTION_MATCHER.match(method).singleOrNull()
val const1 = it[0].intConstant if (match != null) {
if (const1 != 0 && const1 != 2) { // find os.arch and platform ID variables
return@filter false val archStore = match[12] as VarInsnNode
} val archVar = archStore.`var`
val platformStore = match[match.size - 5] as VarInsnNode
val platformVar = platformStore.`var`
val const2 = it[it.size - 2].intConstant // generate our own platform detection code
if (const2 != 0 && const2 != 2) { val list = InsnList()
return@filter false val end = LabelNode()
val os = OperatingSystem.WINDOWS
for ((i, arch) in os.architectures.withIndex()) {
val matchingArch = LabelNode()
val nextArch = LabelNode()
if (i != os.architectures.size - 1) {
for ((j, needle) in arch.needles.withIndex()) {
list.add(VarInsnNode(Opcodes.ALOAD, archVar))
list.add(LdcInsnNode(needle))
list.add(
MethodInsnNode(
Opcodes.INVOKEVIRTUAL,
STARTS_WITH.owner,
STARTS_WITH.name,
STARTS_WITH.desc
)
)
if (j != arch.needles.size - 1) {
list.add(JumpInsnNode(Opcodes.IFNE, matchingArch))
} else {
list.add(JumpInsnNode(Opcodes.IFEQ, nextArch))
}
}
}
list.add(matchingArch)
list.add(i.toAbstractInsnNode())
list.add(VarInsnNode(Opcodes.ISTORE, platformVar))
list.add(JumpInsnNode(Opcodes.GOTO, end))
list.add(nextArch)
} }
if (const1 == const2) { list.add(end)
return@filter false
// replace existing platform detection code with our own
for (i in (13 until match.size - 4)) {
method.instructions.remove(match[i])
} }
val store1 = it[1] as VarInsnNode method.instructions.insert(match[12], list)
val store2 = it[it.size - 1] as VarInsnNode
return@filter store1.`var` == store2.`var`
}.singleOrNull()
if (miscMatch != null) {
val iconst = miscMatch.single { it.intConstant == 2 }
method.instructions.set(iconst, InsnNode(Opcodes.ICONST_1))
miscBlocks++ miscBlocks++
} }
@ -161,9 +192,14 @@ public class PlatformDetectionTransformer : Transformer() {
ICONST ISTORE ILOAD GETSTATIC ILOAD AALOAD ARRAYLENGTH ICONST ISTORE ILOAD GETSTATIC ILOAD AALOAD ARRAYLENGTH
""" """
) )
private val MISC_PLATFORM_DETECTION_MATCHER = private val MISC_PLATFORM_DETECTION_MATCHER = InsnMatcher.compile(
InsnMatcher.compile("ICONST ISTORE ((GETSTATIC | ILOAD) IFEQ | GOTO) ICONST ISTORE") """
private val OS_NAMES = listOf("win", "mac", "linux") LDC INVOKESTATIC INVOKEVIRTUAL ASTORE ALOAD LDC INVOKEVIRTUAL IFNE GOTO
LDC INVOKESTATIC INVOKEVIRTUAL ASTORE
.*
ICONST ISTORE ALOAD ALOAD LDC INVOKEVIRTUAL
"""
)
private val STARTS_WITH = MemberRef("java/lang/String", "startsWith", "(Ljava/lang/String;)Z") private val STARTS_WITH = MemberRef("java/lang/String", "startsWith", "(Ljava/lang/String;)Z")
private fun findUnknownOs(match: List<AbstractInsnNode>): InsnList { private fun findUnknownOs(match: List<AbstractInsnNode>): InsnList {

Loading…
Cancel
Save