Kotlin WebAssembly direct buffer access with UTF-16 string

Submitted by Dickens A S on Fri, 05/01/2020 - 06:07

Kotlin WebAssembly runtime provides a global JavaScript array called heap

which can be accessed if the pointer of a variable is known

The pointer and size of the variable can be determined by library methods stringPointer and stringLengthBytes

The from JavaScript the value can be updated with below logic

Kotlin Main Code

package wasm

import kotlinx.interop.wasm.dom.*
import kotlinx.wasm.jsinterop.*
import mymod.*

var str1 = "                                                                                        "

fun main() {
   mod.domEval("document.getElementById('mydiv').innerHTML", stringPointer(str1), stringLengthBytes(str1))
   println(str1)
}

Kotlin Stub

@SymbolName("domEval")
external public fun domEval(arena: Int, index: Int, idPtr: Int, idLen: Int, rdPtr: Int, rdLen: Int, resultArena: Int): Unit

open class MyModule(arena: Int, index: Int): JsValue(arena, index) {
    constructor(jsValue: JsValue): this(jsValue.arena, jsValue.index)
    fun domEval(js: String, rdPtr: Int, rdLen: Int): Unit {
      domEval(this.arena, this.index, stringPointer(js), stringLengthBytes(js), rdPtr, rdLen, ArenaManager.currentArena)
    }
    companion object {
    }
}

val mod: MyModule
    get() {
      val wasmRetVal = getMyModule(ArenaManager.currentArena)
      return MyModule(ArenaManager.currentArena, wasmRetVal)
    }

JavaScript Stub

function fromUTF16String(string, pointer, size) {
    var j=0;
    for (let i = pointer; i < pointer + size; i += 2) {
        if(j<string.length)
            heap[i] = string.charCodeAt(j);
        else
            heap[i] = 0
        heap[i + 1] = 0
        j++;
    }
}

konan.libraries.push ({
  domEval(arena, obj, idPtr, idLen, rdPtr, rdLen, resultArena) {
     var js = toUTF16String(idPtr, idLen);
     var result = eval(js);
     fromUTF16String(result, rdPtr, rdLen)
  }
})

Explanation

UTF16 String holds two heap spaces therefore a loop with i += 2 will allows us to put values in heap, the above code explains each character converted to ASCII code and stored in heap[1], heap[3], heap[5] ... accordingly

heap[2], heap[4], heap[6] are filled with zero reason being the ASCII is less than or equal to 255 which is plain english

if there is asian/latin/accented characters or symbols then it should be split 

Example ASCII code for Ĝ is 196 156 then 

heap[1] = 196
heap[2] = 156

when converting it back, we should do

String.fromCharCode(heap[1] + heap[2] * 256)

this is already done in the inbuilt method toUTF16String

This reduces the method calls between WebAssembly and JavaScript for each byte, but in the code we need to allocate a big string string with spaces as below

var str1 = "                                                                                        "

the double quotes allocates around 90 size string, which sound little bit unethical, but it works fine

 

GitHubhttps://github.com/dickensas/kotlin-gradle-templates/tree/master/sboot-wasm-heap

 

 

Add new comment