From b3c0f776a066c3f0a24837fa597fbbb6745828e9 Mon Sep 17 00:00:00 2001 From: Rob23oba Date: Fri, 16 Aug 2024 00:09:40 +0200 Subject: [PATCH 1/5] compiler, runner: fixes, added run-wasm and --include-all-builtins --- compiler/assemble.js | 44 +++++++++- compiler/codegen.js | 31 +++++-- compiler/encoding.js | 21 +++++ compiler/index.js | 10 +-- compiler/pgo.js | 2 +- compiler/precompile.js | 4 +- compiler/wrap.js | 184 ++++++++++++++++++++++++++++++++++++++++- runner/index.js | 26 +++++- 8 files changed, 299 insertions(+), 23 deletions(-) diff --git a/compiler/assemble.js b/compiler/assemble.js index 67e3ea91..8fdb61ad 100644 --- a/compiler/assemble.js +++ b/compiler/assemble.js @@ -47,7 +47,46 @@ const encodeNames = funcs => { ]; }; -export default (funcs, globals, tags, pages, data, flags, noTreeshake = false) => { +const encodeDebugInfo = (funcs, globals, tags, exceptions, pages, data, excMode) => { + const encodeSection = (id, section) => [ + id, + ...unsignedLEB128(section.length), + ...section + ]; + let exceptionSection = []; + switch (excMode) { + case 'lut': + exceptionSection.push(0); + unsignedLEB128_into(exceptions.length, exceptionSection); + for (let i = 0; i < exceptions.length; i++) { + exceptionSection.push(...encodeString(exceptions[i].constructor ?? "")); + exceptionSection.push(...encodeString(exceptions[i].message)); + } + break; + case 'stack': + exceptionSection.push(1); + break; + case 'stackest': + exceptionSection.push(2); + break; + case 'partial': + exceptionSection.push(3); + unsignedLEB128_into(exceptions.length, exceptionSection); + for (let i = 0; i < exceptions.length; i++) { + exceptionSection.push(...encodeString(exceptions[i].constructor ?? "")); + } + break; + } + const typeSection = [ valtypeBinary ]; + + // TODO: add more information like where funcrefs are, etc. + return [ + ...encodeSection(0, exceptionSection), + ...encodeSection(1, typeSection), + ]; +}; + +export default (funcs, globals, tags, exceptions, pages, data, flags, noTreeshake = false) => { const types = [], typeCache = {}; const optLevel = parseInt(process.argv.find(x => x.startsWith('-O'))?.[2] ?? 1); @@ -121,6 +160,8 @@ export default (funcs, globals, tags, pages, data, flags, noTreeshake = false) = const nameSection = Prefs.d ? customSection('name', encodeNames(funcs)) : []; + const porfforDebugInfoSection = Prefs.d ? customSection('porffor_debug_info', encodeDebugInfo(funcs, globals, tags, exceptions, pages, data, Prefs.exceptionMode ?? 'lut')) : []; + const tableSection = !funcs.table ? [] : createSection( Section.table, encodeVector([ [ Reftype.funcref, 0x00, ...unsignedLEB128(funcs.length) ] ]) @@ -424,6 +465,7 @@ export default (funcs, globals, tags, pages, data, flags, noTreeshake = false) = ...exportSection, ...elementSection, ...dataCountSection, + ...porfforDebugInfoSection, ...codeSection, ...dataSection, ...nameSection diff --git a/compiler/codegen.js b/compiler/codegen.js index f62df5c1..2c330ae0 100644 --- a/compiler/codegen.js +++ b/compiler/codegen.js @@ -1023,10 +1023,6 @@ const asmFunc = (name, { wasm, params = [], typedParams = false, locals: localTy locals[nameParam(i)] = { idx: i, type: allLocals[i] }; } - for (const x in _data) { - data.push({ page: x, bytes: _data[x] }); - } - const func = { name, params, @@ -1042,6 +1038,11 @@ const asmFunc = (name, { wasm, params = [], typedParams = false, locals: localTy globalInits }; + for (const x in _data) { + allocPage(func, x); + data.push({ page: x, bytes: _data[x] }); + } + funcs.push(func); funcIndex[name] = func.index; @@ -1050,11 +1051,15 @@ const asmFunc = (name, { wasm, params = [], typedParams = false, locals: localTy else wasm = asmFuncToAsm(func, wasm); } - let baseGlobalIdx, i = 0; + let globalRefs = [], i = 0; for (const type of globalTypes) { - if (baseGlobalIdx === undefined) baseGlobalIdx = globals['#ind']; - - globals[globalNames[i] ?? `${name}_global_${i}`] = { idx: globals['#ind']++, type, init: globalInits[i] ?? 0 }; + let nm = globalNames[i] ?? `${name}_global_${i}`; + if (globals[nm]) { + globalRefs.push(globals[nm].idx); + continue; + } + globalRefs.push(globals['#ind']); + globals[nm] = { idx: globals['#ind']++, type, init: globalInits[i] ?? 0 }; i++; } @@ -1062,7 +1067,10 @@ const asmFunc = (name, { wasm, params = [], typedParams = false, locals: localTy // offset global ops for base global idx for (const inst of wasm) { if (inst[0] === Opcodes.global_get || inst[0] === Opcodes.global_set) { - inst[1] += baseGlobalIdx; + if (inst[1] >= globalRefs.length) { + throw new Error('in builtin ' + name + ': global_get / global_set out of range'); + } + inst[1] = globalRefs[inst[1]]; } } } @@ -5944,6 +5952,11 @@ const generateFunc = (scope, decl) => { } const wasm = prelude.concat(generate(func, body)); + if (Prefs.includeAllBuiltins) { + for (let x in builtinFuncs) { + includeBuiltin(func, x); + } + } if (decl.async) { // make promise at the start diff --git a/compiler/encoding.js b/compiler/encoding.js index 4803ecdb..bc8e54c6 100644 --- a/compiler/encoding.js +++ b/compiler/encoding.js @@ -202,4 +202,25 @@ export const ieee754_binary64_into = (value, buffer) => { const data = new Uint8Array(new Float64Array([ value ]).buffer); for (let i = 0; i < 8; i++) buffer.push(data[i]); // buffer.push(...new Uint8Array(new Float64Array([ value ]).buffer)); +}; + +export const readUnsignedLEB128FromBuffer = (buffer, index) => { + let value = 0; + let shift = 0; + while (true) { + let b = buffer[index]; + value |= (b & 0x7F) << shift; + if ((value & 0x80) == 0) { + return [ value, index ]; + } + shift += 7; + } +}; + +export const readStringFromBuffer = (buffer, index) => { + let length; + [ length, index ] = readUnsignedLEB128FromBuffer(buffer, index); + let slice = buffer.subarray(index, index + length); + let decoder = new TextDecoder(); + return [ decoder.decode(slice), index + length ]; }; \ No newline at end of file diff --git a/compiler/index.js b/compiler/index.js index e0248150..5841d0ae 100644 --- a/compiler/index.js +++ b/compiler/index.js @@ -98,7 +98,7 @@ export default (code, flags) => { if (Prefs.pgo) { if (Prefs.pgoLog) { - const oldSize = assemble(funcs, globals, tags, pages, data, flags, true).byteLength; + const oldSize = assemble(funcs, globals, tags, exceptions, pages, data, flags, true).byteLength; const t = performance.now(); pgo.run({ funcs, globals, tags, exceptions, pages, data }); @@ -106,7 +106,7 @@ export default (code, flags) => { console.log(`PGO total time: ${(performance.now() - t).toFixed(2)}ms`); - const newSize = assemble(funcs, globals, tags, pages, data, flags, true).byteLength; + const newSize = assemble(funcs, globals, tags, exceptions, pages, data, flags, true).byteLength; console.log(`PGO size diff: ${oldSize - newSize} bytes (${oldSize} -> ${newSize})\n`); } else { pgo.run({ funcs, globals, tags, exceptions, pages, data }); @@ -116,7 +116,7 @@ export default (code, flags) => { if (Prefs.cyclone) { if (Prefs.cycloneLog) { - const oldSize = assemble(funcs, globals, tags, pages, data, flags, true).byteLength; + const oldSize = assemble(funcs, globals, tags, exceptions, pages, data, flags, true).byteLength; const t = performance.now(); for (const x of funcs) { @@ -129,7 +129,7 @@ export default (code, flags) => { console.log(`cyclone total time: ${(performance.now() - t).toFixed(2)}ms`); - const newSize = assemble(funcs, globals, tags, pages, data, flags, true).byteLength; + const newSize = assemble(funcs, globals, tags, exceptions, pages, data, flags, true).byteLength; console.log(`cyclone size diff: ${oldSize - newSize} bytes (${oldSize} -> ${newSize})\n`); } else { for (const x of funcs) { @@ -171,7 +171,7 @@ export default (code, flags) => { const out = { funcs, globals, tags, exceptions, pages, data, times: [ t0, t1, t2, t3 ] }; if (globalThis.precompile) return out; - const wasm = out.wasm = assemble(funcs, globals, tags, pages, data, flags); + const wasm = out.wasm = assemble(funcs, globals, tags, exceptions, pages, data, flags); if (logProgress) progressDone('assembled', t3); if (Prefs.optFuncs || Prefs.f) logFuncs(funcs, globals, exceptions); diff --git a/compiler/pgo.js b/compiler/pgo.js index 154850b7..d924205b 100644 --- a/compiler/pgo.js +++ b/compiler/pgo.js @@ -81,7 +81,7 @@ export const run = obj => { let activeFunc = null, abort = false; try { - obj.wasm = assemble(obj.funcs, obj.globals, obj.tags, obj.pages, obj.data, obj.flags, true); + obj.wasm = assemble(obj.funcs, obj.globals, obj.tags, obj.exceptions, obj.pages, obj.data, obj.flags, true); Prefs._profileCompiler = Prefs.profileCompiler; Prefs.profileCompiler = false; diff --git a/compiler/precompile.js b/compiler/precompile.js index 2160fb64..ff713ebb 100644 --- a/compiler/precompile.js +++ b/compiler/precompile.js @@ -21,7 +21,7 @@ const compile = async (file, _funcs) => { let first = source.slice(0, source.indexOf('\n')); if (first.startsWith('export default')) { - source = await (await import(file)).default(); + source = await (await import('file://' + file)).default(); first = source.slice(0, source.indexOf('\n')); } @@ -178,7 +178,7 @@ const precompile = async () => { let funcs = []; let fileCount = 0; - for (const file of fs.readdirSync(dir)) { + for (const file of fs.readdirSync(dir).toSorted()) { if (file.endsWith('.d.ts')) continue; fileCount++; diff --git a/compiler/wrap.js b/compiler/wrap.js index 8337b7e9..65e4b4ac 100644 --- a/compiler/wrap.js +++ b/compiler/wrap.js @@ -1,4 +1,5 @@ -import { encodeVector, encodeLocal } from './encoding.js'; +import { encodeVector, encodeLocal, readUnsignedLEB128FromBuffer, readStringFromBuffer } from './encoding.js'; +import { Section, Valtype } from './wasmSpec.js'; import { importedFuncs } from './builtins.js'; import compile from './index.js'; import decompile from './decompile.js'; @@ -123,6 +124,7 @@ ${flags & 0b0001 ? ` get func idx: ${get} } case TYPES.function: { + if (!funcs) return function () {}; let func; if (value < 0) { func = importedFuncs[value + importedFuncs.length]; @@ -177,6 +179,7 @@ ${flags & 0b0001 ? ` get func idx: ${get} } case TYPES.symbol: { + if (!pages) return Symbol(); const page = pages.get('array: symbol.ts/descStore'); if (!page) return Symbol(); @@ -557,4 +560,181 @@ export default (source, flags = [ 'module' ], customImports = {}, print = str => } return { exports, wasm, times, pages, c }; -}; \ No newline at end of file +}; + +const collectDebugInfo = wasm => { + let index = 8; // skip magic and version + let exceptions = [], exceptionMode, valtypeBinary; + while (index < wasm.length) { + let sectionType = wasm[index++]; + let length; + [ length, index ] = readUnsignedLEB128FromBuffer(wasm, index); + if (sectionType !== Section.custom) { + continue; + } + let startPosition = index; + let endPosition = index + length; + let name; + [ name, index ] = readStringFromBuffer(wasm, index); + if (name !== 'porffor_debug_info') { + continue; + } + while (index < endPosition) { + sectionType = wasm[index++]; + let length; + [ length, index ] = readUnsignedLEB128FromBuffer(wasm, index); + if (sectionType === 0) { // porffor exceptions + let type = wasm[index++]; + if (type === 0) { + exceptionMode = 'lut'; + let count; + [ count, index ] = readUnsignedLEB128FromBuffer(wasm, index); + for (let i = 0; i < count; i++) { + let exInd, constructor, message; + [ exInd, index ] = readUnsignedLEB128FromBuffer(wasm, index); + [ constructor, index ] = readStringFromBuffer(wasm, index); + [ message, index ] = readStringFromBuffer(wasm, index); + if (constructor === '') constructor = null; + exceptions[exInd] = { constructor, message }; + } + } else if (type === 1) { + exceptionMode = 'stack'; + } else if (type === 2) { + exceptionMode = 'stackest'; + } else if (type === 3) { + exceptionMode = 'partial'; + let count; + [ count, index ] = readUnsignedLEB128FromBuffer(wasm, index); + for (let i = 0; i < count; i++) { + let exInd, constructor; + [ exInd, index ] = readUnsignedLEB128FromBuffer(wasm, index); + [ constructor, index ] = readStringFromBuffer(wasm, index); + if (constructor === '') constructor = null; + exceptions[exInd] = { constructor }; + } + } + } else if (type === 1) { // valtype + valtypeBinary = wasm[index++]; + } else { + index += length; + } + } + break; + } + return { exceptions, exceptionMode, valtypeBinary }; +}; + +// TODO: integrate with default +export const fromWasm = (wasm, print = str => process.stdout.write(str)) => { + let { exceptions, exceptionMode, valtypeBinary } = collectDebugInfo(wasm); + let instance, memory; + try { + const module = new WebAssembly.Module(wasm); + instance = new WebAssembly.Instance(module, { + '': { + p: valtypeBinary === Valtype.i64 ? i => print(Number(i).toString()) : i => print(i.toString()), + c: valtypeBinary === Valtype.i64 ? i => print(String.fromCharCode(Number(i))) : i => print(String.fromCharCode(i)), + t: () => performance.now(), + u: () => performance.timeOrigin, + y: () => {}, + z: () => {}, + w: (ind, outPtr) => { // readArgv + let args = process.argv.slice(2); + args = args.slice(args.findIndex(x => !x.startsWith('-')) + 1); + + const str = args[ind - 1]; + if (!str) return -1; + + writeByteStr(memory, outPtr, str); + return str.length; + }, + q: (pathPtr, outPtr) => { // readFile + try { + const path = pathPtr === 0 ? 0 : readByteStr(memory, pathPtr); + const contents = fs.readFileSync(path, 'utf8'); + writeByteStr(memory, outPtr, contents); + return contents.length; + } catch { + return -1; + } + }, + b: () => { + debugger; + } + } + }); + } catch (e) { + throw e; + } + const exports = {}; + + const exceptTag = instance.exports['0']; + memory = instance.exports['$']; + + for (const x in instance.exports) { + if (x === '0') continue; + if (x === '$') { + exports.$ = instance.exports.$; + continue; + } + + const name = x === 'm' ? 'main' : x; + + const exp = instance.exports[x]; + exports[name] = exp; + + exports[name] = function() { + try { + const ret = exp.apply(this, arguments); + if (ret == null) return undefined; + + return porfToJSValue({ memory }, ret[0], ret[1]); + } catch (e) { + if (e.is && e.is(exceptTag)) { + if (exceptionMode === 'lut') { + const exceptId = e.getArg(exceptTag, 0); + const exception = exceptions[exceptId]; + + const constructorName = exception.constructor; + + // no constructor, just throw message + if (!constructorName) throw exception.message; + + const constructor = globalThis[constructorName] ?? eval(`class ${constructorName} extends Error { constructor(message) { super(message); this.name = "${constructorName}"; } }; ${constructorName}`); + throw new constructor(exception.message); + } + + if (exceptionMode === 'stack') { + const value = e.getArg(exceptTag, 0); + const type = e.getArg(exceptTag, 1); + + throw porfToJSValue({ memory }, value, type); + } + + // TODO: support exception mode stackest + + if (exceptionMode === 'partial') { + const exceptId = e.getArg(exceptTag, 0); + const exception = exceptions[exceptId]; + + const constructorName = exception.constructor; + + const value = e.getArg(exceptTag, 1); + const type = e.getArg(exceptTag, 2); + const message = porfToJSValue({ memory }, value, type); + + // no constructor, just throw message + if (!constructorName) throw message; + + const constructor = globalThis[constructorName] ?? eval(`class ${constructorName} extends Error { constructor(message) { super(message); this.name = "${constructorName}"; } }; ${constructorName}`); + throw new constructor(message); + } + } + + throw e; + } + }; + } + + return { exports, wasm }; +}; diff --git a/runner/index.js b/runner/index.js index b4a2eb98..46574608 100644 --- a/runner/index.js +++ b/runner/index.js @@ -32,7 +32,8 @@ if (process.argv.includes('--help')) { console.log(`\n\x1B[1mCommands:\x1B[0m`); for (const [ cmd, [ color, desc ] ] of Object.entries({ run: [ 34, 'Run a JS file' ], - wasm: [ 34, 'Compile a JS file to a Wasm binary\n' ], + wasm: [ 34, 'Compile a JS file to a Wasm binary' ], + 'run-wasm': [ 34, 'Run a compiled Wasm binary (requires compilation with -d)\n' ], c: [ 31, 'Compile a JS file to C source code' ], native: [ 31, 'Compile a JS file to a native binary\n' ], @@ -71,7 +72,7 @@ const done = async () => { }; let file = process.argv.slice(2).find(x => x[0] !== '-'); -if (['precompile', 'run', 'wasm', 'native', 'c', 'profile', 'debug', 'debug-wasm'].includes(file)) { +if (['precompile', 'run', 'wasm', 'run-wasm', 'native', 'c', 'profile', 'debug', 'debug-wasm'].includes(file)) { // remove this arg process.argv.splice(process.argv.indexOf(file), 1); @@ -90,6 +91,25 @@ if (['precompile', 'run', 'wasm', 'native', 'c', 'profile', 'debug', 'debug-wasm await done(); } + if (file === 'run-wasm') { + file = process.argv.slice(2).find(x => x[0] !== '-'); + const buffer = fs.readFileSync(file); + + let runStart; + const fromWasm = (await import('../compiler/wrap.js')).fromWasm; + try { + const out = fromWasm(buffer); + runStart = performance.now(); + out.exports.main(); + } catch (e) { + let out = e; + if (Object.getPrototypeOf(e).message != null) out = `${e.constructor.name}${e.message != null ? `: ${e.message}` : ''}`; + throw e; // show backtrace + } + if (process.argv.includes('-t')) console.log(`execution time: ${(performance.now() - runStart).toFixed(2)}ms`); + process.exit(); + } + if (['wasm', 'native', 'c'].includes(file)) { process.argv.push(`--target=${file}`); } @@ -168,7 +188,7 @@ try { } catch (e) { let out = e; if (!process.argv.includes('-d') && Object.getPrototypeOf(e).message != null) out = `${e.constructor.name}${e.message != null ? `: ${e.message}` : ''}`; - console.error(out); + throw e; // show backtrace } if (process.argv.includes('-t')) console.log(`${process.argv.includes('-b') ? '' : '\n'}total time: ${(performance.now() - start).toFixed(2)}ms\nexecution time: ${(performance.now() - runStart).toFixed(2)}ms`); From 66a2d24c0378d2b4d90e10ef4f19c77b57f7446f Mon Sep 17 00:00:00 2001 From: Rob23oba Date: Fri, 16 Aug 2024 00:43:05 +0200 Subject: [PATCH 2/5] compiler / runner: fixes for exceptions --- compiler/assemble.js | 2 ++ compiler/encoding.js | 2 +- compiler/wrap.js | 13 ++++++++++++- runner/index.js | 6 ++++-- 4 files changed, 19 insertions(+), 4 deletions(-) diff --git a/compiler/assemble.js b/compiler/assemble.js index 8fdb61ad..e4d01420 100644 --- a/compiler/assemble.js +++ b/compiler/assemble.js @@ -59,6 +59,7 @@ const encodeDebugInfo = (funcs, globals, tags, exceptions, pages, data, excMode) exceptionSection.push(0); unsignedLEB128_into(exceptions.length, exceptionSection); for (let i = 0; i < exceptions.length; i++) { + unsignedLEB128_into(i, exceptionSection); exceptionSection.push(...encodeString(exceptions[i].constructor ?? "")); exceptionSection.push(...encodeString(exceptions[i].message)); } @@ -73,6 +74,7 @@ const encodeDebugInfo = (funcs, globals, tags, exceptions, pages, data, excMode) exceptionSection.push(3); unsignedLEB128_into(exceptions.length, exceptionSection); for (let i = 0; i < exceptions.length; i++) { + unsignedLEB128_into(i, exceptionSection); exceptionSection.push(...encodeString(exceptions[i].constructor ?? "")); } break; diff --git a/compiler/encoding.js b/compiler/encoding.js index bc8e54c6..ded91e6f 100644 --- a/compiler/encoding.js +++ b/compiler/encoding.js @@ -211,7 +211,7 @@ export const readUnsignedLEB128FromBuffer = (buffer, index) => { let b = buffer[index]; value |= (b & 0x7F) << shift; if ((value & 0x80) == 0) { - return [ value, index ]; + return [ value, index + 1 ]; } shift += 7; } diff --git a/compiler/wrap.js b/compiler/wrap.js index 65e4b4ac..5a37b426 100644 --- a/compiler/wrap.js +++ b/compiler/wrap.js @@ -570,6 +570,7 @@ const collectDebugInfo = wasm => { let length; [ length, index ] = readUnsignedLEB128FromBuffer(wasm, index); if (sectionType !== Section.custom) { + index += length; continue; } let startPosition = index; @@ -577,6 +578,7 @@ const collectDebugInfo = wasm => { let name; [ name, index ] = readStringFromBuffer(wasm, index); if (name !== 'porffor_debug_info') { + index = endPosition; continue; } while (index < endPosition) { @@ -613,7 +615,7 @@ const collectDebugInfo = wasm => { exceptions[exInd] = { constructor }; } } - } else if (type === 1) { // valtype + } else if (sectionType === 1) { // valtype valtypeBinary = wasm[index++]; } else { index += length; @@ -627,6 +629,11 @@ const collectDebugInfo = wasm => { // TODO: integrate with default export const fromWasm = (wasm, print = str => process.stdout.write(str)) => { let { exceptions, exceptionMode, valtypeBinary } = collectDebugInfo(wasm); + if (exceptionMode == null || valtypeBinary == null) { + console.warn("Wasm binary not compiled with debug information"); + exceptionMode = 'lut'; + valtypeBinary = Valtype.f64; + } let instance, memory; try { const module = new WebAssembly.Module(wasm); @@ -695,6 +702,10 @@ export const fromWasm = (wasm, print = str => process.stdout.write(str)) => { const exceptId = e.getArg(exceptTag, 0); const exception = exceptions[exceptId]; + if (!exception) { + throw new Error('Porffor error id: ' + exceptId); + } + const constructorName = exception.constructor; // no constructor, just throw message diff --git a/runner/index.js b/runner/index.js index 46574608..e2d0834c 100644 --- a/runner/index.js +++ b/runner/index.js @@ -104,7 +104,8 @@ if (['precompile', 'run', 'wasm', 'run-wasm', 'native', 'c', 'profile', 'debug', } catch (e) { let out = e; if (Object.getPrototypeOf(e).message != null) out = `${e.constructor.name}${e.message != null ? `: ${e.message}` : ''}`; - throw e; // show backtrace + if (e instanceof Error && process.argv.includes('-d')) throw e; + console.error(e); } if (process.argv.includes('-t')) console.log(`execution time: ${(performance.now() - runStart).toFixed(2)}ms`); process.exit(); @@ -188,7 +189,8 @@ try { } catch (e) { let out = e; if (!process.argv.includes('-d') && Object.getPrototypeOf(e).message != null) out = `${e.constructor.name}${e.message != null ? `: ${e.message}` : ''}`; - throw e; // show backtrace + if (e instanceof Error && process.argv.includes('-d')) throw e; + console.error(out); } if (process.argv.includes('-t')) console.log(`${process.argv.includes('-b') ? '' : '\n'}total time: ${(performance.now() - start).toFixed(2)}ms\nexecution time: ${(performance.now() - runStart).toFixed(2)}ms`); From 43926df25ad9d19b2e9f2949591752e14140798b Mon Sep 17 00:00:00 2001 From: Rob23oba Date: Fri, 16 Aug 2024 01:30:54 +0200 Subject: [PATCH 3/5] compiler: added --size-log and --size-log-count --- compiler/index.js | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/compiler/index.js b/compiler/index.js index 5841d0ae..50c68a25 100644 --- a/compiler/index.js +++ b/compiler/index.js @@ -176,6 +176,15 @@ export default (code, flags) => { if (Prefs.optFuncs || Prefs.f) logFuncs(funcs, globals, exceptions); + if (Prefs.sizeLog) { + console.log('Functions ordered by size:'); + const sortedFuncs = funcs.toSorted((x, y) => y.wasm.length - x.wasm.length); + const toShow = Math.min(funcs.length, Prefs.sizeLogCount ?? 10); + for (let i = 0; i < toShow; i++) { + console.log((i + 1) + '. ' + sortedFuncs[i].name + ' with ' + sortedFuncs[i].wasm.length + ' instructions'); + } + } + if (Prefs.compileAllocLog) { const wasmPages = Math.ceil((pages.size * pageSize) / 65536); const bytes = wasmPages * 65536; From aa9faba8cc289068a60e13a1932c2a3d2defc723 Mon Sep 17 00:00:00 2001 From: Rob23oba Date: Thu, 5 Sep 2024 21:05:19 +0200 Subject: [PATCH 4/5] Remove debug information warning --- runner/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/runner/index.js b/runner/index.js index 02df6329..79625168 100644 --- a/runner/index.js +++ b/runner/index.js @@ -33,7 +33,7 @@ if (process.argv.includes('--help')) { for (const [ cmd, [ color, desc ] ] of Object.entries({ run: [ 34, 'Run a JS file' ], wasm: [ 34, 'Compile a JS file to a Wasm binary' ], - 'run-wasm': [ 34, 'Run a compiled Wasm binary (requires compilation with -d)\n' ], + 'run-wasm': [ 34, 'Run a compiled Wasm binary\n' ], c: [ 31, 'Compile a JS file to C source code' ], native: [ 31, 'Compile a JS file to a native binary\n' ], From 9180970f51557e38d56b92aa640711d15fbfa686 Mon Sep 17 00:00:00 2001 From: Rob23oba Date: Wed, 23 Oct 2024 16:47:00 +0200 Subject: [PATCH 5/5] assemble / wrap: remove debug information altogether --- compiler/assemble.js | 17 ----------------- compiler/wrap.js | 43 ++----------------------------------------- 2 files changed, 2 insertions(+), 58 deletions(-) diff --git a/compiler/assemble.js b/compiler/assemble.js index 4ea1139b..db0eb57d 100644 --- a/compiler/assemble.js +++ b/compiler/assemble.js @@ -47,20 +47,6 @@ const encodeNames = funcs => { ]; }; -const encodeDebugInfo = (funcs, globals, tags, exceptions, pages, data, excMode) => { - const encodeSection = (id, section) => [ - id, - ...unsignedLEB128(section.length), - ...section - ]; - const typeSection = [ valtypeBinary ]; - - // TODO: add more information like where funcrefs are, etc. - return [ - ...encodeSection(0, typeSection), - ]; -}; - export default (funcs, globals, tags, pages, data, noTreeshake = false) => { const types = [], typeCache = {}; @@ -135,8 +121,6 @@ export default (funcs, globals, tags, pages, data, noTreeshake = false) => { const nameSection = Prefs.d ? customSection('name', encodeNames(funcs)) : []; - const porfforDebugInfoSection = Prefs.d ? customSection('porffor_debug_info', encodeDebugInfo(funcs, globals, tags, pages, data, Prefs.exceptionMode ?? 'lut')) : []; - const directFuncs = funcs.filter(x => !x.indirect); const tableSection = !funcs.table ? [] : createSection( Section.table, @@ -440,7 +424,6 @@ export default (funcs, globals, tags, pages, data, noTreeshake = false) => { ...exportSection, ...elementSection, ...dataCountSection, - ...porfforDebugInfoSection, ...codeSection, ...dataSection, ...nameSection diff --git a/compiler/wrap.js b/compiler/wrap.js index 9449c360..f87fd8ad 100644 --- a/compiler/wrap.js +++ b/compiler/wrap.js @@ -551,54 +551,15 @@ export default (source, module = undefined, customImports = {}, print = str => p return { exports, wasm, times, pages, c }; }; -const collectDebugInfo = wasm => { - let index = 8; // skip magic and version - let exceptions = [], exceptionMode, valtypeBinary; - while (index < wasm.length) { - let sectionType = wasm[index++]; - let length; - [ length, index ] = readUnsignedLEB128FromBuffer(wasm, index); - if (sectionType !== Section.custom) { - index += length; - continue; - } - let startPosition = index; - let endPosition = index + length; - let name; - [ name, index ] = readStringFromBuffer(wasm, index); - if (name !== 'porffor_debug_info') { - index = endPosition; - continue; - } - while (index < endPosition) { - sectionType = wasm[index++]; - let length; - [ length, index ] = readUnsignedLEB128FromBuffer(wasm, index); - if (sectionType === 0) { // valtype - valtypeBinary = wasm[index++]; - } else { - index += length; - } - } - break; - } - return { valtypeBinary }; -}; - // TODO: integrate with default export const fromWasm = (wasm, print = str => process.stdout.write(str)) => { - let { valtypeBinary } = collectDebugInfo(wasm); - if (valtypeBinary == null) { - // console.warn("Wasm binary not compiled with debug information"); - valtypeBinary = Valtype.f64; - } let instance, memory; try { const module = new WebAssembly.Module(wasm); instance = new WebAssembly.Instance(module, { '': { - p: valtypeBinary === Valtype.i64 ? i => print(Number(i).toString()) : i => print(i.toString()), - c: valtypeBinary === Valtype.i64 ? i => print(String.fromCharCode(Number(i))) : i => print(String.fromCharCode(i)), + p: i => print(i.toString()), + c: i => print(String.fromCharCode(Number(i))), t: () => performance.now(), u: () => performance.timeOrigin, y: () => {},