Skip to content

Commit 6c6208b

Browse files
committed
Intrinsify sys.exit, intrinsify SystemExit exception
1 parent 11dd7e6 commit 6c6208b

File tree

11 files changed

+221
-66
lines changed

11 files changed

+221
-66
lines changed

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

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@
4444
import java.util.regex.Matcher;
4545
import java.util.regex.Pattern;
4646

47+
import com.oracle.graal.python.builtins.objects.exception.SystemExitBuiltins;
4748
import org.graalvm.nativeimage.ImageInfo;
4849

4950
import com.oracle.graal.python.PythonLanguage;
@@ -297,7 +298,6 @@ private static String[] initializeCoreFiles() {
297298
// Order matters!
298299
List<String> coreFiles = new ArrayList<>(Arrays.asList(
299300
"object",
300-
"sys",
301301
"type",
302302
"_imp",
303303
"function",
@@ -432,6 +432,8 @@ private static PythonBuiltins[] initializeBuiltins(boolean nativeAccessAllowed)
432432
new WeakRefModuleBuiltins(),
433433
new ReferenceTypeBuiltins(),
434434
new WarningsModuleBuiltins(),
435+
// exceptions
436+
new SystemExitBuiltins(),
435437

436438
// io
437439
new IOModuleBuiltins(),

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

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@
6969
import static com.oracle.graal.python.nodes.BuiltinNames.BUILTINS;
7070
import static com.oracle.graal.python.nodes.BuiltinNames.DISPLAYHOOK;
7171
import static com.oracle.graal.python.nodes.BuiltinNames.EXCEPTHOOK;
72+
import static com.oracle.graal.python.nodes.BuiltinNames.EXIT;
7273
import static com.oracle.graal.python.nodes.BuiltinNames.PYTHONBREAKPOINT;
7374
import static com.oracle.graal.python.nodes.BuiltinNames.STDERR;
7475
import static com.oracle.graal.python.nodes.BuiltinNames.STDIN;
@@ -1559,4 +1560,27 @@ Object setCheckInterval(VirtualFrame frame, @SuppressWarnings("unused") PythonMo
15591560
return PNone.NONE;
15601561
}
15611562
}
1563+
1564+
@Builtin(name = EXIT, declaresExplicitSelf = true, minNumOfPositionalArgs = 1, maxNumOfPositionalArgs = 2, doc = "exit($module, status=None, /)\n" +
1565+
"--\n" +
1566+
"\n" +
1567+
"Exit the interpreter by raising SystemExit(status).\n" +
1568+
"\n" +
1569+
"If the status is omitted or None, it defaults to zero (i.e., success).\n" +
1570+
"If the status is an integer, it will be used as the system exit status.\n" +
1571+
"If it is another kind of object, it will be printed and the system\n" +
1572+
"exit status will be one (i.e., failure).")
1573+
@GenerateNodeFactory
1574+
abstract static class ExitNode extends PythonBinaryBuiltinNode {
1575+
@Specialization(guards = "!isPNone(status)")
1576+
Object exit(@SuppressWarnings("unused") PythonModule sys, Object status) {
1577+
throw raiseSystemExit(status);
1578+
}
1579+
1580+
@Specialization
1581+
@SuppressWarnings("unused")
1582+
Object exitNoCode(PythonModule sys, PNone status) {
1583+
throw raiseSystemExit(0);
1584+
}
1585+
}
15621586
}

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/exception/BaseExceptionBuiltins.java

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,9 @@ protected List<? extends NodeFactory<? extends PythonBuiltinBaseNode>> getNodeFa
9696

9797
@Builtin(name = __INIT__, minNumOfPositionalArgs = 1, takesVarArgs = true)
9898
@GenerateNodeFactory
99-
public abstract static class InitNode extends PythonBuiltinNode {
99+
public abstract static class BaseExceptionInitNode extends PythonBuiltinNode {
100+
public abstract Object execute(PBaseException self, Object[] args);
101+
100102
@Specialization(guards = "args.length == 0")
101103
static Object initNoArgs(@SuppressWarnings("unused") PBaseException self, @SuppressWarnings("unused") Object[] args) {
102104
self.setArgs(null);
@@ -108,6 +110,10 @@ Object initArgs(PBaseException self, Object[] args) {
108110
self.setArgs(factory().createTuple(args));
109111
return PNone.NONE;
110112
}
113+
114+
public static BaseExceptionInitNode create() {
115+
return BaseExceptionBuiltinsFactory.BaseExceptionInitNodeFactory.create(null);
116+
}
111117
}
112118

113119
@Builtin(name = "args", minNumOfPositionalArgs = 1, maxNumOfPositionalArgs = 2, isGetter = true, isSetter = true)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
/*
2+
* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
3+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+
*
5+
* The Universal Permissive License (UPL), Version 1.0
6+
*
7+
* Subject to the condition set forth below, permission is hereby granted to any
8+
* person obtaining a copy of this software, associated documentation and/or
9+
* data (collectively the "Software"), free of charge and under any and all
10+
* copyright rights in the Software, and any and all patent rights owned or
11+
* freely licensable by each licensor hereunder covering either (i) the
12+
* unmodified Software as contributed to or provided by such licensor, or (ii)
13+
* the Larger Works (as defined below), to deal in both
14+
*
15+
* (a) the Software, and
16+
*
17+
* (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if
18+
* one is included with the Software each a "Larger Work" to which the Software
19+
* is contributed by such licensors),
20+
*
21+
* without restriction, including without limitation the rights to copy, create
22+
* derivative works of, display, perform, and distribute the Software and make,
23+
* use, sell, offer for sale, import, export, have made, and have sold the
24+
* Software and the Larger Work(s), and to sublicense the foregoing rights on
25+
* either these or other terms.
26+
*
27+
* This license is subject to the following condition:
28+
*
29+
* The above copyright notice and either this complete permission notice or at a
30+
* minimum a reference to the UPL must be included in all copies or substantial
31+
* portions of the Software.
32+
*
33+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
34+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
35+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
36+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
37+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
38+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
39+
* SOFTWARE.
40+
*/
41+
package com.oracle.graal.python.builtins.objects.exception;
42+
43+
public abstract class BaseExceptionData {
44+
}

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/exception/PBaseException.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,16 @@ public final class PBaseException extends PythonObject {
8989
private PBaseException context;
9090
private PBaseException cause;
9191
private boolean suppressContext = false;
92+
// the data instance is used to store additional information for some of the builtin exceptions not unlike subclassing
93+
private BaseExceptionData data;
94+
95+
public BaseExceptionData getData() {
96+
return data;
97+
}
98+
99+
public void setData(BaseExceptionData data) {
100+
this.data = data;
101+
}
92102

93103
public PBaseException getContext() {
94104
return context;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
/*
2+
* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
3+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+
*
5+
* The Universal Permissive License (UPL), Version 1.0
6+
*
7+
* Subject to the condition set forth below, permission is hereby granted to any
8+
* person obtaining a copy of this software, associated documentation and/or
9+
* data (collectively the "Software"), free of charge and under any and all
10+
* copyright rights in the Software, and any and all patent rights owned or
11+
* freely licensable by each licensor hereunder covering either (i) the
12+
* unmodified Software as contributed to or provided by such licensor, or (ii)
13+
* the Larger Works (as defined below), to deal in both
14+
*
15+
* (a) the Software, and
16+
*
17+
* (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if
18+
* one is included with the Software each a "Larger Work" to which the Software
19+
* is contributed by such licensors),
20+
*
21+
* without restriction, including without limitation the rights to copy, create
22+
* derivative works of, display, perform, and distribute the Software and make,
23+
* use, sell, offer for sale, import, export, have made, and have sold the
24+
* Software and the Larger Work(s), and to sublicense the foregoing rights on
25+
* either these or other terms.
26+
*
27+
* This license is subject to the following condition:
28+
*
29+
* The above copyright notice and either this complete permission notice or at a
30+
* minimum a reference to the UPL must be included in all copies or substantial
31+
* portions of the Software.
32+
*
33+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
34+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
35+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
36+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
37+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
38+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
39+
* SOFTWARE.
40+
*/
41+
package com.oracle.graal.python.builtins.objects.exception;
42+
43+
import static com.oracle.graal.python.nodes.SpecialMethodNames.__INIT__;
44+
45+
import java.util.List;
46+
47+
import com.oracle.graal.python.builtins.Builtin;
48+
import com.oracle.graal.python.builtins.CoreFunctions;
49+
import com.oracle.graal.python.builtins.PythonBuiltinClassType;
50+
import com.oracle.graal.python.builtins.PythonBuiltins;
51+
import com.oracle.graal.python.builtins.objects.PNone;
52+
import com.oracle.graal.python.nodes.function.PythonBuiltinBaseNode;
53+
import com.oracle.graal.python.nodes.function.PythonBuiltinNode;
54+
import com.oracle.truffle.api.CompilerDirectives;
55+
import com.oracle.truffle.api.dsl.Cached;
56+
import com.oracle.truffle.api.dsl.GenerateNodeFactory;
57+
import com.oracle.truffle.api.dsl.NodeFactory;
58+
import com.oracle.truffle.api.dsl.Specialization;
59+
import com.oracle.truffle.api.frame.VirtualFrame;
60+
61+
@CoreFunctions(extendClasses = PythonBuiltinClassType.SystemExit)
62+
public class SystemExitBuiltins extends PythonBuiltins {
63+
64+
@Override
65+
protected List<? extends NodeFactory<? extends PythonBuiltinBaseNode>> getNodeFactories() {
66+
return SystemExitBuiltinsFactory.getFactories();
67+
}
68+
69+
@CompilerDirectives.ValueType
70+
public static class SystemExitData extends BaseExceptionData {
71+
private Object code;
72+
73+
public Object getCode() {
74+
return code;
75+
}
76+
77+
public void setCode(Object code) {
78+
this.code = code;
79+
}
80+
}
81+
82+
@Builtin(name = __INIT__, minNumOfPositionalArgs = 1, takesVarArgs = true)
83+
@GenerateNodeFactory
84+
public abstract static class InitNode extends PythonBuiltinNode {
85+
@Specialization
86+
Object initNoArgs(PBaseException self, Object[] args,
87+
@Cached BaseExceptionBuiltins.BaseExceptionInitNode baseExceptionInitNode) {
88+
final SystemExitData data = new SystemExitData();
89+
if (args.length == 1) {
90+
data.setCode(args[0]);
91+
} else {
92+
data.setCode(factory().createTuple(args));
93+
}
94+
self.setData(data);
95+
baseExceptionInitNode.execute(self, args);
96+
return PNone.NONE;
97+
}
98+
}
99+
100+
@Builtin(name = "code", minNumOfPositionalArgs = 1, maxNumOfPositionalArgs = 2, isGetter = true, isSetter = true, doc = "exception code")
101+
@GenerateNodeFactory
102+
public abstract static class CodeNode extends PythonBuiltinNode {
103+
@Specialization(guards = "isNoValue(none)")
104+
public Object code(PBaseException self, @SuppressWarnings("unused") PNone none) {
105+
return ((SystemExitData)self.getData()).getCode();
106+
}
107+
108+
@Specialization(guards = "!isNoValue(value)")
109+
public Object code(PBaseException self, Object value) {
110+
SystemExitData data = (SystemExitData) self.getData();
111+
if (data == null) {
112+
data = new SystemExitData();
113+
self.setData(data);
114+
}
115+
data.setCode(value);
116+
return PNone.NONE;
117+
}
118+
}
119+
}

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,4 +93,8 @@ public final PException raiseBadInternalCall() {
9393
public final PException raiseOverflow() {
9494
return getRaiseNode().raiseNumberTooLarge(OverflowError, 0);
9595
}
96+
97+
public final PException raiseSystemExit(Object code) {
98+
return getRaiseNode().raiseSystemExit(code);
99+
}
96100
}

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,10 @@ public final PException raiseNumberTooLarge(PythonBuiltinClassType type, Object
121121
return execute(this, type, PNone.NO_VALUE, ErrorMessages.CANNOT_FIT_P_INTO_INDEXSIZED_INT, new Object[]{result});
122122
}
123123

124+
public final PException raiseSystemExit(Object code) {
125+
return raise(PythonBuiltinClassType.SystemExit, code);
126+
}
127+
124128
public final PException raiseHasNoLength(Object result) {
125129
return raise(PythonBuiltinClassType.TypeError, ErrorMessages.OBJ_HAS_NO_LEN, result);
126130
}

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/control/TopLevelExceptionHandler.java

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -47,8 +47,10 @@
4747
import com.oracle.graal.python.builtins.Python3Core;
4848
import com.oracle.graal.python.builtins.objects.PNone;
4949
import com.oracle.graal.python.builtins.objects.dict.PDict;
50+
import com.oracle.graal.python.builtins.objects.exception.BaseExceptionData;
5051
import com.oracle.graal.python.builtins.objects.exception.GetExceptionTracebackNode;
5152
import com.oracle.graal.python.builtins.objects.exception.PBaseException;
53+
import com.oracle.graal.python.builtins.objects.exception.SystemExitBuiltins;
5254
import com.oracle.graal.python.builtins.objects.function.PArguments;
5355
import com.oracle.graal.python.builtins.objects.module.PythonModule;
5456
import com.oracle.graal.python.builtins.objects.traceback.PTraceback;
@@ -248,12 +250,11 @@ private Object handleChildContextExit(PBaseException pythonException) throws PEx
248250
}
249251

250252
private static int getExitCode(PBaseException pythonException) throws CannotCastException {
251-
Object attribute = pythonException.getAttribute("code");
253+
final BaseExceptionData data = pythonException.getData();
252254
int exitcode = 0;
253-
if (attribute != PNone.NONE) {
254-
// CPython checks if the object is subclass of PyLong and only then calls
255-
// PyLong_AsLong, so it always skips __index__/__int__
256-
exitcode = (int) CastToJavaLongLossyNode.getUncached().execute(attribute);
255+
if (data instanceof SystemExitBuiltins.SystemExitData) {
256+
final Object code = ((SystemExitBuiltins.SystemExitData) data).getCode();
257+
exitcode = (int) CastToJavaLongLossyNode.getUncached().execute(code);
257258
}
258259
return exitcode;
259260
}

graalpython/lib-graalpython/exceptions.py

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -43,18 +43,6 @@
4343
#
4444
# ----------------------------------------------------------------------------------------------------------------------
4545

46-
def SystemExit__init__(self, *args):
47-
if len(args) > 1:
48-
self.code = args
49-
elif len(args) == 1:
50-
self.code = args[0]
51-
else:
52-
self.code = 0
53-
BaseException.__init__(self, *args)
54-
55-
SystemExit.__init__ = SystemExit__init__
56-
del SystemExit__init__
57-
5846
def ImportError__init__(self, *args, name=None, path=None, **kwargs):
5947
if kwargs:
6048
kwarg = next(iter(kwargs))

0 commit comments

Comments
 (0)