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

com.oracle.graal.python.util.PythonUtils Maven / Gradle / Ivy

There is a newer version: 24.1.1
Show newest version
/*
 * Copyright (c) 2020, 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.util;

import static com.oracle.graal.python.builtins.PythonBuiltinClassType.PString;
import static com.oracle.graal.python.builtins.PythonBuiltinClassType.SystemError;
import static com.oracle.graal.python.nodes.SpecialAttributeNames.T___DOC__;
import static com.oracle.graal.python.nodes.SpecialMethodNames.J___NEW__;
import static com.oracle.graal.python.nodes.SpecialMethodNames.T___NEW__;
import static com.oracle.graal.python.nodes.StringLiterals.T_EMPTY_STRING;
import static com.oracle.truffle.api.CompilerDirectives.shouldNotReachHere;

import java.lang.management.ManagementFactory;
import java.lang.reflect.Field;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import javax.management.InstanceNotFoundException;
import javax.management.MBeanException;
import javax.management.MBeanServer;
import javax.management.MalformedObjectNameException;
import javax.management.ObjectName;
import javax.management.ReflectionException;

import org.graalvm.nativeimage.ImageInfo;
import org.graalvm.polyglot.io.ByteSequence;

import com.oracle.graal.python.PythonLanguage;
import com.oracle.graal.python.builtins.Builtin;
import com.oracle.graal.python.builtins.PythonBuiltinClassType;
import com.oracle.graal.python.builtins.objects.PNone;
import com.oracle.graal.python.builtins.objects.ellipsis.PEllipsis;
import com.oracle.graal.python.builtins.objects.function.PBuiltinFunction;
import com.oracle.graal.python.builtins.objects.getsetdescriptor.GetSetDescriptor;
import com.oracle.graal.python.builtins.objects.method.PBuiltinMethod;
import com.oracle.graal.python.builtins.objects.str.PString;
import com.oracle.graal.python.nodes.ErrorMessages;
import com.oracle.graal.python.nodes.PRaiseNode;
import com.oracle.graal.python.nodes.attributes.WriteAttributeToObjectNode;
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.util.CastToTruffleStringNode;
import com.oracle.graal.python.pegparser.scope.ScopeEnvironment;
import com.oracle.graal.python.pegparser.sst.ConstantValue;
import com.oracle.graal.python.runtime.object.PythonObjectFactory;
import com.oracle.graal.python.runtime.object.PythonObjectSlowPathFactory;
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.TruffleOptions;
import com.oracle.truffle.api.dsl.NodeFactory;
import com.oracle.truffle.api.frame.Frame;
import com.oracle.truffle.api.frame.MaterializedFrame;
import com.oracle.truffle.api.interop.InteropLibrary;
import com.oracle.truffle.api.interop.UnsupportedMessageException;
import com.oracle.truffle.api.memory.ByteArraySupport;
import com.oracle.truffle.api.nodes.Node;
import com.oracle.truffle.api.nodes.NodeVisitor;
import com.oracle.truffle.api.nodes.RootNode;
import com.oracle.truffle.api.profiles.ConditionProfile;
import com.oracle.truffle.api.profiles.ValueProfile;
import com.oracle.truffle.api.source.Source;
import com.oracle.truffle.api.strings.TruffleString;
import com.oracle.truffle.api.strings.TruffleString.Encoding;

import sun.misc.Unsafe;

public final class PythonUtils {

    public static final ByteArraySupport ARRAY_ACCESSOR_LE = ByteArraySupport.littleEndian();
    public static final ByteArraySupport ARRAY_ACCESSOR_BE = ByteArraySupport.bigEndian();
    public static final ByteArraySupport ARRAY_ACCESSOR = ByteOrder.nativeOrder() == ByteOrder.LITTLE_ENDIAN ? ARRAY_ACCESSOR_LE : ARRAY_ACCESSOR_BE;
    public static final ByteArraySupport ARRAY_ACCESSOR_SWAPPED = ByteOrder.nativeOrder() == ByteOrder.LITTLE_ENDIAN ? ARRAY_ACCESSOR_BE : ARRAY_ACCESSOR_LE;

    public static final ConditionProfile[] DISABLED = new ConditionProfile[]{ConditionProfile.getUncached()};

    public static ByteArraySupport byteArraySupport(ByteOrder order) {
        return order == ByteOrder.LITTLE_ENDIAN ? ARRAY_ACCESSOR_LE : ARRAY_ACCESSOR_BE;
    }

    private PythonUtils() {
        // no instances
    }

    /**
     * Encoding of all {@link TruffleString} instances.
     */
    public static final TruffleString.Encoding TS_ENCODING = TruffleString.Encoding.UTF_32;

    public static final String[] EMPTY_STRING_ARRAY = new String[0];
    public static final TruffleString[] EMPTY_TRUFFLESTRING_ARRAY = new TruffleString[0];
    public static final Object[] EMPTY_OBJECT_ARRAY = new Object[0];
    public static final byte[] EMPTY_BYTE_ARRAY = new byte[0];
    public static final int[] EMPTY_INT_ARRAY = new int[0];
    public static final double[] EMPTY_DOUBLE_ARRAY = new double[0];
    public static final char[] EMPTY_CHAR_ARRAY = new char[0];
    public static final ByteSequence EMPTY_BYTE_SEQUENCE = ByteSequence.create(EMPTY_BYTE_ARRAY);

    /**
     * Returns an estimate for the initial capacity of a
     * {@link com.oracle.truffle.api.strings.TruffleStringBuilder}.
     *
     * @param cpCount the initial capacity in code points
     * @return the estimate in bytes
     */
    public static int tsbCapacity(int cpCount) {
        assert TS_ENCODING == Encoding.UTF_32;
        return 4 * cpCount;
    }

    /**
     * Uncached conversion of {@link String} to {@link TruffleString}. The intended use of this
     * method is in static initializers where the argument is a string literal (or a static final
     * constant).
     */
    @TruffleBoundary
    public static TruffleString tsLiteral(String s) {
        assert s != null;
        return TruffleString.fromConstant(s, TS_ENCODING);
    }

    /**
     * Uncached conversion of {@link String} to {@link TruffleString}. The intended use of this
     * method is in slow-path where the argument is a variable as a shortcut for
     * {@link TruffleString#fromJavaStringUncached(String, Encoding)}.
     */
    @TruffleBoundary
    public static TruffleString toTruffleStringUncached(String s) {
        return s == null ? null : TruffleString.fromJavaStringUncached(s, TS_ENCODING);
    }

    public static PString toPString(TruffleString name) {
        return new PString(PString, PString.getInstanceShape(PythonLanguage.get(null)), name);
    }

    /**
     * Creates an array of {@link TruffleString}s using uncached conversion. The intended use of
     * this method is in static initializers where the arguments are string literals as a shortcut
     * for {@code TruffleString[] X = {tsLiteral("a"), tsLiteral("b")};}
     */
    @TruffleBoundary
    public static TruffleString[] tsArray(String... s) {
        TruffleString[] result = new TruffleString[s.length];
        for (int i = 0; i < result.length; ++i) {
            result[i] = tsLiteral(s[i]);
        }
        return result;
    }

    /**
     * Creates an array of {@link TruffleString}s using uncached conversion. The intended use of
     * this method is in slow-path where the argument is a variable.
     */
    @TruffleBoundary
    public static TruffleString[] toTruffleStringArrayUncached(String[] s) {
        if (s == null) {
            return null;
        }
        if (s.length == 0) {
            return EMPTY_TRUFFLESTRING_ARRAY;
        }
        TruffleString[] result = new TruffleString[s.length];
        for (int i = 0; i < result.length; ++i) {
            result[i] = toTruffleStringUncached(s[i]);
        }
        return result;
    }

    /**
     * Creates an array of {@link Object}'s. The intended use of this method is in slow-path in
     * calls to methods like {@link PythonObjectFactory#createTuple(Object[])}.
     */
    public static Object[] convertToObjectArray(TruffleString[] src) {
        if (src == null) {
            return null;
        }
        if (src.length == 0) {
            return EMPTY_OBJECT_ARRAY;
        }
        Object[] result = new Object[src.length];
        for (int i = 0; i < src.length; ++i) {
            result[i] = src[i];
        }
        return result;
    }

    // parser.c:_Py_Mangle
    @TruffleBoundary
    public static TruffleString mangleName(TruffleString className, TruffleString name) {
        return toTruffleStringUncached(ScopeEnvironment.mangle(className.toJavaStringUncached(), name.toJavaStringUncached()));
    }

    @TruffleBoundary
    public static TruffleString getMessage(Exception ex) {
        return toTruffleStringUncached(ex.getMessage());
    }

    /**
     * Execute Arrays.fill and puts all exceptions on slow path.
     */
    public static void fill(byte[] array, int from, int to, byte value) {
        try {
            Arrays.fill(array, from, to, value);
        } catch (Throwable t) {
            // this is really unexpected and we want to break exception edges in compiled code
            CompilerDirectives.transferToInterpreterAndInvalidate();
            throw t;
        }
    }

    /**
     * Executes System.arraycopy and puts all exceptions on the slow path.
     */
    public static void arraycopy(Object src, int srcPos, Object dest, int destPos, int length) {
        try {
            System.arraycopy(src, srcPos, dest, destPos, length);
        } catch (Throwable t) {
            // this is really unexpected and we want to break exception edges in compiled code
            CompilerDirectives.transferToInterpreterAndInvalidate();
            throw t;
        }
    }

    /**
     * Executes {@link Arrays#copyOfRange(Object[], int, int)} and puts all exceptions on the slow
     * path.
     */
    public static  T[] arrayCopyOfRange(T[] original, int from, int to) {
        try {
            return Arrays.copyOfRange(original, from, to);
        } catch (Throwable t) {
            // this is really unexpected and we want to break exception edges in compiled code
            CompilerDirectives.transferToInterpreterAndInvalidate();
            throw t;
        }
    }

    /**
     * Executes {@link Arrays#copyOfRange(byte[], int, int)} and puts all exceptions on the slow
     * path.
     */
    public static byte[] arrayCopyOfRange(byte[] original, int from, int to) {
        try {
            return Arrays.copyOfRange(original, from, to);
        } catch (Throwable t) {
            // this is really unexpected and we want to break exception edges in compiled code
            CompilerDirectives.transferToInterpreterAndInvalidate();
            throw t;
        }
    }

    /**
     * Executes {@link Arrays#copyOf(Object[], int)} and puts all exceptions on the slow path.
     */
    public static  T[] arrayCopyOf(T[] original, int newLength) {
        try {
            return Arrays.copyOf(original, newLength);
        } catch (Throwable t) {
            // this is really unexpected and we want to break exception edges in compiled code
            CompilerDirectives.transferToInterpreterAndInvalidate();
            throw t;
        }
    }

    /**
     * Executes {@link Arrays#copyOf(char[], int)} and puts all exceptions on the slow path.
     */
    public static char[] arrayCopyOf(char[] original, int newLength) {
        try {
            return Arrays.copyOf(original, newLength);
        } catch (Throwable t) {
            // Break exception edges
            CompilerDirectives.transferToInterpreterAndInvalidate();
            throw t;
        }
    }

    /**
     * Executes {@link Arrays#copyOf(boolean[], int)} and puts all exceptions on the slow path.
     */
    public static boolean[] arrayCopyOf(boolean[] original, int newLength) {
        try {
            return Arrays.copyOf(original, newLength);
        } catch (Throwable t) {
            // Break exception edges
            CompilerDirectives.transferToInterpreterAndInvalidate();
            throw t;
        }
    }

    /**
     * Executes {@link Arrays#copyOf(byte[], int)} and puts all exceptions on the slow path.
     */
    public static byte[] arrayCopyOf(byte[] original, int newLength) {
        try {
            return Arrays.copyOf(original, newLength);
        } catch (Throwable t) {
            // Break exception edges
            CompilerDirectives.transferToInterpreterAndInvalidate();
            throw t;
        }
    }

    /**
     * Executes {@link Arrays#copyOf(int[], int)} and puts all exceptions on the slow path.
     */
    public static int[] arrayCopyOf(int[] original, int newLength) {
        try {
            return Arrays.copyOf(original, newLength);
        } catch (Throwable t) {
            // Break exception edges
            CompilerDirectives.transferToInterpreterAndInvalidate();
            throw t;
        }
    }

    /**
     * Executes {@link Arrays#copyOf(double[], int)} and puts all exceptions on the slow path.
     */
    public static double[] arrayCopyOf(double[] original, int newLength) {
        try {
            return Arrays.copyOf(original, newLength);
        } catch (Throwable t) {
            // Break exception edges
            CompilerDirectives.transferToInterpreterAndInvalidate();
            throw t;
        }
    }

    /**
     * Executes {@link Arrays#copyOf(long[], int)} and puts all exceptions on the slow path.
     */
    public static long[] arrayCopyOf(long[] original, int newLength) {
        try {
            return Arrays.copyOf(original, newLength);
        } catch (Throwable t) {
            // Break exception edges
            CompilerDirectives.transferToInterpreterAndInvalidate();
            throw t;
        }
    }

    /*
     * Replacements for JDK's exact math methods that throw the checked singleton {@link
     * OverflowException}. The implementation is taken from JDK.
     */
    public static int addExact(int x, int y) throws OverflowException {
        int r = x + y;
        if (((x ^ r) & (y ^ r)) < 0) {
            throw OverflowException.INSTANCE;
        }
        return r;
    }

    public static long addExact(long x, long y) throws OverflowException {
        long r = x + y;
        if (((x ^ r) & (y ^ r)) < 0) {
            throw OverflowException.INSTANCE;
        }
        return r;
    }

    public static int subtractExact(int x, int y) throws OverflowException {
        int r = x - y;
        if (((x ^ y) & (x ^ r)) < 0) {
            throw OverflowException.INSTANCE;
        }
        return r;
    }

    public static long subtractExact(long x, long y) throws OverflowException {
        long r = x - y;
        if (((x ^ y) & (x ^ r)) < 0) {
            throw OverflowException.INSTANCE;
        }
        return r;
    }

    public static int negateExact(int a) throws OverflowException {
        if (a == Integer.MIN_VALUE) {
            throw OverflowException.INSTANCE;
        }

        return -a;
    }

    public static long negateExact(long a) throws OverflowException {
        if (a == Long.MIN_VALUE) {
            throw OverflowException.INSTANCE;
        }

        return -a;
    }

    public static int toIntExact(long x) throws OverflowException {
        int r = (int) x;
        if (r != x) {
            throw OverflowException.INSTANCE;
        }
        return r;
    }

    public static int toIntError(long x) {
        int r = (int) x;
        if (r != x) {
            CompilerDirectives.transferToInterpreterAndInvalidate();
            throw PRaiseNode.raiseUncached(null, SystemError, ErrorMessages.INTERNAL_INT_OVERFLOW);
        }
        return r;
    }

    public static int multiplyExact(int x, int y) throws OverflowException {
        // copy&paste from Math.multiplyExact
        long r = (long) x * (long) y;
        if ((int) r != r) {
            throw OverflowException.INSTANCE;
        }
        return (int) r;
    }

    public static long multiplyExact(long x, long y) throws OverflowException {
        // copy&paste from Math.multiplyExact
        long r = x * y;
        long ax = Math.abs(x);
        long ay = Math.abs(y);
        if (((ax | ay) >>> 31 != 0)) {
            if (((y != 0) && (r / y != x)) || (x == Long.MIN_VALUE && y == -1)) {
                throw OverflowException.INSTANCE;
            }
        }
        return r;
    }

    private static final MBeanServer SERVER;
    private static final String OPERATION_NAME = "gcRun";
    private static final Object[] PARAMS = new Object[]{null};
    private static final String[] SIGNATURE = new String[]{String[].class.getName()};
    private static final ObjectName OBJECT_NAME;

    static {
        if (ImageInfo.inImageCode()) {
            OBJECT_NAME = null;
            SERVER = null;
        } else {
            SERVER = ManagementFactory.getPlatformMBeanServer();
            ObjectName n;
            try {
                n = new ObjectName("com.sun.management:type=DiagnosticCommand");
            } catch (final MalformedObjectNameException e) {
                n = null;
            }
            OBJECT_NAME = n;
        }
    }

    /**
     * {@link System#gc()} does not force a GC, but the DiagnosticCommand "gcRun" does.
     */
    @TruffleBoundary
    public static void forceFullGC() {
        if (OBJECT_NAME != null && SERVER != null) {
            try {
                SERVER.invoke(OBJECT_NAME, OPERATION_NAME, PARAMS, SIGNATURE);
            } catch (InstanceNotFoundException | ReflectionException | MBeanException e) {
                // use fallback
            }
        }
        System.gc();
        Runtime.getRuntime().freeMemory();
    }

    @TruffleBoundary
    public static void dumpHeap(String path) {
        if (SERVER != null) {
            try {
                Class mxBeanClass = Class.forName("com.sun.management.HotSpotDiagnosticMXBean");
                Object mxBean = ManagementFactory.newPlatformMXBeanProxy(SERVER,
                                "com.sun.management:type=HotSpotDiagnostic",
                                mxBeanClass);
                mxBeanClass.getMethod("dumpHeap", String.class, boolean.class).invoke(mxBean, path, true);
            } catch (Throwable e) {
                System.err.println("Cannot dump heap: " + e.getMessage());
                e.printStackTrace();
            }
        }
    }

    /**
     * Get the existing or create a new {@link CallTarget} for the provided root node.
     */
    @TruffleBoundary
    public static RootCallTarget getOrCreateCallTarget(RootNode rootNode) {
        return rootNode.getCallTarget();
    }

    @TruffleBoundary
    public static String formatJString(String fmt, Object... args) {
        return String.format(fmt, args);
    }

    @TruffleBoundary
    public static TruffleString getPythonArch() {
        String arch = System.getProperty("os.arch", "");
        if (arch.equals("amd64")) {
            // be compatible with CPython's designation
            arch = "x86_64";
        }
        return toTruffleStringUncached(arch);
    }

    @TruffleBoundary
    public static ByteBuffer allocateByteBuffer(int capacity) {
        return ByteBuffer.allocate(capacity);
    }

    @TruffleBoundary
    public static ByteBuffer wrapByteBuffer(byte[] array) {
        return ByteBuffer.wrap(array);
    }

    @TruffleBoundary
    public static ByteBuffer wrapByteBuffer(byte[] array, int offset, int length) {
        return ByteBuffer.wrap(array, offset, length);
    }

    @TruffleBoundary
    public static byte[] getBufferArray(ByteBuffer buffer) {
        return buffer.array();
    }

    @TruffleBoundary
    public static int getBufferPosition(ByteBuffer buffer) {
        return buffer.position();
    }

    @TruffleBoundary
    public static int getBufferLimit(ByteBuffer buffer) {
        return buffer.limit();
    }

    @TruffleBoundary
    public static int getBufferRemaining(ByteBuffer buffer) {
        return buffer.remaining();
    }

    @TruffleBoundary
    public static void flipBuffer(ByteBuffer buffer) {
        buffer.flip();
    }

    @TruffleBoundary
    public static boolean bufferHasRemaining(ByteBuffer buffer) {
        return buffer.hasRemaining();
    }

    @TruffleBoundary
    public static boolean equals(Object a, Object b) {
        return a.equals(b);
    }

    @TruffleBoundary
    public static  ArrayDeque newDeque() {
        return new ArrayDeque<>();
    }

    @TruffleBoundary
    public static  void push(ArrayDeque q, E e) {
        q.push(e);
    }

    @TruffleBoundary
    public static  E pop(ArrayDeque q) {
        return q.pop();
    }

    @TruffleBoundary
    public static  List newList() {
        return new ArrayList<>();
    }

    @TruffleBoundary
    public static  void add(List list, E e) {
        list.add(e);
    }

    @TruffleBoundary
    public static  E get(List list, int index) {
        return list.get(index);
    }

    @TruffleBoundary
    public static  Object[] toArray(List list) {
        return list.toArray();
    }

    /**
     * Same as {@link Character#isBmpCodePoint(int)}.
     */
    public static boolean isBmpCodePoint(int codePoint) {
        return codePoint >>> 16 == 0;
        // Optimized form of:
        // codePoint >= MIN_VALUE && codePoint <= MAX_VALUE
        // We consistently use logical shift (>>>) to facilitate
        // additional runtime optimizations.
    }

    public static ValueProfile createValueIdentityProfile() {
        CompilerAsserts.neverPartOfCompilation();
        return PythonLanguage.get(null).isSingleContext() ? ValueProfile.createIdentityProfile() : ValueProfile.createClassProfile();
    }

    @TruffleBoundary
    public static void createMember(PythonObjectSlowPathFactory factory, PythonLanguage language, Object klass, Class nodeClass, TruffleString name, TruffleString doc, int idx,
                    Function rootNodeSupplier) {
        RootCallTarget callTarget = language.createCachedCallTarget(rootNodeSupplier, nodeClass, idx);
        PBuiltinFunction getter = factory.createBuiltinFunction(name, klass, 0, 0, callTarget);
        GetSetDescriptor callable = factory.createGetSetDescriptor(getter, null, name, klass, false);
        if (doc != null) {
            callable.setAttribute(T___DOC__, doc);
        }
        WriteAttributeToObjectNode.getUncached(true).execute(klass, name, callable);
    }

    @TruffleBoundary
    public static PBuiltinFunction createMethod(PythonLanguage language, Object klass, Class nodeClass, Object type, int numDefaults, Supplier nodeSupplier,
                    Object... callTargetCacheKeys) {
        return createMethod(PythonObjectFactory.getUncached(), language, klass, nodeClass, type, numDefaults, nodeSupplier, callTargetCacheKeys);
    }

    @TruffleBoundary
    public static PBuiltinFunction createMethod(PythonObjectFactory factory, PythonLanguage language, Object klass, Class nodeClass, Object type, int numDefaults,
                    Supplier nodeSupplier,
                    Object... callTargetCacheKeys) {
        Builtin builtin = nodeClass.getAnnotation(Builtin.class);
        RootCallTarget callTarget = language.createCachedCallTarget(l -> {
            NodeFactory nodeFactory = new BuiltinFunctionRootNode.StandaloneBuiltinFactory<>(nodeSupplier.get());
            return new BuiltinFunctionRootNode(l, builtin, nodeFactory, true);
        }, nodeClass, createCalltargetKeys(callTargetCacheKeys, nodeClass));
        int flags = PBuiltinFunction.getFlags(builtin, callTarget);
        TruffleString name = toTruffleStringUncached(builtin.name());
        PBuiltinFunction function = factory.createBuiltinFunction(name, type, numDefaults, flags, callTarget);
        if (klass != null) {
            WriteAttributeToObjectNode.getUncached(true).execute(klass, name, function);
        }
        return function;
    }

    @TruffleBoundary
    public static void createConstructor(PythonObjectSlowPathFactory factory, PythonLanguage language, Object klass, Class nodeClass, Supplier nodeSupplier,
                    Object... callTargetCacheKeys) {
        Builtin builtin = nodeClass.getAnnotation(Builtin.class);
        assert J___NEW__.equals(builtin.name());
        assert IsSubtypeNode.getUncached().execute(klass, PythonBuiltinClassType.PTuple);
        RootCallTarget callTarget = language.createCachedCallTarget(l -> {
            NodeFactory nodeFactory = new BuiltinFunctionRootNode.StandaloneBuiltinFactory<>(nodeSupplier.get());
            return new BuiltinFunctionRootNode(l, builtin, nodeFactory, false, PythonBuiltinClassType.PTuple);
        }, nodeClass, createCalltargetKeys(callTargetCacheKeys, nodeClass));
        int flags = PBuiltinFunction.getFlags(builtin, callTarget);
        PBuiltinFunction function = factory.createBuiltinFunction(toTruffleStringUncached(builtin.name()), PythonBuiltinClassType.PTuple, 1, flags, callTarget);
        PBuiltinMethod method = factory.createBuiltinMethod(PythonBuiltinClassType.PTuple, function);
        WriteAttributeToObjectNode.getUncached(true).execute(klass, T___NEW__, method);
    }

    private static Object[] createCalltargetKeys(Object[] callTargetCacheKeys, Class nodeClass) {
        Object[] keys = new Object[callTargetCacheKeys.length + 1];
        keys[0] = nodeClass;
        arraycopy(callTargetCacheKeys, 0, keys, 1, callTargetCacheKeys.length);
        return keys;
    }

    public static Unsafe initUnsafe() {
        try {
            return Unsafe.getUnsafe();
        } catch (SecurityException se) {
            try {
                Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe");
                theUnsafe.setAccessible(true);
                return (Unsafe) theUnsafe.get(Unsafe.class);
            } catch (Exception e) {
                throw new UnsupportedOperationException("Cannot initialize Unsafe for the native backends", e);
            }
        }
    }

    public static void copyFrameSlot(Frame frameToSync, MaterializedFrame target, int slot) {
        if (frameToSync.isObject(slot)) {
            target.setObject(slot, frameToSync.getObject(slot));
        } else if (frameToSync.isInt(slot)) {
            target.setInt(slot, frameToSync.getInt(slot));
        } else if (frameToSync.isLong(slot)) {
            target.setLong(slot, frameToSync.getLong(slot));
        } else if (frameToSync.isBoolean(slot)) {
            target.setBoolean(slot, frameToSync.getBoolean(slot));
        } else if (frameToSync.isDouble(slot)) {
            target.setDouble(slot, frameToSync.getDouble(slot));
        } else if (frameToSync.isFloat(slot)) {
            target.setFloat(slot, frameToSync.getFloat(slot));
        } else if (frameToSync.isByte(slot)) {
            target.setByte(slot, frameToSync.getByte(slot));
        }
    }

    public static TruffleString[] objectArrayToTruffleStringArray(Node inliningTarget, Object[] array, CastToTruffleStringNode cast) {
        if (array.length == 0) {
            return EMPTY_TRUFFLESTRING_ARRAY;
        }
        TruffleString[] result = new TruffleString[array.length];
        for (int i = 0; i < array.length; i++) {
            result[i] = cast.execute(inliningTarget, array[i]);
        }
        return result;
    }

    public static Source createFakeSource() {
        return createFakeSource(T_EMPTY_STRING);
    }

    @TruffleBoundary
    public static Source createFakeSource(TruffleString name) {
        return Source.newBuilder(PythonLanguage.ID, EMPTY_BYTE_SEQUENCE, name.toJavaStringUncached()).build();
    }

    public static Object[] prependArgument(Object primary, Object[] arguments) {
        Object[] result = new Object[arguments.length + 1];
        result[0] = primary;
        arraycopy(arguments, 0, result, 1, arguments.length);
        return result;
    }

    public static final class NodeCounterWithLimit implements NodeVisitor {
        private int count;
        private final int limit;

        public NodeCounterWithLimit(int counterStart, int limit) {
            this.count = counterStart;
            this.limit = limit;
        }

        public NodeCounterWithLimit(int limit) {
            this.limit = limit;
        }

        public boolean visit(Node node) {
            return ++count < limit;
        }

        public int getCount() {
            return count;
        }

        public boolean isOverLimit() {
            return count >= limit;
        }
    }

    public static Object pythonObjectFromConstantValue(ConstantValue v, PythonObjectFactory factory) {
        switch (v.kind) {
            case BOOLEAN:
                return v.getBoolean();
            case LONG: {
                long l = v.getLong();
                if (l == (int) l) {
                    return (int) l;
                }
                return l;
            }
            case DOUBLE:
                return v.getDouble();
            case COMPLEX: {
                double[] c = v.getComplex();
                return factory.createComplex(c[0], c[1]);
            }
            case NONE:
                return PNone.NONE;
            case ELLIPSIS:
                return PEllipsis.INSTANCE;
            case BIGINTEGER:
                return factory.createInt(v.getBigInteger());
            case BYTES:
                return factory.createBytes(v.getBytes());
            case RAW:
                return v.getRaw(TruffleString.class);
            case TUPLE:
            case FROZENSET:
                // These cases cannot happen:
                // - when called from Sst2ObjVisitor, the SST comes from the parser which never
                // emits tuples or frozensets
                // - when called from the compiler of pattern matching, the SST has been checked by
                // Validator#validatePatternMatchValue() which rejects tuples and frozensets
            default:
                throw shouldNotReachHere();
        }
    }

    public static long crc32(int initialValue, byte[] bytes, int offset, int length) {
        int crc = ~initialValue;
        for (int i = 0; i < length; ++i) {
            crc = CRC_32_TAB[(crc ^ bytes[offset + i]) & 0xff] ^ (crc >>> 8);
        }
        return ~crc & 0xFFFFFFFFL;
    }

    private static final int[] CRC_32_TAB = {
                    0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,
                    0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91,
                    0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
                    0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5,
                    0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
                    0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
                    0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f,
                    0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d,
                    0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
                    0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
                    0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457,
                    0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
                    0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb,
                    0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9,
                    0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
                    0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad,
                    0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683,
                    0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
                    0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7,
                    0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
                    0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
                    0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79,
                    0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f,
                    0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
                    0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
                    0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21,
                    0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
                    0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45,
                    0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db,
                    0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
                    0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf,
                    0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
    };

    /**
     * Use as a documentation and safety guard in specializations that are meant to be activated
     * only in the uncached case. Those Specializations exist only to allow to generate an uncached
     * variant of the node, but should never be activated in a regular cached case.
     *
     * Note that such specializations can take VirtualFrame and should forward it to other uncached
     * (and cached) nodes. The uncached nodes may be executed during the uncached execution of the
     * bytecode root node where it is allowed to pass the VirtualFrame around without materializing
     * it.
     */
    public static void assertUncached() {
        if (!TruffleOptions.AOT) {
            // We cannot assert that it's never part of compilation, because then it would fail
            // during native-image build since it cannot prove that this Specialization is never
            // activated at runtime and includes this in runtime compiled methods.
            CompilerAsserts.neverPartOfCompilation();
        }
        CompilerDirectives.transferToInterpreter();
    }

    public static boolean isBitSet(int state, int position) {
        return ((state >>> position) & 0x1) != 0;
    }

    public static String formatPointer(Object pointer) {
        CompilerAsserts.neverPartOfCompilation();
        InteropLibrary lib = InteropLibrary.getUncached();
        if (lib.isPointer(pointer)) {
            try {
                return String.format("%s#0x%016x", pointer.getClass().getSimpleName(), lib.asPointer(pointer));
            } catch (UnsupportedMessageException e) {
                throw CompilerDirectives.shouldNotReachHere(e);
            }
        }
        return String.valueOf(pointer);
    }

    public static long coerceToLong(Object allocated, InteropLibrary lib) {
        if (allocated instanceof Long) {
            return (long) allocated;
        } else {
            if (!lib.isPointer(allocated)) {
                lib.toNative(allocated);
            }
            try {
                return lib.asPointer(allocated);
            } catch (UnsupportedMessageException e) {
                throw CompilerDirectives.shouldNotReachHere(e);
            }
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy