/* -*- 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/. */
#include"vm/SelfHosting.h"
#ifdef ENABLE_EXPLICIT_RESOURCE_MANAGEMENT # include "builtin/AsyncDisposableStackObject.h" # include "builtin/DisposableStackObject.h" #endif #include"mozilla/BinarySearch.h" #include"mozilla/Casting.h" #include"mozilla/Maybe.h" #include"mozilla/ScopeExit.h"// mozilla::MakeScopeExit #include"mozilla/Utf8.h"// mozilla::Utf8Unit
/** * Handles an assertion failure in self-hosted code just like an assertion * failure in C++ code. Information about the failure can be provided in * args[0].
*/ staticbool intrinsic_AssertionFailed(JSContext* cx, unsigned argc, Value* vp) { #ifdef DEBUG
CallArgs args = CallArgsFromVp(argc, vp); if (args.length() > 0) { // try to dump the informative string
JSString* str = ToString<CanGC>(cx, args[0]); if (str) {
js::Fprinter out(stderr);
out.put("Self-hosted JavaScript assertion info: ");
str->dumpCharsNoQuote(out);
out.putChar('\n');
}
} #endif
MOZ_ASSERT(false); returnfalse;
}
/** * Dumps a message to stderr, after stringifying it. Doesn't append a newline.
*/ staticbool intrinsic_DumpMessage(JSContext* cx, unsigned argc, Value* vp) {
CallArgs args = CallArgsFromVp(argc, vp); #ifdef DEBUG if (args.length() > 0) { // try to dump the informative string
js::Fprinter out(stderr);
JSString* str = ToString<CanGC>(cx, args[0]); if (str) {
str->dumpCharsNoQuote(out);
out.putChar('\n');
} else {
cx->recoverFromOutOfMemory();
}
} #endif
args.rval().setUndefined(); returntrue;
}
/* * Used to decompile values in the nearest non-builtin stack frame, falling * back to decompiling in the current frame. Helpful for printing higher-order * function arguments. * * The user must supply the argument number of the value in question; it * _cannot_ be automatically determined.
*/ staticbool intrinsic_DecompileArg(JSContext* cx, unsigned argc, Value* vp) {
CallArgs args = CallArgsFromVp(argc, vp);
MOZ_ASSERT(args.length() == 2);
MOZ_RELEASE_ASSERT(args[0].isInt32());
HandleValue value = args[1];
JSString* str = DecompileArgument(cx, args[0].toInt32(), value); if (!str) { returnfalse;
}
args.rval().setString(str); returntrue;
}
// When DefineDataProperty is called with 3 arguments, it's compiled to // JSOp::InitElem in the bytecode emitter so we shouldn't get here.
MOZ_ASSERT(args.length() == 4);
MOZ_ASSERT(args[0].isObject());
MOZ_RELEASE_ASSERT(args[3].isInt32());
// When args[4] is |null|, the data descriptor has a value component. if ((attributes & DATA_DESCRIPTOR_KIND) && args[4].isNull()) {
desc.setValue(args[3]);
}
if (attributes & ACCESSOR_DESCRIPTOR_KIND) {
Value getter = args[3]; if (getter.isObject()) {
desc.setGetter(&getter.toObject());
} elseif (getter.isUndefined()) {
desc.setGetter(nullptr);
} else {
MOZ_ASSERT(getter.isNull());
}
Value setter = args[4]; if (setter.isObject()) {
desc.setSetter(&setter.toObject());
} elseif (setter.isUndefined()) {
desc.setSetter(nullptr);
} else {
MOZ_ASSERT(setter.isNull());
}
}
bool strict = args[5].toBoolean(); if (strict && !result.ok()) { // We need to tell our caller Object.defineProperty, // that this operation failed, without actually throwing // for web-compatibility reasons. if (result.failureCode() == JSMSG_CANT_DEFINE_WINDOW_NC) {
args.rval().setBoolean(false); returntrue;
}
// Self-hosted code calls this intrinsic with builtin prototypes. These are // always native objects. auto* obj = &args[0].toObject().as<NativeObject>(); auto* proto = &args[1].toObject().as<NativeObject>();
mozilla::Maybe<size_t> length = tarr->length(); if (!length) { // Return zero for detached buffers to match JIT code. if (tarr->hasDetachedBuffer()) {
args.rval().setInt32(0); returntrue;
}
// Return the value of [[ArrayLength]] internal slot of the TypedArray. If the // length is out-of-bounds, always return zero. staticbool intrinsic_TypedArrayLengthZeroOnOutOfBounds(JSContext* cx, unsigned argc,
Value* vp) {
CallArgs args = CallArgsFromVp(argc, vp);
MOZ_ASSERT(args.length() == 1);
MOZ_ASSERT(args[0].toObject().is<TypedArrayObject>());
TypedArrayObject* obj = args[0].toObject().maybeUnwrapAs<TypedArrayObject>(); if (!obj) {
ReportAccessDenied(cx); returnfalse;
}
mozilla::Maybe<size_t> length = obj->length(); if (!length) { // Return zero for detached buffers to match JIT code. if (obj->hasDetachedBuffer()) {
args.rval().setInt32(0); returntrue;
}
// Extract the TypedArrayObject* underlying |obj| and return it. This method, // in a TOTALLY UNSAFE manner, completely violates the normal compartment // boundaries, returning an object not necessarily in the current compartment // or in |obj|'s compartment. // // All callers of this method are expected to sigil this TypedArrayObject*, and // all values and information derived from it, with an "unsafe" prefix, to // indicate the extreme caution required when dealing with such values. // // If calling code discipline ever fails to be maintained, it's gonna have a // bad time. static TypedArrayObject* DangerouslyUnwrapTypedArray(JSContext* cx,
JSObject* obj) { // An unwrapped pointer to an object potentially on the other side of a // compartment boundary! Isn't this such fun?
TypedArrayObject* unwrapped = obj->maybeUnwrapAs<TypedArrayObject>(); if (!unwrapped) {
ReportAccessDenied(cx); return nullptr;
}
// Be super-duper careful using this, as we've just punched through // the compartment boundary, and things like buffer() on this aren't // same-compartment with anything else in the calling method. return unwrapped;
}
auto sourceLength = source->length(); if (!sourceLength) { if (source->hasDetachedBuffer()) {
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
JSMSG_TYPED_ARRAY_DETACHED);
} else {
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
JSMSG_TYPED_ARRAY_RESIZED_BOUNDS);
} returnfalse;
}
MOZ_ASSERT(!source->hasDetachedBuffer());
// As directed by |DangerouslyUnwrapTypedArray|, sigil this pointer and all // variables derived from it to counsel extreme caution here.
Rooted<TypedArrayObject*> unsafeTypedArrayCrossCompartment(cx);
unsafeTypedArrayCrossCompartment =
DangerouslyUnwrapTypedArray(cx, &args[1].toObject()); if (!unsafeTypedArrayCrossCompartment) { returnfalse;
}
MOZ_ASSERT(!unsafeTypedArrayCrossCompartment->hasDetachedBuffer());
// The specification requires us to perform bitwise copying when |sourceType| // and |targetType| are the same (ES2017, §22.2.3.24, step 15). Additionally, // as an optimization, we can also perform bitwise copying when |sourceType| // and |targetType| have compatible bit-level representations.
Scalar::Type sourceType = source->type(); if (!CanUseBitwiseCopy(unsafeTypedArrayCrossCompartment->type(),
sourceType)) {
args.rval().setBoolean(false); returntrue;
}
// The same-type case requires exact copying preserving the bit-level // encoding of the source data, so use memcpy if possible. If source and // target are the same buffer, we can't use memcpy (or memmove), because // the specification requires sequential copying of the values. This case // is only possible if a @@species constructor created a specifically // crafted typed array. It won't happen in normal code and hence doesn't // need to be optimized. if (!TypedArrayObject::sameBuffer(source, unsafeTypedArrayCrossCompartment)) { if (source->isSharedMemory() ||
unsafeTypedArrayCrossCompartment->isSharedMemory()) {
jit::AtomicOperations::memcpySafeWhenRacy(
unsafeTargetDataCrossCompartment, sourceData, byteLength);
} else {
memcpy(unsafeTargetDataCrossCompartment.unwrapUnshared(),
sourceData.unwrapUnshared(), byteLength);
}
} else { usingnamespace jit;
// args[2] should be already in UInt32 range, but it could be double typed, // because of Ion optimization.
uint32_t limit = uint32_t(args[2].toNumber());
MOZ_ASSERT(limit > 0, "Zero limit case is already handled in self-hosted code.");
bool CallSelfHostedNonGenericMethod(JSContext* cx, const CallArgs& args) { // This function is called when a self-hosted method is invoked on a // wrapper object, like a CrossCompartmentWrapper. The last argument is // the name of the self-hosted function. The other arguments are the // arguments to pass to this function.
bool js::ReportIncompatibleSelfHostedMethod(JSContext* cx,
Handle<Value> thisValue) { // The contract for this function is the same as // CallSelfHostedNonGenericMethod. The normal ReportIncompatible function // doesn't work for selfhosted functions, because they always call the // different CallXXXMethodIfWrapped methods, which would be reported as the // called function instead.
// Lookup the selfhosted method that was invoked. But skip over // internal self-hosted function frames, because those are never the // actual self-hosted callee from external code. We can't just skip // self-hosted things until we find a non-self-hosted one because of cases // like array.sort(somethingSelfHosted), where we want to report the error // in the somethingSelfHosted, not in the sort() call.
// |undefined| is the default value when the Intl runtime caches haven't // yet been initialized. Handle it the same way as a cache miss. if (args[0].isUndefined()) {
args.rval().setBoolean(false); returntrue;
}
constchar* locale = cx->realm()->getLocale(); if (!locale) { returnfalse;
}
JSLinearString* str = args[0].toString()->ensureLinear(cx); if (!str) { returnfalse;
}
// While it may seem like an invariant that in any compartment, // seeing a typed array object implies that the TypedArray constructor // for that type is initialized on the compartment's global, this is not // the case. When we construct a typed array given a cross-compartment // ArrayBuffer, we put the constructed TypedArray in the same compartment // as the ArrayBuffer. Since we use the prototype from the initial // compartment, and never call the constructor in the ArrayBuffer's // compartment from script, we are not guaranteed to have initialized // the constructor.
JSObject* ctor = GlobalObject::getOrCreateConstructor(cx, protoKey); if (!ctor) { returnfalse;
}
staticvoid CheckSelfHostedIntrinsics() { // The `intrinsic_functions` list must be sorted so that we can use // mozilla::BinarySearch to do lookups on demand. constchar* prev = ""; for (JSFunctionSpec spec : intrinsic_functions) { if (spec.name.string()) {
MOZ_ASSERT(strcmp(prev, spec.name.string()) < 0, "Self-hosted intrinsics must be sorted");
prev = spec.name.string();
}
}
}
class CheckTenuredTracer : public JS::CallbackTracer {
HashSet<gc::Cell*, DefaultHasher<gc::Cell*>, SystemAllocPolicy> visited;
Vector<JS::GCCellPtr, 0, SystemAllocPolicy> stack;
public: explicit CheckTenuredTracer(JSRuntime* rt) : JS::CallbackTracer(rt) {} void check() { while (!stack.empty()) {
JS::TraceChildren(this, stack.popCopy());
}
} void onChild(JS::GCCellPtr thing, constchar* name) override {
gc::Cell* cell = thing.asCell();
MOZ_RELEASE_ASSERT(cell->isTenured(), "Expected tenured cell"); if (!visited.has(cell)) { if (!visited.put(cell) || !stack.append(thing)) { // Ignore OOM. This can happen during fuzzing. return;
}
}
}
};
staticvoid CheckSelfHostingDataIsTenured(JSRuntime* rt) { // Check everything is tenured as we don't trace it when collecting the // nursery.
CheckTenuredTracer trc(rt);
rt->traceSelfHostingStencil(&trc);
trc.check();
}
JS::AutoCheckCannotGC nogc; constchar* chars = reinterpret_cast<constchar*>(name->latin1Chars(nogc));
size_t len = name->length();
// NOTE: CheckSelfHostedIntrinsics checks that the intrinsic_functions list is // sorted appropriately so that we can use binary search here.
size_t loc = 0; bool match = mozilla::BinarySearchIf(
intrinsic_functions, 0, limit,
[chars, len](const JSFunctionSpec& spec) { // The spec string is null terminated but the `name` string is not, so // compare chars up until the length of `name`. Since the `name` string // does not contain any nulls, seeing the null terminator of the spec // string will terminate the loop appropriately. A final comparison // against null is needed to determine if the spec string has an extra // suffix. constchar* spec_chars = spec.name.string(); for (size_t i = 0; i < len; ++i) { if (auto cmp_result = int(chars[i]) - int(spec_chars[i])) { return cmp_result;
}
} returnint('\0') - int(spec_chars[len]);
},
&loc); if (match) { return &intrinsic_functions[loc];
} return nullptr;
}
void js::FillSelfHostingCompileOptions(CompileOptions& options) { /* * In self-hosting mode, scripts use JSOp::GetIntrinsic instead of * JSOp::GetName or JSOp::GetGName to access unbound variables. * JSOp::GetIntrinsic does a name lookup on a special object, whose * properties are filled in lazily upon first access for a given global. * * As that object is inaccessible to client code, the lookups are * guaranteed to return the original objects, ensuring safe implementation * of self-hosted builtins. * * Additionally, the special syntax callFunction(fun, receiver, ...args) * is supported, for which bytecode is emitted that invokes |fun| with * |receiver| as the this-object and ...args as the arguments.
*/
options.setIntroductionType("self-hosted");
options.setFileAndLine("self-hosted", 1);
options.setSkipFilenameValidation(true);
options.setSelfHostingMode(true);
options.setForceFullParse();
options.setForceStrictMode();
options.setDiscardSource();
options.setIsRunOnce(true);
options.setNoScriptRval(true);
}
// Report all errors and warnings to stderr because it is too early in the // startup process for any other error reporting to be used, and we don't want // errors in self-hosted code to be silently swallowed. class MOZ_STACK_CLASS AutoPrintSelfHostingFrontendContext
: public FrontendContext {
JSContext* cx_;
public: explicit AutoPrintSelfHostingFrontendContext(JSContext* cx) : cx_(cx) {
setCurrentJSContext(cx_);
}
~AutoPrintSelfHostingFrontendContext() { // TODO: Remove this once JSContext is removed from frontend.
MaybePrintAndClearPendingException(cx_);
if (hadOutOfMemory()) {
fprintf(stderr, "Out of memory\n");
}
if (maybeError()) {
JS::PrintError(stderr, &*maybeError(), true);
} for (CompileError& error : warnings()) {
JS::PrintError(stderr, &error, true);
} if (hadOverRecursed()) {
fprintf(stderr, "Over recursed\n");
} if (hadAllocationOverflow()) {
fprintf(stderr, "Allocation overflow\n");
}
}
};
[[nodiscard]] staticbool InitSelfHostingFromStencil(
JSContext* cx, frontend::CompilationAtomCache& atomCache, const frontend::CompilationStencil& stencil) { // Build the JSAtom -> ScriptIndexRange mapping and save on the runtime.
{ auto& scriptMap = cx->runtime()->selfHostScriptMap.ref();
// We don't easily know the number of top-level functions, so use the total // number of stencil functions instead. There is very little nesting of // functions in self-hosted code so this is a good approximation.
size_t numSelfHostedScripts = stencil.scriptData.size(); if (!scriptMap.reserve(numSelfHostedScripts)) {
ReportOutOfMemory(cx); returnfalse;
}
auto topLevelThings =
stencil.scriptData[frontend::CompilationStencil::TopLevelIndex]
.gcthings(stencil);
// Iterate over the (named) top-level functions. We record the ScriptIndex // as well as the ScriptIndex of the next top-level function. Scripts // between these two indices are the inner functions of the first one. We // only record named scripts here since they are what might be looked up.
Rooted<JSAtom*> prevAtom(cx);
frontend::ScriptIndex prevIndex; for (frontend::TaggedScriptThingIndex thing : topLevelThings) { if (!thing.isFunction()) { continue;
}
frontend::ScriptIndex index = thing.toFunction(); constauto& script = stencil.scriptData[index];
if (prevAtom) {
frontend::ScriptIndexRange range{prevIndex, index};
scriptMap.putNewInfallible(prevAtom, range);
}
// We over-estimated the capacity of `scriptMap`, so check that the estimate // hasn't drifted too hasn't drifted too far since this was written. If this // assert fails, we may need a new way to size the `scriptMap`.
MOZ_ASSERT(numSelfHostedScripts < (scriptMap.count() * 1.15));
}
#ifdef DEBUG // Check that the list of intrinsics is well-formed.
CheckSelfHostedIntrinsics();
CheckSelfHostingDataIsTenured(cx->runtime()); #endif
returntrue;
}
bool JSRuntime::initSelfHostingStencil(JSContext* cx,
JS::SelfHostedCache xdrCache,
JS::SelfHostedWriter xdrWriter) { if (parentRuntime) {
MOZ_RELEASE_ASSERT(
parentRuntime->hasInitializedSelfHosting(), "Parent runtime must initialize self-hosting before workers");
// Variables used to instantiate scripts.
CompileOptions options(cx);
FillSelfHostingCompileOptions(options);
// Try initializing from Stencil XDR.
AutoPrintSelfHostingFrontendContext fc(cx); if (xdrCache.Length() > 0) { // Allow the VM to directly use bytecode from the XDR buffer without // copying it. The buffer must outlive all runtimes (including workers).
options.borrowBuffer = true;
options.usePinnedBytecode = true;
Rooted<UniquePtr<frontend::CompilationInput>> input(
cx, cx->new_<frontend::CompilationInput>(options)); if (!input) { returnfalse;
}
{
AutoReportFrontendContext fc(cx); if (!input->initForSelfHostingGlobal(&fc)) { returnfalse;
}
}
JS::DecodeOptions decodeOption(options);
RefPtr<frontend::CompilationStencil> stencil;
JS::TranscodeResult result =
js::DecodeStencil(&fc, decodeOption, xdrCache, getter_AddRefs(stencil)); if (result == JS::TranscodeResult::Ok) {
MOZ_ASSERT(input->atomCache.empty());
MOZ_ASSERT(!hasSelfHostStencil());
// Move it to the runtime.
setSelfHostingStencil(&input, std::move(stencil));
auto end = mozilla::TimeStamp::Now();
JS_LOG(startup, Info, "Used XDR for process self-hosted startup. Took %f us",
(end - start).ToMicroseconds()); returntrue;
}
}
// If script wasn't generated, it means XDR was either not provided or that it // failed the decoding phase. Parse from text as before.
uint32_t srcLen = GetRawScriptsSize(); constunsignedchar* compressed = compressedSources;
uint32_t compressedLen = GetCompressedSize(); auto src = cx->make_pod_array<char>(srcLen); if (!src) { returnfalse;
} if (!DecompressString(compressed, compressedLen, reinterpret_cast<unsignedchar*>(src.get()), srcLen)) { returnfalse;
}
JS::SourceText<mozilla::Utf8Unit> srcBuf; if (!srcBuf.init(cx, std::move(src), srcLen)) { returnfalse;
}
mozilla::TimeDuration xdrDuration; // Serialize the stencil to XDR. if (xdrWriter) { auto encodeStart = mozilla::TimeStamp::Now();
JS::TranscodeBuffer xdrBuffer;
JS::TranscodeResult result = js::EncodeStencil(cx, stencil, xdrBuffer); if (result != JS::TranscodeResult::Ok) {
JS_ReportErrorASCII(cx, "Encoding failure"); returnfalse;
}
if (!xdrWriter(cx, xdrBuffer)) { returnfalse;
} auto encodeEnd = mozilla::TimeStamp::Now();
xdrDuration = (encodeEnd - encodeStart);
JS_LOG(startup, Info, "Saved XDR Buffer. Took %f us",
xdrDuration.ToMicroseconds());
}
MOZ_ASSERT(input->atomCache.empty());
MOZ_ASSERT(!hasSelfHostStencil());
// Move it to the runtime.
setSelfHostingStencil(&input, std::move(stencil));
auto end = mozilla::TimeStamp::Now();
JS_LOG(startup, Info, "Used source text for process self-hosted startup. Took %f us (%f us " "XDR encode)",
(end - start).ToMicroseconds(), xdrDuration.ToMicroseconds()); returntrue;
}
void JSRuntime::finishSelfHosting() { if (!parentRuntime) {
js_delete(selfHostStencilInput_.ref()); if (selfHostStencil_) { // delete selfHostStencil_ by decrementing the ref-count of the last // instance.
RefPtr<frontend::CompilationStencil> stencil;
*getter_AddRefs(stencil) = selfHostStencil_;
MOZ_ASSERT(!stencil->hasMultipleReference());
}
}
GeneratorKind JSRuntime::getSelfHostedFunctionGeneratorKind(
js::PropertyName* name) {
frontend::ScriptIndex index = getSelfHostedScriptIndexRange(name)->start; auto flags = selfHostStencil().scriptExtra[index].immutableFlags; return flags.hasFlag(js::ImmutableScriptFlagsEnum::IsGenerator)
? GeneratorKind::Generator
: GeneratorKind::NotGenerator;
}
// Returns the ScriptSourceObject to use for cloned self-hosted scripts in the // current realm.
ScriptSourceObject* js::SelfHostingScriptSourceObject(JSContext* cx) { return GlobalObject::getOrCreateSelfHostingScriptSourceObject(cx,
cx->global());
}
auto indexRange = *getSelfHostedScriptIndexRange(name); auto& stencil = cx->runtime()->selfHostStencil();
if (!stencil.delazifySelfHostedFunction(
cx, cx->runtime()->selfHostStencilInput().atomCache, indexRange,
targetFun)) { returnfalse;
}
// Relazifiable self-hosted functions may be relazified later into a // SelfHostedLazyScript, dropping the BaseScript entirely. This only applies // to named function being delazified. Inner functions used by self-hosting // are never relazified.
BaseScript* targetScript = targetFun->baseScript(); if (targetScript->isRelazifiable()) {
targetScript->setAllowRelazify();
}
staticbool GetComputedIntrinsic(JSContext* cx, Handle<PropertyName*> name,
MutableHandleValue vp) { // If the intrinsic was not in hardcoded set, run the top-level of the // selfhosted script. This will generate values and call `SetIntrinsic` to // save them on a special "computed intrinsics holder". We then can check for // our required values and cache on the normal intrinsics holder.
Rooted<NativeObject*> computedIntrinsicsHolder(
cx, cx->global()->getComputedIntrinsicsHolder()); if (!computedIntrinsicsHolder) { auto computedIntrinsicHolderGuard = mozilla::MakeScopeExit(
[cx]() { cx->global()->setComputedIntrinsicsHolder(nullptr); });
// Instantiate a script in current realm from the shared Stencil.
JSRuntime* runtime = cx->runtime();
RootedScript script(
cx, runtime->selfHostStencil().instantiateSelfHostedTopLevelForRealm(
cx, runtime->selfHostStencilInput())); if (!script) { returnfalse;
}
// Attach the computed intrinsics holder to the global now to capture // generated values.
computedIntrinsicsHolder =
NewPlainObjectWithProto(cx, nullptr, TenuredObject); if (!computedIntrinsicsHolder) { returnfalse;
}
cx->global()->setComputedIntrinsicsHolder(computedIntrinsicsHolder);
// Disable the interrupt callback while executing the top-level script. // This prevents recursive calls to GetComputedIntrinsic through the // interrupt callback. bool hadInterruptsDisabled = JS_DisableInterruptCallback(cx); auto resetInterrupts = mozilla::MakeScopeExit(
[&]() { JS_ResetInterruptCallback(cx, hadInterruptsDisabled); });
// Attempt to execute the top-level script. If they fails to run to // successful completion, throw away the holder to avoid a partial // initialization state. if (!JS_ExecuteScript(cx, script)) { returnfalse;
}
// Successfully ran the self-host top-level in current realm, so these // computed intrinsic values are now source of truth for the realm.
computedIntrinsicHolderGuard.release();
}
// Cache the individual intrinsic on the standard holder object so that we // only have to look for it in one place when performing `GetIntrinsic`.
mozilla::Maybe<PropertyInfo> prop =
computedIntrinsicsHolder->lookup(cx, name); #ifdef DEBUG if (!prop) {
Fprinter out(stderr);
out.printf("SelfHosted intrinsic not found: ");
name->dumpPropertyName(out);
out.printf("\n");
} #endif
MOZ_RELEASE_ASSERT(prop, "SelfHosted intrinsic not found");
RootedValue value(cx, computedIntrinsicsHolder->getSlot(prop->slot())); return GlobalObject::addIntrinsicValue(cx, cx->global(), name, value);
}
bool JSRuntime::getSelfHostedValue(JSContext* cx, Handle<PropertyName*> name,
MutableHandleValue vp) { // If the self-hosted value we want is a function in the stencil, instantiate // a lazy self-hosted function for it. This is typical when a self-hosted // function calls other self-hosted helper functions. if (auto index = getSelfHostedScriptIndexRange(name)) {
JSFunction* fun =
cx->runtime()->selfHostStencil().instantiateSelfHostedLazyFunction(
cx, cx->runtime()->selfHostStencilInput().atomCache, index->start,
name); if (!fun) { returnfalse;
}
vp.setObject(*fun); returntrue;
}
static_assert(
JSString::MAX_LENGTH <= INT32_MAX, "StringIteratorNext in builtin/String.js assumes the stored index " "into the string is an Int32Value");
static_assert(JSString::MAX_LENGTH == MAX_STRING_LENGTH, "JSString::MAX_LENGTH matches self-hosted constant for maximum " "string length");
static_assert(ARGS_LENGTH_MAX == MAX_ARGS_LENGTH, "ARGS_LENGTH_MAX matches self-hosted constant for maximum " "arguments length");
Messung V0.5 in Prozent
¤ Dauer der Verarbeitung: 0.42 Sekunden
(vorverarbeitet am 2026-06-06)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.