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

com.oracle.graal.python.builtins.modules.GraalPythonModuleBuiltins Maven / Gradle / Ivy

There is a newer version: 24.1.1
Show newest version
/*
 * Copyright (c) 2019, 2023, 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.graal.python.builtins.modules;

import static com.oracle.graal.python.PythonLanguage.J_GRAALPYTHON_ID;
import static com.oracle.graal.python.nodes.BuiltinNames.J_EXTEND;
import static com.oracle.graal.python.nodes.BuiltinNames.J___GRAALPYTHON__;
import static com.oracle.graal.python.nodes.BuiltinNames.T___GRAALPYTHON__;
import static com.oracle.graal.python.nodes.BuiltinNames.T___MAIN__;
import static com.oracle.graal.python.nodes.SpecialAttributeNames.T___NAME__;
import static com.oracle.graal.python.nodes.SpecialMethodNames.T_INSERT;
import static com.oracle.graal.python.nodes.StringLiterals.J_LLVM_LANGUAGE;
import static com.oracle.graal.python.nodes.StringLiterals.T_COLON;
import static com.oracle.graal.python.nodes.StringLiterals.T_EMPTY_STRING;
import static com.oracle.graal.python.nodes.StringLiterals.T_LLVM_LANGUAGE;
import static com.oracle.graal.python.nodes.StringLiterals.T_NATIVE;
import static com.oracle.graal.python.nodes.StringLiterals.T_PATH;
import static com.oracle.graal.python.nodes.StringLiterals.T_STRICT;
import static com.oracle.graal.python.nodes.StringLiterals.T_SURROGATEESCAPE;
import static com.oracle.graal.python.nodes.StringLiterals.T_UTF8;
import static com.oracle.graal.python.runtime.exception.PythonErrorType.ImportError;
import static com.oracle.graal.python.runtime.exception.PythonErrorType.SystemError;
import static com.oracle.graal.python.runtime.exception.PythonErrorType.TypeError;
import static com.oracle.graal.python.util.PythonUtils.TS_ENCODING;
import static com.oracle.graal.python.util.PythonUtils.toTruffleStringUncached;
import static com.oracle.graal.python.util.PythonUtils.tsLiteral;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.logging.Level;

import org.graalvm.nativeimage.ImageInfo;

import com.oracle.graal.python.PythonLanguage;
import com.oracle.graal.python.annotations.ArgumentClinic;
import com.oracle.graal.python.builtins.Builtin;
import com.oracle.graal.python.builtins.CoreFunctions;
import com.oracle.graal.python.builtins.Python3Core;
import com.oracle.graal.python.builtins.PythonBuiltinClassType;
import com.oracle.graal.python.builtins.PythonBuiltins;
import com.oracle.graal.python.builtins.modules.GraalPythonModuleBuiltinsFactory.DebugNodeFactory;
import com.oracle.graal.python.builtins.objects.PNone;
import com.oracle.graal.python.builtins.objects.bytes.PBytes;
import com.oracle.graal.python.builtins.objects.bytes.PBytesLike;
import com.oracle.graal.python.builtins.objects.cext.PythonAbstractNativeObject;
import com.oracle.graal.python.builtins.objects.cext.capi.CApiContext;
import com.oracle.graal.python.builtins.objects.cext.capi.PySequenceArrayWrapper.ToNativeStorageNode;
import com.oracle.graal.python.builtins.objects.code.CodeNodes;
import com.oracle.graal.python.builtins.objects.code.PCode;
import com.oracle.graal.python.builtins.objects.common.DynamicObjectStorage;
import com.oracle.graal.python.builtins.objects.common.EconomicMapStorage;
import com.oracle.graal.python.builtins.objects.common.EmptyStorage;
import com.oracle.graal.python.builtins.objects.common.HashingStorage;
import com.oracle.graal.python.builtins.objects.common.HashingStorageNodes.HashingStorageLen;
import com.oracle.graal.python.builtins.objects.dict.PDict;
import com.oracle.graal.python.builtins.objects.exception.OSErrorEnum;
import com.oracle.graal.python.builtins.objects.exception.OSErrorEnum.ErrorAndMessagePair;
import com.oracle.graal.python.builtins.objects.function.PBuiltinFunction;
import com.oracle.graal.python.builtins.objects.function.PFunction;
import com.oracle.graal.python.builtins.objects.function.PKeyword;
import com.oracle.graal.python.builtins.objects.generator.PGenerator;
import com.oracle.graal.python.builtins.objects.list.PList;
import com.oracle.graal.python.builtins.objects.method.PBuiltinMethod;
import com.oracle.graal.python.builtins.objects.method.PMethod;
import com.oracle.graal.python.builtins.objects.module.PythonModule;
import com.oracle.graal.python.builtins.objects.object.PythonObject;
import com.oracle.graal.python.builtins.objects.set.PSet;
import com.oracle.graal.python.builtins.objects.str.StringUtils;
import com.oracle.graal.python.builtins.objects.tuple.PTuple;
import com.oracle.graal.python.builtins.objects.type.PythonClass;
import com.oracle.graal.python.builtins.objects.type.TypeNodes.CreateTypeNode;
import com.oracle.graal.python.lib.PyObjectCallMethodObjArgs;
import com.oracle.graal.python.lib.PyObjectGetItem;
import com.oracle.graal.python.nodes.ErrorMessages;
import com.oracle.graal.python.nodes.PConstructAndRaiseNode;
import com.oracle.graal.python.nodes.builtins.FunctionNodes.GetCallTargetNode;
import com.oracle.graal.python.nodes.bytecode.PBytecodeRootNode;
import com.oracle.graal.python.nodes.call.CallNode;
import com.oracle.graal.python.nodes.classes.IsSubtypeNode;
import com.oracle.graal.python.nodes.function.BuiltinFunctionRootNode;
import com.oracle.graal.python.nodes.function.PythonBuiltinBaseNode;
import com.oracle.graal.python.nodes.function.PythonBuiltinNode;
import com.oracle.graal.python.nodes.function.builtins.PythonBinaryBuiltinNode;
import com.oracle.graal.python.nodes.function.builtins.PythonBinaryClinicBuiltinNode;
import com.oracle.graal.python.nodes.function.builtins.PythonQuaternaryBuiltinNode;
import com.oracle.graal.python.nodes.function.builtins.PythonUnaryBuiltinNode;
import com.oracle.graal.python.nodes.function.builtins.clinic.ArgumentClinicProvider;
import com.oracle.graal.python.nodes.object.GetClassNode;
import com.oracle.graal.python.nodes.statement.AbstractImportNode;
import com.oracle.graal.python.nodes.truffle.PythonArithmeticTypes;
import com.oracle.graal.python.nodes.util.CastToTruffleStringNode;
import com.oracle.graal.python.runtime.PosixSupportLibrary;
import com.oracle.graal.python.runtime.PythonContext;
import com.oracle.graal.python.runtime.PythonOptions;
import com.oracle.graal.python.runtime.exception.PException;
import com.oracle.graal.python.runtime.exception.PythonExitException;
import com.oracle.graal.python.runtime.object.PythonObjectFactory;
import com.oracle.graal.python.runtime.sequence.PSequence;
import com.oracle.graal.python.runtime.sequence.storage.NativeSequenceStorage;
import com.oracle.graal.python.runtime.sequence.storage.SequenceStorage;
import com.oracle.graal.python.util.PythonUtils;
import com.oracle.truffle.api.CallTarget;
import com.oracle.truffle.api.CompilerAsserts;
import com.oracle.truffle.api.CompilerDirectives;
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
import com.oracle.truffle.api.RootCallTarget;
import com.oracle.truffle.api.TruffleFile;
import com.oracle.truffle.api.TruffleLanguage.Env;
import com.oracle.truffle.api.TruffleLogger;
import com.oracle.truffle.api.dsl.Bind;
import com.oracle.truffle.api.dsl.Cached;
import com.oracle.truffle.api.dsl.Fallback;
import com.oracle.truffle.api.dsl.GenerateNodeFactory;
import com.oracle.truffle.api.dsl.NeverDefault;
import com.oracle.truffle.api.dsl.NodeFactory;
import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.dsl.TypeSystemReference;
import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.interop.InteropLibrary;
import com.oracle.truffle.api.interop.UnknownIdentifierException;
import com.oracle.truffle.api.interop.UnsupportedMessageException;
import com.oracle.truffle.api.library.CachedLibrary;
import com.oracle.truffle.api.nodes.LanguageInfo;
import com.oracle.truffle.api.nodes.Node;
import com.oracle.truffle.api.nodes.NodeUtil;
import com.oracle.truffle.api.nodes.RootNode;
import com.oracle.truffle.api.source.Source;
import com.oracle.truffle.api.strings.TruffleString;
import com.oracle.truffle.llvm.api.Toolchain;
import org.graalvm.home.Version;

@CoreFunctions(defineModule = J___GRAALPYTHON__, isEager = true)
public final class GraalPythonModuleBuiltins extends PythonBuiltins {
    private static final TruffleLogger LOGGER = PythonLanguage.getLogger(GraalPythonModuleBuiltins.class);

    private static final TruffleString T_PATH_HOOKS = tsLiteral("path_hooks");
    private static final TruffleString T_PATH_IMPORTER_CACHE = tsLiteral("path_importer_cache");
    private static final TruffleString T__RUN_MODULE_AS_MAIN = tsLiteral("_run_module_as_main");
    private static final TruffleString T_STDIO_ENCODING = tsLiteral("stdio_encoding");
    private static final TruffleString T_STDIO_ERROR = tsLiteral("stdio_error");

    @Override
    protected List> getNodeFactories() {
        return GraalPythonModuleBuiltinsFactory.getFactories();
    }

    @Override
    public void initialize(Python3Core core) {
        super.initialize(core);
        addBuiltinConstant("is_native", ImageInfo.inImageCode());
        PythonContext ctx = core.getContext();
        TruffleString encodingOpt = ctx.getLanguage().getEngineOption(PythonOptions.StandardStreamEncoding);
        TruffleString standardStreamEncoding = null;
        TruffleString standardStreamError = null;
        if (encodingOpt != null && !encodingOpt.isEmpty()) {
            TruffleString[] parts = StringUtils.split(encodingOpt, T_COLON, TruffleString.CodePointLengthNode.getUncached(), TruffleString.IndexOfStringNode.getUncached(),
                            TruffleString.SubstringNode.getUncached(), TruffleString.EqualNode.getUncached());
            if (parts.length > 0) {
                standardStreamEncoding = parts[0].isEmpty() ? T_UTF8 : parts[0];
                standardStreamError = parts.length > 1 && !parts[1].isEmpty() ? parts[1] : T_STRICT;
            }
        }
        if (standardStreamEncoding == null) {
            standardStreamEncoding = T_UTF8;
            standardStreamError = T_SURROGATEESCAPE;
        }

        if (LOGGER.isLoggable(Level.FINE)) {
            LOGGER.fine(String.format("Setting default stdio encoding to %s:%s", standardStreamEncoding, standardStreamError));
        }
        this.addBuiltinConstant(T_STDIO_ENCODING, standardStreamEncoding);
        this.addBuiltinConstant(T_STDIO_ERROR, standardStreamError);
        this.addBuiltinConstant("startup_wall_clock_ts", -1L);
        this.addBuiltinConstant("startup_nano", -1L);
        // we need these during core initialization, they are re-set in postInitialize
        postInitialize(core);
    }

    @Override
    public void postInitialize(Python3Core core) {
        super.postInitialize(core);
        PythonContext context = core.getContext();
        PythonModule mod = core.lookupBuiltinModule(T___GRAALPYTHON__);
        PythonLanguage language = context.getLanguage();
        if (!ImageInfo.inImageBuildtimeCode()) {
            mod.setAttribute(tsLiteral("home"), context.getLanguageHome());
        }
        mod.setAttribute(tsLiteral("in_image_buildtime"), ImageInfo.inImageBuildtimeCode());
        mod.setAttribute(tsLiteral("in_image"), ImageInfo.inImageCode());
        TruffleString coreHome = context.getCoreHome();
        TruffleString stdlibHome = context.getStdlibHome();
        TruffleString capiHome = context.getCAPIHome();
        Env env = context.getEnv();
        LanguageInfo llvmInfo = env.getInternalLanguages().get(J_LLVM_LANGUAGE);
        mod.setAttribute(tsLiteral("jython_emulation_enabled"), language.getEngineOption(PythonOptions.EmulateJython));
        mod.setAttribute(tsLiteral("host_import_enabled"), context.getEnv().isHostLookupAllowed());
        mod.setAttribute(tsLiteral("core_home"), coreHome);
        mod.setAttribute(tsLiteral("stdlib_home"), stdlibHome);
        mod.setAttribute(tsLiteral("capi_home"), capiHome);
        mod.setAttribute(tsLiteral("jni_home"), context.getJNIHome());
        Object[] arr = convertToObjectArray(PythonOptions.getExecutableList(context));
        PList executableList = PythonObjectFactory.getUncached().createList(arr);
        mod.setAttribute(tsLiteral("executable_list"), executableList);
        mod.setAttribute(tsLiteral("ForeignType"), core.lookupType(PythonBuiltinClassType.ForeignObject));
        mod.setAttribute(tsLiteral("use_system_toolchain"), context.getOption(PythonOptions.UseSystemToolchain));
        mod.setAttribute(tsLiteral("ext_mode"), context.getOption(PythonOptions.NativeModules) ? T_NATIVE : T_LLVM_LANGUAGE);

        if (!context.getOption(PythonOptions.EnableDebuggingBuiltins)) {
            mod.setAttribute(tsLiteral("dump_truffle_ast"), PNone.NO_VALUE);
            mod.setAttribute(tsLiteral("tdebug"), PNone.NO_VALUE);
            mod.setAttribute(tsLiteral("set_storage_strategy"), PNone.NO_VALUE);
            mod.setAttribute(tsLiteral("storage_to_native"), PNone.NO_VALUE);
            mod.setAttribute(tsLiteral("dump_heap"), PNone.NO_VALUE);
            mod.setAttribute(tsLiteral("is_native_object"), PNone.NO_VALUE);
        }
        if (PythonOptions.WITHOUT_PLATFORM_ACCESS || !context.getOption(PythonOptions.RunViaLauncher)) {
            mod.setAttribute(tsLiteral("list_files"), PNone.NO_VALUE);
        }
    }

    @TruffleBoundary
    TruffleString getStdIOEncoding() {
        return (TruffleString) getBuiltinConstant(T_STDIO_ENCODING);
    }

    @TruffleBoundary
    TruffleString getStdIOError() {
        return (TruffleString) getBuiltinConstant(T_STDIO_ERROR);
    }

    /**
     * Entry point for executing a path using the launcher, e.g. {@code python foo.py}
     */
    @Builtin(name = "run_path")
    @GenerateNodeFactory
    abstract static class RunPathNode extends PythonBuiltinNode {

        public static final TruffleString T_RUNPY = tsLiteral("runpy");

        @Specialization
        @TruffleBoundary
        PNone run() {
            /*
             * This node handles the part of pymain_run_python where the filename is not null. The
             * other paths through pymain_run_python are handled in GraalPythonMain and the path
             * prepending is done in PythonLanguage in those other cases
             */
            assert !ImageInfo.inImageBuildtimeCode();
            PythonContext context = getContext();
            TruffleString inputFilePath = context.getOption(PythonOptions.InputFilePath);
            PythonModule sysModule = context.getSysModule();
            boolean needsMainImporter = !inputFilePath.isEmpty() && getImporter(sysModule, inputFilePath);
            if (needsMainImporter) {
                Object sysPath = sysModule.getAttribute(T_PATH);
                PyObjectCallMethodObjArgs.getUncached().execute(null, null, sysPath, T_INSERT, 0, inputFilePath);
            } else {
                // This is normally done by PythonLanguage, but is suppressed when we have a path
                // argument
                context.addSysPath0();
            }

            if (needsMainImporter) {
                runModule(T___MAIN__, false);
            } else {
                runFile(context, inputFilePath);
            }
            return PNone.NONE;
        }

        // Equivalent of CPython's pymain_run_file and pymain_run_stdin
        private void runFile(PythonContext context, TruffleString inputFilePath) {
            Source source;
            try {
                Source.SourceBuilder builder;
                if (inputFilePath.isEmpty()) {
                    // Reading from stdin
                    builder = Source.newBuilder(PythonLanguage.ID, new InputStreamReader(context.getStandardIn()), "");
                } else {
                    TruffleFile file = context.getPublicTruffleFileRelaxed(inputFilePath);
                    builder = Source.newBuilder(PythonLanguage.ID, file);
                }
                source = builder.mimeType(PythonLanguage.MIME_TYPE).build();
                // TODO we should handle non-IO errors better
            } catch (IOException e) {
                ErrorAndMessagePair error = OSErrorEnum.fromException(e, TruffleString.EqualNode.getUncached());
                String msg = String.format("%s: can't open file '%s': [Errno %d] %s\n", context.getOption(PythonOptions.Executable), inputFilePath, error.oserror.getNumber(), error.message);
                // CPython uses fprintf(stderr, ...)
                try {
                    context.getStandardErr().write(msg.getBytes(StandardCharsets.UTF_8));
                } catch (IOException ioException) {
                    // Ignore
                }
                // The exit value is hardcoded in CPython too
                throw new PythonExitException(this, 2);
            }
            CallTarget callTarget = context.getEnv().parsePublic(source);
            callTarget.call(PythonUtils.EMPTY_OBJECT_ARRAY);
        }

        // Equivalent of CPython's pymain_run_module
        private static void runModule(TruffleString module, boolean setArgv0) {
            Object runpy = AbstractImportNode.importModule(T_RUNPY);
            PyObjectCallMethodObjArgs.executeUncached(runpy, T__RUN_MODULE_AS_MAIN, module, setArgv0);
        }

        // Equivalent of CPython's pymain_get_importer, but returns a boolean
        private static boolean getImporter(PythonModule sysModule, TruffleString inputFilePath) {
            Object importer = null;
            Object pathHooks = sysModule.getAttribute(T_PATH_HOOKS);
            Object pathImporterCache = sysModule.getAttribute(T_PATH_IMPORTER_CACHE);
            if (pathHooks instanceof PList && pathImporterCache instanceof PDict) {
                PDict pathImporterCacheDict = (PDict) pathImporterCache;
                importer = pathImporterCacheDict.getItem(inputFilePath);
                if (importer == null) {
                    /* set path_importer_cache[p] to None to avoid recursion */
                    pathImporterCacheDict.setItem(inputFilePath, PNone.NONE);
                    SequenceStorage storage = ((PList) pathHooks).getSequenceStorage();
                    Object[] hooks = storage.getInternalArray();
                    int numHooks = storage.length();
                    for (int i = 0; i < numHooks; i++) {
                        try {
                            importer = CallNode.getUncached().execute(hooks[i], inputFilePath);
                            break;
                        } catch (PException e) {
                            if (!IsSubtypeNode.getUncached().execute(GetClassNode.executeUncached(e.getUnreifiedException()), ImportError)) {
                                throw e;
                            }
                        }
                    }
                    if (importer != null) {
                        pathImporterCacheDict.setItem(inputFilePath, importer);
                    }
                }
            }
            return importer != null && importer != PNone.NONE;
        }
    }

    private static Object[] convertToObjectArray(TruffleString[] arr) {
        Object[] objectArr = new Object[arr.length];
        System.arraycopy(arr, 0, objectArr, 0, arr.length);
        return objectArr;
    }

    @Builtin(name = "read_file", minNumOfPositionalArgs = 1)
    @GenerateNodeFactory
    public abstract static class ReadFileNode extends PythonUnaryBuiltinNode {
        @Specialization
        PBytes doString(VirtualFrame frame, Object filenameObj,
                        @Bind("this") Node inliningTarget,
                        @Cached CastToTruffleStringNode castToTruffleStringNode,
                        @Cached TruffleString.EqualNode eqNode,
                        @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) {
            try {
                TruffleString filename = castToTruffleStringNode.execute(inliningTarget, filenameObj);
                TruffleFile file = getContext().getPublicTruffleFileRelaxed(filename, PythonLanguage.T_DEFAULT_PYTHON_EXTENSIONS);
                byte[] bytes = file.readAllBytes();
                return factory().createBytes(bytes);
            } catch (Exception ex) {
                ErrorAndMessagePair errAndMsg = OSErrorEnum.fromException(ex, eqNode);
                throw constructAndRaiseNode.get(inliningTarget).raiseOSError(frame, errAndMsg.oserror.getNumber(), errAndMsg.message);
            }
        }
    }

    @Builtin(name = "dump_truffle_ast", minNumOfPositionalArgs = 1)
    @GenerateNodeFactory
    public abstract static class DumpTruffleAstNode extends PythonUnaryBuiltinNode {
        @Specialization
        @TruffleBoundary
        public TruffleString doIt(PFunction func) {
            return toTruffleStringUncached(NodeUtil.printTreeToString(GetCallTargetNode.getUncached().execute(func).getRootNode()));
        }

        @Specialization(guards = "isFunction(method.getFunction())")
        @TruffleBoundary
        public TruffleString doIt(PMethod method) {
            return toTruffleStringUncached(NodeUtil.printTreeToString(GetCallTargetNode.getUncached().execute(method).getRootNode()));
        }

        @Specialization
        @TruffleBoundary
        public TruffleString doIt(PGenerator gen) {
            return toTruffleStringUncached(NodeUtil.printTreeToString(gen.getCurrentCallTarget().getRootNode()));
        }

        @Specialization
        @TruffleBoundary
        public TruffleString doIt(PCode code) {
            return toTruffleStringUncached(NodeUtil.printTreeToString(CodeNodes.GetCodeRootNode.executeUncached(code)));
        }

        @Fallback
        @TruffleBoundary
        public TruffleString doit(Object object) {
            return toTruffleStringUncached("truffle ast dump not supported for " + object.toString());
        }

        protected static boolean isFunction(Object callee) {
            return callee instanceof PFunction;
        }
    }

    @Builtin(name = "current_import", minNumOfPositionalArgs = 0)
    @GenerateNodeFactory
    public abstract static class CurrentImport extends PythonBuiltinNode {
        @Specialization
        TruffleString doIt() {
            return getContext().getCurrentImport();
        }
    }

    @Builtin(name = "tdebug", takesVarArgs = true)
    @GenerateNodeFactory
    public abstract static class DebugNode extends PythonBuiltinNode {

        public abstract Object execute(Object[] args);

        @Specialization
        @TruffleBoundary
        public Object doIt(Object[] args) {
            PrintWriter stdout = new PrintWriter(getContext().getStandardOut());
            for (int i = 0; i < args.length; i++) {
                stdout.println(args[i]);
            }
            stdout.flush();
            return PNone.NONE;
        }

        @NeverDefault
        public static DebugNode create() {
            return DebugNodeFactory.create(null);
        }
    }

    @Builtin(name = "builtin", minNumOfPositionalArgs = 1)
    @GenerateNodeFactory
    public abstract static class BuiltinNode extends PythonUnaryBuiltinNode {
        @Specialization
        public Object doIt(VirtualFrame frame, PFunction func,
                        @Bind("this") Node inliningTarget,
                        @Cached PyObjectGetItem getItem) {
            PFunction builtinFunc = convertToBuiltin(func);
            PythonObject globals = func.getGlobals();
            PythonModule builtinModule;
            if (globals instanceof PythonModule) {
                builtinModule = (PythonModule) globals;
            } else {
                TruffleString moduleName = (TruffleString) getItem.execute(frame, inliningTarget, globals, T___NAME__);
                builtinModule = getContext().lookupBuiltinModule(moduleName);
                assert builtinModule != null;
            }
            return factory().createBuiltinMethod(builtinModule, builtinFunc);
        }

        @TruffleBoundary
        public synchronized PFunction convertToBuiltin(PFunction func) {
            RootNode rootNode = CodeNodes.GetCodeRootNode.executeUncached(func.getCode());
            if (rootNode instanceof PBytecodeRootNode) {
                ((PBytecodeRootNode) rootNode).setPythonInternal(true);
            }
            func.setBuiltin(true);
            return func;
        }
    }

    @Builtin(name = "builtin_method", minNumOfPositionalArgs = 1)
    @GenerateNodeFactory
    public abstract static class BuiltinMethodNode extends PythonUnaryBuiltinNode {
        @Specialization
        public Object doIt(PFunction func,
                        @Bind("this") Node inliningTarget,
                        @Cached CodeNodes.GetCodeRootNode getRootNode) {
            RootNode rootNode = getRootNode.execute(inliningTarget, func.getCode());
            if (rootNode instanceof PBytecodeRootNode) {
                ((PBytecodeRootNode) rootNode).setPythonInternal(true);
            }
            return func;
        }
    }

    @Builtin(name = "force_split_direct_calls", minNumOfPositionalArgs = 1)
    @GenerateNodeFactory
    public abstract static class ForceSplitDirectCallsNode extends PythonUnaryBuiltinNode {
        @Specialization
        public Object doIt(PFunction func) {
            func.setForceSplitDirectCalls(true);
            return func;
        }
    }

    @Builtin(name = "get_toolchain_tools_for_venv")
    @TypeSystemReference(PythonArithmeticTypes.class)
    @GenerateNodeFactory
    public abstract static class GetToolchainToolsForVenv extends PythonBuiltinNode {
        private static final class Tool {
            final String name;
            final boolean isVariableName;
            final Object[] targets;

            public Tool(String name, boolean isVariableName, Object[] targets) {
                this.name = name;
                this.isVariableName = isVariableName;
                this.targets = targets;
            }

            static Tool forVariable(String name, Object... targets) {
                return new Tool(name, true, targets);
            }

            static Tool forBinary(String name, Object... targets) {
                return new Tool(name, true, targets);
            }
        }

        static final Tool[] tools = new Tool[]{
                        Tool.forVariable("AR", tsLiteral("ar")),
                        Tool.forVariable("RANLIB", tsLiteral("ranlib")),
                        Tool.forVariable("NM", tsLiteral("nm")),
                        Tool.forVariable("LD", tsLiteral("ld.lld"), tsLiteral("ld"), tsLiteral("lld")),
                        Tool.forVariable("CC", tsLiteral("clang"), tsLiteral("cc")),
                        Tool.forVariable("CXX", tsLiteral("clang++"), tsLiteral("c++")),
                        Tool.forVariable("FC", tsLiteral("graalvm-flang"), tsLiteral("flang-new"), tsLiteral("flang")),
                        Tool.forBinary("llvm-as", tsLiteral("as")),
                        Tool.forBinary("clang-cl", tsLiteral("cl")),
                        Tool.forBinary("clang-cpp", tsLiteral("cpp")),
        };

        @Specialization
        @TruffleBoundary
        protected Object getToolPath() {
            Env env = getContext().getEnv();
            LanguageInfo llvmInfo = env.getInternalLanguages().get(J_LLVM_LANGUAGE);
            Toolchain toolchain = env.lookup(llvmInfo, Toolchain.class);
            List toolchainPaths = toolchain.getPaths("PATH");
            EconomicMapStorage storage = EconomicMapStorage.create(tools.length);
            for (Tool tool : tools) {
                String path = null;
                if (tool.isVariableName) {
                    TruffleFile toolPath = toolchain.getToolPath(tool.name);
                    if (toolPath != null) {
                        path = toolPath.getAbsoluteFile().getPath();
                    }
                } else {
                    for (TruffleFile toolchainPath : toolchainPaths) {
                        LOGGER.finest(() -> " Testing path " + toolchainPath.getPath() + " for tool " + tool.name);
                        TruffleFile pathToTest = toolchainPath.resolve(tool.name);
                        if (pathToTest.exists()) {
                            path = pathToTest.getAbsoluteFile().getPath();
                            break;
                        }
                    }
                }
                if (path != null) {
                    storage.putUncached(toTruffleStringUncached(path), factory().createTuple(tool.targets));
                } else {
                    LOGGER.fine("Could not locate tool " + tool.name);
                }
            }
            return factory().createDict(storage);
        }
    }

    /*
     * Internal check used in tests only to check that we are running through managed launcher.
     */
    @Builtin(name = "is_managed_launcher")
    @TypeSystemReference(PythonArithmeticTypes.class)
    @GenerateNodeFactory
    public abstract static class IsManagedLauncher extends PythonBuiltinNode {
        @Specialization
        @TruffleBoundary
        protected boolean isManaged() {
            // The best approximation for now
            return !getContext().getEnv().isNativeAccessAllowed() && getContext().getOption(PythonOptions.RunViaLauncher);
        }
    }

    @Builtin(name = "get_toolchain_tool_path", minNumOfPositionalArgs = 1)
    @TypeSystemReference(PythonArithmeticTypes.class)
    @GenerateNodeFactory
    public abstract static class GetToolPathNode extends PythonUnaryBuiltinNode {
        @Specialization
        @TruffleBoundary
        protected Object getToolPath(TruffleString tool) {
            Env env = getContext().getEnv();
            LanguageInfo llvmInfo = env.getInternalLanguages().get(J_LLVM_LANGUAGE);
            Toolchain toolchain = env.lookup(llvmInfo, Toolchain.class);
            TruffleFile toolPath = toolchain.getToolPath(tool.toJavaStringUncached());
            if (toolPath == null) {
                return PNone.NONE;
            }
            return toTruffleStringUncached(toolPath.toString().replace("\\", "/"));
        }
    }

    @Builtin(name = "get_platform_id", minNumOfPositionalArgs = 0)
    @TypeSystemReference(PythonArithmeticTypes.class)
    @GenerateNodeFactory
    public abstract static class GetPlatformId extends PythonBuiltinNode {
        @Specialization
        @TruffleBoundary
        protected TruffleString getPlatformId() {
            return getContext().getPlatformId();
        }

    }

    @Builtin(name = "get_toolchain_paths", minNumOfPositionalArgs = 1)
    @TypeSystemReference(PythonArithmeticTypes.class)
    @GenerateNodeFactory
    public abstract static class GetToolchainPathsNode extends PythonUnaryBuiltinNode {
        @Specialization
        @TruffleBoundary
        protected Object getToolPath(TruffleString tool) {
            Env env = getContext().getEnv();
            LanguageInfo llvmInfo = env.getInternalLanguages().get(J_LLVM_LANGUAGE);
            Toolchain toolchain = env.lookup(llvmInfo, Toolchain.class);
            List toolPaths = toolchain.getPaths(tool.toJavaStringUncached());
            if (toolPaths == null) {
                return PNone.NONE;
            }
            Object[] pathNames = new Object[toolPaths.size()];
            for (int i = 0; i < pathNames.length; i++) {
                pathNames[i] = toTruffleStringUncached(toolPaths.get(i).toString().replace("\\", "/"));
            }
            return PythonObjectFactory.getUncached().createList(pathNames);
        }
    }

    @Builtin(name = "determine_system_toolchain", maxNumOfPositionalArgs = 1)
    @GenerateNodeFactory
    public abstract static class DetermineSystemToolchain extends PythonUnaryBuiltinNode {
        /**
         * This is derived from {@code distutils.unixccompiler._is_gcc}
         */
        private static final String[] C_COMPILER_PRECEDENCE = {"gcc", "clang"};
        private static final String[] CXX_COMPILER_PRECEDENCE = {"g++", "clang++"};

        private static final PKeyword[] GENERIC_TOOLCHAIN = {
                        new PKeyword(tsLiteral("CC"), tsLiteral("cc")),
                        new PKeyword(tsLiteral("CXX"), tsLiteral("c++")),
                        new PKeyword(tsLiteral("AR"), tsLiteral("ar")),
                        new PKeyword(tsLiteral("RANLIB"), tsLiteral("ranlib")),
                        new PKeyword(tsLiteral("LD"), tsLiteral("ld")),
                        new PKeyword(tsLiteral("NM"), tsLiteral("nm"))
        };

        @Specialization
        PDict doGeneric(@SuppressWarnings("unused") Object unused) {
            return factory().createDict(fromToolchain());
        }

        @TruffleBoundary
        private static PKeyword[] fromToolchain() {
            PKeyword[] result = GENERIC_TOOLCHAIN;
            int id = which();
            if (id >= 0) {
                assert id < C_COMPILER_PRECEDENCE.length;
                result = Arrays.copyOf(GENERIC_TOOLCHAIN, GENERIC_TOOLCHAIN.length);
                result[0] = new PKeyword(tsLiteral("CC"), tsLiteral(C_COMPILER_PRECEDENCE[id]));
                result[1] = new PKeyword(tsLiteral("CXX"), tsLiteral(CXX_COMPILER_PRECEDENCE[id]));
            }
            return result;
        }

        private static int which() {
            CompilerAsserts.neverPartOfCompilation();
            String path = System.getenv("PATH");
            if (path != null) {
                for (int i = 0; i < C_COMPILER_PRECEDENCE.length; i++) {
                    int last = 0;
                    for (int j = path.indexOf(File.pathSeparatorChar); j != -1; j = path.indexOf(File.pathSeparatorChar, last)) {
                        Path resolvedProgramName = Paths.get(path.substring(last, j)).resolve(C_COMPILER_PRECEDENCE[i]);
                        if (Files.isExecutable(resolvedProgramName)) {
                            return i;
                        }
                        /*
                         * next start is the char after the separator because we have "path0:path1"
                         * and 'i' points to ':'
                         */
                        last = j + 1;
                    }
                }
            }
            return -1;
        }
    }

    @Builtin(name = "posix_module_backend", minNumOfPositionalArgs = 0)
    @GenerateNodeFactory
    public abstract static class PosixModuleBackendNode extends PythonBuiltinNode {
        @Specialization
        TruffleString posixModuleBackend(
                        @CachedLibrary("getPosixSupport()") PosixSupportLibrary posixLib) {
            return posixLib.getBackend(getPosixSupport());
        }
    }

    @Builtin(name = "time_millis", minNumOfPositionalArgs = 0, maxNumOfPositionalArgs = 1, doc = "Like time.time() but in milliseconds resolution.")
    @GenerateNodeFactory
    public abstract static class TimeMillis extends PythonUnaryBuiltinNode {
        @Specialization
        @TruffleBoundary
        static long doIt(@SuppressWarnings("unused") Object dummy) {
            return System.currentTimeMillis();
        }
    }

// Internal builtin used for testing: changes strategy of newly allocated set or map
    @Builtin(name = "set_storage_strategy", minNumOfPositionalArgs = 2)
    @GenerateNodeFactory
    public abstract static class SetStorageStrategyNode extends PythonBinaryBuiltinNode {
        @Specialization
        Object doSet(PSet set, TruffleString strategyName) {
            validate(set.getDictStorage());
            set.setDictStorage(getStrategy(strategyName, getLanguage()));
            return set;
        }

        @Specialization
        Object doDict(PDict dict, TruffleString strategyName) {
            validate(dict.getDictStorage());
            dict.setDictStorage(getStrategy(strategyName, getLanguage()));
            return dict;
        }

        private HashingStorage getStrategy(TruffleString tname, PythonLanguage lang) {
            String name = tname.toJavaStringUncached();
            switch (name) {
                case "empty":
                    return EmptyStorage.INSTANCE;
                case "dynamicobject":
                    return new DynamicObjectStorage(lang);
                case "economicmap":
                    return EconomicMapStorage.create();
                default:
                    throw raise(PythonBuiltinClassType.ValueError, ErrorMessages.UNKNOWN_STORAGE_STRATEGY);
            }
        }

        private void validate(HashingStorage dictStorage) {
            if (HashingStorageLen.executeUncached(dictStorage) != 0) {
                throw raise(PythonBuiltinClassType.ValueError, ErrorMessages.SHOULD_BE_USED_ONLY_NEW_SETS);
            }
        }
    }

    @Builtin(name = "storage_to_native", minNumOfPositionalArgs = 1)
    @GenerateNodeFactory
    abstract static class StorageToNative extends PythonUnaryBuiltinNode {
        @Specialization
        @TruffleBoundary
        Object toNative(PBytesLike bytes) {
            ensureCapi();
            NativeSequenceStorage newStorage = ToNativeStorageNode.getUncached().execute(bytes.getSequenceStorage(), true);
            bytes.setSequenceStorage(newStorage);
            return bytes;
        }

        @Specialization
        @TruffleBoundary
        Object toNative(PSequence sequence) {
            ensureCapi();
            NativeSequenceStorage newStorage = ToNativeStorageNode.getUncached().execute(sequence.getSequenceStorage(), false);
            sequence.setSequenceStorage(newStorage);
            return sequence;
        }

        private void ensureCapi() {
            try {
                CApiContext.ensureCapiWasLoaded(null, getContext(), T_EMPTY_STRING, T_EMPTY_STRING);
            } catch (Exception e) {
                throw CompilerDirectives.shouldNotReachHere(e);
            }
        }
    }

    @Builtin(name = J_EXTEND, minNumOfPositionalArgs = 1, doc = "Extends Java class and return HostAdapterCLass")
    @GenerateNodeFactory
    public abstract static class JavaExtendNode extends PythonUnaryBuiltinNode {
        @Specialization
        Object doIt(Object value,
                        @CachedLibrary(limit = "3") InteropLibrary lib) {
            if (ImageInfo.inImageBuildtimeCode()) {
                CompilerDirectives.transferToInterpreterAndInvalidate();
                throw new UnsupportedOperationException(ErrorMessages.CANT_EXTEND_JAVA_CLASS_NOT_JVM.toJavaStringUncached());
            }
            if (ImageInfo.inImageRuntimeCode()) {
                CompilerDirectives.transferToInterpreterAndInvalidate();
                throw raise(SystemError, ErrorMessages.CANT_EXTEND_JAVA_CLASS_NOT_JVM);
            }

            Env env = getContext().getEnv();
            if (!isType(value, env, lib)) {
                throw raise(TypeError, ErrorMessages.CANT_EXTEND_JAVA_CLASS_NOT_TYPE, value);
            }

            try {
                return env.createHostAdapter(new Object[]{value});
            } catch (Exception ex) {
                throw raise(TypeError, PythonUtils.getMessage(ex), ex);
            }
        }

        protected static boolean isType(Object obj, Env env, InteropLibrary lib) {
            return env.isHostObject(obj) && (env.isHostSymbol(obj) || lib.isMetaObject(obj));
        }

    }

    @Builtin(name = "dis", minNumOfPositionalArgs = 1, parameterNames = {"obj", "quickened"}, doc = "Helper to disassemble code objects")
    @ArgumentClinic(name = "quickened", conversion = ArgumentClinic.ClinicConversion.Boolean, defaultValue = "false")
    @GenerateNodeFactory
    abstract static class DisNode extends PythonBinaryClinicBuiltinNode {
        @Specialization
        Object doMethod(PMethod method, boolean quickened) {
            final Object function = method.getFunction();
            if (function instanceof PFunction) {
                return doFunction((PFunction) function, quickened);
            }
            return PNone.NONE;
        }

        @Specialization
        Object doFunction(PFunction function, boolean quickened) {
            return doCode(function.getCode(), quickened);
        }

        @Specialization
        @TruffleBoundary
        Object doCode(PCode code, boolean quickened) {
            return toTruffleStringUncached(code.toDisassembledString(quickened));
        }

        @Fallback
        @SuppressWarnings("unused")
        Object doObject(Object value, Object quickened) {
            return PNone.NONE;
        }

        @Override
        protected ArgumentClinicProvider getArgumentClinic() {
            return GraalPythonModuleBuiltinsClinicProviders.DisNodeClinicProviderGen.INSTANCE;
        }
    }

    @Builtin(name = "super", minNumOfPositionalArgs = 1, doc = "Returns HostAdapter instance of the object or None")
    @GenerateNodeFactory
    public abstract static class JavaSuperNode extends PythonUnaryBuiltinNode {
        @Specialization
        @TruffleBoundary
        Object doIt(Object value) {
            try {
                return InteropLibrary.getUncached().readMember(value, "super");
            } catch (UnsupportedMessageException | UnknownIdentifierException e) {
                return PNone.NONE;
            }
        }
    }

    @Builtin(name = "which", minNumOfPositionalArgs = 1)
    @GenerateNodeFactory
    abstract static class WhichNode extends PythonUnaryBuiltinNode {
        @Specialization
        @TruffleBoundary
        Object which(PBuiltinFunction object) {
            RootCallTarget callTarget = object.getCallTarget();
            return toTruffleStringUncached(String.format("%s(%s)", object.getClass().getName(), whichCallTarget(callTarget)));
        }

        @Specialization
        @TruffleBoundary
        Object which(PBuiltinMethod object) {
            return toTruffleStringUncached(String.format("%s(%s)", object.getClass().getName(), whichCallTarget(object.getBuiltinFunction().getCallTarget())));
        }

        private static String whichCallTarget(RootCallTarget callTarget) {
            RootNode rootNode = callTarget.getRootNode();
            String rootStr;
            if (rootNode instanceof BuiltinFunctionRootNode builtinFunctionRootNode) {
                rootStr = String.format("nodeClass=%s", builtinFunctionRootNode.getFactory().getNodeClass().getName());
            } else {
                rootStr = String.format("root=%s", rootNode.getClass().getName());
            }
            return rootStr;
        }

        @Specialization
        @TruffleBoundary
        Object which(Object object) {
            return toTruffleStringUncached(object.getClass().getName());
        }
    }

    @Builtin(name = "dump_heap", minNumOfPositionalArgs = 0)
    @GenerateNodeFactory
    abstract static class DumpHeapNode extends PythonBuiltinNode {
        @Specialization
        TruffleString doit(VirtualFrame frame,
                        @Bind("this") Node inliningTarget,
                        @Cached TruffleString.FromJavaStringNode fromJavaStringNode,
                        @Cached TruffleString.EqualNode eqNode,
                        @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) {
            TruffleFile tempFile;
            try {
                PythonContext context = getContext();
                tempFile = context.getEnv().createTempFile(context.getEnv().getCurrentWorkingDirectory(), J_GRAALPYTHON_ID, ".hprof");
                tempFile.delete();
            } catch (IOException e) {
                throw constructAndRaiseNode.get(inliningTarget).raiseOSError(frame, e, eqNode);
            }
            PythonUtils.dumpHeap(tempFile.getPath());
            return fromJavaStringNode.execute(tempFile.getPath(), TS_ENCODING);
        }
    }

    @Builtin(name = "java_assert", minNumOfPositionalArgs = 0)
    @GenerateNodeFactory
    abstract static class JavaAssertNode extends PythonBuiltinNode {
        @Specialization
        Object doit() {
            boolean assertOn = false;
            assert assertOn = true;
            return assertOn;
        }
    }

    @Builtin(name = "is_native_object", minNumOfPositionalArgs = 1)
    @GenerateNodeFactory
    abstract static class IsNativeObject extends PythonUnaryBuiltinNode {
        @Specialization
        boolean isNative(@SuppressWarnings("unused") PythonAbstractNativeObject obj) {
            return true;
        }

        @Fallback
        boolean isNative(@SuppressWarnings("unused") Object obj) {
            return false;
        }

    }

    // This is only used from HPy
    @Builtin(name = "PyTruffle_CreateType", minNumOfPositionalArgs = 4)
    @GenerateNodeFactory
    abstract static class PyTruffle_CreateType extends PythonQuaternaryBuiltinNode {
        @Specialization
        static PythonClass createType(VirtualFrame frame, TruffleString name, PTuple bases, PDict namespaceOrig, Object metaclass,
                        @Cached CreateTypeNode createType) {
            return createType.execute(frame, namespaceOrig, name, bases, metaclass, PKeyword.EMPTY_KEYWORDS);
        }
    }

    @Builtin(name = "list_files", minNumOfPositionalArgs = 2)
    @GenerateNodeFactory
    abstract static class ListFiles extends PythonBinaryBuiltinNode {
        @TruffleBoundary
        @Specialization
        Object list(TruffleString dirPath, TruffleString filesListPath) {
            if (PythonOptions.WITHOUT_PLATFORM_ACCESS) {
                throw CompilerDirectives.shouldNotReachHere();
            }
            print(getContext().getStandardOut(), String.format("listing files from '%s' to '%s'\n", dirPath, filesListPath));

            TruffleFile dir = getContext().getPublicTruffleFileRelaxed(dirPath);
            if (!dir.exists() || !dir.isDirectory()) {
                print(getContext().getStandardErr(), String.format("'%s' has to exist and be a directory.\n", dirPath));
            }

            try (BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(filesListPath.toJavaStringUncached())))) {
                TruffleFile p = getContext().getPublicTruffleFileRelaxed(filesListPath).getParent();
                if (!p.exists()) {
                    getContext().getPublicTruffleFileRelaxed(filesListPath).getParent().createDirectories();
                }
                Set ret = list(dir, null);
                String[] a = ret.toArray(new String[ret.size()]);
                Arrays.sort(a);
                for (String f : a) {
                    if (f.charAt(0) == '\\') {
                        f = f.replace("\\", "/");
                    }

                    bw.write(f);
                    bw.write("\n");
                }
            } catch (IOException e) {
                String msg = String.format("error while creating '%s': %s \n", filesListPath, e);
                print(getContext().getStandardErr(), msg);
            }
            return PNone.NONE;
        }

        private static Set list(TruffleFile dir, TruffleFile rd) throws IOException {
            HashSet ret = new HashSet<>();
            Collection files = dir.list();
            String dirPath = makeDirPath(dir.getAbsoluteFile().getPath());

            // add dir
            TruffleFile rootDir = rd == null ? dir : rd;
            String rootPath = makeDirPath(rootDir.getAbsoluteFile().getPath());
            int rootEndIdx = rootPath.lastIndexOf(File.separator, rootPath.lastIndexOf(File.separator) - 1);
            ret.add(dirPath.substring(rootEndIdx));

            // add parents up to root
            TruffleFile parent = dir;
            while (!parent.equals(rootDir)) {
                String p = makeDirPath(parent.getAbsoluteFile().getPath());
                p = p.substring(rootEndIdx);
                ret.add(p);
                parent = parent.getParent();
            }

            // add children
            if (files != null) {
                for (TruffleFile f : files) {
                    if (f.isRegularFile()) {
                        ret.add(f.getAbsoluteFile().getPath().substring(rootEndIdx));
                    } else {
                        ret.addAll(list(f, rootDir));
                    }
                }
            }
            return ret;
        }

        private static String makeDirPath(String p) {
            if (!p.endsWith(File.separator)) {
                p = p + File.separator;
            }
            return p;
        }

        private void print(OutputStream out, String msg) {
            try {
                out.write(String.format("%s: %s", getContext().getOption(PythonOptions.Executable), msg).getBytes(StandardCharsets.UTF_8));
            } catch (IOException ioException) {
                // Ignore
            }
        }
    }

    @Builtin(name = "get_graalvm_version", minNumOfPositionalArgs = 0)
    @GenerateNodeFactory
    abstract static class GetGraalVmVersion extends PythonBuiltinNode {
        @TruffleBoundary
        @Specialization
        TruffleString get() {
            Version current = Version.getCurrent();
            return TruffleString.fromJavaStringUncached(current.toString(), TS_ENCODING);
        }
    }

    @Builtin(name = "get_jdk_version", minNumOfPositionalArgs = 0)
    @GenerateNodeFactory
    abstract static class GetJdkVersion extends PythonBuiltinNode {
        @TruffleBoundary
        @Specialization
        TruffleString get() {
            return TruffleString.fromJavaStringUncached(System.getProperty("java.version"), TS_ENCODING);
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy