Skip to content
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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions build/moz.configure/rust.configure
Original file line number Diff line number Diff line change
Expand Up @@ -417,6 +417,13 @@ def detect_rustc_target(
if len(narrowed) == 1:
return narrowed[0].rust_target

# Failing that, prefer the generic "unknown" vendor over a
# vendor-specific target (rustc 1.98 added x86_64-oe-linux-gnu beside
# x86_64-unknown-linux-gnu, and the host vendor is "pc").
narrowed = [c for c in candidates if c.target.vendor == "unknown"]
if len(narrowed) == 1:
return narrowed[0].rust_target

return None

rustc_target = find_candidate(candidates)
Expand Down
18 changes: 13 additions & 5 deletions build/moz.configure/toolchain.configure
Original file line number Diff line number Diff line change
Expand Up @@ -677,6 +677,14 @@ def check_compiler(configure_cache, compiler, language, target, android_version)
else:
toolchain = target.toolchain

# clang 22 deprecates the bare wasm32-wasi target name, and the warning
# makes every flag probe fail; older clangs ship a sysroot and compiler-rt
# laid out under the plain name only. Only the --target flag changes; the
# sysroot keeps the plain name.
target_triple = toolchain
if target.os == "WASI" and info.type == "clang" and info.version >= "22.0":
target_triple = "%s-wasip1" % target.cpu

if info.type == "clang":
# Add the target explicitly when the target is aarch64 macosx, because
# the Xcode clang target is named differently, and we need to work around
Expand All @@ -689,7 +697,7 @@ def check_compiler(configure_cache, compiler, language, target, android_version)
flags.append("--target=arm64-apple-darwin")
has_target = True
elif target.os == "iOS":
target_flag = "--target=%s" % toolchain
target_flag = "--target=%s" % target_triple
if target_flag not in compiler:
flags.append(target_flag)
has_target = True
Expand All @@ -699,7 +707,7 @@ def check_compiler(configure_cache, compiler, language, target, android_version)
or not info.endianness
or info.endianness != target.endianness
):
flags.append("--target=%s" % toolchain)
flags.append("--target=%s" % target_triple)
has_target = True

# Add target flag when there is an OS mismatch (e.g. building for Android on
Expand All @@ -708,7 +716,7 @@ def check_compiler(configure_cache, compiler, language, target, android_version)
elif target.os in OS_preprocessor_checks and (
not info.os or info.os != target.os
):
flags.append("--target=%s" % toolchain)
flags.append("--target=%s" % target_triple)
has_target = True

if not has_target and (not info.cpu or info.cpu != target.cpu):
Expand All @@ -718,9 +726,9 @@ def check_compiler(configure_cache, compiler, language, target, android_version)
elif (info.cpu, target.cpu) in same_arch:
flags.append("-m64")
elif info.type == "clang-cl" and target.cpu == "aarch64":
flags.append("--target=%s" % toolchain)
flags.append("--target=%s" % target_triple)
elif info.type == "clang":
flags.append("--target=%s" % toolchain)
flags.append("--target=%s" % target_triple)

return namespace(
type=info.type,
Expand Down
1 change: 1 addition & 0 deletions config/system-headers.mozbuild
Original file line number Diff line number Diff line change
Expand Up @@ -835,6 +835,7 @@ system_headers = [
"sys/link.h",
"sys/locking.h",
"syslog.h",
"system_error",
"sys/lwp.h",
"sys/machine.h",
"sys/mman.h",
Expand Down
23 changes: 23 additions & 0 deletions js/moz.configure
Original file line number Diff line number Diff line change
Expand Up @@ -207,11 +207,13 @@ option(
help="{Support|Do not support} wevaling the PBL interpreter",
)


@depends("--enable-portable-baseline-interp", "--enable-pbl-weval")
def js_pbl_weval(pbl, weval):
if pbl and weval:
return True


set_define("ENABLE_JS_PBL_WEVAL", js_pbl_weval)
set_config("ENABLE_JS_PBL_WEVAL", js_pbl_weval)

Expand Down Expand Up @@ -263,6 +265,26 @@ set_config(
depends_if("--enable-aot-ics-enforce")(lambda _: True),
)

# External compiler hooks: the object-model, script-entry, GC and regexp
# hook surface an external compilation tier (such as NightMonkey) plugs into
# (js/public/ExternalCompilerHooks.h), plus the private-header export and the
# `jsshell` static library such a tier links its own shell against. Off by
# default; an ordinary build is unaffected.
option(
"--enable-external-compiler-hooks",
default=False,
help="{Enable|Disable} the external compiler tier hook surface",
)


@depends("--enable-external-compiler-hooks")
def external_compiler_hooks(value):
if value:
return True


set_config("JS_EXTERNAL_COMPILER_HOOKS", external_compiler_hooks)
set_define("JS_EXTERNAL_COMPILER_HOOKS", external_compiler_hooks)

# Enable JS Streams
# ===================================================
Expand All @@ -282,6 +304,7 @@ def enable_js_streams(value):
set_config("MOZ_JS_STREAMS", enable_js_streams)
set_define("MOZ_JS_STREAMS", enable_js_streams)


# JIT support
# =======================================================
@depends(target, "--enable-portable-baseline-interp")
Expand Down
161 changes: 161 additions & 0 deletions js/public/ExternalCompilerHooks.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
* vim: set ts=8 sts=2 et sw=2 tw=80:
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */

/*
* Hooks for an external compilation tier layered on top of the engine.
*
* Built only with --enable-external-compiler-hooks
* (JS_EXTERNAL_COMPILER_HOOKS). The engine reserves one pointer-sized word per
* object, per script and per RegExpShared for the external tier's use, calls
* the hook table registered on the runtime at the points where the tier's
* assumptions about the heap or control flow can be invalidated, and lets the
* tier take over script entry. Each context caches the runtime's table and
* carries an opaque per-context state the tier creates and destroys with the
* context. With no table registered every hook site costs one load and a
* predictable branch.
*/

#ifndef js_ExternalCompilerHooks_h
#define js_ExternalCompilerHooks_h

#ifdef JS_EXTERNAL_COMPILER_HOOKS

# include <stddef.h>
# include <stdint.h>

# include "jstypes.h"

# include "js/CallArgs.h"
# include "js/Id.h"
# include "js/RootingAPI.h"
# include "js/TypeDecls.h"
# include "js/Value.h"

namespace js {
class AbstractGeneratorObject;
class NativeObject;
class RegExpShared;
class RunState;
class VectorMatchPairs;
enum class RegExpRunStatus : int32_t;
} // namespace js

namespace JS {

// Why an object's external word was reset.
enum class ExternalObjectMutation : uint32_t {
ToDictionary = 1,
ChangeProperty,
ChangeCustomDataProp,
RemoveProperty,
FreezeOrSeal,
Swap,
ObjectFlagChange,
// A slot store through an engine path cleared bits per the store masks.
StoredValue,
};

enum class ExternalEnterStatus : uint32_t { NotEntered, Ok, Error };

// Every hook receives the context the engine is running on. The one site
// without a context of its own, the slot-store choke, passes the runtime's
// main context.
struct ExternalCompilerHooks {
// Per-context state: created when a context is initialized (or when the
// table is registered on a runtime whose context already exists) and
// destroyed with the context. JSContext::getExternalCompilerState returns
// it. Either may be null.
void* (*newContext)(JSContext* cx);
void (*destroyContext)(JSContext* cx, void* state);

// Object model. Every object carries a pointer-sized external word, zero
// at birth. A structural change (shape change, dictionary mode, freeze,
// flag change, swap) on an object whose word is nonzero resets the word to
// zero and reports the old word here.
void (*objectDemoted)(JSContext* cx, JSObject* obj, uintptr_t oldWord,
ExternalObjectMutation why);
// Slot-store policy, applied on every engine-path slot store to an object
// whose word intersects either mask: storeClearMask bits are cleared on any
// store, storeNonNumberClearMask bits when the value is not a number. When
// the word changes, objectDemoted fires with StoredValue.
uintptr_t storeClearMask;
uintptr_t storeNonNumberClearMask;
// A property was added to an object whose word is nonzero.
void (*propertyAdded)(JSContext* cx, js::NativeObject* obj,
JS::PropertyKey id, uint32_t slot,
uint32_t numFixedSlots);

// Global object. A property was defined or deleted on a global, a data
// property of a global was written, or a global lexical binding now
// shadows a same-named global property.
void (*globalKeyChanged)(JSContext* cx, JS::PropertyKey id);
void (*globalDataStored)(JSContext* cx, JS::PropertyKey id,
uint64_t valueBits);
void (*globalLexicalShadowAdded)(JSContext* cx, uint64_t idBits);

// Script entry. Every script carries a pointer-sized external word, zero
// at birth; the engine consults these only for scripts whose word is
// nonzero.
ExternalEnterStatus (*enterScript)(JSContext* cx, js::RunState& state);
ExternalEnterStatus (*enterCall)(JSContext* cx, const JS::CallArgs& args,
JSScript* script, bool constructing);
// A generator whose frame belongs to the external tier cannot be resumed
// by the interpreter.
bool (*isForeignGenerator)(JSContext* cx, js::AbstractGeneratorObject* gen);
ExternalEnterStatus (*resumeGenerator)(
JSContext* cx, JS::Handle<js::AbstractGeneratorObject*> gen,
JS::HandleValue arg, JS::HandleValue resumeKind,
JS::MutableHandleValue rval);

// GC: traced on every collection, minor and major.
void (*traceRoots)(JSContext* cx, JSTracer* trc);

// Frontend: source text entered the compiler (eval, Function, module or
// embedder compile alike). Not reported for a compile with no context of
// its own (an off-thread compile).
void (*sourceAssigned)(JSContext* cx);
// Lower bound on the fixed-slot estimate for constructor `this` objects
// (0 leaves the engine's estimate alone).
uint32_t minConstructorThisSlots;

// RegExp: decide a match before the engine's own matcher runs. Return true
// with *status set to take over; false to fall through.
bool (*regexpMatch)(JSContext* cx, JS::MutableHandle<js::RegExpShared*> re,
JS::Handle<JSLinearString*> input, size_t start,
js::VectorMatchPairs* matches, bool latin1,
js::RegExpRunStatus* status);
};

// Register (or, with nullptr, unregister) the hook table on a runtime. The
// table must outlive its registration. The runtime's context caches the
// table; per-context state is created for it here (and destroyed on
// unregistration). Call from the runtime's own thread, before any script the
// tier cares about runs.
extern JS_PUBLIC_API void SetExternalCompilerHooks(
JSRuntime* rt, ExternalCompilerHooks* hooks);
extern JS_PUBLIC_API ExternalCompilerHooks* GetExternalCompilerHooks(
JSRuntime* rt);

} // namespace JS

namespace js {

// Out-of-line halves of the inline hook sites (vm/JSObject.h).
extern JS_PUBLIC_API void ExternalObjectDemoted(JSContext* cx, JSObject* obj,
uintptr_t oldWord,
JS::ExternalObjectMutation why);
extern JS_PUBLIC_API void ExternalObjectStore(JSObject* obj,
const JS::Value& v);
extern JS_PUBLIC_API void ExternalPropertyAdded(JSContext* cx,
NativeObject* obj,
JS::PropertyKey id,
uint32_t slot);

} // namespace js

#endif // JS_EXTERNAL_COMPILER_HOOKS

#endif // js_ExternalCompilerHooks_h
5 changes: 4 additions & 1 deletion js/public/shadow/Object.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,10 @@ namespace shadow {
*/
struct Object {
shadow::Shape* shape;
#ifndef JS_64BIT
#ifdef JS_EXTERNAL_COMPILER_HOOKS
// Mirrors JSObject: the external tier's pointer-sized per-object word.
uintptr_t externalWord_;
#elif !defined(JS_64BIT)
uint32_t padding_;
#endif
Value* slots;
Expand Down
Loading
Loading