From 343381bdee1607a4f0f528e851ffdfe2e8eccb6a Mon Sep 17 00:00:00 2001 From: Sapu94 Date: Wed, 6 Dec 2023 08:25:30 -0800 Subject: [PATCH 1/2] Leverage WASM_BIGINT for 64-bit integers --- README.md | 4 ---- build.sh | 15 +-------------- package-lock.json | 1 - package.json | 4 ++-- src/luawasm.ts | 12 ++++++------ src/thread.ts | 9 ++------- src/type-extensions/function.ts | 2 +- src/type-extensions/table.ts | 4 ++-- test/engine.test.js | 17 +++++++---------- 9 files changed, 21 insertions(+), 47 deletions(-) diff --git a/README.md b/README.md index 3434bf3..a519ed5 100644 --- a/README.md +++ b/README.md @@ -184,10 +184,6 @@ npm test # ensure everything it's working fine ## Edge Cases -### Numbers - -WASM does not support 64 bit integers only 32 bit integers and 64 bit doubles. If a number is an integer and will fit within a Lua integer then it will be pushed as a Lua native integer type. However, if it exceeds that size even if it is still an integer it will be pushed as a 64 bit double. This is unlikely to effect inteoperability with JS since JS treats all numbers the same but should allow some optimisation within Lua for smaller numbers. - ### Null `null` is not exposed to Lua and it has no awareness of it which can cause some issues when using it a table. `nil` is equivalent to `undefined`. Issue #39 tracks this and a workaround until `null` is added into Wasmoon. diff --git a/build.sh b/build.sh index c033f64..3b420d9 100755 --- a/build.sh +++ b/build.sh @@ -14,14 +14,6 @@ else extension="-O3 --closure 1 -s ASSERTIONS=1" fi -# Instead of telling Lua to be 32 bit for both floats and ints override the default -# int type to 32 bit and leave the float as 64 bits. -if [[ "$OSTYPE" == "darwin"* ]]; then - sed -E -i '' "s/#define LUA_INT_DEFAULT\s+LUA_INT_LONGLONG/#define LUA_INT_DEFAULT \tLUA_INT_INT/" ./lua/luaconf.h -else - sed -E -i "s/#define LUA_INT_DEFAULT\s+LUA_INT_LONGLONG/#define LUA_INT_DEFAULT \tLUA_INT_INT/" ./lua/luaconf.h -fi - emcc \ -s WASM=1 $extension -o ./build/glue.js \ -s EXPORTED_RUNTIME_METHODS="[ @@ -51,6 +43,7 @@ emcc \ -s NODEJS_CATCH_REJECTION=0 \ -s MALLOC=emmalloc \ -s STACK_SIZE=1MB \ + -s WASM_BIGINT \ -s EXPORTED_FUNCTIONS="[ '_malloc', \ '_free', \ @@ -205,9 +198,3 @@ emcc \ '_luaL_openlibs' \ ]" \ ${LUA_SRC} - -if [[ "$OSTYPE" == "darwin"* ]]; then - sed -i '' "s/^#define LUA_32BITS\t1$/#define LUA_32BITS\t0/" ./lua/luaconf.h -else - sed -i "s/^#define LUA_32BITS\t1$/#define LUA_32BITS\t0/" ./lua/luaconf.h -fi diff --git a/package-lock.json b/package-lock.json index af927e5..85a2115 100644 --- a/package-lock.json +++ b/package-lock.json @@ -5,7 +5,6 @@ "requires": true, "packages": { "": { - "name": "wasmoon", "version": "1.15.1", "license": "MIT", "dependencies": { diff --git a/package.json b/package.json index c7aea10..0fdffbf 100755 --- a/package.json +++ b/package.json @@ -44,8 +44,6 @@ "@types/node": "20.8.9", "@typescript-eslint/eslint-plugin": "6.9.0", "@typescript-eslint/parser": "6.9.0", - "mocha": "10.2.0", - "jest-mock": "29.7.0", "chai": "4.3.10", "chai-as-promised": "7.1.1", "eslint": "8.52.0", @@ -53,6 +51,8 @@ "eslint-plugin-prettier": "5.0.1", "eslint-plugin-sort-imports-es6-autofix": "0.6.0", "fengari": "0.1.4", + "jest-mock": "29.7.0", + "mocha": "10.2.0", "prettier": "3.0.3", "rollup": "4.1.5", "rollup-plugin-copy": "3.5.0", diff --git a/src/luawasm.ts b/src/luawasm.ts index 73a700a..57985ff 100755 --- a/src/luawasm.ts +++ b/src/luawasm.ts @@ -108,7 +108,7 @@ export default class LuaWasm { public lua_type: (L: LuaState, idx: number) => LuaType public lua_typename: (L: LuaState, tp: number) => string public lua_tonumberx: (L: LuaState, idx: number, isnum: number | null) => number - public lua_tointegerx: (L: LuaState, idx: number, isnum: number | null) => number + public lua_tointegerx: (L: LuaState, idx: number, isnum: number | null) => bigint public lua_toboolean: (L: LuaState, idx: number) => number public lua_tolstring: (L: LuaState, idx: number, len: number | null) => string public lua_rawlen: (L: LuaState, idx: number) => number @@ -121,7 +121,7 @@ export default class LuaWasm { public lua_compare: (L: LuaState, idx1: number, idx2: number, op: number) => number public lua_pushnil: (L: LuaState) => void public lua_pushnumber: (L: LuaState, n: number) => void - public lua_pushinteger: (L: LuaState, n: number) => void + public lua_pushinteger: (L: LuaState, n: bigint) => void public lua_pushlstring: (L: LuaState, s: string | number | null, len: number) => string public lua_pushstring: (L: LuaState, s: string | number | null) => string public lua_pushcclosure: (L: LuaState, fn: number, n: number) => void @@ -131,9 +131,9 @@ export default class LuaWasm { public lua_getglobal: (L: LuaState, name: string | null) => LuaType public lua_gettable: (L: LuaState, idx: number) => LuaType public lua_getfield: (L: LuaState, idx: number, k: string | null) => LuaType - public lua_geti: (L: LuaState, idx: number, n: number) => LuaType + public lua_geti: (L: LuaState, idx: number, n: bigint) => LuaType public lua_rawget: (L: LuaState, idx: number) => number - public lua_rawgeti: (L: LuaState, idx: number, n: number) => LuaType + public lua_rawgeti: (L: LuaState, idx: number, n: bigint) => LuaType public lua_rawgetp: (L: LuaState, idx: number, p: number | null) => LuaType public lua_createtable: (L: LuaState, narr: number, nrec: number) => void public lua_newuserdatauv: (L: LuaState, sz: number, nuvalue: number) => number @@ -142,9 +142,9 @@ export default class LuaWasm { public lua_setglobal: (L: LuaState, name: string | null) => void public lua_settable: (L: LuaState, idx: number) => void public lua_setfield: (L: LuaState, idx: number, k: string | null) => void - public lua_seti: (L: LuaState, idx: number, n: number) => void + public lua_seti: (L: LuaState, idx: number, n: bigint) => void public lua_rawset: (L: LuaState, idx: number) => void - public lua_rawseti: (L: LuaState, idx: number, n: number) => void + public lua_rawseti: (L: LuaState, idx: number, n: bigint) => void public lua_rawsetp: (L: LuaState, idx: number, p: number | null) => void public lua_setmetatable: (L: LuaState, objindex: number) => number public lua_setiuservalue: (L: LuaState, idx: number, n: number) => number diff --git a/src/thread.ts b/src/thread.ts index bd14898..bc82245 100755 --- a/src/thread.ts +++ b/src/thread.ts @@ -23,9 +23,6 @@ export interface OrderedExtension { // When the debug count hook is set, call it every X instructions. const INSTRUCTION_HOOK_COUNT = 1000 -// These reflect math.maxinteger and math.mininteger with 32 bit ints in Lua. -const MAX_SAFE_INTEGER = Math.pow(2, 31) - 1 -const MIN_SAFE_INTEGER = -Math.pow(2, 31) export default class Thread { public readonly address: LuaState @@ -207,10 +204,8 @@ export default class Thread { this.lua.lua_pushnil(this.address) break case 'number': - // Only push it as an integer if it fits within 32 bits, otherwise treat it as a double. - // This is because wasm doesn't support 32 bit ints but does support 64 bit floats. - if (Number.isInteger(target) && target <= MAX_SAFE_INTEGER && target >= MIN_SAFE_INTEGER) { - this.lua.lua_pushinteger(this.address, target) + if (Number.isInteger(target)) { + this.lua.lua_pushinteger(this.address, BigInt(target)) } else { this.lua.lua_pushnumber(this.address, target) } diff --git a/src/type-extensions/function.ts b/src/type-extensions/function.ts index 1a48c52..d4875cd 100644 --- a/src/type-extensions/function.ts +++ b/src/type-extensions/function.ts @@ -164,7 +164,7 @@ class FunctionTypeExtension extends TypeExtension { const seenMap = userdata || new Map() const existingReference = seenMap.get(target) if (existingReference !== undefined) { - thread.lua.lua_rawgeti(thread.address, LUA_REGISTRYINDEX, existingReference) + thread.lua.lua_rawgeti(thread.address, LUA_REGISTRYINDEX, BigInt(existingReference)) return true } @@ -58,7 +58,7 @@ class TableTypeExtension extends TypeExtension { thread.lua.lua_createtable(thread.address, arrayCount, keyCount) const ref = thread.lua.luaL_ref(thread.address, LUA_REGISTRYINDEX) seenMap.set(target, ref) - thread.lua.lua_rawgeti(thread.address, LUA_REGISTRYINDEX, ref) + thread.lua.lua_rawgeti(thread.address, LUA_REGISTRYINDEX, BigInt(ref)) } if (Array.isArray(target)) { diff --git a/test/engine.test.js b/test/engine.test.js index 0b63982..719ffa1 100755 --- a/test/engine.test.js +++ b/test/engine.test.js @@ -686,8 +686,7 @@ describe('Engine', () => { const res = await engine.doString(`return tostring(value)`) - // Since it's a float in Lua it will be prefixed with .0 from tostring() - expect(res).to.be.equal(`${String(value)}.0`) + expect(res).to.be.equal(`${String(value)}`) }) it('number greater than 32 bit int should be pushed and retrieved as number', async () => { @@ -700,15 +699,13 @@ describe('Engine', () => { expect(res).to.be.equal(value) }) - it('print max integer as 32 bits', async () => { + it('number greater than 32 bit int should be usable as a format argument', async () => { const engine = await getEngine() - const res = await engine.doString(`return math.maxinteger`) - expect(res).to.be.equal(2147483647) - }) + const value = 1689031554550 + engine.global.set('value', value) - it('print min integer as 32 bits', async () => { - const engine = await getEngine() - const res = await engine.doString(`return math.mininteger`) - expect(res).to.be.equal(-2147483648) + const res = await engine.doString(`return ("%d"):format(value)`) + + expect(res).to.be.equal('1689031554550') }) }) From c292434d6df1fc5148b59056897ec34880bc5939 Mon Sep 17 00:00:00 2001 From: Sapu94 Date: Wed, 6 Dec 2023 08:58:07 -0800 Subject: [PATCH 2/2] Revert package-lock change --- package-lock.json | 1 + 1 file changed, 1 insertion(+) diff --git a/package-lock.json b/package-lock.json index 85a2115..af927e5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -5,6 +5,7 @@ "requires": true, "packages": { "": { + "name": "wasmoon", "version": "1.15.1", "license": "MIT", "dependencies": {