mirror of
https://github.com/fluencelabs/asmble
synced 2025-07-06 18:01:37 +00:00
Support large data sections. Fixes #18
This commit is contained in:
@ -210,3 +210,7 @@ fun ByteArray.asClassNode(): ClassNode {
|
||||
ClassReader(this).accept(newNode, 0)
|
||||
return newNode
|
||||
}
|
||||
|
||||
fun ByteArray.chunked(v: Int) = (0 until size step v).asSequence().map {
|
||||
copyOfRange(it, (it + v).takeIf { it < size } ?: size)
|
||||
}
|
@ -46,8 +46,12 @@ open class ByteBufferMem(val direct: Boolean = true) : Mem {
|
||||
let(buildOffset).popExpecting(Int::class.ref).
|
||||
addInsns(
|
||||
forceFnType<ByteBuffer.(Int) -> Buffer>(ByteBuffer::position).invokeVirtual(),
|
||||
TypeInsnNode(Opcodes.CHECKCAST, memType.asmName),
|
||||
// We're going to do this as an LDC string in ISO-8859 and read it back at runtime
|
||||
TypeInsnNode(Opcodes.CHECKCAST, memType.asmName)
|
||||
).addInsns(
|
||||
// We're going to do this as an LDC string in ISO-8859 and read it back at runtime. However,
|
||||
// due to JVM limits, we can't have a string > 65536 chars, so I'll chunk it every 65500 chars.
|
||||
bytes.chunked(65500).flatMap { bytes ->
|
||||
sequenceOf(
|
||||
LdcInsnNode(bytes.toString(Charsets.ISO_8859_1)),
|
||||
LdcInsnNode("ISO-8859-1"),
|
||||
// Ug, can't do func refs on native types here...
|
||||
@ -55,7 +59,10 @@ open class ByteBufferMem(val direct: Boolean = true) : Mem {
|
||||
"getBytes", "(Ljava/lang/String;)[B", false),
|
||||
0.const,
|
||||
bytes.size.const,
|
||||
forceFnType<ByteBuffer.(ByteArray, Int, Int) -> ByteBuffer>(ByteBuffer::put).invokeVirtual(),
|
||||
forceFnType<ByteBuffer.(ByteArray, Int, Int) -> ByteBuffer>(ByteBuffer::put).invokeVirtual()
|
||||
)
|
||||
}.toList()
|
||||
).addInsns(
|
||||
InsnNode(Opcodes.POP)
|
||||
)
|
||||
|
||||
|
43
compiler/src/test/kotlin/asmble/compile/jvm/LargeDataTest.kt
Normal file
43
compiler/src/test/kotlin/asmble/compile/jvm/LargeDataTest.kt
Normal file
@ -0,0 +1,43 @@
|
||||
package asmble.compile.jvm
|
||||
|
||||
import asmble.TestBase
|
||||
import asmble.ast.Node
|
||||
import asmble.run.jvm.ScriptContext
|
||||
import asmble.util.get
|
||||
import org.junit.Test
|
||||
import java.nio.ByteBuffer
|
||||
import java.util.*
|
||||
import kotlin.test.assertEquals
|
||||
|
||||
class LargeDataTest : TestBase() {
|
||||
@Test
|
||||
fun testLargeData() {
|
||||
// This previously failed because string constants can't be longer than 65536 chars
|
||||
val mod = Node.Module(
|
||||
memories = listOf(Node.Type.Memory(
|
||||
limits = Node.ResizableLimits(initial = 2, maximum = 2)
|
||||
)),
|
||||
data = listOf(Node.Data(
|
||||
index = 0,
|
||||
offset = listOf(Node.Instr.I32Const(0)),
|
||||
data = ByteArray(70000) { 'a'.toByte() }
|
||||
))
|
||||
)
|
||||
val ctx = ClsContext(
|
||||
packageName = "test",
|
||||
className = "Temp" + UUID.randomUUID().toString().replace("-", ""),
|
||||
mod = mod,
|
||||
logger = logger
|
||||
)
|
||||
AstToAsm.fromModule(ctx)
|
||||
val cls = ScriptContext.SimpleClassLoader(javaClass.classLoader, logger).fromBuiltContext(ctx)
|
||||
// Instantiate it, get the memory out, and check it
|
||||
val field = cls.getDeclaredField("memory").apply { isAccessible = true }
|
||||
val buf = field[cls.newInstance()] as ByteBuffer
|
||||
// Grab all + 1 and check values
|
||||
val bytes = ByteArray(70001).also { buf.get(0, it) }
|
||||
bytes.forEachIndexed { index, byte ->
|
||||
assertEquals(if (index == 70000) 0.toByte() else 'a'.toByte(), byte)
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user