diff --git a/runtime/js/embind/_wrap/emval.cpp b/runtime/js/embind/_wrap/emval.cpp index 48da31e5..44a7eda1 100644 --- a/runtime/js/embind/_wrap/emval.cpp +++ b/runtime/js/embind/_wrap/emval.cpp @@ -122,17 +122,14 @@ bool llgo_emval_equals(EM_VAL first, EM_VAL second) { EM_VAL llgo_emval_method_call(EM_VAL object, const char* name, EM_VAL args[], int nargs, int *error) { std::vector arr; arr.resize(nargs+1); - std::vector _args; - _args.resize(nargs); std::vector elements; elements.resize(nargs); GenericWireType *cursor = elements.data(); arr[0] = typeid_val; for (int i = 0; i < nargs; i++) { arr[i+1] = typeid_val; - val v = val::take_ownership(args[i]); - _args[i] = v; - writeGenericWireTypes(cursor, v); + _emval_incref(args[i]); + writeGenericWireTypes(cursor, args[i]); } EM_METHOD_CALLER caller = _emval_get_method_caller(nargs+1,&arr[0],EM_METHOD_CALLER_KIND::FUNCTION); EM_GENERIC_WIRE_TYPE ret; @@ -141,7 +138,7 @@ EM_VAL llgo_emval_method_call(EM_VAL object, const char* name, EM_VAL args[], in ret = _emval_call_method(caller, object, name, &destructors, elements.data()); } catch(const emscripten::val& jsErr) { printf("error\n"); - *error = 1; + *error = 1; return EM_VAL(internal::_EMVAL_UNDEFINED); } return fromGenericWireType(ret).release_ownership(); @@ -153,51 +150,36 @@ FUNCTION = 0, CONSTRUCTOR = 1, */ EM_VAL llgo_emval_call(EM_VAL fn, EM_VAL args[], int nargs, int kind, int *error) { - std::vector arr; - arr.resize(nargs+1); - std::vector _args; - _args.resize(nargs); - std::vector elements; - elements.resize(nargs); - GenericWireType *cursor = elements.data(); - arr[0] = typeid_val; - for (int i = 0; i < nargs; i++) { - arr[i+1] = typeid_val; - val v = val::take_ownership(args[i]); - _args[i] = v; - writeGenericWireTypes(cursor, v); - } - EM_METHOD_CALLER caller = _emval_get_method_caller(nargs+1,&arr[0],EM_METHOD_CALLER_KIND(kind)); - EM_GENERIC_WIRE_TYPE ret; - try { - EM_DESTRUCTORS destructors = nullptr; - ret = _emval_call(caller, fn, &destructors, elements.data()); - } catch(const emscripten::val& jsErr) { - *error = 1; - return EM_VAL(internal::_EMVAL_UNDEFINED); - } - return fromGenericWireType(ret).release_ownership(); + std::vector arr; + arr.resize(nargs+1); + std::vector elements; + elements.resize(nargs); + GenericWireType *cursor = elements.data(); + arr[0] = typeid_val; + for (int i = 0; i < nargs; i++) { + arr[i+1] = typeid_val; + _emval_incref(args[i]); + writeGenericWireTypes(cursor, args[i]); + } + EM_METHOD_CALLER caller = _emval_get_method_caller(nargs+1,&arr[0],EM_METHOD_CALLER_KIND(kind)); + EM_GENERIC_WIRE_TYPE ret; + try { + EM_DESTRUCTORS destructors = nullptr; + ret = _emval_call(caller, fn, &destructors, elements.data()); + } catch(const emscripten::val& jsErr) { + *error = 1; + return EM_VAL(internal::_EMVAL_UNDEFINED); + } + return fromGenericWireType(ret).release_ownership(); } -/* -TYPEID llgo_emval_typeid_void() { - return take_typeid(); +EM_VAL llgo_emval_memory_view_uint8(size_t length, uint8_t *data) { + val view{ typed_memory_view(length,data) }; + return view.release_ownership(); } -TYPEID llgo_emval_typeid_double() { - return take_typeid(); -} - -TYPEID llgo_emval_typeid_string() { - return take_typeid(); -} - -TYPEID llgo_emval_typeid_val() { - return take_typeid(); -} -*/ - void llgo_emval_dump(EM_VAL v) { + _emval_incref(v); val console = val::global("console"); console.call("log", val::take_ownership(v)); } diff --git a/runtime/js/emval.go b/runtime/js/emval.go index d8034d50..0e53fdab 100644 --- a/runtime/js/emval.go +++ b/runtime/js/emval.go @@ -83,6 +83,9 @@ func emval_method_call(object Value, name *c.Char, args *Value, nargs c.Int, err //go:linkname emval_call C.llgo_emval_call func emval_call(fn Value, args *Value, nargs c.Int, kind c.Int, err *c.Int) Value +//go:linkname emval_memory_view_uint8 C.llgo_emval_memory_view_uint8 +func emval_memory_view_uint8(length c.SizeT, data *c.Uint8T) Value + //go:linkname emval_dump C.llgo_emval_dump func emval_dump(v Value) diff --git a/runtime/js/func.go b/runtime/js/func.go index c6f8c2e2..e9011ede 100644 --- a/runtime/js/func.go +++ b/runtime/js/func.go @@ -8,7 +8,6 @@ package js import ( - "strconv" "sync" ) @@ -48,7 +47,8 @@ func FuncOf(fn func(this Value, args []Value) any) Func { nextFuncID++ funcs[id] = fn funcsMu.Unlock() - sid := strconv.Itoa(int(id)) + var buf [20]byte + sid := string(itoa(buf[:], uint64(id))) wrap := functionConstructor.New(ValueOf(` const event = { id:` + sid + `, this: this, args: arguments }; Module._llgo_invoke(event); @@ -60,6 +60,17 @@ func FuncOf(fn func(this Value, args []Value) any) Func { } } +func itoa(buf []byte, val uint64) []byte { + i := len(buf) - 1 + for val >= 10 { + buf[i] = byte(val%10 + '0') + i-- + val /= 10 + } + buf[i] = byte(val + '0') + return buf[i:] +} + // Release frees up resources allocated for the function. // The function must not be invoked after calling Release. // It is allowed to call Release while the function is still running. diff --git a/runtime/js/js.go b/runtime/js/js.go index 7f4d1bad..40509936 100644 --- a/runtime/js/js.go +++ b/runtime/js/js.go @@ -666,7 +666,13 @@ func (e *ValueError) Error() string { // It panics if src is not a Uint8Array or Uint8ClampedArray. // It returns the number of bytes copied, which will be the minimum of the lengths of src and dst. func CopyBytesToGo(dst []byte, src Value) int { - return 0 + if !(emval_instanceof(src, uint8Array) || emval_instanceof(src, uint8ClampedArray)) { + return 0 + } + toCopy := src.Call("subarray", 0, len(dst)) + view := emval_memory_view_uint8(uintptr(len(dst)), *(**byte)(unsafe.Pointer(&dst))) + view.Call("set", toCopy) + return toCopy.Length() // n, ok := copyBytesToGo(dst, src.ref) // runtime.KeepAlive(src) // if !ok { @@ -675,6 +681,23 @@ func CopyBytesToGo(dst []byte, src Value) int { // return n } +/* + // func copyBytesToGo(dst []byte, src ref) (int, bool) + "syscall/js.copyBytesToGo": (sp) => { + sp >>>= 0; + const dst = loadSlice(sp + 8); + const src = loadValue(sp + 32); + if (!(src instanceof Uint8Array || src instanceof Uint8ClampedArray)) { + this.mem.setUint8(sp + 48, 0); + return; + } + const toCopy = src.subarray(0, dst.length); + dst.set(toCopy); + setInt64(sp + 40, toCopy.length); + this.mem.setUint8(sp + 48, 1); + }, +*/ + // copyBytesToGo copies bytes from src to dst. // // Using go:noescape is safe because the dst byte slice is only used as a dst @@ -688,7 +711,13 @@ func CopyBytesToGo(dst []byte, src Value) int { // It panics if dst is not a Uint8Array or Uint8ClampedArray. // It returns the number of bytes copied, which will be the minimum of the lengths of src and dst. func CopyBytesToJS(dst Value, src []byte) int { - return 0 + if !(emval_instanceof(dst, uint8Array) || emval_instanceof(dst, uint8ClampedArray)) { + return 0 + } + view := emval_memory_view_uint8(uintptr(len(src)), *(**byte)(unsafe.Pointer(&src))) + toCopy := view.Call("subarray", 0, dst.Length()) + dst.Call("set", toCopy) + return toCopy.Length() // n, ok := copyBytesToJS(dst.ref, src) // runtime.KeepAlive(dst) // if !ok { @@ -697,6 +726,28 @@ func CopyBytesToJS(dst Value, src []byte) int { // return n } +/* + // func copyBytesToJS(dst ref, src []byte) (int, bool) + "syscall/js.copyBytesToJS": (sp) => { + sp >>>= 0; + const dst = loadValue(sp + 8); + const src = loadSlice(sp + 16); + if (!(dst instanceof Uint8Array || dst instanceof Uint8ClampedArray)) { + this.mem.setUint8(sp + 48, 0); + return; + } + const toCopy = src.subarray(0, dst.length); + dst.set(toCopy); + setInt64(sp + 40, toCopy.length); + this.mem.setUint8(sp + 48, 1); + }, +*/ + +var ( + uint8Array = emval_get_global(c.Str("Uint8Array")) + uint8ClampedArray = emval_get_global(c.Str("Uint8ClampedArray")) +) + // copyBytesToJS copies bytes from src to dst. // // Using go:noescape is safe because the src byte slice is only used as a src