|
|
@@ -1,5 +1,5 @@
|
|
|
/*
|
|
|
- * Copyright 2019-2021 Mamoe Technologies and contributors.
|
|
|
+ * Copyright 2019-2022 Mamoe Technologies and contributors.
|
|
|
*
|
|
|
* 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
|
|
|
* Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
|
|
|
@@ -10,7 +10,12 @@
|
|
|
package net.mamoe.console.integrationtest
|
|
|
|
|
|
import org.junit.jupiter.api.fail
|
|
|
+import org.objectweb.asm.ClassReader
|
|
|
+import org.objectweb.asm.ClassWriter
|
|
|
+import org.objectweb.asm.Opcodes
|
|
|
+import org.objectweb.asm.tree.ClassNode
|
|
|
import java.io.File
|
|
|
+import java.util.UUID
|
|
|
|
|
|
internal fun readStringListFromEnv(key: String): MutableList<String> {
|
|
|
val size = System.getenv(key)!!.toInt()
|
|
|
@@ -35,3 +40,51 @@ public fun File.assertNotExists() {
|
|
|
}
|
|
|
}
|
|
|
// endregion
|
|
|
+
|
|
|
+// region JVM Utils
|
|
|
+public val vmClassfileVersion: Int = runCatching {
|
|
|
+ val obj = ClassReader("java.lang.Object")
|
|
|
+ val classobj = ClassNode().also { obj.accept(it, ClassReader.SKIP_CODE) }
|
|
|
+ classobj.version
|
|
|
+}.recoverCatching {
|
|
|
+ val ccl = object : ClassLoader(null) {
|
|
|
+ fun canLoad(ver: Int) : Boolean{
|
|
|
+ val klass = ClassWriter(ClassWriter.COMPUTE_MAXS)
|
|
|
+ val cname =
|
|
|
+ "net/mamoe/console/integrationtest/vtest/C${ver}_${System.currentTimeMillis()}_${UUID.randomUUID()}"
|
|
|
+ .replace('-', '_')
|
|
|
+
|
|
|
+ klass.visit(
|
|
|
+ ver,
|
|
|
+ Opcodes.ACC_PUBLIC or Opcodes.ACC_FINAL,
|
|
|
+ cname,
|
|
|
+ null, "java/lang/Object", null
|
|
|
+ )
|
|
|
+ klass.visitMethod(Opcodes.ACC_PRIVATE, "<init>", "()V", null, null)!!.also { cinit ->
|
|
|
+ cinit.visitVarInsn(Opcodes.ALOAD, 0)
|
|
|
+ cinit.visitMethodInsn(Opcodes.INVOKESPECIAL, "java/lang/Object", "<init>", "()V", false)
|
|
|
+ cinit.visitInsn(Opcodes.RETURN)
|
|
|
+ cinit.visitMaxs(0, 0)
|
|
|
+ }
|
|
|
+ val code = klass.toByteArray()
|
|
|
+ return kotlin.runCatching {
|
|
|
+ val k = defineClass(null, code, 0, code.size)
|
|
|
+ Class.forName(k.name, true, this)
|
|
|
+ }.isSuccess
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (ccl.canLoad(Opcodes.V17)) return@recoverCatching Opcodes.V17
|
|
|
+ if (ccl.canLoad(Opcodes.V16)) return@recoverCatching Opcodes.V16
|
|
|
+ if (ccl.canLoad(Opcodes.V15)) return@recoverCatching Opcodes.V15
|
|
|
+ if (ccl.canLoad(Opcodes.V14)) return@recoverCatching Opcodes.V14
|
|
|
+ if (ccl.canLoad(Opcodes.V13)) return@recoverCatching Opcodes.V13
|
|
|
+ if (ccl.canLoad(Opcodes.V12)) return@recoverCatching Opcodes.V12
|
|
|
+ if (ccl.canLoad(Opcodes.V11)) return@recoverCatching Opcodes.V11
|
|
|
+ if (ccl.canLoad(Opcodes.V10)) return@recoverCatching Opcodes.V10
|
|
|
+ if (ccl.canLoad(Opcodes.V9)) return@recoverCatching Opcodes.V9
|
|
|
+ Opcodes.V1_8
|
|
|
+}.getOrElse { Opcodes.V1_8 } // Fallback
|
|
|
+
|
|
|
+public fun canVmLoad(opversion: Int): Boolean = opversion <= vmClassfileVersion
|
|
|
+
|
|
|
+// endregion
|