Skip to content

Add hooks to allow for an external compiler. - #3

Merged
cfallin merged 2 commits into
bytecodealliance:wasi-ff147from
cfallin:nightmonkey-external
Sep 22, 2026
Merged

cfallin merged 2 commits into
bytecodealliance:wasi-ff147from
cfallin:nightmonkey-external

Conversation

@cfallin

@cfallin cfallin commented Sep 22, 2026

Copy link
Copy Markdown
Member

This permits a library layered on top of SpiderMonkey to attach to various key extension points: the external compiler can store its own (opaque) pointer word on every script and take over the script-entry point, and it can also store state on objects potentially used for type-inference or invariant tracking.

This PR also extends the JS shell so that it can be used to build a shell that wraps up an external compiler's
setup/snapshotting/compilation in an appropriate manner.

As part of this, a build with external compiler hooks enabled will export all of its (internal) headers into dist/ in the build directory, so the external compiler can build with them. This interface is of course still private and has no version guarantees; it is the responsibility of the external compiler to keep track of any changes and use it appropriately.

This was built in order for NightMonkey to attach to / layer on top of SpiderMonkey.

All changes are under a new configure flag
--enable-external-compiler-hooks; without that flag, the engine is unchanged.

This permits a library layered on top of SpiderMonkey to attach to
various key extension points: the external compiler can store its
own (opaque) pointer word on every script and take over the
script-entry point, and it can also store state on objects potentially
used for type-inference or invariant tracking.

This PR also extends the JS shell so that it can be used to build a
shell that wraps up an external compiler's
setup/snapshotting/compilation in an appropriate manner.

As part of this, a build with external compiler hooks enabled will
export all of its (internal) headers into `dist/` in the build
directory, so the external compiler can build with them. This
interface is of course still private and has no version guarantees; it
is the responsibility of the external compiler to keep track of any
changes and use it appropriately.

This was built in order for NightMonkey to attach to / layer on top of
SpiderMonkey.

All changes are under a new configure flag
`--enable-external-compiler-hooks`; without that flag, the engine is
unchanged.
@cfallin
cfallin force-pushed the nightmonkey-external branch from 244b793 to 164f660 Compare September 22, 2026 06:07

@tschneidereit tschneidereit left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is all pretty straightforward, very nice!

I left a few comments inline, but apart from the JSObject padding question, none of them are particularly important.

Comment thread js/public/ExternalCompilerHooks.h Outdated
Comment thread js/src/shell/wizer.cpp
Comment on lines +49 to +52
// `glob`, not `cx->global()`: the latter is a Handle<GlobalObject*>,
// which does not convert to the Handle<JSObject*> this takes.
if (!JS_CallFunctionName(cx, glob, "main", JS::HandleValueArray::empty(),
&ret)) {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems fishy to me—both because it used to work before, and because the reason seems implausible: I'm fairly sure (but haven't checked just now) Handle<GlobalObject*> does convert to Handle<JSObject*>

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This perplexed me for a bit too but actually it appears to be broken in-tree as-is, and CI doesn't build a Wizer config (this Wizer integration is only for testing and I guess we don't use it anywhere in production). It must have broken during some upgrade/rebase?

Comment thread js/public/shadow/Object.h Outdated
Comment on lines +38 to +41
#elif defined(JS_EXTERNAL_COMPILER_HOOKS)
// Mirrors JSObject: the external tier's per-object word, plus alignment.
uint32_t padding_;
uint32_t padding2_;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this right? It's different from the change in #2, and if I'm not weirdly misreading it adds 64 bits of padding on 64bit builds, not on 32bit ones? Or did you add 64bit support to NM since #2, and this is in support of that?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reworked a bit -- the layout was correct here for the design (a fixed 32-bit external compiler's word) but I decided to switch to a uintptr_t (more flexible -- external tier could, say, stuff a whole pointer in, in hypothetical 64-bit case). Now we have just a uintptr_t field and no padding words (here and in the JSObject); the compiler slips it into the unused padding space on 32-bit builds and consumes a full 64 bits on 64 bit builds.

(64-bit support is new in this externalized API, but I haven't tested NightMonkey in that mode because there is no 64-bit backend. I wanted to make it just that tiny bit more generic regardless, with an eye toward upstreaming and/or future NightMonkey extensions...)

Comment thread js/src/vm/JSObject.h Outdated
@cfallin
cfallin merged commit f0c060c into bytecodealliance:wasi-ff147 Sep 22, 2026
10 checks passed
@cfallin
cfallin deleted the nightmonkey-external branch September 22, 2026 21:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants