Skip to content

Commit

Permalink
Fixed global NaN bug.
Browse files Browse the repository at this point in the history
  • Loading branch information
jakobgetz committed Nov 27, 2023
1 parent 53c8ed7 commit 82d252c
Show file tree
Hide file tree
Showing 8 changed files with 75 additions and 81 deletions.
109 changes: 54 additions & 55 deletions src/replay-generator.cts
Original file line number Diff line number Diff line change
Expand Up @@ -14,20 +14,19 @@ type GlobalSet = { type: "GlobalSet", value: number, bigInt: boolean } & ImpExp
type Event = Call | Store | MemGrow | TableSet | TableGrow | GlobalSet
type Import = { module: string, name: string }
type Result = { results: number[], reps: number }
type Body = Event[]
type Function = Import & { bodys: Body[], results: Result[] }
type Function = Import & { bodys: Event[][], results: Result[] }
type Memory = Import & WebAssembly.MemoryDescriptor
type Table = Import & WebAssembly.TableDescriptor
type Global = Import & WebAssembly.GlobalDescriptor & { initial: number }
type State = { callStack: Function[], lastFunc?: Function }
type State = { importCallStack: Function[], lastFunc?: Function }

export default class Generator {
private code: Code
private state: State

constructor() {
this.code = new Code()
this.state = { callStack: [] }
this.state = { importCallStack: [] }
}

generateReplay(trace: Trace) {
Expand Down Expand Up @@ -59,19 +58,14 @@ export default class Generator {
private consumeEvent(event: WasmEvent) {
switch (event.type) {
case "ExportCall":
if (this.state.callStack.length === 0) {
this.code.calls.push({ name: event.name, params: event.params })
// this.pushEvent({ type: 'Call', name: event.name, params: event.params })
break
}
this.pushEvent({ type: 'Call', name: event.name, params: event.params })
break
case "ImportCall":
this.code.funcImports[event.idx].bodys.push([])
this.state.callStack.push(this.code.funcImports[event.idx])
this.state.importCallStack.push(this.code.funcImports[event.idx])
break
case "ImportReturn":
this.state.lastFunc = this.state.callStack.pop()
this.state.lastFunc = this.state.importCallStack.pop()
let r = this.state.lastFunc.results
if (r.length > 0) {
if (r.slice(-1)[0].results[0] === event.results[0]) {
Expand Down Expand Up @@ -170,20 +164,20 @@ export default class Generator {
}

private pushEvent(event: Event) {
const stackTop = this.state.callStack.slice(-1)[0]?.bodys.slice(-1)[0]
if (stackTop === undefined) {
if (this.state.lastFunc === undefined) {
this.code.initialization.push(event)
let currentFunk = this.state.importCallStack.slice(-1)[0]?.bodys.slice(-1)[0]
if (currentFunk === undefined) {
currentFunk = this.code.initialization
if (this.state.lastFunc !== undefined && event.type !== 'Call') {
currentFunk = this.state.lastFunc.bodys.slice(-1)[0]
currentFunk.push(event)
return
}
this.state.lastFunc.bodys.slice(-1)[0].push(event)
return
}
if (stackTop.slice(-1)[0]?.type === "Call") {
stackTop.splice(stackTop.length - 1, 0, event)
if (currentFunk.slice(-1)[0]?.type === "Call" && event.type !== 'Call') {
currentFunk.splice(currentFunk.length - 1, 0, event)
return
}
stackTop.push(event)
currentFunk.push(event)
}

private addModule(event: Import) {
Expand Down Expand Up @@ -255,22 +249,22 @@ class Code {
stream.write(`${writeImport(table.module, table.name)}${table.name}\n`)
}
// Init entity states
for (let event of this.initialization) {
switch (event.type) {
case 'Store':
stream.write(this.storeEvent(event))
break
case 'MemGrow':
stream.write(this.memGrowEvent(event))
break
case 'TableSet':
stream.write(this.tableSetEvent(event))
break
case 'TableGrow':
stream.write(this.tableGrowEvent(event))
break
}
}
// for (let event of this.initialization) {
// switch (event.type) {
// case 'Store':
// stream.write(this.storeEvent(event))
// break
// case 'MemGrow':
// stream.write(this.memGrowEvent(event))
// break
// case 'TableSet':
// stream.write(this.tableSetEvent(event))
// break
// case 'TableGrow':
// stream.write(this.tableGrowEvent(event))
// break
// }
// }
// Imported functions
for (let funcidx in this.funcImports) {
stream.write(`let ${writeFuncGlobal(funcidx)} = -1\n`)
Expand All @@ -293,24 +287,29 @@ class Code {
stream.write(`instance.exports.${exp.name}(${writeParamsString(exp.params)}) \n`)
}
// Init entity states
// for (let event of this.initialization) {
// switch (event.type) {
// case 'Store':
// stream.write(this.storeEvent(event))
// break
// case 'MemGrow':
// stream.write(this.memGrowEvent(event))
// break
// case 'TableSet':
// stream.write(this.tableSetEvent(event))
// break
// case 'TableGrow':
// stream.write(this.tableGrowEvent(event))
// break
// case 'Call':
// stream.write(this.callEvent(event))
// }
// }
for (let event of this.initialization) {
switch (event.type) {
case 'Store':
stream.write(this.storeEvent(event))
break
case 'MemGrow':
stream.write(this.memGrowEvent(event))
break
case 'TableSet':
stream.write(this.tableSetEvent(event))
break
case 'TableGrow':
stream.write(this.tableGrowEvent(event))
break
case 'Call':
stream.write(this.callEvent(event))
break
case 'GlobalSet':
stream.write(this.globalSet(event))
break
default: unreachable(event)
}
}
stream.write(`}\n`)
stream.write(`if (process.argv[2] === 'run') {\n`)
stream.write(`const p = path.join(path.dirname(import.meta.url).replace(/^file:/, ''), 'index.wasm')\n`)
Expand All @@ -320,7 +319,7 @@ class Code {
stream.close()
}

private async writeBody(stream: WriteStream, b: Body, i: number) {
private async writeBody(stream: WriteStream, b: Event[], i: number) {
if (b.length !== 0) {
await this.write(stream, `case ${i}:\n`)
for (let event of b) {
Expand Down
3 changes: 2 additions & 1 deletion src/tracer.cts
Original file line number Diff line number Diff line change
Expand Up @@ -493,7 +493,8 @@ export default class Analysis implements AnalysisI<Trace> {
}
if (op === 'global.get') {
let globalInfo = Wasabi.module.info.globals[idx]
if (this.shadowGlobals[idx] !== value) {
// can be NaN in case of the NaN being imported to the WebAssembly Module. Google it!
if (this.shadowGlobals[idx] !== value && !Number.isNaN(this.shadowGlobals[idx]) && !Number.isNaN(value)) {
let valtype = globalInfo.valType
this.trace.push(['G', idx, this.getName(globalInfo), value, valtype])
}
Expand Down
9 changes: 0 additions & 9 deletions tests/node/glob-imp-host-mod/index.wat

This file was deleted.

15 changes: 0 additions & 15 deletions tests/node/glob-imp-host-mod/test.js

This file was deleted.

8 changes: 8 additions & 0 deletions tests/node/mem-exp-host-mod-toplevel/index.wat
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
(module
(func $main (export "main")
i32.const 1
i32.load
drop
)
(memory (export "memory") 1)
)
9 changes: 9 additions & 0 deletions tests/node/mem-exp-host-mod-toplevel/test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
export default async function test(wasmBinary) {
let instance
let imports = {}
let wasm = await WebAssembly.instantiate(wasmBinary, imports)
instance = wasm.instance
instance.exports.main()
new Uint8Array(instance.exports.memory.buffer)[1] = 1
instance.exports.main()
}
2 changes: 1 addition & 1 deletion tests/online/ffmpeg/test.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { delay } from '../../../dist/tests/test-utils.cjs'

export default async function test(analyser) {
const url = 'https://w3reality.github.io/async-thread-worker/examples/wasm-ffmpeg/index.html'
const page = await analyser.start(url, { headless: false })
const page = await analyser.start(url, { headless: true })
// const estimateButton = page.locator('#devHelpButton')
// const logWindow = page.locator('#log')
// await estimateButton.waitFor({ state: 'visible' })
Expand Down
1 change: 1 addition & 0 deletions tests/run-tests.cts
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,7 @@ async function runOnlineTests(names: string[]) {
'funky-kart', // takes so long and we know that record and replay trace differ
'image-convolute', // takes so long
'javascriptcore',
'ffmpeg', // runs for ever
]
names = names.filter((n) => !filter.includes(n))
for (let name of names) {
Expand Down

0 comments on commit 82d252c

Please sign in to comment.