diff --git a/graalpython/com.oracle.graal.python.test/src/tests/test_int.py b/graalpython/com.oracle.graal.python.test/src/tests/test_int.py index 4a7bdf9c05..e5095dbd8f 100644 --- a/graalpython/com.oracle.graal.python.test/src/tests/test_int.py +++ b/graalpython/com.oracle.graal.python.test/src/tests/test_int.py @@ -150,11 +150,41 @@ def test_bigint_mul(): assert 99999937497465632974931 * 1223432423545234234123123 == 122343165886896325043539375228725106116626429513 assert 99999937497465632974931 * (2**100) == 126764980791447734004805377032945185921379990352429056 + +def test_bigint_mul_powers_of_two(): + for shift in (0, 1, 31, 32, 63, 64, 127, 1024, 8192): + power = 1 << shift + for value in (0, 1, -1, 3, -3, (1 << 100) + 7, -((1 << 100) + 7)): + expected = value << shift + assert value * power == expected + assert power * value == expected + assert value * -power == -expected + assert value * (power + 1) == expected + value + assert value * (power - 1) == expected - value + assert value * -(power + 1) == -expected - value + + def test_floordiv(): assert 0 // (-92233720368547394651) == 0 assert -234 // (-92233720368547394651) == 0 assert 234 // (-92233720368547394651) == -1 + +def test_bigint_floordiv_small_quotient(): + for bits in (128, 129, 130, 256, 1024, 8192): + for divisor in (1 << (bits - 1), + (1 << (bits - 1)) + (1 << (bits - 32)) - 1, + (1 << bits) - 1): + for quotient in (0, 1, 2, 3, 9, 31, (1 << 30) - 1, 1 << 30, (1 << 31) - 1, 1 << 31): + for remainder in (0, 1, divisor >> 1, divisor - 1): + dividend = quotient * divisor + remainder + negative_quotient = -quotient - (remainder != 0) + assert dividend // divisor == quotient + assert -dividend // -divisor == quotient + assert -dividend // divisor == negative_quotient + assert dividend // -divisor == negative_quotient + + def test_pow(): assert 2 ** 10 == 1024 assert type(2 ** -1) is float diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/Python3Core.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/Python3Core.java index 703a6de553..280cc9680e 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/Python3Core.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/Python3Core.java @@ -1262,6 +1262,7 @@ private void initializeTypes() { } private void populateBuiltins() { + sysModule = builtinModules.get(T_SYS); assert PythonBuiltinClassType.verifySlotsConventions(builtins); for (PythonBuiltins builtin : builtins) { builtin.initialize(this); @@ -1292,7 +1293,6 @@ private void populateBuiltins() { } // core machinery - sysModule = builtinModules.get(T_SYS); sysModules = (PDict) sysModule.getAttribute(T_MODULES); } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/BuiltinFunctions.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/BuiltinFunctions.java index cd369906d2..2eaeb899fc 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/BuiltinFunctions.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/BuiltinFunctions.java @@ -191,9 +191,9 @@ import com.oracle.graal.python.lib.PyObjectDir; import com.oracle.graal.python.lib.PyObjectFormat; import com.oracle.graal.python.lib.PyObjectGetAIter; -import com.oracle.graal.python.lib.PyObjectGetAttr; import com.oracle.graal.python.lib.PyObjectGetAttrO; import com.oracle.graal.python.lib.PyObjectGetIter; +import com.oracle.graal.python.lib.PyObjectGetMethod; import com.oracle.graal.python.lib.PyObjectHashNode; import com.oracle.graal.python.lib.PyObjectIsInstanceNode; import com.oracle.graal.python.lib.PyObjectIsSubclassNode; @@ -232,6 +232,7 @@ import com.oracle.graal.python.nodes.bytecode_dsl.PBytecodeDSLRootNode; import com.oracle.graal.python.nodes.call.CallDispatchers; import com.oracle.graal.python.nodes.call.CallNode; +import com.oracle.graal.python.nodes.call.special.CallBinaryMethodNode; import com.oracle.graal.python.nodes.call.special.CallUnaryMethodNode; import com.oracle.graal.python.nodes.call.special.LookupAndCallBinaryNode; import com.oracle.graal.python.nodes.call.special.LookupAndCallUnaryNode; @@ -283,7 +284,6 @@ 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.HostCompilerDirectives.InliningCutoff; import com.oracle.truffle.api.RootCallTarget; @@ -1575,14 +1575,13 @@ static Object ord(@SuppressWarnings("unused") Object obj, @GenerateNodeFactory public abstract static class PrintNode extends PythonBuiltinNode { @Child private ReadAttributeFromModuleNode readStdout; - @CompilationFinal private PythonModule cachedSys; @Specialization @SuppressWarnings("unused") PNone printNoKeywords(VirtualFrame frame, Object[] values, PNone sep, PNone end, PNone file, PNone flush, @Bind Node inliningTarget, - @Shared("getWriteMethod") @Cached PyObjectGetAttr getWriteMethod, - @Shared("callWrite") @Cached CallNode callWrite, + @Shared("getWriteMethod") @Cached PyObjectGetMethod getWriteMethod, + @Shared("callWrite") @Cached CallBinaryMethodNode callWrite, @Shared("callFlush") @Cached PyObjectCallMethodObjArgs callFlush, @Shared("strNode") @Cached PyObjectStrAsObjectNode strNode) { Object stdout = getStdout(); @@ -1596,23 +1595,22 @@ PNone printNoKeywords(VirtualFrame frame, Object[] values, PNone sep, PNone end, @Specialization(guards = {"!isNone(file)", "!isNoValue(file)"}) static PNone printAllGiven(VirtualFrame frame, Object[] values, TruffleString sep, TruffleString end, Object file, boolean flush, @Bind Node inliningTarget, - @Shared("getWriteMethod") @Cached PyObjectGetAttr getWriteMethod, - @Shared("callWrite") @Cached CallNode callWrite, + @Shared("getWriteMethod") @Cached PyObjectGetMethod getWriteMethod, + @Shared("callWrite") @Cached CallBinaryMethodNode callWrite, @Shared("callFlush") @Cached PyObjectCallMethodObjArgs callFlush, @Shared("strNode") @Cached PyObjectStrAsObjectNode strNode) { int lastValue = values.length - 1; - // Note: the separate lookup is necessary due to different __getattr__ treatment than - // method lookup + // Resolve write once, before converting the values to strings. Object writeMethod = getWriteMethod.execute(frame, inliningTarget, file, T_WRITE); for (int i = 0; i < lastValue; i++) { - callWrite.execute(frame, writeMethod, strNode.execute(frame, inliningTarget, values[i])); - callWrite.execute(frame, writeMethod, sep); + callWrite.executeObject(frame, writeMethod, file, strNode.execute(frame, inliningTarget, values[i])); + callWrite.executeObject(frame, writeMethod, file, sep); } LoopNode.reportLoopCount(inliningTarget, values.length == 0 ? 0 : values.length - 1); if (lastValue >= 0) { - callWrite.execute(frame, writeMethod, strNode.execute(frame, inliningTarget, values[lastValue])); + callWrite.executeObject(frame, writeMethod, file, strNode.execute(frame, inliningTarget, values[lastValue])); } - callWrite.execute(frame, writeMethod, end); + callWrite.executeObject(frame, writeMethod, file, end); if (flush) { callFlush.execute(frame, inliningTarget, file, T_FLUSH); } @@ -1626,8 +1624,8 @@ PNone printGeneric(VirtualFrame frame, Object[] values, Object sepIn, Object end @Cached CastToTruffleStringNode castSep, @Cached CastToTruffleStringNode castEnd, @Cached PyObjectIsTrueNode castFlush, - @Exclusive @Cached PyObjectGetAttr getWriteMethod, - @Exclusive @Cached CallNode callWrite, + @Exclusive @Cached PyObjectGetMethod getWriteMethod, + @Exclusive @Cached CallBinaryMethodNode callWrite, @Exclusive @Cached PyObjectCallMethodObjArgs callFlush, @Exclusive @Cached PyObjectStrAsObjectNode strNode, @Cached PRaiseNode raiseNode) { @@ -1665,20 +1663,7 @@ PNone printGeneric(VirtualFrame frame, Object[] values, Object sepIn, Object end } private Object getStdout() { - PythonModule sys; - if (getLanguage().isSingleContext()) { - if (cachedSys == null) { - CompilerDirectives.transferToInterpreterAndInvalidate(); - cachedSys = getContext().lookupBuiltinModule(T_SYS); - } - sys = cachedSys; - } else { - if (cachedSys != null) { - CompilerDirectives.transferToInterpreterAndInvalidate(); - cachedSys = null; - } - sys = getContext().lookupBuiltinModule(T_SYS); - } + PythonModule sys = getContext().getSysModule(); if (readStdout == null) { CompilerDirectives.transferToInterpreterAndInvalidate(); readStdout = insert(ReadAttributeFromModuleNode.create()); diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/ReadlineModuleBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/ReadlineModuleBuiltins.java index 80de318a86..b94417c219 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/ReadlineModuleBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/ReadlineModuleBuiltins.java @@ -42,7 +42,6 @@ import static com.oracle.graal.python.nodes.BuiltinNames.J_READLINE; import static com.oracle.graal.python.nodes.BuiltinNames.T_READLINE; -import static com.oracle.graal.python.nodes.BuiltinNames.T_SYS; import static com.oracle.graal.python.nodes.StringLiterals.T_EMPTY_STRING; import static com.oracle.graal.python.util.PythonUtils.toTruffleStringUncached; import static com.oracle.graal.python.util.PythonUtils.tsLiteral; @@ -115,7 +114,7 @@ public void postInitialize(Python3Core core) { module.setAttribute(T_BACKEND, T_JLINE); LocalData moduleState = new LocalData(); module.setModuleState(moduleState); - Object consoleHandler = core.lookupBuiltinModule(T_SYS).getAttribute(T__CONSOLE_HANDLER); + Object consoleHandler = core.getSysModule().getAttribute(T__CONSOLE_HANDLER); if (consoleHandler != PNone.NO_VALUE) { InteropLibrary lib = InteropLibrary.getUncached(consoleHandler); try { diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/SysModuleBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/SysModuleBuiltins.java index e76f46c806..6e8c4836aa 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/SysModuleBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/SysModuleBuiltins.java @@ -94,7 +94,6 @@ import static com.oracle.graal.python.nodes.BuiltinNames.T_STDERR; import static com.oracle.graal.python.nodes.BuiltinNames.T_STDIN; import static com.oracle.graal.python.nodes.BuiltinNames.T_STDOUT; -import static com.oracle.graal.python.nodes.BuiltinNames.T_SYS; import static com.oracle.graal.python.nodes.BuiltinNames.T_UNRAISABLEHOOK; import static com.oracle.graal.python.nodes.BuiltinNames.T___BREAKPOINTHOOK__; import static com.oracle.graal.python.nodes.BuiltinNames.T___DISPLAYHOOK__; @@ -614,7 +613,7 @@ public static PTuple createIntInfo(PythonLanguage language) { public void postInitialize0(Python3Core core) { super.postInitialize(core); - PythonModule sys = core.lookupBuiltinModule(T_SYS); + PythonModule sys = core.getSysModule(); PythonContext context = core.getContext(); PythonLanguage language = core.getLanguage(); String[] args = context.getEnv().getApplicationArguments(); @@ -761,7 +760,7 @@ private static Object[] convertToObjectArray(TruffleString[] arr) { public void postInitialize(Python3Core core) { postInitialize0(core); initStd(core); - PythonModule sys = core.lookupBuiltinModule(T_SYS); + PythonModule sys = core.getSysModule(); core.getContext().registerCApiHook(() -> { sys.setAttribute(toTruffleStringUncached("_dllhandle_name"), toTruffleStringUncached(core.getContext().getCApiContext().getLibraryName())); }); @@ -777,7 +776,7 @@ static void initStd(Python3Core core) { TruffleString stdioEncoding = gp.getStdIOEncoding(); TruffleString stdioError = gp.getStdIOError(); PosixSupport posixSupport = context.getPosixSupport(); - PythonModule sysModule = core.lookupBuiltinModule(T_SYS); + PythonModule sysModule = core.getSysModule(); // Note that stdin is always buffered, this only applies to stdout and stderr boolean buffering = !context.getOption(PythonOptions.UnbufferedIO); diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/WarningsModuleBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/WarningsModuleBuiltins.java index a186658601..535af5b494 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/WarningsModuleBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/WarningsModuleBuiltins.java @@ -44,7 +44,6 @@ import static com.oracle.graal.python.nodes.BuiltinNames.J__WARNINGS; import static com.oracle.graal.python.nodes.BuiltinNames.T_MODULE; import static com.oracle.graal.python.nodes.BuiltinNames.T_MODULES; -import static com.oracle.graal.python.nodes.BuiltinNames.T_SYS; import static com.oracle.graal.python.nodes.BuiltinNames.T__WARNINGS; import static com.oracle.graal.python.nodes.BuiltinNames.T___MAIN__; import static com.oracle.graal.python.nodes.SpecialAttributeNames.T___LOADER__; @@ -405,7 +404,7 @@ private PDict getSysDict() { reportPolymorphicSpecialize(); getDictNode = insert(GetOrCreateDictNode.create()); } - return getDictNode.executeCached(getContext().lookupBuiltinModule(T_SYS)); + return getDictNode.executeCached(getContext().getSysModule()); } private PFrame getCallerFrame(VirtualFrame frame, int stackLevel, TruffleString[] skipFilePrefixes) { @@ -520,7 +519,7 @@ private static Object getWarningsAttr(VirtualFrame frame, BoundaryCallData bound return null; } } else { - Object sys = context.lookupBuiltinModule(T_SYS); + Object sys = context.getSysModule(); Object modules = lookup.executeCached(frame, sys, T_MODULES); try { warningsModule = callMethod.executeCached(frame, modules, T_GET, T_WARNINGS, PNone.NONE); diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/cext/PythonCextSysBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/cext/PythonCextSysBuiltins.java index 8f40f49c60..e32485a23a 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/cext/PythonCextSysBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/cext/PythonCextSysBuiltins.java @@ -50,7 +50,6 @@ import static com.oracle.graal.python.builtins.objects.cext.capi.transitions.ArgDescriptor.PyObjectBorrowed; import static com.oracle.graal.python.nodes.BuiltinNames.T_STDERR; import static com.oracle.graal.python.nodes.BuiltinNames.T_STDOUT; -import static com.oracle.graal.python.nodes.BuiltinNames.T_SYS; import static com.oracle.graal.python.runtime.PythonContext.NATIVE_NULL; import com.oracle.graal.python.builtins.modules.cext.PythonCextBuiltins.CApiBuiltin; @@ -87,7 +86,7 @@ Object getObject(TruffleString name, @Cached PyObjectLookupAttr lookupNode, @Cached PyObjectSetAttr setAttrNode) { try { - PythonModule sys = getCore().lookupBuiltinModule(T_SYS); + PythonModule sys = getCore().getSysModule(); Object value = lookupNode.execute(null, inliningTarget, sys, name); if (value == PNone.NO_VALUE) { return NATIVE_NULL; @@ -109,7 +108,7 @@ Object getObject(TruffleString name, private static Object selectOut(int fd) { CompilerAsserts.neverPartOfCompilation(); Object file; - PythonModule sys = PythonContext.get(null).lookupBuiltinModule(T_SYS); + PythonModule sys = PythonContext.get(null).getSysModule(); if (fd == 0) { file = sys.getAttribute(T_STDOUT); } else { diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/ints/IntBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/ints/IntBuiltins.java index e65bfff2f7..ed0bb74d89 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/ints/IntBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/ints/IntBuiltins.java @@ -892,6 +892,33 @@ static PInt doPiPi(PInt left, PInt right, static BigInteger op(BigInteger left, BigInteger right) { // Math.floorDiv for BigInteger int leftSign = left.signum(); + if (leftSign > 0 && right.signum() > 0) { + int rightBits = right.bitLength(); + int bitDifference = left.bitLength() - rightBits; + if (rightBits > 128 && bitDifference >= 0 && bitDifference < 31) { + /* + * Keep 32 leading divisor bits and at most 62 dividend bits. If these truncated + * operands are u and v, the exact floor-division quotient is between u / (v + 1) and u / v. + * When both bounds agree, no full-width arithmetic is needed. Otherwise, a single multiplication + * and comparison determine the exact quotient. + */ + int shift = rightBits - 32; + long u = left.shiftRight(shift).longValue(); + long v = right.shiftRight(shift).longValue(); + long lower = u / (v + 1); + long upper = u / v; + if (lower == upper) { + return BigInteger.valueOf(lower); + } else { + assert upper == lower + 1; + if (left.compareTo(right.multiply(BigInteger.valueOf(upper))) < 0) { + return BigInteger.valueOf(lower); + } else { + return BigInteger.valueOf(upper); + } + } + } + } if (leftSign == 0 || leftSign == right.signum()) { return left.divide(right); } @@ -1224,8 +1251,8 @@ static PInt doPIntPInt(PInt left, PInt right, @TruffleBoundary public static BigInteger mul(BigInteger a, BigInteger b) { - if (!BigInteger.ZERO.equals(b) && b.and(b.subtract(BigInteger.ONE)).equals(BigInteger.ZERO)) { - return bigIntegerShift(a, b.getLowestSetBit()); + if (b.signum() > 0 && b.getLowestSetBit() == b.bitLength() - 1) { + return bigIntegerShift(a, b.bitLength() - 1); } else { return bigIntegerMul(a, b); } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/ints/PInt.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/ints/PInt.java index ca134fc083..bca7223786 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/ints/PInt.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/ints/PInt.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2025, Oracle and/or its affiliates. + * Copyright (c) 2017, 2026, Oracle and/or its affiliates. * Copyright (c) 2013, Regents of the University of California * * All rights reserved. @@ -60,15 +60,6 @@ @ExportLibrary(InteropLibrary.class) public final class PInt extends PythonBuiltinObject { - public static final BigInteger MAX_INT = BigInteger.valueOf(Integer.MAX_VALUE); - public static final BigInteger MIN_INT = BigInteger.valueOf(Integer.MIN_VALUE); - public static final BigInteger MAX_LONG = BigInteger.valueOf(Long.MAX_VALUE); - public static final BigInteger MIN_LONG = BigInteger.valueOf(Long.MIN_VALUE); - private static final BigInteger MAX_BYTE = BigInteger.valueOf(Byte.MAX_VALUE); - private static final BigInteger MIN_BYTE = BigInteger.valueOf(Byte.MIN_VALUE); - private static final BigInteger MAX_SHORT = BigInteger.valueOf(Short.MAX_VALUE); - private static final BigInteger MIN_SHORT = BigInteger.valueOf(Short.MIN_VALUE); - private final BigInteger value; public PInt(Object clazz, Shape instanceShape, BigInteger value) { @@ -133,7 +124,7 @@ public boolean fitsInByte( @Shared("isBoolean") @Cached InlinedConditionProfile isBoolean, @CachedLibrary("this") InteropLibrary self) { if (isNumber(inliningTarget, isBoolean, self)) { - return fitsIn(MIN_BYTE, MAX_BYTE); + return fitsInSignedBits(value, Byte.SIZE); } else { return false; } @@ -162,7 +153,7 @@ boolean fitsInShort( @Shared("isBoolean") @Cached InlinedConditionProfile isBoolean, @CachedLibrary("this") InteropLibrary self) { if (isNumber(inliningTarget, isBoolean, self)) { - return fitsIn(MIN_SHORT, MAX_SHORT); + return fitsInSignedBits(value, Short.SIZE); } else { return false; } @@ -191,7 +182,7 @@ public boolean fitsInInt( @Shared("isBoolean") @Cached InlinedConditionProfile isBoolean, @CachedLibrary("this") InteropLibrary self) { if (isNumber(inliningTarget, isBoolean, self)) { - return fitsIn(MIN_INT, MAX_INT); + return bigIntegerFitsInInt(value); } else { return false; } @@ -220,7 +211,7 @@ public boolean fitsInLong( @Shared("isBoolean") @Cached InlinedConditionProfile isBoolean, @CachedLibrary("this") InteropLibrary self) { if (isNumber(inliningTarget, isBoolean, self)) { - return fitsIn(MIN_LONG, MAX_LONG); + return bigIntegerFitsInLong(value); } else { return false; } @@ -439,7 +430,11 @@ public static long longValueExact(BigInteger x) throws OverflowException { } public static boolean bigIntegerFitsInLong(BigInteger x) { - return fitsIn(x, MIN_LONG, MAX_LONG); + return fitsInSignedBits(x, Long.SIZE); + } + + public static boolean bigIntegerFitsInInt(BigInteger x) { + return fitsInSignedBits(x, Integer.SIZE); } public PInt max(PInt val) { @@ -501,28 +496,12 @@ public static int intValueExact(long val) throws OverflowException { } public static int intValueExact(BigInteger x) throws OverflowException { - if (!fitsIn(x, MIN_INT, MAX_INT)) { + if (!bigIntegerFitsInInt(x)) { throw OverflowException.INSTANCE; } return intValue(x); } - public static char charValueExact(int val) throws OverflowException { - char t = (char) val; - if (t != val) { - throw OverflowException.INSTANCE; - } - return t; - } - - public static char charValueExact(long val) throws OverflowException { - char t = (char) val; - if (t != val) { - throw OverflowException.INSTANCE; - } - return t; - } - public static boolean isByteRange(int val) { return val >= 0 && val < 256; } @@ -674,12 +653,8 @@ public static long hashBigInteger(BigInteger i) { } @TruffleBoundary(allowInlining = true) - public static boolean fitsIn(BigInteger value, BigInteger left, BigInteger right) { - return value.compareTo(left) >= 0 && value.compareTo(right) <= 0; - } - - public boolean fitsIn(BigInteger left, BigInteger right) { - return fitsIn(value, left, right); + private static boolean fitsInSignedBits(BigInteger value, int bits) { + return value.bitLength() < bits; } /** diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/WriteUnraisableNode.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/WriteUnraisableNode.java index 96b0bc08a8..d201ac7d4d 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/WriteUnraisableNode.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/WriteUnraisableNode.java @@ -40,7 +40,6 @@ */ package com.oracle.graal.python.nodes; -import static com.oracle.graal.python.nodes.BuiltinNames.T_SYS; import static com.oracle.graal.python.util.PythonUtils.TS_ENCODING; import java.io.IOException; @@ -93,7 +92,7 @@ static void writeUnraisable(VirtualFrame frame, Object exception, TruffleString @Cached TruffleString.CopyToByteArrayNode copyToByteArrayNode) { PythonContext context = PythonContext.get(inliningTarget); try { - PythonModule sysModule = context.lookupBuiltinModule(T_SYS); + PythonModule sysModule = context.getSysModule(); Object unraisablehook = lookup.execute(frame, inliningTarget, sysModule, BuiltinNames.T_UNRAISABLEHOOK); Object exceptionType = getClassNode.execute(inliningTarget, exception); Object traceback = getTracebackNode.execute(inliningTarget, exception); diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/exception/TopLevelExceptionHandler.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/exception/TopLevelExceptionHandler.java index 3956c0a9ae..3e092484b2 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/exception/TopLevelExceptionHandler.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/exception/TopLevelExceptionHandler.java @@ -41,7 +41,6 @@ package com.oracle.graal.python.nodes.exception; import static com.oracle.graal.python.builtins.modules.io.IONodes.T_WRITE; -import static com.oracle.graal.python.nodes.BuiltinNames.T_SYS; import static com.oracle.graal.python.nodes.BuiltinNames.T___BUILTINS__; import static com.oracle.graal.python.runtime.exception.PythonErrorType.SystemExit; import static com.oracle.graal.python.util.PythonUtils.TS_ENCODING; @@ -194,7 +193,7 @@ private AbstractTruffleException handlePythonException(AbstractTruffleException Object type = GetClassNode.executeUncached(pythonException); Object tb = ExceptionNodes.GetTracebackNode.executeUncached(pythonException); - PythonModule sys = getContext().lookupBuiltinModule(T_SYS); + PythonModule sys = getContext().getSysModule(); sys.setAttribute(BuiltinNames.T_LAST_TYPE, type); sys.setAttribute(BuiltinNames.T_LAST_VALUE, pythonException); sys.setAttribute(BuiltinNames.T_LAST_TRACEBACK, tb); diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/statement/AbstractImportNode.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/statement/AbstractImportNode.java index dbab409377..e2291b19a9 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/statement/AbstractImportNode.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/statement/AbstractImportNode.java @@ -44,7 +44,6 @@ import static com.oracle.graal.python.builtins.PythonBuiltinClassType.RuntimeError; import static com.oracle.graal.python.builtins.objects.module.ModuleBuiltins.T__INITIALIZING; import static com.oracle.graal.python.nodes.BuiltinNames.T_MODULES; -import static com.oracle.graal.python.nodes.BuiltinNames.T_SYS; import static com.oracle.graal.python.nodes.BuiltinNames.T___IMPORT__; import static com.oracle.graal.python.nodes.ErrorMessages.ATTEMPTED_RELATIVE_IMPORT_BEYOND_TOPLEVEL; import static com.oracle.graal.python.nodes.ErrorMessages.IMPORT_NOT_FOUND; @@ -142,7 +141,7 @@ public static PythonModule importModule(TruffleString name) { @TruffleBoundary public static PythonModule lookupImportedModule(PythonContext context, TruffleString name) { - PythonModule sysModule = context.lookupBuiltinModule(T_SYS); + PythonModule sysModule = context.getSysModule(); Object modules = sysModule.getAttribute(T_MODULES); if (modules == PNone.NO_VALUE) { throw PRaiseNode.raiseStatic(null, RuntimeError, ErrorMessages.UNABLE_TO_GET_S, "sys.modules"); diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/util/CastToJavaIntLossyNode.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/util/CastToJavaIntLossyNode.java index 741d500a96..4f893e45c7 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/util/CastToJavaIntLossyNode.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/util/CastToJavaIntLossyNode.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2026, 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 @@ -40,6 +40,8 @@ */ package com.oracle.graal.python.nodes.util; +import java.math.BigInteger; + import com.oracle.graal.python.builtins.objects.ints.PInt; import com.oracle.graal.python.util.OverflowException; import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; @@ -79,12 +81,13 @@ protected static int toIntPInt(PInt x) throws OverflowException { @TruffleBoundary @Specialization(replaces = "toIntPInt") protected static int toIntOverflow(PInt x) { - if (x.compareTo(PInt.MAX_INT) > 0) { + BigInteger value = x.getValue(); + if (PInt.bigIntegerFitsInInt(value)) { + return value.intValue(); + } else if (value.signum() > 0) { return Integer.MAX_VALUE; - } else if (x.compareTo(PInt.MIN_INT) < 0) { - return Integer.MIN_VALUE; } else { - return x.intValue(); + return Integer.MIN_VALUE; } } } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/util/CastToJavaLongLossyNode.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/util/CastToJavaLongLossyNode.java index e4283c758f..8b46451c5a 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/util/CastToJavaLongLossyNode.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/util/CastToJavaLongLossyNode.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2026, 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 @@ -40,8 +40,11 @@ */ package com.oracle.graal.python.nodes.util; +import java.math.BigInteger; + import com.oracle.graal.python.builtins.objects.ints.PInt; import com.oracle.graal.python.util.OverflowException; +import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; import com.oracle.truffle.api.dsl.GenerateCached; import com.oracle.truffle.api.dsl.GenerateInline; import com.oracle.truffle.api.dsl.GenerateUncached; @@ -66,13 +69,15 @@ protected static long toLong(PInt x) throws OverflowException { } @Specialization(replaces = "toLong") + @TruffleBoundary protected static long toLongOverflow(PInt x) { - if (x.compareTo(PInt.MAX_LONG) > 0) { + BigInteger value = x.getValue(); + if (PInt.bigIntegerFitsInLong(value)) { + return value.longValue(); + } else if (value.signum() > 0) { return Long.MAX_VALUE; - } else if (x.compareTo(PInt.MIN_LONG) < 0) { - return Long.MIN_VALUE; } else { - return x.longValue(); + return Long.MIN_VALUE; } } } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/util/NarrowBigIntegerNode.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/util/NarrowBigIntegerNode.java index ba7025a57e..7f1fc35857 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/util/NarrowBigIntegerNode.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/util/NarrowBigIntegerNode.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2026, 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 @@ -74,11 +74,12 @@ static Object narrowBigInteger0(@SuppressWarnings("unused") BigInteger x) { static Object narrowBigInteger(Node inliningTarget, BigInteger x, @Cached InlinedConditionProfile fitsIntProfile, @Cached InlinedConditionProfile fitsLongProfile) { - if (fitsIntProfile.profile(inliningTarget, PInt.fitsIn(x, PInt.MIN_INT, PInt.MAX_INT))) { - return PInt.intValue(x); - } - if (fitsLongProfile.profile(inliningTarget, PInt.fitsIn(x, PInt.MIN_LONG, PInt.MAX_LONG))) { - return PInt.longValue(x); + if (fitsLongProfile.profile(inliningTarget, PInt.bigIntegerFitsInLong(x))) { + long l = PInt.longValue(x); + if (fitsIntProfile.profile(inliningTarget, PInt.fitsInInt(l))) { + return (int) l; + } + return l; } return PFactory.createInt(PythonLanguage.get(inliningTarget), x); } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PythonContext.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PythonContext.java index a78029cddb..fc8204d1ae 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PythonContext.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PythonContext.java @@ -37,7 +37,6 @@ import static com.oracle.graal.python.nodes.BuiltinNames.T_SHA3; import static com.oracle.graal.python.nodes.BuiltinNames.T_STDERR; import static com.oracle.graal.python.nodes.BuiltinNames.T_STDOUT; -import static com.oracle.graal.python.nodes.BuiltinNames.T_SYS; import static com.oracle.graal.python.nodes.BuiltinNames.T_THREADING; import static com.oracle.graal.python.nodes.BuiltinNames.T___BUILTINS__; import static com.oracle.graal.python.nodes.BuiltinNames.T___MAIN__; @@ -1281,7 +1280,7 @@ public void addSysPath0() { if (!getOption(PythonOptions.SafePathFlag)) { TruffleString path0 = computeSysPath0(); if (path0 != null) { - PythonModule sys = lookupBuiltinModule(T_SYS); + PythonModule sys = getSysModule(); Object path = sys.getAttribute(T_PATH); PyObjectCallMethodObjArgs.executeUncached(path, T_INSERT, 0, path0); } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/exception/ExceptionUtils.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/exception/ExceptionUtils.java index 1b2ee81929..58f66fab94 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/exception/ExceptionUtils.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/exception/ExceptionUtils.java @@ -42,7 +42,6 @@ import static com.oracle.graal.python.builtins.PythonBuiltinClassType.MemoryError; import static com.oracle.graal.python.builtins.PythonBuiltinClassType.RecursionError; -import static com.oracle.graal.python.nodes.BuiltinNames.T_SYS; import java.io.IOException; import java.io.PrintWriter; @@ -251,7 +250,7 @@ public static void printExceptionTraceback(PythonContext context, Object pythonE Object type = GetClassNode.executeUncached(pythonException); Object tb = ExceptionNodes.GetTracebackNode.executeUncached(pythonException); - Object hook = context.lookupBuiltinModule(T_SYS).getAttribute(BuiltinNames.T_EXCEPTHOOK); + Object hook = context.getSysModule().getAttribute(BuiltinNames.T_EXCEPTHOOK); if (hook != PNone.NO_VALUE) { try { // Note: it is important to pass frame 'null' because that will cause the