Skip to content

Commit

Permalink
Merge pull request #100 from Sapu94/bigint
Browse files Browse the repository at this point in the history
Leverage WASM_BIGINT for 64-bit integers
  • Loading branch information
ceifa authored Dec 8, 2023
2 parents 730e21e + c292434 commit f716b2f
Show file tree
Hide file tree
Showing 8 changed files with 21 additions and 46 deletions.
4 changes: 0 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
15 changes: 1 addition & 14 deletions build.sh
Original file line number Diff line number Diff line change
Expand Up @@ -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="[
Expand Down Expand Up @@ -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', \
Expand Down Expand Up @@ -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
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -44,15 +44,15 @@
"@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",
"eslint-config-prettier": "9.0.0",
"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",
Expand Down
12 changes: 6 additions & 6 deletions src/luawasm.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand All @@ -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
Expand All @@ -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
Expand Down
9 changes: 2 additions & 7 deletions src/thread.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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)
}
Expand Down
2 changes: 1 addition & 1 deletion src/type-extensions/function.ts
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,7 @@ class FunctionTypeExtension extends TypeExtension<FunctionType, FunctionDecorati
return
}

const internalType = thread.lua.lua_rawgeti(thread.address, LUA_REGISTRYINDEX, func)
const internalType = thread.lua.lua_rawgeti(thread.address, LUA_REGISTRYINDEX, BigInt(func))
if (internalType !== LuaType.Function) {
const callMetafieldType = thread.lua.luaL_getmetafield(thread.address, -1, '__call')
thread.pop()
Expand Down
4 changes: 2 additions & 2 deletions src/type-extensions/table.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ class TableTypeExtension extends TypeExtension<TableType> {
const seenMap = userdata || new Map<any, number>()
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
}

Expand All @@ -58,7 +58,7 @@ class TableTypeExtension extends TypeExtension<TableType> {
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)) {
Expand Down
17 changes: 7 additions & 10 deletions test/engine.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -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 () => {
Expand All @@ -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')
})
})

0 comments on commit f716b2f

Please sign in to comment.