Skip to content

Commit deef5bc

Browse files
committed
SysModuleBuiltins add get/setrecursion limit builtins
1 parent b71282e commit deef5bc

File tree

5 files changed

+96
-12
lines changed

5 files changed

+96
-12
lines changed

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/Python3Core.java

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -286,6 +286,8 @@
286286
* through an extra field in the context.
287287
*/
288288
public abstract class Python3Core extends ParserErrorCallback {
289+
private static final int REC_LIM = 8000;
290+
private static final int NATIVE_REC_LIM = 1000;
289291
private static final TruffleLogger LOGGER = PythonLanguage.getLogger(Python3Core.class);
290292
private final String[] coreFiles;
291293

@@ -601,6 +603,7 @@ private static PythonBuiltins[] initializeBuiltins(boolean nativeAccessAllowed)
601603
@CompilationFinal private PFloat pyNaN;
602604

603605
private final PythonParser parser;
606+
private final SysModuleState sysModuleState = new SysModuleState();
604607

605608
@CompilationFinal private Object globalScopeObject;
606609

@@ -620,6 +623,41 @@ public Python3Core(PythonLanguage language, PythonParser parser, boolean isNativ
620623
this.coreFiles = initializeCoreFiles();
621624
}
622625

626+
@CompilerDirectives.ValueType
627+
public static class SysModuleState {
628+
private int recursionLimit = ImageInfo.inImageCode() ? NATIVE_REC_LIM : REC_LIM;
629+
private int checkInterval = 100;
630+
private double switchInterval = 0.005;
631+
632+
public int getRecursionLimit() {
633+
return recursionLimit;
634+
}
635+
636+
public void setRecursionLimit(int recursionLimit) {
637+
this.recursionLimit = recursionLimit;
638+
}
639+
640+
public int getCheckInterval() {
641+
return checkInterval;
642+
}
643+
644+
public void setCheckInterval(int checkInterval) {
645+
this.checkInterval = checkInterval;
646+
}
647+
648+
public double getSwitchInterval() {
649+
return switchInterval;
650+
}
651+
652+
public void setSwitchInterval(double switchInterval) {
653+
this.switchInterval = switchInterval;
654+
}
655+
}
656+
657+
public SysModuleState getSysModuleState() {
658+
return sysModuleState;
659+
}
660+
623661
@Override
624662
public final PythonContext getContext() {
625663
// Small hack: we know that this is the only implementation of Python3Core, this should be

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/SysModuleBuiltins.java

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@
4444
import static com.oracle.graal.python.builtins.PythonBuiltinClassType.ImportError;
4545
import static com.oracle.graal.python.builtins.PythonBuiltinClassType.RuntimeError;
4646
import static com.oracle.graal.python.builtins.PythonBuiltinClassType.RuntimeWarning;
47+
import static com.oracle.graal.python.builtins.PythonBuiltinClassType.SystemExit;
4748
import static com.oracle.graal.python.builtins.PythonBuiltinClassType.TypeError;
4849
import static com.oracle.graal.python.builtins.PythonBuiltinClassType.UnicodeEncodeError;
4950
import static com.oracle.graal.python.builtins.PythonBuiltinClassType.ValueError;
@@ -68,6 +69,7 @@
6869
import static com.oracle.graal.python.nodes.BuiltinNames.BUILTINS;
6970
import static com.oracle.graal.python.nodes.BuiltinNames.DISPLAYHOOK;
7071
import static com.oracle.graal.python.nodes.BuiltinNames.EXCEPTHOOK;
72+
import static com.oracle.graal.python.nodes.BuiltinNames.EXIT;
7173
import static com.oracle.graal.python.nodes.BuiltinNames.PYTHONBREAKPOINT;
7274
import static com.oracle.graal.python.nodes.BuiltinNames.STDERR;
7375
import static com.oracle.graal.python.nodes.BuiltinNames.STDIN;
@@ -82,6 +84,8 @@
8284
import static com.oracle.graal.python.nodes.BuiltinNames.__UNRAISABLEHOOK__;
8385
import static com.oracle.graal.python.nodes.ErrorMessages.ARG_TYPE_MUST_BE;
8486
import static com.oracle.graal.python.nodes.ErrorMessages.LOST_S;
87+
import static com.oracle.graal.python.nodes.ErrorMessages.REC_LIMIT_GREATER_THAN_1;
88+
import static com.oracle.graal.python.nodes.ErrorMessages.S_EXPECTED_GOT_P;
8589
import static com.oracle.graal.python.nodes.ErrorMessages.WARN_CANNOT_RUN_PDB_YET;
8690
import static com.oracle.graal.python.nodes.ErrorMessages.WARN_IGNORE_UNIMPORTABLE_BREAKPOINT_S;
8791
import static com.oracle.graal.python.nodes.SpecialAttributeNames.__;
@@ -99,6 +103,9 @@
99103
import java.util.Map;
100104
import java.util.Set;
101105

106+
import com.oracle.graal.python.lib.PyFloatCheckExactNode;
107+
import com.oracle.graal.python.lib.PyLongAsIntNode;
108+
import com.oracle.graal.python.runtime.exception.PythonExitException;
102109
import org.graalvm.nativeimage.ImageInfo;
103110

104111
import com.oracle.graal.python.PythonLanguage;
@@ -1386,4 +1393,53 @@ Object doHook(VirtualFrame frame, Object[] args, PKeyword[] keywords,
13861393
return callNode.execute(hook, args, keywords);
13871394
}
13881395
}
1396+
1397+
@Builtin(name = "getrecursionlimit", minNumOfPositionalArgs = 1, declaresExplicitSelf = true, doc = "getrecursionlimit($module, /)\n" +
1398+
"--\n" +
1399+
"\n" +
1400+
"Return the current value of the recursion limit.\n" +
1401+
"\n" +
1402+
"The recursion limit is the maximum depth of the Python interpreter\n" +
1403+
"stack. This limit prevents infinite recursion from causing an overflow\n" +
1404+
"of the C stack and crashing Python.")
1405+
@GenerateNodeFactory
1406+
abstract static class GetRecursionLimitNode extends PythonBuiltinNode {
1407+
@Specialization
1408+
Object getRecLim(@SuppressWarnings("unused") PythonModule sys) {
1409+
return getContext().getSysModuleState().getRecursionLimit();
1410+
}
1411+
}
1412+
1413+
@Builtin(name = "setrecursionlimit", minNumOfPositionalArgs = 2, declaresExplicitSelf = true, doc = "setrecursionlimit($module, limit, /)\n" +
1414+
"--\n" +
1415+
"\n" +
1416+
"Set the maximum depth of the Python interpreter stack to n.\n" +
1417+
"\n" +
1418+
"This limit prevents infinite recursion from causing an overflow of the C\n" +
1419+
"stack and crashing Python. The highest possible limit is platform-\n" +
1420+
"dependent.")
1421+
@GenerateNodeFactory
1422+
abstract static class SetRecursionLimitNode extends PythonBuiltinNode {
1423+
@Specialization
1424+
Object setRecLim(VirtualFrame frame, @SuppressWarnings("unused") PythonModule sys, Object limit,
1425+
@Cached PyLongAsIntNode longAsIntNode,
1426+
@Cached PyFloatCheckExactNode floatCheckExactNode) {
1427+
if (floatCheckExactNode.execute(limit)) {
1428+
throw raise(TypeError, S_EXPECTED_GOT_P, "integer", limit);
1429+
}
1430+
1431+
try {
1432+
final int newLimit = longAsIntNode.execute(frame, limit);
1433+
if (newLimit < 1) {
1434+
throw raise(ValueError, REC_LIMIT_GREATER_THAN_1);
1435+
}
1436+
1437+
// TODO: check to see if Issue #25274 applies
1438+
getContext().getSysModuleState().setRecursionLimit(newLimit);
1439+
} catch (PException ignore) {
1440+
}
1441+
return PNone.NONE;
1442+
}
1443+
}
1444+
13891445
}

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/BuiltinNames.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ public abstract class BuiltinNames {
7575
public static final String __STDOUT__ = "__stdout__";
7676
public static final String STDOUT = "stdout";
7777
public static final String PYTHONBREAKPOINT = "PYTHONBREAKPOINT";
78+
public static final String EXIT = "exit";
7879

7980
// builtin functions
8081
public static final String ABS = "abs";

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/ErrorMessages.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -325,6 +325,7 @@ public abstract class ErrorMessages {
325325
public static final String INTEGER_DIVISION_BY_ZERO = "ZeroDivisionError: integer division or modulo by zero";
326326
public static final String INTEGER_DIVISION_RESULT_TOO_LARGE = "integer division result too large for a float";
327327
public static final String S_EXPECTED_GOT_P = "%s argument expected, got %p";
328+
public static final String REC_LIMIT_GREATER_THAN_1 = "recursion limit must be greater or equal than 1";
328329
public static final String INTEGER_GREATER_THAN_MAX = "integer is greater than maximum";
329330
public static final String INTEGER_REQUIRED = "an integer is required";
330331
public static final String INTEGER_REQUIRED_GOT = "an integer is required (got type %p)";

graalpython/lib-graalpython/sys.py

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -58,18 +58,6 @@ def exit(arg=None):
5858
code = arg[0]
5959
raise SystemExit(code)
6060

61-
@__graalpython__.builtin
62-
def getrecursionlimit():
63-
return __graalpython__.sys_state.recursionlimit
64-
65-
@__graalpython__.builtin
66-
def setrecursionlimit(value):
67-
if not isinstance(value, int):
68-
raise TypeError("an integer is required")
69-
if value <= 0:
70-
raise ValueError("recursion limit must be greater or equal than 1")
71-
__graalpython__.sys_state.recursionlimit = value
72-
7361
@__graalpython__.builtin
7462
def getcheckinterval():
7563
return __graalpython__.sys_state.checkinterval

0 commit comments

Comments
 (0)