Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Move stack switching logic into a new stack switching folder. #3987

Merged
merged 4 commits into from
Jul 10, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
13 changes: 7 additions & 6 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ all: check \
dist/module_webworker_dev.js
echo -e "\nSUCCESS!"

src/core/pyodide_pre.o: src/js/_pyodide.out.js src/core/pre.js src/core/create_invokes.out.js
src/core/pyodide_pre.o: src/js/_pyodide.out.js src/core/pre.js src/core/stack_switching/stack_switching.out.js
# Our goal here is to inject src/js/_pyodide.out.js into an archive file so that
# when linked, Emscripten will include it. We use the same pathway that EM_JS
# uses, but EM_JS is itself unsuitable. Why? Because the C preprocessor /
Expand Down Expand Up @@ -56,7 +56,7 @@ src/core/pyodide_pre.o: src/js/_pyodide.out.js src/core/pre.js src/core/create_i
echo '()<::>{' >> tmp.dat # zero argument argspec and start body
cat src/js/_pyodide.out.js >> tmp.dat # All of _pyodide.out.js is body
echo '}' >> tmp.dat # Close function body
cat src/core/create_invokes.out.js >> tmp.dat
cat src/core/stack_switching/stack_switching.out.js >> tmp.dat
cat src/core/pre.js >> tmp.dat # And pre.js
echo "pyodide_js_init();" >> tmp.dat # Then execute the function.

Expand Down Expand Up @@ -128,8 +128,8 @@ node_modules/.installed : src/js/package.json src/js/package-lock.json
dist/pyodide.js src/js/_pyodide.out.js: src/js/*.ts src/js/pyproxy.gen.ts src/js/error_handling.gen.ts node_modules/.installed
cd src/js && npm run tsc && node esbuild.config.mjs && cd -

src/core/create_invokes.out.js : src/core/create_invokes.mjs src/core/runtime_wasm.mjs
cd src/core && npx esbuild --bundle create_invokes.mjs --outfile=create_invokes.out.js
src/core/stack_switching/stack_switching.out.js : src/core/stack_switching/*.mjs
node src/core/stack_switching/esbuild.config.mjs

dist/package.json : src/js/package.json
cp $< $@
Expand Down Expand Up @@ -225,9 +225,10 @@ benchmark: all

clean:
rm -fr dist/*
rm -fr src/*/*.o
rm -fr src/*/*.gen.*
rm -fr node_modules
find src -name '*.o' -delete
find src -name '*.gen.*' -delete
find src -name '*.out.*' -delete
make -C packages clean
echo "The Emsdk, CPython are not cleaned. cd into those directories to do so."

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,6 @@ import {
typeCodes,
} from "./runtime_wasm.mjs";

if (typeof Module === "undefined") {
globalThis.Module = {};
}

/**
* These produce the following pseudocode:
* ```
Expand Down Expand Up @@ -136,15 +132,13 @@ export function createInvokeModule(sig) {
return mod.generate();
}

let jsWrapperTag;
export let jsWrapperTag;
try {
jsWrapperTag = new WebAssembly.Tag({ parameters: ["externref"] });
Module.jsWrapperTag = jsWrapperTag;
} catch (e) {}

if (jsWrapperTag) {
Module.wrapException = (e) => new WebAssembly.Exception(jsWrapperTag, [e]);
}
export const wrapException = (e) =>
new WebAssembly.Exception(jsWrapperTag, [e]);

function createInvoke(sig) {
if (!jsWrapperTag) {
Expand All @@ -162,19 +156,16 @@ function createInvoke(sig) {
});
return instance.exports["o"];
}
Module.createInvoke = createInvoke;

// We patched Emscripten to call this function on the wasmImports just prior to
// wasm instantiation if it is defined. It replaces all invoke functions with
// our Wasm invokes if wasm EH is available.
Module.adjustWasmImports = function (wasmImports) {
if (jsWrapperTag) {
const i = "invoke_";
for (let name of Object.keys(wasmImports)) {
if (!name.startsWith(i)) {
continue;
}
wasmImports[name] = createInvoke(name.slice(i.length));
export function adjustWasmImports(wasmImports) {
const i = "invoke_";
for (let name of Object.keys(wasmImports)) {
if (!name.startsWith(i)) {
continue;
}
wasmImports[name] = createInvoke(name.slice(i.length));
}
};
}
44 changes: 44 additions & 0 deletions src/core/stack_switching/esbuild.config.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/**
* Bundle the stack switching folder as iife and then export names exported from
* stack_switching.mjs onto Module and into the Emscripten namespace.
*/

import { build } from "esbuild";
import { dirname, join } from "node:path";

const __dirname = dirname(new URL(import.meta.url).pathname);

const outfile = join(__dirname, "stack_switching.out.js");
const globalName = "StackSwitching";

const config = {
entryPoints: [join(__dirname, "stack_switching.mjs")],
outfile,
format: "iife",
bundle: true,
globalName,
metafile: true,
};

// First build as "esm" to get the list of exports. The metafile doesn't list
// exports except when we set `format: "esm"`. Setting bundle: false saves a
// tiny amount of time on this pass.
const { metafile } = await build(
Object.assign({}, config, { format: "esm", bundle: false }),
);

// The file name is the metafile.outputs key. It is relative to the current
// working directory, so it's annoying to work it out. There will only be one
// key in any case, so we just extract it with Object.values().
const exports = Object.values(metafile.outputs)[0].exports;

// Add a footer that destructures the exports into the Emscripten namespace.
// Also Object.assign them onto Module.
const footer = `
const {${exports}} = ${globalName};
Object.assign(Module, ${globalName});
`.replaceAll(/\s/g, "");
config.footer = { js: footer };

// Build again, this time as an iife bundle with our extra footer.
await build(config);
File renamed without changes.
17 changes: 17 additions & 0 deletions src/core/stack_switching/stack_switching.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
/**
* Files exported from here are copied into the Emscripten namespace.
* See esbuild.config.mjs.
*/

import {
jsWrapperTag,
wrapException,
adjustWasmImports,
} from "./create_invokes.mjs";

export { jsWrapperTag };

if (jsWrapperTag) {
Module.adjustWasmImports = adjustWasmImports;
Module.wrapException = wrapException;
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { expect } from "chai";

import { readFileSync, writeFileSync } from "node:fs";
import * as vm from "node:vm";
import { readFileSync } from "node:fs";
import loadWabt from "wabt";
import { URL } from "url"; // in Browser, the URL in native accessible on window
import {
Expand All @@ -12,8 +11,8 @@ import {
TypeSection,
WASM_PRELUDE,
insertSectionPrefix,
} from "../../../core/runtime_wasm.mjs";
import { createInvokeModule } from "../../../core/create_invokes.mjs";
} from "../../../core/stack_switching/runtime_wasm.mjs";
import { createInvokeModule } from "../../../core/stack_switching/create_invokes.mjs";

const __dirname = new URL(".", import.meta.url).pathname;

Expand All @@ -29,7 +28,7 @@ function fromWat(wat) {
function fromWatFile(file) {
return parseWat(
file,
readFileSync(__dirname + "invokes/" + file, { encoding: "utf8" }),
readFileSync(__dirname + "wat/" + file, { encoding: "utf8" }),
{
mutable_globals: true,
exceptions: true,
Expand Down