mirror of
https://github.com/Z3Prover/z3
synced 2025-07-19 10:52:02 +00:00
Update emscripten (#7473)
* fixes for newer emscripten thread handling behavior * fix return type for async wrapper functions * update prettier * update typescript and fix errors * update emscripten version in CI * update js readme about tests
This commit is contained in:
parent
4fbf54afd0
commit
e5f8327483
17 changed files with 275 additions and 108 deletions
|
@ -40,7 +40,13 @@ function spawnSync(command: string, opts: SpawnOptions = {}) {
|
|||
}
|
||||
|
||||
function exportedFuncs(): string[] {
|
||||
const extras = ['_malloc', '_set_throwy_error_handler', '_set_noop_error_handler', ...asyncFuncs.map(f => '_async_' + f)];
|
||||
const extras = [
|
||||
'_malloc',
|
||||
'_free',
|
||||
'_set_throwy_error_handler',
|
||||
'_set_noop_error_handler',
|
||||
...asyncFuncs.map(f => '_async_' + f),
|
||||
];
|
||||
|
||||
// TODO(ritave): This variable is unused in original script, find out if it's important
|
||||
const fns: any[] = (functions as any[]).filter(f => !asyncFuncs.includes(f.name));
|
||||
|
@ -66,10 +72,10 @@ fs.mkdirSync(path.dirname(ccWrapperPath), { recursive: true });
|
|||
fs.writeFileSync(ccWrapperPath, makeCCWrapper());
|
||||
|
||||
const fns = JSON.stringify(exportedFuncs());
|
||||
const methods = '["ccall","FS","allocate","UTF8ToString","intArrayFromString","ALLOC_NORMAL"]';
|
||||
const methods = '["PThread","ccall","FS","UTF8ToString","intArrayFromString"]';
|
||||
const libz3a = path.normalize('../../../build/libz3.a');
|
||||
spawnSync(
|
||||
`emcc build/async-fns.cc ${libz3a} --std=c++20 --pre-js src/low-level/async-wrapper.js -g2 -pthread -fexceptions -s WASM_BIGINT -s USE_PTHREADS=1 -s PTHREAD_POOL_SIZE=0 -s PTHREAD_POOL_SIZE_STRICT=0 -s MODULARIZE=1 -s 'EXPORT_NAME="initZ3"' -s EXPORTED_RUNTIME_METHODS=${methods} -s EXPORTED_FUNCTIONS=${fns} -s DISABLE_EXCEPTION_CATCHING=0 -s SAFE_HEAP=0 -s DEMANGLE_SUPPORT=1 -s TOTAL_MEMORY=2GB -s TOTAL_STACK=20MB -I z3/src/api/ -o build/z3-built.js`,
|
||||
`emcc build/async-fns.cc ${libz3a} --std=c++20 --pre-js src/low-level/async-wrapper.js -g2 -pthread -fexceptions -s WASM_BIGINT -s USE_PTHREADS=1 -s PTHREAD_POOL_SIZE=0 -s PTHREAD_POOL_SIZE_STRICT=0 -s MODULARIZE=1 -s 'EXPORT_NAME="initZ3"' -s EXPORTED_RUNTIME_METHODS=${methods} -s EXPORTED_FUNCTIONS=${fns} -s DISABLE_EXCEPTION_CATCHING=0 -s SAFE_HEAP=0 -s TOTAL_MEMORY=2GB -s TOTAL_STACK=20MB -I z3/src/api/ -o build/z3-built.js`,
|
||||
);
|
||||
|
||||
fs.rmSync(ccWrapperPath);
|
||||
|
|
|
@ -58,8 +58,24 @@ void wrapper(Args&&... args) {
|
|||
reject_async('failed with unknown exception');
|
||||
});
|
||||
}
|
||||
MAIN_THREAD_ASYNC_EM_ASM({
|
||||
// this clears the earliest timeout
|
||||
// not necessarily the one corresponding to this thread
|
||||
// but that's ok
|
||||
clearTimeout(threadTimeouts.shift());
|
||||
});
|
||||
});
|
||||
t.detach();
|
||||
EM_ASM({
|
||||
// https://github.com/emscripten-core/emscripten/issues/23092
|
||||
// in Node.js, the process will die if there is no active work
|
||||
// which can happen while the thread is spawning
|
||||
// or while it is running
|
||||
// so we set a timeout here so it stays alive
|
||||
// this needs to be longer than it could conceivably take to call the one function
|
||||
// it gets cleared as soon as the thread actually finishes
|
||||
threadTimeouts.push(setTimeout(() => {}, 600000));
|
||||
});
|
||||
}
|
||||
|
||||
template<typename Fn, Fn fn, typename... Args>
|
||||
|
@ -79,8 +95,24 @@ void wrapper_str(Args&&... args) {
|
|||
reject_async(new Error('failed with unknown exception'));
|
||||
});
|
||||
}
|
||||
MAIN_THREAD_ASYNC_EM_ASM({
|
||||
// this clears the earliest timeout
|
||||
// not necessarily the one corresponding to this thread
|
||||
// but that's ok
|
||||
clearTimeout(threadTimeouts.shift());
|
||||
});
|
||||
});
|
||||
t.detach();
|
||||
EM_ASM({
|
||||
// https://github.com/emscripten-core/emscripten/issues/23092
|
||||
// in Node.js, the process will die if there is no active work
|
||||
// which can happen while the thread is spawning
|
||||
// or while it is running
|
||||
// so we set a timeout here so it stays alive
|
||||
// this needs to be longer than it could conceivably take to call the one function
|
||||
// it gets cleared as soon as the thread actually finishes
|
||||
threadTimeouts.push(setTimeout(() => {}, 600000));
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -10,7 +10,7 @@ assert(process.argv.length === 4, `Usage: ${process.argv[0]} ${process.argv[1]}
|
|||
const wrapperFilePath = process.argv[2];
|
||||
const typesFilePath = process.argv[3];
|
||||
|
||||
function makeTsWrapper() {
|
||||
async function makeTsWrapper() {
|
||||
const subtypes = {
|
||||
__proto__: null,
|
||||
Z3_sort: 'Z3_ast',
|
||||
|
@ -339,8 +339,10 @@ function makeTsWrapper() {
|
|||
`.trim();
|
||||
}
|
||||
|
||||
// async functions are invocations of the wrapper from make-ts-wrapper.ts
|
||||
// the wrapper spawns a thread and returns void, so we need to use void as the return type here
|
||||
// prettier-ignore
|
||||
let invocation = `Mod.ccall('${isAsync ? "async_" : ""}${fn.name}', '${cReturnType}', ${JSON.stringify(ctypes)}, [${args.map(toEm).join(", ")}])`;
|
||||
let invocation = `Mod.ccall('${isAsync ? "async_" : ""}${fn.name}', '${isAsync ? 'void' : cReturnType}', ${JSON.stringify(ctypes)}, [${args.map(toEm).join(", ")}])`;
|
||||
|
||||
if (isAsync) {
|
||||
invocation = `await Mod.async_call(() => ${invocation})`;
|
||||
|
@ -462,13 +464,18 @@ export async function init(initModule: any) {
|
|||
`;
|
||||
|
||||
return {
|
||||
wrapperDocument: prettier.format(wrapperDocument, { singleQuote: true, parser: 'typescript' }),
|
||||
typesDocument: prettier.format(typesDocument, { singleQuote: true, parser: 'typescript' }),
|
||||
wrapperDocument: await prettier.format(wrapperDocument, { singleQuote: true, parser: 'typescript' }),
|
||||
typesDocument: await prettier.format(typesDocument, { singleQuote: true, parser: 'typescript' }),
|
||||
};
|
||||
}
|
||||
|
||||
const { wrapperDocument, typesDocument } = makeTsWrapper();
|
||||
fs.mkdirSync(path.dirname(wrapperFilePath), { recursive: true });
|
||||
fs.writeFileSync(wrapperFilePath, wrapperDocument);
|
||||
fs.mkdirSync(path.dirname(typesFilePath), { recursive: true });
|
||||
fs.writeFileSync(typesFilePath, typesDocument);
|
||||
(async () => {
|
||||
const { wrapperDocument, typesDocument } = await makeTsWrapper();
|
||||
fs.mkdirSync(path.dirname(wrapperFilePath), { recursive: true });
|
||||
fs.writeFileSync(wrapperFilePath, wrapperDocument);
|
||||
fs.mkdirSync(path.dirname(typesFilePath), { recursive: true });
|
||||
fs.writeFileSync(typesFilePath, typesDocument);
|
||||
})().catch(e => {
|
||||
console.error(e);
|
||||
process.exit(1);
|
||||
});
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue