1 Commits

Author SHA1 Message Date
Constantine Solovev
9172fba948 Add posibillity to add a Logger Wasm module (#3)
* Add logger module

* Add LoggerModuleTest
2018-11-15 12:38:50 +04:00
5 changed files with 121 additions and 5 deletions

View File

@@ -21,7 +21,7 @@ buildscript {
allprojects {
apply plugin: 'java'
group 'com.github.cretz.asmble'
version '0.4.1-fl'
version '0.4.2-fl'
// skips building and running for the specified examples
ext.skipExamples = ['c-simple', 'go-simple', 'rust-regex']

View File

@@ -2,9 +2,11 @@ package asmble.cli
import asmble.ast.Script
import asmble.compile.jvm.javaIdent
import asmble.run.jvm.LoggerModule
import asmble.run.jvm.Module
import asmble.run.jvm.ScriptContext
import java.io.File
import java.io.PrintWriter
import java.util.*
abstract class ScriptCommand<T> : Command<T>() {
@@ -41,6 +43,13 @@ abstract class ScriptCommand<T> : Command<T>() {
desc = "The maximum number of memory pages when a module doesn't say.",
default = "5",
lowPriority = true
).toInt(),
loggerMemPages = bld.arg(
name = "loggerMemPages",
opt = "loggermempages",
desc = "The maximum number of memory pages of the logger module.",
default = "0",
lowPriority = true
).toInt()
)
@@ -82,7 +91,16 @@ abstract class ScriptCommand<T> : Command<T>() {
ctx.withModuleRegistered(moduleName,
Module.Native(Class.forName(className, true, ctx.classLoader).newInstance()))
}
if (args.specTestRegister) context = context.withHarnessRegistered() // проверить что не так с "Cannot find compatible import for spectest::print"
if (args.specTestRegister) context = context.withHarnessRegistered()
if (args.loggerMemPages > 0) {
// creates additional Wasm module with logger functionality
context =
context.withModuleRegistered(
"logger",
Module.Native(LoggerModule(args.loggerMemPages, PrintWriter(System.out)))
)
}
return context
}
@@ -94,12 +112,14 @@ abstract class ScriptCommand<T> : Command<T>() {
* @param disableAutoRegister If set, this will not auto-register modules with names
* @param specTestRegister If true, registers the spec test harness as 'spectest'
* @param defaultMaxMemPages The maximum number of memory pages when a module doesn't say
* @param loggerMemPages The maximum number of memory pages of the logger module.
*/
data class ScriptArgs(
val inFiles: List<String>,
val registrations: List<Pair<String, String>>,
val disableAutoRegister: Boolean,
val specTestRegister: Boolean,
val defaultMaxMemPages: Int
val defaultMaxMemPages: Int,
val loggerMemPages: Int
)
}
}

View File

@@ -0,0 +1,44 @@
package asmble.run.jvm
import asmble.compile.jvm.Mem
import java.io.PrintWriter
import java.nio.ByteBuffer
/**
* Module with possibility to write bytes to any 'writer'. This module actually
* used for logging from the Wasm code outside to 'embedder' (host environment).
*/
open class LoggerModule(pagesOfMemory: Int, val writer: PrintWriter) {
private val memory =
ByteBuffer.allocate(pagesOfMemory * Mem.PAGE_SIZE) as ByteBuffer
/**
* [Wasm function]
* Writes one byte to the logger memory buffer. If there is no place to write
* one byte into the buffer then flush all data from the buffer to [PrintWriter]
* and after that try to put the byte again.
*/
fun write(byte: Int) {
val isFull = memory.position() >= memory.limit()
if (isFull) {
flush()
}
memory.put(byte.toByte())
}
/**
* [Wasm function]
* Reads all bytes from the logger memory buffer, convert its to UTF-8
* string and writes to stdout.
* Cleans the logger memory buffer.
*/
fun flush() {
val message = String(memory.array(), 0, memory.position())
writer.print(message)
writer.flush()
memory.clear()
}
}

View File

@@ -45,6 +45,7 @@ data class ScriptContext(
val defaultMaxMemPages: Int = 1,
val includeBinaryInCompiledClass: Boolean = false
) : Logger by logger {
fun withHarnessRegistered(out: PrintWriter = PrintWriter(System.out, true)) =
withModuleRegistered("spectest", Module.Native(TestHarness(out)))
@@ -344,4 +345,4 @@ data class ScriptContext(
defineClass(className, bytes, 0, bytes.size)
}
}
}
}

View File

@@ -0,0 +1,51 @@
package asmble.run.jvm
import asmble.TestBase
import org.junit.Test
import java.io.PrintWriter
import java.io.StringWriter
import kotlin.test.assertEquals
class LoggerModuleTest : TestBase() {
@Test
fun writeAndFlushTest() {
val stream = StringWriter()
val logger = LoggerModule(1, PrintWriter(stream))
logger.flush() // checks that no raise error
val testString = "test String for log to stdout"
for (byte: Byte in testString.toByteArray()) {
logger.write(byte.toInt())
}
logger.flush()
val loggedString = stream.toString()
assertEquals(testString, loggedString)
}
@Test
fun writeAndFlushMoreThanLoggerBufferTest() {
val stream = StringWriter()
// logger buffer has 65Kb size
val logger = LoggerModule(1, PrintWriter(stream))
val testString = longString(65_000 * 2) // twice as much as logger buffer
for (byte: Byte in testString.toByteArray()) {
logger.write(byte.toInt())
}
logger.flush()
val loggedString = stream.toString()
assertEquals(testString, loggedString)
}
private fun longString(size: Int): String {
val stringBuffer = StringBuffer()
for (idx: Int in (1 until size)) {
stringBuffer.append((idx % Byte.MAX_VALUE).toChar())
}
return stringBuffer.toString()
}
}