All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.oracle.truffle.js.runtime.JSContext Maven / Gradle / Ivy

/*
 * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * The Universal Permissive License (UPL), Version 1.0
 *
 * Subject to the condition set forth below, permission is hereby granted to any
 * person obtaining a copy of this software, associated documentation and/or
 * data (collectively the "Software"), free of charge and under any and all
 * copyright rights in the Software, and any and all patent rights owned or
 * freely licensable by each licensor hereunder covering either (i) the
 * unmodified Software as contributed to or provided by such licensor, or (ii)
 * the Larger Works (as defined below), to deal in both
 *
 * (a) the Software, and
 *
 * (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if
 * one is included with the Software each a "Larger Work" to which the Software
 * is contributed by such licensors),
 *
 * without restriction, including without limitation the rights to copy, create
 * derivative works of, display, perform, and distribute the Software and make,
 * use, sell, offer for sale, import, export, have made, and have sold the
 * Software and the Larger Work(s), and to sublicense the foregoing rights on
 * either these or other terms.
 *
 * This license is subject to the following condition:
 *
 * The above copyright notice and either this complete permission notice or at a
 * minimum a reference to the UPL must be included in all copies or substantial
 * portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */
package com.oracle.truffle.js.runtime;

import static com.oracle.truffle.js.runtime.JSRealm.SYMBOL_ITERATOR_NAME;
import static com.oracle.truffle.js.runtime.builtins.JSNonProxy.GET_SYMBOL_SPECIES_NAME;

import java.lang.invoke.MethodHandles;
import java.lang.invoke.VarHandle;
import java.util.Locale;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Function;

import com.oracle.js.parser.ir.Module;
import com.oracle.truffle.api.Assumption;
import com.oracle.truffle.api.CallTarget;
import com.oracle.truffle.api.CompilerAsserts;
import com.oracle.truffle.api.CompilerDirectives;
import com.oracle.truffle.api.CompilerDirectives.CompilationFinal;
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
import com.oracle.truffle.api.RootCallTarget;
import com.oracle.truffle.api.Truffle;
import com.oracle.truffle.api.TruffleLanguage;
import com.oracle.truffle.api.TruffleLanguage.ContextReference;
import com.oracle.truffle.api.dsl.Idempotent;
import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.instrumentation.AllocationReporter;
import com.oracle.truffle.api.nodes.Node;
import com.oracle.truffle.api.object.Shape;
import com.oracle.truffle.api.strings.TruffleString;
import com.oracle.truffle.js.lang.JavaScriptLanguage;
import com.oracle.truffle.js.nodes.ThrowTypeErrorRootNode;
import com.oracle.truffle.js.nodes.access.GetPrototypeNode;
import com.oracle.truffle.js.nodes.cast.JSToObjectNode;
import com.oracle.truffle.js.nodes.promise.BuiltinPromiseRejectionTracker;
import com.oracle.truffle.js.runtime.array.TypedArray;
import com.oracle.truffle.js.runtime.array.TypedArrayFactory;
import com.oracle.truffle.js.runtime.builtins.Builtin;
import com.oracle.truffle.js.runtime.builtins.JSAdapter;
import com.oracle.truffle.js.runtime.builtins.JSArgumentsArray;
import com.oracle.truffle.js.runtime.builtins.JSArray;
import com.oracle.truffle.js.runtime.builtins.JSArrayBuffer;
import com.oracle.truffle.js.runtime.builtins.JSArrayBufferView;
import com.oracle.truffle.js.runtime.builtins.JSArrayIterator;
import com.oracle.truffle.js.runtime.builtins.JSAsyncGenerator;
import com.oracle.truffle.js.runtime.builtins.JSAsyncIterator;
import com.oracle.truffle.js.runtime.builtins.JSBigInt;
import com.oracle.truffle.js.runtime.builtins.JSBoolean;
import com.oracle.truffle.js.runtime.builtins.JSClass;
import com.oracle.truffle.js.runtime.builtins.JSDataView;
import com.oracle.truffle.js.runtime.builtins.JSDate;
import com.oracle.truffle.js.runtime.builtins.JSDictionary;
import com.oracle.truffle.js.runtime.builtins.JSError;
import com.oracle.truffle.js.runtime.builtins.JSFinalizationRegistry;
import com.oracle.truffle.js.runtime.builtins.JSFinalizationRegistryObject;
import com.oracle.truffle.js.runtime.builtins.JSForInIterator;
import com.oracle.truffle.js.runtime.builtins.JSFunction;
import com.oracle.truffle.js.runtime.builtins.JSFunctionData;
import com.oracle.truffle.js.runtime.builtins.JSFunctionFactory;
import com.oracle.truffle.js.runtime.builtins.JSFunctionObject;
import com.oracle.truffle.js.runtime.builtins.JSGenerator;
import com.oracle.truffle.js.runtime.builtins.JSGlobal;
import com.oracle.truffle.js.runtime.builtins.JSIterator;
import com.oracle.truffle.js.runtime.builtins.JSMap;
import com.oracle.truffle.js.runtime.builtins.JSMapIterator;
import com.oracle.truffle.js.runtime.builtins.JSModuleNamespace;
import com.oracle.truffle.js.runtime.builtins.JSNumber;
import com.oracle.truffle.js.runtime.builtins.JSObjectFactory;
import com.oracle.truffle.js.runtime.builtins.JSOrdinary;
import com.oracle.truffle.js.runtime.builtins.JSPromise;
import com.oracle.truffle.js.runtime.builtins.JSPromiseObject;
import com.oracle.truffle.js.runtime.builtins.JSProxy;
import com.oracle.truffle.js.runtime.builtins.JSRawJSON;
import com.oracle.truffle.js.runtime.builtins.JSRegExp;
import com.oracle.truffle.js.runtime.builtins.JSSet;
import com.oracle.truffle.js.runtime.builtins.JSSetIterator;
import com.oracle.truffle.js.runtime.builtins.JSShadowRealm;
import com.oracle.truffle.js.runtime.builtins.JSSharedArrayBuffer;
import com.oracle.truffle.js.runtime.builtins.JSString;
import com.oracle.truffle.js.runtime.builtins.JSStringIterator;
import com.oracle.truffle.js.runtime.builtins.JSSymbol;
import com.oracle.truffle.js.runtime.builtins.JSUncheckedProxyHandler;
import com.oracle.truffle.js.runtime.builtins.JSWeakMap;
import com.oracle.truffle.js.runtime.builtins.JSWeakRef;
import com.oracle.truffle.js.runtime.builtins.JSWeakSet;
import com.oracle.truffle.js.runtime.builtins.JSWrapForValidAsyncIterator;
import com.oracle.truffle.js.runtime.builtins.JSWrapForValidIterator;
import com.oracle.truffle.js.runtime.builtins.PrototypeSupplier;
import com.oracle.truffle.js.runtime.builtins.asynccontext.JSAsyncContextSnapshot;
import com.oracle.truffle.js.runtime.builtins.asynccontext.JSAsyncContextVariable;
import com.oracle.truffle.js.runtime.builtins.intl.JSCollator;
import com.oracle.truffle.js.runtime.builtins.intl.JSDateTimeFormat;
import com.oracle.truffle.js.runtime.builtins.intl.JSDisplayNames;
import com.oracle.truffle.js.runtime.builtins.intl.JSListFormat;
import com.oracle.truffle.js.runtime.builtins.intl.JSLocale;
import com.oracle.truffle.js.runtime.builtins.intl.JSNumberFormat;
import com.oracle.truffle.js.runtime.builtins.intl.JSPluralRules;
import com.oracle.truffle.js.runtime.builtins.intl.JSRelativeTimeFormat;
import com.oracle.truffle.js.runtime.builtins.intl.JSSegmenter;
import com.oracle.truffle.js.runtime.builtins.temporal.JSTemporalCalendar;
import com.oracle.truffle.js.runtime.builtins.temporal.JSTemporalDuration;
import com.oracle.truffle.js.runtime.builtins.temporal.JSTemporalInstant;
import com.oracle.truffle.js.runtime.builtins.temporal.JSTemporalPlainDate;
import com.oracle.truffle.js.runtime.builtins.temporal.JSTemporalPlainDateTime;
import com.oracle.truffle.js.runtime.builtins.temporal.JSTemporalPlainMonthDay;
import com.oracle.truffle.js.runtime.builtins.temporal.JSTemporalPlainTime;
import com.oracle.truffle.js.runtime.builtins.temporal.JSTemporalPlainYearMonth;
import com.oracle.truffle.js.runtime.builtins.temporal.JSTemporalTimeZone;
import com.oracle.truffle.js.runtime.builtins.temporal.JSTemporalZonedDateTime;
import com.oracle.truffle.js.runtime.builtins.wasm.JSWebAssemblyGlobal;
import com.oracle.truffle.js.runtime.builtins.wasm.JSWebAssemblyInstance;
import com.oracle.truffle.js.runtime.builtins.wasm.JSWebAssemblyMemory;
import com.oracle.truffle.js.runtime.builtins.wasm.JSWebAssemblyModule;
import com.oracle.truffle.js.runtime.builtins.wasm.JSWebAssemblyTable;
import com.oracle.truffle.js.runtime.java.JavaImporter;
import com.oracle.truffle.js.runtime.java.JavaPackage;
import com.oracle.truffle.js.runtime.objects.JSDynamicObject;
import com.oracle.truffle.js.runtime.objects.JSModuleRecord;
import com.oracle.truffle.js.runtime.objects.JSObject;
import com.oracle.truffle.js.runtime.objects.JSPrototypeData;
import com.oracle.truffle.js.runtime.objects.JSShape;
import com.oracle.truffle.js.runtime.objects.JSShapeData;
import com.oracle.truffle.js.runtime.objects.Null;
import com.oracle.truffle.js.runtime.objects.ScriptOrModule;
import com.oracle.truffle.js.runtime.objects.Undefined;
import com.oracle.truffle.js.runtime.util.CompilableBiFunction;
import com.oracle.truffle.js.runtime.util.ConcurrentWeakIdentityHashMap;
import com.oracle.truffle.js.runtime.util.DebugJSAgent;
import com.oracle.truffle.js.runtime.util.StableContextOptionValue;
import com.oracle.truffle.js.runtime.util.TRegexUtil;
import com.oracle.truffle.js.runtime.util.TimeProfiler;

public class JSContext {

    private static final VarHandle FUNCTION_DATA_ARRAY_VAR_HANDLE = MethodHandles.arrayElementVarHandle(JSFunctionData[].class);

    private final Evaluator evaluator;

    private final JavaScriptLanguage language;

    private final Shape emptyShape;
    private final Shape emptyShapePrototypeInObject;
    private final Shape promiseShapePrototypeInObject;
    private final Shape globalScopeShape;

    /**
     * Slot for a context-specific data of the embedder of the JS engine.
     */
    private Object embedderData;

    /**
     * Nashorn compatibility mode only: Assumption is valid as long as no
     * {@code __noSuchProperty__}, {@code __noSuchMethod__} properties have been defined.
     */
    private final Assumption noSuchPropertyUnusedAssumption;
    private final Assumption noSuchMethodUnusedAssumption;

    /**
     * Assumption: There is no array that has a prototype that has indexed (array) elements. As long
     * as this assumption holds, certain checks can be omitted as all the indexed elements are in
     * the ScriptArray itself.
     */
    private final Assumption arrayPrototypeNoElementsAssumption;
    private final Assumption fastArrayAssumption;
    private final Assumption fastArgumentsObjectAssumption;

    /**
     * Assumption: TypedArrays never have their elements detached (i.e., buffer set to null).
     */
    private final Assumption typedArrayNotDetachedAssumption;

    /**
     * Assumption: ArrayBuffer never shrunk.
     */
    private final Assumption arrayBufferNotShrunkAssumption;

    /**
     * Assumption: Static RegExp results (RegExp.$1 etc) are never used. As long as this assumption
     * holds, just the arguments of the last RegExp execution are stored, allowing RegExp result
     * objects to be virtualized in RegExp#exec().
     */
    private final Assumption regExpStaticResultUnusedAssumption;

    /**
     * Assumption: The global object has not been replaced and its prototype has not been changed.
     * While valid, guarantees that globalObject.[[HasProperty]] is side effect free.
     */
    private final Assumption globalObjectPristineAssumption;

    private final Map symbolRegistry = new ConcurrentHashMap<>();
    private final Map privateSymbolRegistry = new ConcurrentHashMap<>();

    private final Object nodeFactory;

    private final TimeProfiler timeProfiler;

    private final JSObjectFactory.BoundProto moduleNamespaceFactory;

    @CompilationFinal private Object tRegexEmptyResult;

    private final String regexOptions;
    private final String regexValidateOptions;

    private final Shape regExpGroupsEmptyShape;

    private PrepareStackTraceCallback prepareStackTraceCallback;
    private final Assumption prepareStackTraceCallbackNotUsedAssumption;

    private final Assumption promiseRejectionTrackerNotUsedAssumption;

    private PromiseHook promiseHook;
    private final Assumption promiseHookNotUsedAssumption;

    private ImportMetaInitializer importMetaInitializer;
    private final Assumption importMetaInitializerNotUsedAssumption;
    private ImportModuleDynamicallyCallback importModuleDynamicallyCallback;
    private final Assumption importModuleDynamicallyCallbackNotUsedAssumption;

    private final CallTarget emptyFunctionCallTarget;

    public final JSFunctionData symbolSpeciesThisGetterFunctionData;
    public final JSFunctionData symbolIteratorThisGetterFunctionData;

    private volatile CallTarget notConstructibleCallTargetCache;
    private volatile CallTarget generatorNotConstructibleCallTargetCache;

    private static final VarHandle notConstructibleCallTargetVarHandle;
    private static final VarHandle generatorNotConstructibleCallTargetVarHandle;

    // Used to track singleton symbols allocations across aux engine cache runs.
    private Object symbolUsageMarker = new Object();

    private final Map unregisteredSymbols = ConcurrentWeakIdentityHashMap.create();

    @TruffleBoundary
    public void unregisteredSymbolCreated(Symbol symbol) {
        unregisteredSymbols.put(symbol, Boolean.TRUE);
    }

    public void clearSymbolInvertedMaps() {
        unregisteredSymbols.forEach((symbol, unused) -> symbol.clearInvertedMap());
    }

    public void resetSymbolUsageMarker() {
        CompilerAsserts.neverPartOfCompilation();
        // Symbols that were used exactly once in previous executions, will most-likely
        // be created one time only when the cache is re-loaded. In this case we can re-use
        // the Symbol cached in the aux image cache to avoid de-optimizations.
        this.symbolUsageMarker = new Object();
    }

    public Object getSymbolUsageMarker() {
        return symbolUsageMarker;
    }

    public enum BuiltinFunctionKey {
        BoundFunction,
        BoundConstructor,
        BoundFunctionAsync,
        BoundConstructorAsync,
        ArrayFlattenIntoArray,
        ArrayFromAsyncIteratorResumption,
        ArrayFromAsyncArrayLikeResumption,
        ArrayFromAsyncAwaitIfAbruptClose,
        ArrayFromAsyncAwaitIfAbruptReturn,
        AwaitFulfilled,
        AwaitRejected,
        AsyncGeneratorReturnFulfilled,
        AsyncGeneratorReturnRejected,
        AsyncFromSyncIteratorCloseIterator,
        AsyncFromSyncIteratorValueUnwrap,
        AsyncIteratorYield,
        AsyncIteratorUnwrapYieldResumptionClose,
        AsyncIteratorUnwrapYieldResumptionCloseResumption,
        AsyncIteratorUnwrapYieldResumptionCloseInnerIterator,
        AsyncIteratorUnwrapYieldResumptionCloseInnerIteratorResumption,
        AsyncIteratorIfAbruptClose,
        AsyncIteratorIfAbruptReturn,
        AsyncIteratorGeneratorIfAbruptClose,
        AsyncIteratorGeneratorIfAbruptReturn,
        AsyncIteratorGeneratorReturn,
        AsyncIteratorClose,
        AsyncIteratorCloseAbrupt,
        AsyncIteratorMap,
        AsyncIteratorMapWithValue,
        AsyncIteratorFilter,
        AsyncIteratorFilterWithValue,
        AsyncIteratorFilterWithResult,
        AsyncIteratorTake,
        AsyncIteratorTakeWithValue,
        AsyncIteratorDrop,
        AsyncIteratorDropWithValueLoop,
        AsyncIteratorDropWithValue,
        AsyncIteratorFlatMap,
        AsyncIteratorFlatMapWithValue,
        AsyncIteratorFlatMapWithResult,
        AsyncIteratorFlatMapInnerWithValue,
        AsyncIteratorReduce,
        AsyncIteratorReduceWithResult,
        AsyncIteratorReduceInitial,
        AsyncIteratorToArray,
        AsyncIteratorForEach,
        AsyncIteratorForEachWithResult,
        AsyncIteratorSome,
        AsyncIteratorSomeWithResult,
        AsyncIteratorEvery,
        AsyncIteratorEveryWithResult,
        AsyncIteratorFind,
        AsyncIteratorFindWithResult,
        AsyncGeneratorAwaitReturnFulfilled,
        AsyncGeneratorAwaitReturnRejected,
        IteratorMap,
        IteratorFilter,
        IteratorTake,
        IteratorDrop,
        IteratorIndexed,
        IteratorFlatMap,
        CollatorCompare,
        DateTimeFormatFormat,
        NumberFormatFormat,
        OrdinaryHasInstance,
        ProxyCall,
        ProxyRevokerFunction,
        PromiseResolveFunction,
        PromiseRejectFunction,
        PromiseGetCapabilitiesExecutor,
        PromiseResolveThenableJob,
        PromiseReactionJob,
        PromiseAllResolveElement,
        PromiseAllSettledResolveElement,
        PromiseAllSettledRejectElement,
        PromiseAnyRejectElement,
        PromiseThenFinally,
        PromiseCatchFinally,
        PromiseValueThunk,
        PromiseThrower,
        ImportModuleDynamically,
        JavaPackageToPrimitive,
        RegExpMultiLine,
        RegExpLastMatch,
        RegExpLastParen,
        RegExpLeftContext,
        RegExpRightContext,
        RegExp$1,
        RegExp$2,
        RegExp$3,
        RegExp$4,
        RegExp$5,
        RegExp$6,
        RegExp$7,
        RegExp$8,
        RegExp$9,
        FunctionAsyncIterator,
        IsGraalRuntime,
        SetUnhandledPromiseRejectionHandler,
        AsyncModuleExecutionFulfilled,
        AsyncModuleExecutionRejected,
        TopLevelAwaitResolve,
        TopLevelAwaitReject,
        WebAssemblySourceInstantiation,
        FinishImportModuleDynamicallyReject,
        FinishImportModuleDynamicallyResolve,
        ExportGetter,
        OrdinaryWrappedFunctionCall,
        DecoratorContextAddInitializer,
        DedentCallback
    }

    @CompilationFinal(dimensions = 1) private final JSFunctionData[] builtinFunctionData;

    final JSFunctionData throwTypeErrorFunctionData;
    final JSFunctionData throwTypeErrorRestrictedPropertyFunctionData;
    final JSFunctionData protoGetterFunctionData;
    final JSFunctionData protoSetterFunctionData;

    private final Map shapeDataMap = ConcurrentWeakIdentityHashMap.create();

    private final Assumption singleRealmAssumption;
    private final boolean isMultiContext;

    private final AtomicInteger realmInit = new AtomicInteger();
    private static final int REALM_UNINITIALIZED = 0;
    private static final int REALM_INITIALIZING = 1;
    private static final int REALM_INITIALIZED = 2;

    @CompilationFinal private AllocationReporter allocationReporter;

    private final JSLanguageOptions languageOptions;
    private final JSParserOptions parserOptions;

    private final StableContextOptionValue optionRegexpStaticResult;
    private final StableContextOptionValue optionV8CompatibilityMode;
    private final StableContextOptionValue optionDirectByteBuffer;
    private final StableContextOptionValue optionTimerResolution;

    private final Map builtinFunctionDataMap = new ConcurrentHashMap<>();
    private final Map namedEmptyFunctionsDataMap = new ConcurrentHashMap<>();

    private final JSPrototypeData nullPrototypeData = new JSPrototypeData();
    private final JSPrototypeData inObjectPrototypeData = new JSPrototypeData();

    private final JSFunctionFactory functionFactory;
    private final JSFunctionFactory constructorFactory;
    private final JSFunctionFactory strictFunctionFactory;
    private final JSFunctionFactory strictConstructorFactory;

    private final JSFunctionFactory generatorFunctionFactory;
    private final JSFunctionFactory asyncFunctionFactory;
    private final JSFunctionFactory asyncGeneratorFunctionFactory;

    private final JSFunctionFactory boundFunctionFactory;
    private final JSFunctionFactory wrappedFunctionFactory;

    static final PrototypeSupplier functionPrototypeSupplier = JSRealm::getFunctionPrototype;
    static final PrototypeSupplier asyncFunctionPrototypeSupplier = JSRealm::getAsyncFunctionPrototype;
    static final PrototypeSupplier generatorFunctionPrototypeSupplier = JSRealm::getGeneratorFunctionPrototype;
    static final PrototypeSupplier asyncGeneratorFunctionPrototypeSupplier = JSRealm::getAsyncGeneratorFunctionPrototype;

    private final JSObjectFactory ordinaryObjectFactory;
    private final JSObjectFactory arrayFactory;
    private final JSObjectFactory iteratorFactory;
    private final JSObjectFactory asyncIteratorFactory;
    private final JSObjectFactory arrayIteratorFactory;
    private final JSObjectFactory wrapForIteratorFactory;
    private final JSObjectFactory wrapForAsyncIteratorFactory;
    private final JSObjectFactory lazyRegexArrayFactory;
    private final JSObjectFactory lazyRegexIndicesArrayFactory;
    private final JSObjectFactory booleanFactory;
    private final JSObjectFactory numberFactory;
    private final JSObjectFactory bigIntFactory;
    private final JSObjectFactory stringFactory;
    private final JSObjectFactory stringIteratorFactory;
    private final JSObjectFactory regExpFactory;
    private final JSObjectFactory dateFactory;
    private final JSObjectFactory nonStrictArgumentsFactory;
    private final JSObjectFactory strictArgumentsFactory;
    private final JSObjectFactory callSiteFactory;
    @CompilationFinal(dimensions = 1) private final JSObjectFactory[] errorObjectFactories;

    private final JSObjectFactory symbolFactory;
    private final JSObjectFactory mapFactory;
    private final JSObjectFactory mapIteratorFactory;
    private final JSObjectFactory setFactory;
    private final JSObjectFactory setIteratorFactory;
    private final JSObjectFactory weakRefFactory;
    private final JSObjectFactory weakMapFactory;
    private final JSObjectFactory weakSetFactory;
    private final JSObjectFactory proxyFactory;
    private final JSObjectFactory uncheckedProxyHandlerFactory;
    private final JSObjectFactory promiseFactory;
    private final JSObjectFactory dataViewFactory;
    private final JSObjectFactory arrayBufferFactory;
    private final JSObjectFactory directArrayBufferFactory;
    private final JSObjectFactory sharedArrayBufferFactory;
    private final JSObjectFactory interopArrayBufferFactory;
    private final JSObjectFactory finalizationRegistryFactory;
    @CompilationFinal(dimensions = 1) private final JSObjectFactory[] typedArrayFactories;

    private final JSObjectFactory enumerateIteratorFactory;
    private final JSObjectFactory forInIteratorFactory;
    private final JSObjectFactory generatorObjectFactory;
    private final JSObjectFactory generatorObjectPrototypeFactory;
    private final JSObjectFactory iteratorHelperObjectFactory;
    private final JSObjectFactory asyncGeneratorObjectFactory;
    private final JSObjectFactory asyncGeneratorObjectPrototypeFactory;
    private final JSObjectFactory asyncFromSyncIteratorFactory;
    private final JSObjectFactory asyncIteratorHelperObjectFactory;

    private final JSObjectFactory collatorFactory;
    private final JSObjectFactory numberFormatFactory;
    private final JSObjectFactory pluralRulesFactory;
    private final JSObjectFactory dateTimeFormatFactory;
    private final JSObjectFactory listFormatFactory;
    private final JSObjectFactory relativeTimeFormatFactory;
    private final JSObjectFactory segmenterFactory;
    private final JSObjectFactory segmentsFactory;
    private final JSObjectFactory segmentIteratorFactory;
    private final JSObjectFactory displayNamesFactory;
    private final JSObjectFactory localeFactory;

    private final JSObjectFactory javaImporterFactory;
    private final JSObjectFactory javaPackageFactory;
    private final JSObjectFactory jsAdapterFactory;
    private final JSObjectFactory dictionaryObjectFactory;

    private final JSObjectFactory temporalPlainTimeFactory;
    private final JSObjectFactory temporalPlainDateFactory;
    private final JSObjectFactory temporalPlainDateTimeFactory;
    private final JSObjectFactory temporalDurationFactory;
    private final JSObjectFactory temporalCalendarFactory;
    private final JSObjectFactory temporalPlainYearMonthFactory;
    private final JSObjectFactory temporalPlainMonthDayFactory;
    private final JSObjectFactory temporalInstantFactory;
    private final JSObjectFactory temporalTimeZoneFactory;
    private final JSObjectFactory temporalZonedDateTimeFactory;

    private final JSObjectFactory globalObjectFactory;

    private final JSObjectFactory webAssemblyModuleFactory;
    private final JSObjectFactory webAssemblyInstanceFactory;
    private final JSObjectFactory webAssemblyMemoryFactory;
    private final JSObjectFactory webAssemblyTableFactory;
    private final JSObjectFactory webAssemblyGlobalFactory;

    private final JSObjectFactory shadowRealmFactory;
    private final JSObjectFactory asyncContextSnapshotFactory;
    private final JSObjectFactory asyncContextVariableFactory;
    private final JSObjectFactory rawJSONFactory;

    private final int factoryCount;

    @CompilationFinal private Locale locale;

    private final Set supportedImportAttributes;

    private static final TruffleString TYPE_IMPORT_ATTRIBUTE = Strings.TYPE;

    /**
     * A shared root node that acts as a parent providing a lock to nodes that are not rooted in a
     * tree but in shared object factories for the purpose of adding properties to newly allocated
     * objects.
     */
    private final SharedRootNode sharedRootNode;

    static {
        MethodHandles.Lookup lookup = MethodHandles.lookup();
        try {
            notConstructibleCallTargetVarHandle = lookup.findVarHandle(JSContext.class, "notConstructibleCallTargetCache", CallTarget.class);
            generatorNotConstructibleCallTargetVarHandle = lookup.findVarHandle(JSContext.class, "generatorNotConstructibleCallTargetCache", CallTarget.class);
        } catch (NoSuchFieldException | IllegalAccessException e) {
            throw Errors.shouldNotReachHere(e);
        }
    }

    @SuppressWarnings("this-escape")
    protected JSContext(Evaluator evaluator, JavaScriptLanguage lang, JSLanguageOptions languageOptions, TruffleLanguage.Env env) {
        this.language = lang;
        this.languageOptions = languageOptions;
        this.parserOptions = JSParserOptions.fromLanguageOptions(languageOptions);

        if (env != null) { // env could still be null
            setAllocationReporter(env);
        }

        this.optionRegexpStaticResult = new StableContextOptionValue<>(JSContextOptions::isRegexpStaticResult, JSContextOptions.REGEXP_STATIC_RESULT, JSContextOptions.REGEXP_STATIC_RESULT_NAME);
        this.optionV8CompatibilityMode = new StableContextOptionValue<>(JSContextOptions::isV8CompatibilityMode, JSContextOptions.V8_COMPATIBILITY_MODE, JSContextOptions.V8_COMPATIBILITY_MODE_NAME);
        this.optionDirectByteBuffer = new StableContextOptionValue<>(JSContextOptions::isDirectByteBuffer, JSContextOptions.DIRECT_BYTE_BUFFER, JSContextOptions.DIRECT_BYTE_BUFFER_NAME);
        this.optionTimerResolution = new StableContextOptionValue<>(JSContextOptions::getTimerResolution, JSContextOptions.TIMER_RESOLUTION, JSContextOptions.TIMER_RESOLUTION_NAME);

        this.sharedRootNode = new SharedRootNode();

        this.emptyShape = createEmptyShape();
        this.emptyShapePrototypeInObject = createEmptyShapePrototypeInObject();
        this.promiseShapePrototypeInObject = createPromiseShapePrototypeInObject();
        this.globalScopeShape = createGlobalScopeShape();

        this.noSuchPropertyUnusedAssumption = Truffle.getRuntime().createAssumption("noSuchPropertyUnusedAssumption");
        this.noSuchMethodUnusedAssumption = Truffle.getRuntime().createAssumption("noSuchMethodUnusedAssumption");
        this.arrayPrototypeNoElementsAssumption = Truffle.getRuntime().createAssumption("arrayPrototypeNoElementsAssumption");
        this.typedArrayNotDetachedAssumption = Truffle.getRuntime().createAssumption("typedArrayNotDetachedAssumption");
        this.arrayBufferNotShrunkAssumption = Truffle.getRuntime().createAssumption("arrayBufferNotShrunkAssumption");
        this.fastArrayAssumption = Truffle.getRuntime().createAssumption("fastArrayAssumption");
        this.fastArgumentsObjectAssumption = Truffle.getRuntime().createAssumption("fastArgumentsObjectAssumption");
        this.regExpStaticResultUnusedAssumption = Truffle.getRuntime().createAssumption("regExpStaticResultUnusedAssumption");
        this.globalObjectPristineAssumption = Truffle.getRuntime().createAssumption("globalObjectPristineAssumption");

        this.evaluator = evaluator;
        this.nodeFactory = evaluator.getDefaultNodeFactory();

        this.moduleNamespaceFactory = JSObjectFactory.createBound(this, Null.instance, JSModuleNamespace.makeInitialShape(this));

        this.prepareStackTraceCallbackNotUsedAssumption = Truffle.getRuntime().createAssumption("prepareStackTraceCallbackNotUsedAssumption");
        this.promiseHookNotUsedAssumption = Truffle.getRuntime().createAssumption("promiseHookNotUsedAssumption");
        this.promiseRejectionTrackerNotUsedAssumption = Truffle.getRuntime().createAssumption("promiseRejectionTrackerNotUsedAssumption");
        this.importMetaInitializerNotUsedAssumption = Truffle.getRuntime().createAssumption("importMetaInitializerNotUsedAssumption");
        this.importModuleDynamicallyCallbackNotUsedAssumption = Truffle.getRuntime().createAssumption("importModuleDynamicallyCallbackNotUsedAssumption");

        this.emptyFunctionCallTarget = createEmptyFunctionCallTarget(lang);
        this.symbolSpeciesThisGetterFunctionData = JSFunctionData.createCallOnly(this, createReadFrameThisCallTarget(lang, GET_SYMBOL_SPECIES_NAME), 0, GET_SYMBOL_SPECIES_NAME);
        this.symbolIteratorThisGetterFunctionData = JSFunctionData.createCallOnly(this, createReadFrameThisCallTarget(lang, SYMBOL_ITERATOR_NAME), 0, SYMBOL_ITERATOR_NAME);

        this.builtinFunctionData = new JSFunctionData[BuiltinFunctionKey.values().length];

        this.timeProfiler = languageOptions.profileTime() ? new TimeProfiler() : null;

        this.singleRealmAssumption = Truffle.getRuntime().createAssumption("single realm");

        this.throwTypeErrorFunctionData = throwTypeErrorFunction(false);
        this.throwTypeErrorRestrictedPropertyFunctionData = throwTypeErrorFunction(true);
        boolean annexB = isOptionAnnexB();
        this.protoGetterFunctionData = annexB ? protoGetterFunction() : null;
        this.protoSetterFunctionData = annexB ? protoSetterFunction() : null;

        this.isMultiContext = lang.isMultiContext();

        // shapes and factories
        PrototypeSupplier objectPrototypeSupplier = JSOrdinary.INSTANCE;
        CompilableBiFunction ordinaryObjectShapeSupplier = JSOrdinary.SHAPE_SUPPLIER;
        JSObjectFactory.IntrinsicBuilder builder = new JSObjectFactory.IntrinsicBuilder(this);

        this.functionFactory = builder.function(functionPrototypeSupplier, false, false, false, false, false);
        this.constructorFactory = builder.function(functionPrototypeSupplier, false, true, false, false, false);
        this.strictFunctionFactory = builder.function(functionPrototypeSupplier, true, false, false, false, false);
        this.strictConstructorFactory = builder.function(functionPrototypeSupplier, true, true, false, false, false);

        this.asyncFunctionFactory = builder.function(asyncFunctionPrototypeSupplier, true, false, false, false, true);
        this.generatorFunctionFactory = builder.function(generatorFunctionPrototypeSupplier, true, false, true, false, false);
        this.asyncGeneratorFunctionFactory = builder.function(asyncGeneratorFunctionPrototypeSupplier, true, false, true, false, true);

        this.boundFunctionFactory = builder.function(functionPrototypeSupplier, true, false, false, true, false);
        this.wrappedFunctionFactory = builder.function(functionPrototypeSupplier, true, false, false, true, false);

        this.ordinaryObjectFactory = builder.create(JSOrdinary.INSTANCE);
        this.arrayFactory = builder.create(JSArray.INSTANCE);
        this.iteratorFactory = builder.create(JSIterator.INSTANCE);
        this.asyncIteratorFactory = builder.create(JSAsyncIterator.INSTANCE);
        this.arrayIteratorFactory = builder.create(JSArrayIterator.INSTANCE);
        this.wrapForIteratorFactory = builder.create(JSWrapForValidIterator.INSTANCE);
        this.wrapForAsyncIteratorFactory = builder.create(JSWrapForValidAsyncIterator.INSTANCE);
        this.lazyRegexArrayFactory = builder.create(JSArray.INSTANCE);
        this.lazyRegexIndicesArrayFactory = builder.create(JSArray.INSTANCE);
        this.booleanFactory = builder.create(JSBoolean.INSTANCE);
        this.numberFactory = builder.create(JSNumber.INSTANCE);
        this.bigIntFactory = builder.create(JSBigInt.INSTANCE);
        this.stringFactory = builder.create(JSString.INSTANCE);
        this.stringIteratorFactory = builder.create(JSStringIterator.INSTANCE);
        this.regExpFactory = builder.create(JSRegExp.INSTANCE);
        this.dateFactory = builder.create(JSDate.INSTANCE);

        this.symbolFactory = builder.create(JSSymbol.INSTANCE);
        this.mapFactory = builder.create(JSMap.INSTANCE);
        this.mapIteratorFactory = builder.create(JSMapIterator.INSTANCE);
        this.setFactory = builder.create(JSSet.INSTANCE);
        this.setIteratorFactory = builder.create(JSSetIterator.INSTANCE);
        this.weakRefFactory = builder.create(JSWeakRef.INSTANCE);
        this.weakMapFactory = builder.create(JSWeakMap.INSTANCE);
        this.weakSetFactory = builder.create(JSWeakSet.INSTANCE);
        this.proxyFactory = builder.create(JSProxy.INSTANCE);
        this.uncheckedProxyHandlerFactory = builder.create(JSUncheckedProxyHandler.INSTANCE);
        this.promiseFactory = builder.create(JSPromise.INSTANCE);
        this.dataViewFactory = builder.create(JSDataView.INSTANCE);
        this.arrayBufferFactory = builder.create(JSArrayBuffer.HEAP_INSTANCE);
        this.directArrayBufferFactory = builder.create(JSArrayBuffer.DIRECT_INSTANCE);
        this.sharedArrayBufferFactory = isOptionSharedArrayBuffer() ? builder.create(JSSharedArrayBuffer.INSTANCE) : null;
        this.interopArrayBufferFactory = builder.create(JSArrayBuffer.INTEROP_INSTANCE);
        this.finalizationRegistryFactory = builder.create(JSFinalizationRegistry.INSTANCE);
        this.typedArrayFactories = new JSObjectFactory[TypedArray.factories(this).length];
        for (TypedArrayFactory factory : TypedArray.factories(this)) {
            typedArrayFactories[factory.getFactoryIndex()] = builder.create(factory, (c, p) -> JSArrayBufferView.makeInitialArrayBufferViewShape(c, p));
        }

        this.errorObjectFactories = new JSObjectFactory[JSErrorType.errorTypes().length];
        for (JSErrorType type : JSErrorType.errorTypes()) {
            errorObjectFactories[type.ordinal()] = builder.create(type, JSError.INSTANCE::makeInitialShape);
        }

        this.callSiteFactory = builder.create(JSRealm::getCallSitePrototype, JSError::makeInitialCallSiteShape);
        this.nonStrictArgumentsFactory = builder.create(objectPrototypeSupplier, JSArgumentsArray.INSTANCE);
        this.strictArgumentsFactory = builder.create(objectPrototypeSupplier, JSArgumentsArray.INSTANCE);
        this.enumerateIteratorFactory = builder.create(JSRealm::getEnumerateIteratorPrototype, JSFunction::makeInitialEnumerateIteratorShape);
        this.forInIteratorFactory = builder.create(JSForInIterator.INSTANCE);

        this.generatorObjectFactory = builder.create(JSGenerator.INSTANCE);
        this.generatorObjectPrototypeFactory = builder.create(JSRealm::getGeneratorObjectPrototype, ordinaryObjectShapeSupplier);
        this.iteratorHelperObjectFactory = builder.create(JSRealm::getIteratorHelperPrototype, JSGenerator.INSTANCE);
        this.asyncGeneratorObjectFactory = builder.create(JSAsyncGenerator.INSTANCE);
        this.asyncGeneratorObjectPrototypeFactory = builder.create(JSRealm::getAsyncGeneratorObjectPrototype, ordinaryObjectShapeSupplier);
        this.asyncFromSyncIteratorFactory = builder.create(JSRealm::getAsyncFromSyncIteratorPrototype, JSIterator.INSTANCE);
        this.asyncIteratorHelperObjectFactory = builder.create(JSRealm::getAsyncIteratorHelperPrototype, JSAsyncGenerator.INSTANCE);

        this.collatorFactory = builder.create(JSCollator.INSTANCE);
        this.numberFormatFactory = builder.create(JSNumberFormat.INSTANCE);
        this.dateTimeFormatFactory = builder.create(JSDateTimeFormat.INSTANCE);
        this.pluralRulesFactory = builder.create(JSPluralRules.INSTANCE);
        this.listFormatFactory = builder.create(JSListFormat.INSTANCE);
        this.relativeTimeFormatFactory = builder.create(JSRelativeTimeFormat.INSTANCE);
        this.segmenterFactory = builder.create(JSSegmenter.INSTANCE);
        this.segmentsFactory = builder.create(JSRealm::getSegmentsPrototype, JSSegmenter::makeInitialSegmentsShape);
        this.segmentIteratorFactory = builder.create(JSRealm::getSegmentIteratorPrototype, JSSegmenter::makeInitialSegmentIteratorShape);
        this.displayNamesFactory = builder.create(JSDisplayNames.INSTANCE);
        this.localeFactory = builder.create(JSLocale.INSTANCE);

        this.javaPackageFactory = builder.create(objectPrototypeSupplier, JavaPackage.INSTANCE::makeInitialShape);
        boolean nashornCompat = isOptionNashornCompatibilityMode();
        this.jsAdapterFactory = nashornCompat ? builder.create(JSAdapter.INSTANCE) : null;
        this.javaImporterFactory = nashornCompat ? builder.create(JavaImporter.instance()) : null;

        this.temporalPlainTimeFactory = builder.create(JSTemporalPlainTime.INSTANCE);
        this.temporalPlainDateFactory = builder.create(JSTemporalPlainDate.INSTANCE);
        this.temporalPlainDateTimeFactory = builder.create(JSTemporalPlainDateTime.INSTANCE);
        this.temporalDurationFactory = builder.create(JSTemporalDuration.INSTANCE);
        this.temporalCalendarFactory = builder.create(JSTemporalCalendar.INSTANCE);
        this.temporalPlainYearMonthFactory = builder.create(JSTemporalPlainYearMonth.INSTANCE);
        this.temporalPlainMonthDayFactory = builder.create(JSTemporalPlainMonthDay.INSTANCE);
        this.temporalInstantFactory = builder.create(JSTemporalInstant.INSTANCE);
        this.temporalTimeZoneFactory = builder.create(JSTemporalTimeZone.INSTANCE);
        this.temporalZonedDateTimeFactory = builder.create(JSTemporalZonedDateTime.INSTANCE);

        this.dictionaryObjectFactory = JSConfig.DictionaryObject ? builder.create(objectPrototypeSupplier, JSDictionary::makeDictionaryShape) : null;

        this.globalObjectFactory = builder.create(objectPrototypeSupplier, JSGlobal::makeGlobalObjectShape);

        this.webAssemblyModuleFactory = builder.create(JSWebAssemblyModule.INSTANCE);
        this.webAssemblyInstanceFactory = builder.create(JSWebAssemblyInstance.INSTANCE);
        this.webAssemblyMemoryFactory = builder.create(JSWebAssemblyMemory.INSTANCE);
        this.webAssemblyTableFactory = builder.create(JSWebAssemblyTable.INSTANCE);
        this.webAssemblyGlobalFactory = builder.create(JSWebAssemblyGlobal.INSTANCE);

        this.shadowRealmFactory = builder.create(JSShadowRealm.INSTANCE);
        this.asyncContextSnapshotFactory = builder.create(JSAsyncContextSnapshot.INSTANCE);
        this.asyncContextVariableFactory = builder.create(JSAsyncContextVariable.INSTANCE);
        this.rawJSONFactory = JSObjectFactory.createBound(this, Null.instance, JSRawJSON.makeInitialShape(this));

        this.factoryCount = builder.finish();

        this.regExpGroupsEmptyShape = JSRegExp.makeInitialGroupsObjectShape(this);

        this.regexOptions = createRegexOptions(languageOptions);
        this.regexValidateOptions = regexOptions.isEmpty() ? REGEX_OPTION_VALIDATE : REGEX_OPTION_VALIDATE + "," + regexOptions;

        this.supportedImportAttributes = languageOptions.importAttributes() ? Set.of(TYPE_IMPORT_ATTRIBUTE) : Set.of();
    }

    public final Evaluator getEvaluator() {
        return evaluator;
    }

    public Object getNodeFactory() {
        return nodeFactory;
    }

    public final JSParserOptions getParserOptions() {
        return parserOptions;
    }

    public final Object getEmbedderData() {
        return embedderData;
    }

    public final void setEmbedderData(Object embedderData) {
        this.embedderData = embedderData;
    }

    public final Assumption getNoSuchPropertyUnusedAssumption() {
        return noSuchPropertyUnusedAssumption;
    }

    public final Assumption getNoSuchMethodUnusedAssumption() {
        return noSuchMethodUnusedAssumption;
    }

    public final Assumption getArrayPrototypeNoElementsAssumption() {
        return arrayPrototypeNoElementsAssumption;
    }

    public final Assumption getFastArrayAssumption() {
        return fastArrayAssumption;
    }

    public final Assumption getFastArgumentsObjectAssumption() {
        return fastArgumentsObjectAssumption;
    }

    public final Assumption getTypedArrayNotDetachedAssumption() {
        return typedArrayNotDetachedAssumption;
    }

    public final Assumption getArrayBufferNotShrunkAssumption() {
        return arrayBufferNotShrunkAssumption;
    }

    public final Assumption getRegExpStaticResultUnusedAssumption() {
        return regExpStaticResultUnusedAssumption;
    }

    public final Assumption getGlobalObjectPristineAssumption() {
        return globalObjectPristineAssumption;
    }

    public static JSContext createContext(Evaluator evaluator, JavaScriptLanguage language, TruffleLanguage.Env env) {
        JSContextOptions contextOptions = JSContextOptions.fromOptionValues(env.getSandboxPolicy(), env.getOptions());
        JSLanguageOptions languageOptions = JSLanguageOptions.fromContextOptions(contextOptions);
        JSContext context = new JSContext(evaluator, language, languageOptions, env);
        if (!env.isPreInitialization()) {
            context.updateStableOptions(contextOptions, StableContextOptionValue.UpdateKind.INITIALIZE);
        }
        return context;
    }

    public JSRealm createRealm(TruffleLanguage.Env env) {
        return createRealm(env, null);
    }

    protected JSRealm createRealm(TruffleLanguage.Env env, JSRealm parentRealm) {
        boolean isTop = (parentRealm == null);
        realmInit.compareAndSet(REALM_UNINITIALIZED, REALM_INITIALIZING);

        if (!isTop) {
            singleRealmAssumption.invalidate("creating another realm");
        }
        JSRealm newRealm = new JSRealm(this, env, parentRealm);
        newRealm.setupGlobals();

        if (isTop) {
            newRealm.setAgent(createAgent());
            if (languageOptions.v8RealmBuiltin()) {
                newRealm.initRealmList();
                newRealm.addToRealmList(newRealm);
            }
        } else {
            if (languageOptions.v8RealmBuiltin()) {
                JSRealm topLevelRealm = parentRealm;
                while (topLevelRealm.getParent() != null) {
                    topLevelRealm = topLevelRealm.getParent();
                }
                topLevelRealm.addToRealmList(newRealm);
            }
        }

        realmInit.set(REALM_INITIALIZED);
        return newRealm;
    }

    private JSAgent createAgent() {
        JSAgent agent;
        if (languageOptions.test262Mode() || languageOptions.testV8Mode()) {
            agent = new DebugJSAgent(languageOptions.agentCanBlock());
        } else {
            agent = new MainJSAgent();
        }
        if (languageOptions.unhandledRejectionsMode() != JSContextOptions.UnhandledRejectionsTrackingMode.NONE) {
            setPromiseRejectionTracker(agent, new BuiltinPromiseRejectionTracker(this, languageOptions.unhandledRejectionsMode()));
        }
        return agent;
    }

    public final Shape createEmptyShape() {
        return makeEmptyShapeWithNullPrototype(JSOrdinary.INSTANCE);
    }

    private Shape createEmptyShapePrototypeInObject() {
        return makeEmptyShapeWithPrototypeInObject(JSOrdinary.INSTANCE);
    }

    private Shape createPromiseShapePrototypeInObject() {
        return makeEmptyShapeWithPrototypeInObject(JSPromise.INSTANCE);
    }

    public final Shape makeEmptyShapeWithNullPrototype(JSClass jsclass) {
        Shape protoChildTree = nullPrototypeData.getProtoChildTree(jsclass);
        if (protoChildTree != null) {
            return protoChildTree;
        }
        return nullPrototypeData.getOrAddProtoChildTree(jsclass, JSShape.makeEmptyRoot(jsclass, this));
    }

    public final Shape makeEmptyShapeWithPrototypeInObject(JSClass jsclass) {
        Shape protoChildTree = inObjectPrototypeData.getProtoChildTree(jsclass);
        if (protoChildTree != null) {
            return protoChildTree;
        }
        return inObjectPrototypeData.getOrAddProtoChildTree(jsclass, JSShape.makeEmptyRootWithInstanceProto(this, jsclass));
    }

    private Shape createGlobalScopeShape() {
        return JSShape.makeEmptyRoot(JSGlobal.INSTANCE, this);
    }

    public final Map getSymbolRegistry() {
        return symbolRegistry;
    }

    public final Map getPrivateSymbolRegistry() {
        return privateSymbolRegistry;
    }

    /**
     * ES abstract operation HostEnqueuePromiseJob.
     */
    public final void enqueuePromiseJob(JSRealm realm, JSFunctionObject job) {
        invalidatePromiseQueueNotUsedAssumption();
        JSAgent agent = realm.getAgent();
        agent.enqueuePromiseJob(job);
    }

    public final void signalAsyncWaiterRecordUsage() {
        invalidatePromiseQueueNotUsedAssumption();
    }

    private void invalidatePromiseQueueNotUsedAssumption() {
        Assumption promiseJobsQueueEmptyAssumption = language.getPromiseJobsQueueEmptyAssumption();
        if (promiseJobsQueueEmptyAssumption.isValid()) {
            CompilerDirectives.transferToInterpreterAndInvalidate();
            promiseJobsQueueEmptyAssumption.invalidate();
        }
    }

    public final void processAllPendingPromiseJobs(JSRealm realm) {
        if (!language.getPromiseJobsQueueEmptyAssumption().isValid()) {
            realm.getAgent().processAllPromises(false);
        }
    }

    public boolean addWeakRefTargetToSet(Object target) {
        invalidatePromiseQueueNotUsedAssumption();
        return getJSAgent().addWeakRefTargetToSet(target);
    }

    public void registerFinalizationRegistry(JSFinalizationRegistryObject finalizationRegistry) {
        invalidatePromiseQueueNotUsedAssumption();
        getJSAgent().registerFinalizationRegistry(finalizationRegistry);
    }

    public TimeProfiler getTimeProfiler() {
        return timeProfiler;
    }

    /**
     * Get the current Realm using {@link ContextReference}.
     */
    private JSRealm getRealm() {
        assert realmInit.get() == REALM_INITIALIZED : "getRealm() while initializing Realm";
        JSRealm currentRealm = JSRealm.get(null);
        assert currentRealm != null;
        return currentRealm;
    }

    public final Shape getEmptyShapeNullPrototype() {
        return emptyShape;
    }

    public final Shape getEmptyShapePrototypeInObject() {
        return emptyShapePrototypeInObject;
    }

    public final Shape getPromiseShapePrototypeInObject() {
        return promiseShapePrototypeInObject;
    }

    public final Shape getGlobalScopeShape() {
        return globalScopeShape;
    }

    public final JSObjectFactory getOrdinaryObjectFactory() {
        return ordinaryObjectFactory;
    }

    public final JSObjectFactory getArrayFactory() {
        return arrayFactory;
    }

    public final JSObjectFactory getIteratorFactory() {
        return iteratorFactory;
    }

    public final JSObjectFactory getAsyncIteratorFactory() {
        return asyncIteratorFactory;
    }

    public final JSObjectFactory getArrayIteratorFactory() {
        return arrayIteratorFactory;
    }

    public final JSObjectFactory getWrapForIteratorFactory() {
        return wrapForIteratorFactory;
    }

    public final JSObjectFactory getWrapForAsyncIteratorFactory() {
        return wrapForAsyncIteratorFactory;
    }

    public final JSObjectFactory getLazyRegexArrayFactory() {
        return lazyRegexArrayFactory;
    }

    public final JSObjectFactory getLazyRegexIndicesArrayFactory() {
        return lazyRegexIndicesArrayFactory;
    }

    public final JSObjectFactory getStringFactory() {
        return stringFactory;
    }

    public final JSObjectFactory getStringIteratorFactory() {
        return stringIteratorFactory;
    }

    public final JSObjectFactory getBooleanFactory() {
        return booleanFactory;
    }

    public final JSObjectFactory getNumberFactory() {
        return numberFactory;
    }

    public final JSObjectFactory getBigIntFactory() {
        return bigIntFactory;
    }

    public final JSObjectFactory getSymbolFactory() {
        return symbolFactory;
    }

    public final JSObjectFactory getArrayBufferViewFactory(TypedArrayFactory factory) {
        return typedArrayFactories[factory.getFactoryIndex()];
    }

    public final JSObjectFactory getArrayBufferFactory() {
        return arrayBufferFactory;
    }

    public final JSObjectFactory getDirectArrayBufferFactory() {
        return directArrayBufferFactory;
    }

    public final JSObjectFactory getRegExpFactory() {
        return regExpFactory;
    }

    public final JSObjectFactory getDateFactory() {
        return dateFactory;
    }

    public final JSObjectFactory getEnumerateIteratorFactory() {
        return enumerateIteratorFactory;
    }

    public final JSObjectFactory getForInIteratorFactory() {
        return forInIteratorFactory;
    }

    public final JSObjectFactory getMapFactory() {
        return mapFactory;
    }

    public final JSObjectFactory getMapIteratorFactory() {
        return mapIteratorFactory;
    }

    public final JSObjectFactory getFinalizationRegistryFactory() {
        return finalizationRegistryFactory;
    }

    public final JSObjectFactory getWeakRefFactory() {
        return weakRefFactory;
    }

    public final JSObjectFactory getWeakMapFactory() {
        return weakMapFactory;
    }

    public final JSObjectFactory getSetFactory() {
        return setFactory;
    }

    public final JSObjectFactory getSetIteratorFactory() {
        return setIteratorFactory;
    }

    public final JSObjectFactory getWeakSetFactory() {
        return weakSetFactory;
    }

    public final JSObjectFactory getDataViewFactory() {
        return dataViewFactory;
    }

    public final JSObjectFactory getProxyFactory() {
        return proxyFactory;
    }

    public final JSObjectFactory getUncheckedProxyHandlerFactory() {
        return uncheckedProxyHandlerFactory;
    }

    public final JSObjectFactory getSharedArrayBufferFactory() {
        assert isOptionSharedArrayBuffer();
        return sharedArrayBufferFactory;
    }

    public JSObjectFactory getInteropArrayBufferFactory() {
        return interopArrayBufferFactory;
    }

    public final JSObjectFactory getNonStrictArgumentsFactory() {
        return nonStrictArgumentsFactory;
    }

    public final JSObjectFactory getStrictArgumentsFactory() {
        return strictArgumentsFactory;
    }

    public final JSObjectFactory getCallSiteFactory() {
        return callSiteFactory;
    }

    public final JSObjectFactory getErrorFactory(JSErrorType type) {
        return errorObjectFactories[type.ordinal()];
    }

    public final JSObjectFactory getPromiseFactory() {
        return promiseFactory;
    }

    public final JSObjectFactory.BoundProto getModuleNamespaceFactory() {
        return moduleNamespaceFactory;
    }

    public final JSObjectFactory getGeneratorObjectFactory() {
        return generatorObjectFactory;
    }

    public final JSObjectFactory getGeneratorObjectPrototypeFactory() {
        return generatorObjectPrototypeFactory;
    }

    public final JSObjectFactory getIteratorHelperObjectFactory() {
        return iteratorHelperObjectFactory;
    }

    public final JSObjectFactory getAsyncGeneratorObjectFactory() {
        return asyncGeneratorObjectFactory;
    }

    public final JSObjectFactory getAsyncGeneratorObjectPrototypeFactory() {
        return asyncGeneratorObjectPrototypeFactory;
    }

    public final JSObjectFactory getAsyncFromSyncIteratorFactory() {
        return asyncFromSyncIteratorFactory;
    }

    public final JSObjectFactory getAsyncIteratorHelperObjectFactory() {
        return asyncIteratorHelperObjectFactory;
    }

    public final JSObjectFactory getCollatorFactory() {
        return collatorFactory;
    }

    public final JSObjectFactory getNumberFormatFactory() {
        return numberFormatFactory;
    }

    public final JSObjectFactory getPluralRulesFactory() {
        return pluralRulesFactory;
    }

    public final JSObjectFactory getListFormatFactory() {
        return listFormatFactory;
    }

    public final JSObjectFactory getRelativeTimeFormatFactory() {
        return relativeTimeFormatFactory;
    }

    public final JSObjectFactory getSegmenterFactory() {
        return segmenterFactory;
    }

    public final JSObjectFactory getSegmentsFactory() {
        return segmentsFactory;
    }

    public final JSObjectFactory getSegmentIteratorFactory() {
        return segmentIteratorFactory;
    }

    public final JSObjectFactory getDisplayNamesFactory() {
        return displayNamesFactory;
    }

    public final JSObjectFactory getLocaleFactory() {
        return localeFactory;
    }

    public final JSObjectFactory getDateTimeFormatFactory() {
        return dateTimeFormatFactory;
    }

    public final JSObjectFactory getJavaImporterFactory() {
        return javaImporterFactory;
    }

    public final JSObjectFactory getJSAdapterFactory() {
        return jsAdapterFactory;
    }

    public final JSObjectFactory getJavaPackageFactory() {
        return javaPackageFactory;
    }

    public final JSObjectFactory getTemporalPlainTimeFactory() {
        return temporalPlainTimeFactory;
    }

    public final JSObjectFactory getTemporalPlainDateFactory() {
        return temporalPlainDateFactory;
    }

    public final JSObjectFactory getTemporalPlainDateTimeFactory() {
        return temporalPlainDateTimeFactory;
    }

    public final JSObjectFactory getTemporalDurationFactory() {
        return temporalDurationFactory;
    }

    public final JSObjectFactory getTemporalCalendarFactory() {
        return temporalCalendarFactory;
    }

    public JSObjectFactory getTemporalPlainYearMonthFactory() {
        return temporalPlainYearMonthFactory;
    }

    public JSObjectFactory getTemporalPlainMonthDayFactory() {
        return temporalPlainMonthDayFactory;
    }

    public JSObjectFactory getTemporalInstantFactory() {
        return temporalInstantFactory;
    }

    public JSObjectFactory getTemporalZonedDateTimeFactory() {
        return temporalZonedDateTimeFactory;
    }

    public JSObjectFactory getTemporalTimeZoneFactory() {
        return temporalTimeZoneFactory;
    }

    public JSObjectFactory getDictionaryObjectFactory() {
        return dictionaryObjectFactory;
    }

    public JSObjectFactory getGlobalObjectFactory() {
        return globalObjectFactory;
    }

    public JSObjectFactory getWebAssemblyModuleFactory() {
        return webAssemblyModuleFactory;
    }

    public JSObjectFactory getWebAssemblyInstanceFactory() {
        return webAssemblyInstanceFactory;
    }

    public JSObjectFactory getWebAssemblyMemoryFactory() {
        return webAssemblyMemoryFactory;
    }

    public JSObjectFactory getWebAssemblyTableFactory() {
        return webAssemblyTableFactory;
    }

    public JSObjectFactory getWebAssemblyGlobalFactory() {
        return webAssemblyGlobalFactory;
    }

    public final JSObjectFactory getShadowRealmFactory() {
        return shadowRealmFactory;
    }

    public final JSObjectFactory getAsyncContextSnapshotFactory() {
        return asyncContextSnapshotFactory;
    }

    public final JSObjectFactory getAsyncContextVariableFactory() {
        return asyncContextVariableFactory;
    }

    public final JSObjectFactory getRawJSONFactory() {
        return rawJSONFactory;
    }

    private static final String REGEX_OPTION_REGRESSION_TEST_MODE = "RegressionTestMode";
    private static final String REGEX_OPTION_DUMP_AUTOMATA = "DumpAutomata";
    private static final String REGEX_OPTION_STEP_EXECUTION = "StepExecution";
    private static final String REGEX_OPTION_ALWAYS_EAGER = "AlwaysEager";
    private static final String REGEX_OPTION_VALIDATE = "Validate=true";

    private static String createRegexOptions(JSLanguageOptions jsOptions) {
        StringBuilder regexOptions = new StringBuilder();
        if (jsOptions.regexRegressionTestMode()) {
            regexOptions.append(REGEX_OPTION_REGRESSION_TEST_MODE).append("=true,");
        }
        if (jsOptions.regexDumpAutomata()) {
            regexOptions.append(REGEX_OPTION_DUMP_AUTOMATA).append("=true,");
        }
        if (jsOptions.regexStepExecution()) {
            regexOptions.append(REGEX_OPTION_STEP_EXECUTION).append("=true,");
        }
        if (jsOptions.regexAlwaysEager()) {
            regexOptions.append(REGEX_OPTION_ALWAYS_EAGER).append("=true,");
        }
        return regexOptions.toString();
    }

    public String getRegexOptions() {
        return regexOptions;
    }

    public String getRegexValidateOptions() {
        return regexValidateOptions;
    }

    public Object getTRegexEmptyResult() {
        if (tRegexEmptyResult == null) {
            CompilerDirectives.transferToInterpreterAndInvalidate();
            tRegexEmptyResult = TRegexUtil.InvokeExecMethodNode.getUncached().execute(null, RegexCompilerInterface.compile("[]", "", this, JSRealm.get(null)), "", 0);
            assert !TRegexUtil.TRegexResultAccessor.isMatch(tRegexEmptyResult, null, TRegexUtil.InteropReadBooleanMemberNode.getUncached());
        }
        return tRegexEmptyResult;
    }

    public Shape getRegExpGroupsEmptyShape() {
        return regExpGroupsEmptyShape;
    }

    public Map getShapeDataMap() {
        return shapeDataMap;
    }

    public JavaScriptLanguage getLanguage() {
        return language;
    }

    public CallTarget getEmptyFunctionCallTarget() {
        return emptyFunctionCallTarget;
    }

    public JSFunctionData getNamedEmptyFunctionData(TruffleString name) {
        return namedEmptyFunctionsDataMap.computeIfAbsent(name, k -> JSFunctionData.createCallOnly(this, emptyFunctionCallTarget, 0, name));
    }

    /** CallTarget for an empty function that returns undefined. */
    private static CallTarget createEmptyFunctionCallTarget(JavaScriptLanguage lang) {
        return new JavaScriptRootNode(lang) {
            @Override
            public Object execute(VirtualFrame frame) {
                return Undefined.instance;
            }
        }.getCallTarget();
    }

    public JSFunctionData getSymbolIteratorThisGetterFunctionData() {
        return symbolIteratorThisGetterFunctionData;
    }

    public JSFunctionData getSymbolSpeciesThisGetterFunctionData() {
        return symbolSpeciesThisGetterFunctionData;
    }

    private static CallTarget createReadFrameThisCallTarget(JavaScriptLanguage lang, TruffleString name) {
        String callTargetName = name.toJavaStringUncached();
        return new JavaScriptRootNode(lang) {
            @Override
            public Object execute(VirtualFrame frame) {
                return JSFrameUtil.getThisObj(frame);
            }

            @Override
            public String getName() {
                return callTargetName;
            }
        }.getCallTarget();
    }

    @TruffleBoundary
    public CallTarget getNotConstructibleCallTarget() {
        CallTarget result = notConstructibleCallTargetCache;
        if (result != null) {
            return result;
        } else {
            result = createNotConstructibleCallTarget(getLanguage(), false, this);
            if (!notConstructibleCallTargetVarHandle.compareAndSet(this, (CallTarget) null, result)) {
                result = notConstructibleCallTargetCache;
            }
            return Objects.requireNonNull(result);
        }
    }

    @TruffleBoundary
    public CallTarget getGeneratorNotConstructibleCallTarget() {
        CallTarget result = generatorNotConstructibleCallTargetCache;
        if (result != null) {
            return result;
        } else {
            result = createNotConstructibleCallTarget(getLanguage(), true, this);
            if (!generatorNotConstructibleCallTargetVarHandle.compareAndSet(this, (CallTarget) null, result)) {
                result = generatorNotConstructibleCallTargetCache;
            }
            return Objects.requireNonNull(result);
        }
    }

    private static RootCallTarget createNotConstructibleCallTarget(JavaScriptLanguage lang, boolean generator, JSContext context) {
        return new JavaScriptRootNode(lang) {
            @Override
            public Object execute(VirtualFrame frame) {
                if (generator) {
                    throw Errors.createTypeError("cannot construct a generator");
                } else {
                    throw Errors.createTypeErrorNotAConstructor(JSArguments.getFunctionObject(frame.getArguments()), context);
                }
            }
        }.getCallTarget();
    }

    public JSFunctionData getBoundFunctionData(boolean constructor, boolean async) {
        if (async) {
            // Mark bound async functions for MLE mode; see ExportValueNode.
            if (constructor) {
                return getOrCreateBuiltinFunctionData(BuiltinFunctionKey.BoundConstructorAsync, c -> makeBoundFunctionData(c, true, true));
            } else {
                return getOrCreateBuiltinFunctionData(BuiltinFunctionKey.BoundFunctionAsync, c -> makeBoundFunctionData(c, false, true));
            }
        } else {
            if (constructor) {
                return getOrCreateBuiltinFunctionData(BuiltinFunctionKey.BoundConstructor, c -> makeBoundFunctionData(c, true, false));
            } else {
                return getOrCreateBuiltinFunctionData(BuiltinFunctionKey.BoundFunction, c -> makeBoundFunctionData(c, false, false));
            }
        }
    }

    private static JSFunctionData makeBoundFunctionData(JSContext context, boolean constructor, boolean async) {
        CallTarget callTarget;
        CallTarget constructTarget;
        CallTarget constructNewTarget;
        // The call targets are the same for all bound function data instances, so reuse them.
        if (constructor || async) {
            JSFunctionData template = context.getBoundFunctionData(false, false);
            callTarget = template.getCallTarget();
            constructTarget = template.getConstructTarget();
            constructNewTarget = template.getConstructNewTarget();
        } else {
            callTarget = JSFunction.createBoundRootNode(context, false, false).getCallTarget();
            constructTarget = JSFunction.createBoundRootNode(context, true, false).getCallTarget();
            constructNewTarget = JSFunction.createBoundRootNode(context, true, true).getCallTarget();
        }
        return JSFunctionData.create(context,
                        callTarget, constructTarget, constructNewTarget,
                        0, Strings.BOUND, constructor, false, true, false, false, false, async, false, true, false, true);
    }

    private JSAgent getJSAgent() {
        return getRealm().getAgent();
    }

    public int getEcmaScriptVersion() {
        return languageOptions.ecmaScriptVersion();
    }

    @Idempotent
    public int getPropertyCacheLimit() {
        return languageOptions.propertyCacheLimit();
    }

    public int getFunctionCacheLimit() {
        return languageOptions.functionCacheLimit();
    }

    void setAllocationReporter(TruffleLanguage.Env env) {
        CompilerAsserts.neverPartOfCompilation();
        this.allocationReporter = env.lookup(AllocationReporter.class);
    }

    public final AllocationReporter getAllocationReporter() {
        assert realmInit.get() == REALM_INITIALIZED : "getAllocationReporter() during Realm initialization";
        return allocationReporter;
    }

    public final  T trackAllocation(T object) {
        AllocationReporter reporter = getAllocationReporter();
        if (reporter != null) {
            reporter.onEnter(null, 0, AllocationReporter.SIZE_UNKNOWN);
            reporter.onReturnValue(object, 0, AllocationReporter.SIZE_UNKNOWN);
        }
        return object;
    }

    public boolean isOptionAnnexB() {
        return languageOptions.annexB();
    }

    public boolean isOptionIntl402() {
        return languageOptions.intl402();
    }

    public boolean isOptionRegexpMatchIndices() {
        return languageOptions.regexpMatchIndices();
    }

    public boolean isOptionRegexpUnicodeSets() {
        return languageOptions.regexpUnicodeSets();
    }

    public boolean isOptionRegexpStaticResult() {
        return optionRegexpStaticResult.get();
    }

    public boolean isOptionSharedArrayBuffer() {
        return languageOptions.sharedArrayBuffer();
    }

    public boolean isOptionTemporal() {
        return languageOptions.temporal();
    }

    public boolean isOptionV8CompatibilityMode() {
        return optionV8CompatibilityMode.get();
    }

    @Idempotent
    public boolean isOptionNashornCompatibilityMode() {
        return languageOptions.nashornCompatibilityMode();
    }

    public boolean isOptionMleBuiltin() {
        return languageOptions.isMLEMode();
    }

    public boolean isOptionDirectByteBuffer() {
        return optionDirectByteBuffer.get();
    }

    public boolean isOptionParseOnly() {
        return languageOptions.parseOnly();
    }

    public boolean isOptionDisableWith() {
        return languageOptions.disableWith();
    }

    public boolean isOptionAsyncStackTraces() {
        return languageOptions.asyncStackTraces();
    }

    public boolean isOptionForeignObjectPrototype() {
        return languageOptions.hasForeignObjectPrototype();
    }

    public long getTimerResolution() {
        return optionTimerResolution.get();
    }

    public long getFunctionArgumentsLimit() {
        return languageOptions.functionArgumentsLimit();
    }

    public int getStringLengthLimit() {
        return languageOptions.stringLengthLimit();
    }

    public boolean usePromiseResolve() {
        return languageOptions.awaitOptimization();
    }

    public final void setPrepareStackTraceCallback(PrepareStackTraceCallback callback) {
        invalidatePrepareStackTraceCallbackNotUsedAssumption();
        this.prepareStackTraceCallback = callback;
    }

    public final PrepareStackTraceCallback getPrepareStackTraceCallback() {
        return prepareStackTraceCallbackNotUsedAssumption.isValid() ? null : prepareStackTraceCallback;
    }

    private void invalidatePrepareStackTraceCallbackNotUsedAssumption() {
        if (prepareStackTraceCallbackNotUsedAssumption.isValid()) {
            CompilerDirectives.transferToInterpreterAndInvalidate();
            prepareStackTraceCallbackNotUsedAssumption.invalidate("prepare stack trace callback unused");
        }
    }

    public final void setPromiseRejectionTracker(JSAgent agent, PromiseRejectionTracker tracker) {
        invalidatePromiseRejectionTrackerNotUsedAssumption();
        agent.setPromiseRejectionTracker(tracker);
    }

    private void invalidatePromiseRejectionTrackerNotUsedAssumption() {
        if (promiseRejectionTrackerNotUsedAssumption.isValid()) {
            CompilerDirectives.transferToInterpreterAndInvalidate();
            promiseRejectionTrackerNotUsedAssumption.invalidate("promise rejection tracker unused");
        }
    }

    public void notifyPromiseRejectionTracker(JSPromiseObject promise, int operation, Object value, JSAgent agent) {
        boolean hasPromiseRejectionTracker = agent.hasPromiseRejectionTracker();
        if (promiseRejectionTrackerNotUsedAssumption.isValid()) {
            assert !hasPromiseRejectionTracker : promiseRejectionTrackerNotUsedAssumption;
            return;
        }
        agent.notifyPromiseRejectionTracker(promise, operation, value);
    }

    public final void setPromiseHook(PromiseHook promiseHook) {
        invalidatePromiseHookNotUsedAssumption();
        this.promiseHook = promiseHook;
    }

    private void invalidatePromiseHookNotUsedAssumption() {
        if (promiseHookNotUsedAssumption.isValid()) {
            CompilerDirectives.transferToInterpreterAndInvalidate();
            promiseHookNotUsedAssumption.invalidate("promise hook unused");
        }
    }

    public final boolean hasPromiseHook() {
        return !promiseHookNotUsedAssumption.isValid() && (promiseHook != null);
    }

    public final void notifyPromiseHook(int changeType, JSDynamicObject promise) {
        if (hasPromiseHook()) {
            JSRealm realm = JSRealm.getMain(null);
            if (changeType == -1) {
                // Information about parent for the incoming INIT event
                realm.storeParentPromise(promise);
            } else {
                JSDynamicObject parent = (changeType == PromiseHook.TYPE_INIT) ? realm.fetchParentPromise() : Undefined.instance;
                try {
                    notifyPromiseHookImpl(changeType, promise, parent);
                } catch (GraalJSException ex) {
                    // Resembles ReportMessageFromMicrotask()
                    notifyPromiseRejectionTracker(JSPromise.create(this, getRealm()), JSPromise.REJECTION_TRACKER_OPERATION_REJECT, ex.getErrorObject(), realm.getAgent());
                }
            }
        }
    }

    @TruffleBoundary
    private void notifyPromiseHookImpl(int changeType, JSDynamicObject promise, JSDynamicObject parent) {
        promiseHook.promiseChanged(changeType, promise, parent);
    }

    public final void setImportMetaInitializer(ImportMetaInitializer importMetaInitializer) {
        importMetaInitializerNotUsedAssumption.invalidate("ImportMetaInitializer unused");
        this.importMetaInitializer = importMetaInitializer;
    }

    public final boolean hasImportMetaInitializerBeenSet() {
        return !importMetaInitializerNotUsedAssumption.isValid();
    }

    @TruffleBoundary
    public final void notifyImportMetaInitializer(JSDynamicObject importMeta, JSModuleRecord module) {
        if (importMetaInitializer != null) {
            importMetaInitializer.initializeImportMeta(importMeta, module);
        }
    }

    public final void setImportModuleDynamicallyCallback(ImportModuleDynamicallyCallback callback) {
        importModuleDynamicallyCallbackNotUsedAssumption.invalidate();
        this.importModuleDynamicallyCallback = callback;
    }

    public final boolean hasImportModuleDynamicallyCallbackBeenSet() {
        return !importModuleDynamicallyCallbackNotUsedAssumption.isValid();
    }

    /**
     * Invokes the HostImportModuleDynamically (and FinishDynamicImport) callback. Returns a promise
     * of dynamic import completion or {@null} if no callback is installed or the callback failed.
     *
     * @return the callback result (a promise or {@code null}).
     */
    @TruffleBoundary
    public final JSDynamicObject hostImportModuleDynamically(JSRealm realm, ScriptOrModule referrer, Module.ModuleRequest moduleRequest) {
        if (importModuleDynamicallyCallback != null) {
            return importModuleDynamicallyCallback.importModuleDynamically(realm, referrer, moduleRequest);
        } else {
            return null;
        }
    }

    public final JSFunctionData getOrCreateBuiltinFunctionData(BuiltinFunctionKey key, Function factory) {
        final int index = key.ordinal();
        JSFunctionData functionData = builtinFunctionData[index];
        if (functionData != null) {
            return functionData;
        }
        CompilerDirectives.transferToInterpreterAndInvalidate();
        functionData = factory.apply(this);
        if (!FUNCTION_DATA_ARRAY_VAR_HANDLE.compareAndSet(builtinFunctionData, index, (JSFunctionData) null, functionData)) {
            functionData = (JSFunctionData) FUNCTION_DATA_ARRAY_VAR_HANDLE.getVolatile(builtinFunctionData, index);
        }
        return Objects.requireNonNull(functionData);
    }

    public final JSFunctionData getBuiltinFunctionData(Builtin key) {
        CompilerAsserts.neverPartOfCompilation();
        return builtinFunctionDataMap.get(key);
    }

    public final void putBuiltinFunctionData(Builtin key, JSFunctionData functionData) {
        CompilerAsserts.neverPartOfCompilation();
        builtinFunctionDataMap.putIfAbsent(key, functionData);
    }

    public final boolean neverCreatedChildRealms() {
        return singleRealmAssumption.isValid();
    }

    public final boolean isSingleRealm() {
        return !isMultiContext() && singleRealmAssumption.isValid();
    }

    public final Assumption getSingleRealmAssumption() {
        return singleRealmAssumption;
    }

    public JSLanguageOptions getLanguageOptions() {
        return languageOptions;
    }

    @Idempotent
    public final boolean isMultiContext() {
        return isMultiContext;
    }

    public JSFunctionFactory getFunctionFactory(JSFunctionData functionData) {
        boolean isBuiltin = functionData.isBuiltin();
        boolean strictFunctionProperties = functionData.hasStrictFunctionProperties();
        boolean isConstructor = functionData.isConstructor();
        boolean isGenerator = functionData.isGenerator();
        boolean isAsync = functionData.isAsync();
        assert !isBuiltin || (!isGenerator && !isAsync) : "built-in functions are never generator or async functions!";
        if (isAsync) {
            if (isGenerator) {
                return asyncGeneratorFunctionFactory;
            } else {
                return asyncFunctionFactory;
            }
        } else if (isGenerator) {
            return generatorFunctionFactory;
        } else if (isConstructor && !isBuiltin) {
            if (strictFunctionProperties) {
                return strictConstructorFactory;
            } else {
                return constructorFactory;
            }
        } else {
            // Built-in constructor functions end up here due to the way they're initialized.
            if (strictFunctionProperties) {
                return strictFunctionFactory;
            } else {
                return functionFactory;
            }
        }
    }

    public JSFunctionFactory getBoundFunctionFactory(JSFunctionData functionData) {
        assert functionData.isStrict();
        return boundFunctionFactory;
    }

    public JSFunctionFactory getWrappedFunctionFactory() {
        return wrappedFunctionFactory;
    }

    JSObjectFactory.RealmData newObjectFactoryRealmData() {
        if (isMultiContext()) {
            return null; // unused
        } else {
            return new JSObjectFactory.RealmData(factoryCount);
        }
    }

    private JSFunctionData throwTypeErrorFunction(boolean restrictedProperty) {
        CallTarget throwTypeErrorCallTarget = new ThrowTypeErrorRootNode(getLanguage(), restrictedProperty).getCallTarget();
        return JSFunctionData.create(this, throwTypeErrorCallTarget, throwTypeErrorCallTarget, 0, Strings.EMPTY_STRING, false, false, false, true);
    }

    private JSFunctionData protoSetterFunction() {
        CallTarget callTarget = new JavaScriptRootNode(getLanguage()) {
            @Override
            public Object execute(VirtualFrame frame) {
                Object[] arguments = frame.getArguments();
                Object obj = JSRuntime.requireObjectCoercible(JSArguments.getThisObject(arguments));
                if (JSArguments.getUserArgumentCount(arguments) < 1) {
                    return Undefined.instance;
                }
                Object value = JSArguments.getUserArgument(arguments, 0);
                if (!JSDynamicObject.isJSDynamicObject(value) || value == Undefined.instance) {
                    return Undefined.instance;
                }
                if (!JSDynamicObject.isJSDynamicObject(obj)) {
                    return Undefined.instance;
                }
                JSDynamicObject thisObj = (JSDynamicObject) obj;
                if (!JSObject.setPrototype(thisObj, (JSDynamicObject) value)) {
                    throw Errors.createTypeErrorCannotSetProto(thisObj, (JSDynamicObject) value);
                }
                return Undefined.instance;
            }

            @Override
            public String getName() {
                return JSObject.SET_PROTO_NAME.toJavaStringUncached();
            }
        }.getCallTarget();
        return JSFunctionData.createCallOnly(this, callTarget, 0, JSObject.SET_PROTO_NAME);
    }

    private JSFunctionData protoGetterFunction() {
        CallTarget callTarget = new JavaScriptRootNode(getLanguage()) {
            @Child private JSToObjectNode toObjectNode = JSToObjectNode.create();
            @Child private GetPrototypeNode getPrototypeNode = GetPrototypeNode.create();

            @Override
            public Object execute(VirtualFrame frame) {
                Object obj = toObjectNode.execute(JSArguments.getThisObject(frame.getArguments()));
                if (JSDynamicObject.isJSDynamicObject(obj)) {
                    return getPrototypeNode.execute(obj);
                }
                return Null.instance;
            }

            @Override
            public String getName() {
                return JSObject.GET_PROTO_NAME.toJavaStringUncached();
            }
        }.getCallTarget();
        return JSFunctionData.createCallOnly(this, callTarget, 0, JSObject.GET_PROTO_NAME);
    }

    public void checkEvalAllowed() {
        if (!languageOptions.allowEval()) {
            throw Errors.createEvalDisabled();
        }
    }

    public Locale getLocale() {
        Locale loc = locale;
        if (loc == null) {
            CompilerDirectives.transferToInterpreterAndInvalidate();
            loc = getLocaleImpl();
            locale = loc;
        }
        return loc;
    }

    @TruffleBoundary
    private Locale getLocaleImpl() {
        String name = getLanguageOptions().locale();
        if (name.isEmpty()) {
            return Locale.getDefault();
        } else {
            return Locale.forLanguageTag(name);
        }
    }

    public  T adoptNode(T node) {
        assert node.getParent() == null;
        sharedRootNode.insertAccessor(node);
        return node;
    }

    static final class SharedRootNode extends JavaScriptRootNode {
        @Override
        public Object execute(VirtualFrame frame) {
            throw Errors.shouldNotReachHere();
        }

        void insertAccessor(Node node) {
            CompilerAsserts.neverPartOfCompilation();
            super.insert(node);
        }
    }

    public boolean isOptionTopLevelAwait() {
        return getLanguageOptions().topLevelAwait();
    }

    public final Set getSupportedImportAttributes() {
        return supportedImportAttributes;
    }

    public static TruffleString getTypeImportAttribute() {
        return TYPE_IMPORT_ATTRIBUTE;
    }

    void updateStableOptions(JSContextOptions contextOptions, StableContextOptionValue.UpdateKind kind) {
        optionRegexpStaticResult.update(contextOptions, kind);
        optionV8CompatibilityMode.update(contextOptions, kind);
        optionDirectByteBuffer.update(contextOptions, kind);
        optionTimerResolution.update(contextOptions, kind);
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy