From 5674c35e1477e21eaafab3a51241d84e47a679dd Mon Sep 17 00:00:00 2001 From: Ayke van Laethem Date: Mon, 6 Apr 2020 23:12:41 +0200 Subject: wasm: backport "garbage collect references to JavaScript values" See commit: https://github.com/golang/go/commit/54e6ba6724dfde355070238f9abc16362cac2e3d Warning: this will drop support for Go 1.13 for WebAssembly targets! I have modified the integration tests to specifically blacklist Go 1.13 instead of whitelisting any other version, to avoid accidentally not testing WebAssembly. --- targets/wasm_exec.js | 40 +++++++++++++++++++++++++++------------- 1 file changed, 27 insertions(+), 13 deletions(-) (limited to 'targets/wasm_exec.js') diff --git a/targets/wasm_exec.js b/targets/wasm_exec.js index 85f147cd0..4c8790667 100644 --- a/targets/wasm_exec.js +++ b/targets/wasm_exec.js @@ -202,26 +202,31 @@ return; } - let ref = this._refs.get(v); - if (ref === undefined) { - ref = this._values.length; - this._values.push(v); - this._refs.set(v, ref); + let id = this._ids.get(v); + if (id === undefined) { + id = this._idPool.pop(); + if (id === undefined) { + id = this._values.length; + } + this._values[id] = v; + this._goRefCounts[id] = 0; + this._ids.set(v, id); } - let typeFlag = 0; + this._goRefCounts[id]++; + let typeFlag = 1; switch (typeof v) { case "string": - typeFlag = 1; + typeFlag = 2; break; case "symbol": - typeFlag = 2; + typeFlag = 3; break; case "function": - typeFlag = 3; + typeFlag = 4; break; } mem().setUint32(addr + 4, nanHead | typeFlag, true); - mem().setUint32(addr, ref, true); + mem().setUint32(addr, id, true); } const loadSlice = (array, len, cap) => { @@ -284,6 +289,13 @@ setTimeout(this._inst.exports.go_scheduler, timeout); }, + // func finalizeRef(v ref) + "syscall/js.finalizeRef": (sp) => { + // Note: TinyGo does not support finalizers so this should never be + // called. + console.error('syscall/js.finalizeRef not implemented'); + }, + // func stringVal(value string) ref "syscall/js.stringVal": (ret_ptr, value_ptr, value_len) => { const s = loadString(value_ptr, value_len); @@ -405,7 +417,7 @@ async run(instance) { this._inst = instance; - this._values = [ // TODO: garbage collection + this._values = [ // JS values that Go currently has references to, indexed by reference id NaN, 0, null, @@ -414,8 +426,10 @@ global, this, ]; - this._refs = new Map(); - this.exited = false; + this._goRefCounts = []; // number of references that Go has to a JS value, indexed by reference id + this._ids = new Map(); // mapping from JS values to reference ids + this._idPool = []; // unused ids that have been garbage collected + this.exited = false; // whether the Go program has exited const mem = new DataView(this._inst.exports.memory.buffer) -- cgit v1.2.3