forked from openrs2/openrs2
parent
099d9c591d
commit
02d3867f4c
@ -0,0 +1,191 @@ |
||||
package dev.openrs2.bundler.transform |
||||
|
||||
import com.github.michaelbull.logging.InlineLogger |
||||
import dev.openrs2.asm.InsnMatcher |
||||
import dev.openrs2.asm.MemberRef |
||||
import dev.openrs2.asm.classpath.ClassPath |
||||
import dev.openrs2.asm.classpath.Library |
||||
import dev.openrs2.asm.createIntConstant |
||||
import dev.openrs2.asm.intConstant |
||||
import dev.openrs2.asm.transform.Transformer |
||||
import org.objectweb.asm.Opcodes |
||||
import org.objectweb.asm.tree.AbstractInsnNode |
||||
import org.objectweb.asm.tree.ClassNode |
||||
import org.objectweb.asm.tree.InsnList |
||||
import org.objectweb.asm.tree.InsnNode |
||||
import org.objectweb.asm.tree.JumpInsnNode |
||||
import org.objectweb.asm.tree.LabelNode |
||||
import org.objectweb.asm.tree.LdcInsnNode |
||||
import org.objectweb.asm.tree.MethodInsnNode |
||||
import org.objectweb.asm.tree.MethodNode |
||||
import org.objectweb.asm.tree.VarInsnNode |
||||
|
||||
class PlatformDetectionTransformer : Transformer() { |
||||
private var glBlocks = 0 |
||||
private var miscBlocks = 0 |
||||
|
||||
override fun preTransform(classPath: ClassPath) { |
||||
glBlocks = 0 |
||||
miscBlocks = 0 |
||||
} |
||||
|
||||
override fun transformCode(classPath: ClassPath, library: Library, clazz: ClassNode, method: MethodNode): Boolean { |
||||
val match = PLATFORM_DETECT_MATCHER.match(method).singleOrNull() |
||||
if (match != null) { |
||||
// find os.name, os.arch and platform ID variables |
||||
val nameStore = match[3] as VarInsnNode |
||||
val nameVar = nameStore.`var` |
||||
|
||||
val archStore = match[7] as VarInsnNode |
||||
val archVar = archStore.`var` |
||||
|
||||
val platformLoad = match[match.size - 3] as VarInsnNode |
||||
val platformVar = platformLoad.`var` |
||||
|
||||
// find unknown OS call |
||||
val unknownOs = findUnknownOs(match) |
||||
|
||||
// generate our own platform detection code |
||||
val list = InsnList() |
||||
val end = LabelNode() |
||||
|
||||
for ((index, os) in OS_NAMES.withIndex()) { |
||||
val next = LabelNode() |
||||
val amd64 = LabelNode() |
||||
val i386 = LabelNode() |
||||
|
||||
list.add(VarInsnNode(Opcodes.ALOAD, nameVar)) |
||||
list.add(LdcInsnNode(os)) |
||||
list.add( |
||||
MethodInsnNode( |
||||
Opcodes.INVOKEVIRTUAL, |
||||
STARTS_WITH.owner, |
||||
STARTS_WITH.name, |
||||
STARTS_WITH.desc, |
||||
false |
||||
) |
||||
) |
||||
list.add(JumpInsnNode(Opcodes.IFEQ, next)) |
||||
|
||||
list.add(VarInsnNode(Opcodes.ALOAD, archVar)) |
||||
list.add(LdcInsnNode("amd64")) |
||||
list.add( |
||||
MethodInsnNode( |
||||
Opcodes.INVOKEVIRTUAL, |
||||
STARTS_WITH.owner, |
||||
STARTS_WITH.name, |
||||
STARTS_WITH.desc, |
||||
false |
||||
) |
||||
) |
||||
list.add(JumpInsnNode(Opcodes.IFNE, amd64)) |
||||
|
||||
list.add(VarInsnNode(Opcodes.ALOAD, archVar)) |
||||
list.add(LdcInsnNode("x86_64")) |
||||
list.add( |
||||
MethodInsnNode( |
||||
Opcodes.INVOKEVIRTUAL, |
||||
STARTS_WITH.owner, |
||||
STARTS_WITH.name, |
||||
STARTS_WITH.desc, |
||||
false |
||||
) |
||||
) |
||||
list.add(JumpInsnNode(Opcodes.IFEQ, i386)) |
||||
|
||||
list.add(amd64) |
||||
list.add(createIntConstant(index * 2 + 1)) |
||||
list.add(VarInsnNode(Opcodes.ISTORE, platformVar)) |
||||
list.add(JumpInsnNode(Opcodes.GOTO, end)) |
||||
|
||||
list.add(i386) |
||||
list.add(createIntConstant(index * 2)) |
||||
list.add(VarInsnNode(Opcodes.ISTORE, platformVar)) |
||||
list.add(JumpInsnNode(Opcodes.GOTO, end)) |
||||
|
||||
list.add(next) |
||||
} |
||||
|
||||
list.add(unknownOs) |
||||
list.add(end) |
||||
|
||||
// replace existing platform detection code with our own |
||||
for (i in (8 until match.size - 7)) { |
||||
method.instructions.remove(match[i]) |
||||
} |
||||
|
||||
method.instructions.insert(match[7], list) |
||||
|
||||
glBlocks++ |
||||
} |
||||
|
||||
// adjust jagmisc platform IDs to account for the removal of MSJVM support |
||||
val miscMatch = MISC_PLATFORM_DETECT_MATCHER.match(method).filter { |
||||
val const1 = it[0].intConstant |
||||
if (const1 != 0 && const1 != 2) { |
||||
return@filter false |
||||
} |
||||
|
||||
val const2 = it[it.size - 2].intConstant |
||||
if (const2 != 0 && const2 != 2) { |
||||
return@filter false |
||||
} |
||||
|
||||
if (const1 == const2) { |
||||
return@filter false |
||||
} |
||||
|
||||
val store1 = it[1] as VarInsnNode |
||||
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++ |
||||
} |
||||
|
||||
return false |
||||
} |
||||
|
||||
override fun postTransform(classPath: ClassPath) { |
||||
logger.info { "Replaced $glBlocks jaggl and $miscBlocks jagmisc platform detection blocks" } |
||||
} |
||||
|
||||
companion object { |
||||
private val logger = InlineLogger() |
||||
private val PLATFORM_DETECT_MATCHER = InsnMatcher.compile( |
||||
""" |
||||
LDC INVOKESTATIC INVOKEVIRTUAL ASTORE |
||||
LDC INVOKESTATIC INVOKEVIRTUAL ASTORE |
||||
.* |
||||
ICONST ISTORE ILOAD GETSTATIC ILOAD AALOAD ARRAYLENGTH |
||||
""" |
||||
) |
||||
private val MISC_PLATFORM_DETECT_MATCHER = |
||||
InsnMatcher.compile("ICONST ISTORE (ILOAD IFEQ | GOTO) ICONST ISTORE") |
||||
private val OS_NAMES = listOf("win", "mac", "linux") |
||||
private val STARTS_WITH = MemberRef("java/lang/String", "startsWith", "(Ljava/lang/String;)Z") |
||||
|
||||
private fun findUnknownOs(match: List<AbstractInsnNode>): InsnList { |
||||
val aloadIndex = match.indexOfFirst { |
||||
it is VarInsnNode && it.opcode == Opcodes.ALOAD && it.`var` == 0 |
||||
} |
||||
if (aloadIndex == -1) { |
||||
throw IllegalArgumentException("Missing ALOAD_0") |
||||
} |
||||
|
||||
val list = InsnList() |
||||
for (i in aloadIndex until match.size) { |
||||
val insn = match[i] |
||||
list.add(insn.clone(emptyMap())) |
||||
|
||||
if (insn.opcode == Opcodes.RETURN) { |
||||
return list |
||||
} |
||||
} |
||||
|
||||
throw IllegalArgumentException("Missing RETURN") |
||||
} |
||||
} |
||||
} |
Loading…
Reference in new issue