Skip to content

Commit a5cae88

Browse files
committed
Factor out exception printing from TopLevelExceptionHandler
1 parent 2d155e5 commit a5cae88

File tree

5 files changed

+108
-124
lines changed

5 files changed

+108
-124
lines changed

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -243,9 +243,9 @@ public Object setSuppressContext(PBaseException self, Object value,
243243
public abstract static class TracebackNode extends PythonBuiltinNode {
244244

245245
@Specialization(guards = "isNoValue(tb)")
246-
public Object getTraceback(VirtualFrame frame, PBaseException self, @SuppressWarnings("unused") Object tb,
246+
public Object getTraceback(PBaseException self, @SuppressWarnings("unused") Object tb,
247247
@Cached GetExceptionTracebackNode getExceptionTracebackNode) {
248-
PTraceback traceback = getExceptionTracebackNode.execute(frame, self);
248+
PTraceback traceback = getExceptionTracebackNode.execute(self);
249249
return traceback == null ? PNone.NONE : traceback;
250250
}
251251

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

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,18 +43,19 @@
4343
import com.oracle.graal.python.builtins.objects.traceback.GetTracebackNode;
4444
import com.oracle.graal.python.builtins.objects.traceback.PTraceback;
4545
import com.oracle.truffle.api.dsl.Cached;
46+
import com.oracle.truffle.api.dsl.GenerateUncached;
4647
import com.oracle.truffle.api.dsl.Specialization;
47-
import com.oracle.truffle.api.frame.VirtualFrame;
4848
import com.oracle.truffle.api.nodes.Node;
4949
import com.oracle.truffle.api.profiles.ConditionProfile;
5050

5151
/**
5252
* Use this node to get the traceback object of an exception object. The traceback may need to be
5353
* created lazily and this node takes care of it.
5454
*/
55+
@GenerateUncached
5556
public abstract class GetExceptionTracebackNode extends Node {
5657

57-
public abstract PTraceback execute(VirtualFrame frame, PBaseException e);
58+
public abstract PTraceback execute(PBaseException e);
5859

5960
@Specialization
6061
static PTraceback doExisting(PBaseException e,
@@ -69,4 +70,8 @@ static PTraceback doExisting(PBaseException e,
6970
public static GetExceptionTracebackNode create() {
7071
return GetExceptionTracebackNodeGen.create();
7172
}
73+
74+
public static GetExceptionTracebackNode getUncached() {
75+
return GetExceptionTracebackNodeGen.getUncached();
76+
}
7277
}

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ static void writeUnraisable(VirtualFrame frame, PBaseException exception, String
8282
Object unraisablehook = getUnraisableHook.executeObject(frame, sysModule);
8383
Object argumentsFactory = getArgumentsFactory.executeObject(frame, sysModule);
8484
Object exceptionType = lib.getLazyPythonClass(exception);
85-
Object traceback = getExceptionTracebackNode.execute(frame, exception);
85+
Object traceback = getExceptionTracebackNode.execute(exception);
8686
if (traceback == null) {
8787
traceback = PNone.NONE;
8888
}

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

Lines changed: 29 additions & 119 deletions
Original file line numberDiff line numberDiff line change
@@ -44,30 +44,20 @@
4444
import static com.oracle.graal.python.nodes.SpecialMethodNames.__STR__;
4545
import static com.oracle.graal.python.runtime.exception.PythonErrorType.SystemExit;
4646

47-
import java.io.IOException;
48-
4947
import com.oracle.graal.python.PythonLanguage;
5048
import com.oracle.graal.python.builtins.objects.PNone;
5149
import com.oracle.graal.python.builtins.objects.dict.PDict;
52-
import com.oracle.graal.python.builtins.objects.exception.GetExceptionTracebackNode;
5350
import com.oracle.graal.python.builtins.objects.exception.PBaseException;
5451
import com.oracle.graal.python.builtins.objects.frame.PFrame;
5552
import com.oracle.graal.python.builtins.objects.function.PArguments;
56-
import com.oracle.graal.python.builtins.objects.function.PKeyword;
5753
import com.oracle.graal.python.builtins.objects.module.PythonModule;
5854
import com.oracle.graal.python.builtins.objects.object.PythonObjectLibrary;
59-
import com.oracle.graal.python.builtins.objects.traceback.LazyTraceback;
60-
import com.oracle.graal.python.builtins.objects.traceback.PTraceback;
61-
import com.oracle.graal.python.nodes.BuiltinNames;
62-
import com.oracle.graal.python.nodes.call.CallNode;
63-
import com.oracle.graal.python.nodes.call.special.LookupAndCallUnaryNode;
6455
import com.oracle.graal.python.nodes.object.IsBuiltinClassProfile;
6556
import com.oracle.graal.python.nodes.statement.ExceptionHandlingStatementNode;
6657
import com.oracle.graal.python.nodes.util.CannotCastException;
6758
import com.oracle.graal.python.nodes.util.CastToJavaLongLossyNode;
6859
import com.oracle.graal.python.runtime.ExecutionContext.IndirectCalleeContext;
6960
import com.oracle.graal.python.runtime.PythonContext;
70-
import com.oracle.graal.python.runtime.PythonCore;
7161
import com.oracle.graal.python.runtime.PythonOptions;
7262
import com.oracle.graal.python.runtime.exception.ExceptionUtils;
7363
import com.oracle.graal.python.runtime.exception.PException;
@@ -94,11 +84,6 @@ public class TopLevelExceptionHandler extends RootNode {
9484
@CompilationFinal private LanguageReference<PythonLanguage> language;
9585
@CompilationFinal private ContextReference<PythonContext> context;
9686

97-
@Child private LookupAndCallUnaryNode callStrNode = LookupAndCallUnaryNode.create(__STR__);
98-
@Child private CallNode exceptionHookCallNode = CallNode.create();
99-
@Child private GetExceptionTracebackNode getExceptionTracebackNode;
100-
@Child private PythonObjectFactory pythonObjectFactory;
101-
10287
public TopLevelExceptionHandler(PythonLanguage language, RootNode child) {
10388
super(language);
10489
this.sourceSection = child.getSourceSection();
@@ -129,48 +114,52 @@ private PythonContext getContext() {
129114
return context.get();
130115
}
131116

132-
private PythonObjectFactory factory() {
133-
if (pythonObjectFactory == null) {
134-
CompilerDirectives.transferToInterpreterAndInvalidate();
135-
pythonObjectFactory = insert(PythonObjectFactory.create());
136-
}
137-
return pythonObjectFactory;
138-
}
139-
140117
@Override
141118
public Object execute(VirtualFrame frame) {
142119
if (exception != null) {
143-
printExc(frame, exception.getEscapedException());
144-
return null;
120+
throw handlePythonException(exception.getEscapedException());
145121
} else {
146122
assert getContext().getCurrentException() == null;
147123
try {
148124
return run(frame);
149125
} catch (PException e) {
150126
assert !PArguments.isPythonFrame(frame);
151-
PBaseException pythonException = e.getEscapedException();
152-
printExc(frame, pythonException);
153-
return null;
127+
throw handlePythonException(e.getEscapedException());
154128
} catch (StackOverflowError e) {
155-
PException pe = ExceptionHandlingStatementNode.wrapJavaException(e, this, factory().createBaseException(RecursionError, "maximum recursion depth exceeded", new Object[]{}));
156-
PBaseException pythonException = pe.getUnreifiedException();
157-
printExc(frame, pythonException);
158-
return null;
129+
PBaseException newException = PythonObjectFactory.getUncached().createBaseException(RecursionError, "maximum recursion depth exceeded", new Object[]{});
130+
PException pe = ExceptionHandlingStatementNode.wrapJavaException(e, this, newException);
131+
throw handlePythonException(pe.getEscapedException());
159132
} catch (Exception e) {
160-
handleException(e);
133+
handleJavaException(e);
161134
throw e;
162135
}
163136
}
164137
}
165138

166139
@TruffleBoundary
167-
private void handleException(Exception e) {
140+
private PException handlePythonException(PBaseException pythonException) {
141+
if (IsBuiltinClassProfile.profileClassSlowPath(PythonObjectLibrary.getUncached().getLazyPythonClass(pythonException), SystemExit)) {
142+
handleSystemExit(pythonException);
143+
}
144+
ExceptionUtils.printExceptionTraceback(getContext(), pythonException);
145+
if (PythonOptions.isPExceptionWithJavaStacktrace(getPythonLanguage())) {
146+
ExceptionUtils.printJavaStackTrace(pythonException.getException());
147+
}
148+
if (getSourceSection().getSource().isInteractive()) {
149+
throw pythonException.getExceptionForReraise(pythonException.getTraceback());
150+
} else {
151+
throw new PythonExitException(this, 1);
152+
}
153+
}
154+
155+
@TruffleBoundary
156+
private void handleJavaException(Exception e) {
168157
try {
169158
boolean exitException = InteropLibrary.getUncached().isException(e) && InteropLibrary.getUncached().getExceptionType(e) == ExceptionType.EXIT;
170159
if (!exitException) {
171160
ExceptionUtils.printPythonLikeStackTrace(e);
172161
if (PythonOptions.isWithJavaStacktrace(getPythonLanguage())) {
173-
printStackTrace(e);
162+
e.printStackTrace();
174163
}
175164
}
176165
} catch (UnsupportedMessageException unsupportedMessageException) {
@@ -183,59 +172,8 @@ public SourceSection getSourceSection() {
183172
return sourceSection;
184173
}
185174

186-
/**
187-
* This function is kind-of analogous to PyErr_PrintEx. TODO (timfel): Figure out if we should
188-
* move this somewhere else
189-
*/
190-
private void printExc(VirtualFrame frame, PBaseException pythonException) {
191-
CompilerDirectives.transferToInterpreter();
192-
PythonContext theContext = getContext();
193-
PythonCore core = theContext.getCore();
194-
if (IsBuiltinClassProfile.profileClassSlowPath(PythonObjectLibrary.getUncached().getLazyPythonClass(pythonException), SystemExit)) {
195-
handleSystemExit(frame, pythonException);
196-
}
197-
198-
PBaseException value = pythonException;
199-
Object type = PythonObjectLibrary.getUncached().getLazyPythonClass(value);
200-
PTraceback execute = ensureGetTracebackNode().execute(frame, value);
201-
Object tb = execute != null ? execute : PNone.NONE;
202-
203-
PythonModule sys = core.lookupBuiltinModule("sys");
204-
sys.setAttribute(BuiltinNames.LAST_TYPE, type);
205-
sys.setAttribute(BuiltinNames.LAST_VALUE, value);
206-
sys.setAttribute(BuiltinNames.LAST_TRACEBACK, tb);
207-
208-
Object hook = sys.getAttribute(BuiltinNames.EXCEPTHOOK);
209-
if (theContext.getOption(PythonOptions.AlwaysRunExcepthook)) {
210-
if (hook != PNone.NO_VALUE) {
211-
try {
212-
// Note: it is important to pass frame 'null' because that will cause the
213-
// CallNode to tread the invoke like a foreign call and access the top frame ref
214-
// in the context.
215-
exceptionHookCallNode.execute(null, hook, new Object[]{type, value, tb}, PKeyword.EMPTY_KEYWORDS);
216-
} catch (PException internalError) {
217-
// More complex handling of errors in exception printing is done in our
218-
// Python code, if we get here, we just fall back to the launcher
219-
throw pythonException.getExceptionForReraise(pythonException.getTraceback());
220-
}
221-
if (PythonOptions.isPExceptionWithJavaStacktrace(getPythonLanguage())) {
222-
printJavaStackTrace(pythonException.getException());
223-
}
224-
if (!getSourceSection().getSource().isInteractive()) {
225-
throw new PythonExitException(this, 1);
226-
}
227-
} else {
228-
try {
229-
theContext.getEnv().err().write("sys.excepthook is missing\n".getBytes());
230-
} catch (IOException ioException) {
231-
ioException.printStackTrace();
232-
}
233-
}
234-
}
235-
throw pythonException.getExceptionForReraise(pythonException.getTraceback());
236-
}
237-
238-
private void handleSystemExit(VirtualFrame frame, PBaseException pythonException) {
175+
@TruffleBoundary
176+
private void handleSystemExit(PBaseException pythonException) {
239177
PythonContext theContext = getContext();
240178
if (theContext.getOption(PythonOptions.InspectFlag) && !getSourceSection().getSource().isInteractive()) {
241179
// Don't exit if -i flag was given and we're not yet running interactively
@@ -255,43 +193,15 @@ private void handleSystemExit(VirtualFrame frame, PBaseException pythonException
255193
}
256194
if (theContext.getOption(PythonOptions.AlwaysRunExcepthook)) {
257195
// If we failed to dig out the exit code we just print and leave
196+
PythonObjectLibrary lib = PythonObjectLibrary.getUncached();
258197
Object stderr = theContext.getCore().getStderr();
259-
Object message = callStrNode.executeObject(frame, pythonException);
260-
PythonObjectLibrary.getUncached().lookupAndCallRegularMethod(stderr, null, "write", message);
198+
Object message = lib.lookupAndCallSpecialMethod(pythonException, null, __STR__);
199+
lib.lookupAndCallRegularMethod(stderr, null, "write", message);
261200
throw new PythonExitException(this, 1);
262201
}
263202
throw pythonException.getExceptionForReraise(pythonException.getTraceback());
264203
}
265204

266-
@TruffleBoundary
267-
private static void printJavaStackTrace(PException e) {
268-
LazyTraceback traceback = e.getTraceback();
269-
while (traceback != null && traceback.getNextChain() != null) {
270-
traceback = traceback.getNextChain();
271-
}
272-
if (traceback != null) {
273-
PException exception = traceback.getException();
274-
if (exception.getCause() != null && exception.getCause().getStackTrace().length != 0) {
275-
exception.getCause().printStackTrace();
276-
} else {
277-
exception.printStackTrace();
278-
}
279-
}
280-
}
281-
282-
@TruffleBoundary
283-
private static void printStackTrace(Throwable e) {
284-
e.printStackTrace();
285-
}
286-
287-
private GetExceptionTracebackNode ensureGetTracebackNode() {
288-
if (getExceptionTracebackNode == null) {
289-
CompilerDirectives.transferToInterpreterAndInvalidate();
290-
getExceptionTracebackNode = insert(GetExceptionTracebackNode.create());
291-
}
292-
return getExceptionTracebackNode;
293-
}
294-
295205
private Object run(VirtualFrame frame) {
296206
Object[] arguments = PArguments.create(frame.getArguments().length);
297207
for (int i = 0; i < frame.getArguments().length; i++) {

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/exception/ExceptionUtils.java

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,10 +40,24 @@
4040
*/
4141
package com.oracle.graal.python.runtime.exception;
4242

43+
import java.io.IOException;
4344
import java.util.ArrayList;
4445
import java.util.List;
4546
import java.util.ListIterator;
4647

48+
import com.oracle.graal.python.builtins.objects.PNone;
49+
import com.oracle.graal.python.builtins.objects.exception.GetExceptionTracebackNode;
50+
import com.oracle.graal.python.builtins.objects.exception.PBaseException;
51+
import com.oracle.graal.python.builtins.objects.function.PKeyword;
52+
import com.oracle.graal.python.builtins.objects.module.PythonModule;
53+
import com.oracle.graal.python.builtins.objects.object.PythonObjectLibrary;
54+
import com.oracle.graal.python.builtins.objects.traceback.LazyTraceback;
55+
import com.oracle.graal.python.builtins.objects.traceback.PTraceback;
56+
import com.oracle.graal.python.nodes.BuiltinNames;
57+
import com.oracle.graal.python.nodes.call.CallNode;
58+
import com.oracle.graal.python.runtime.PythonContext;
59+
import com.oracle.graal.python.runtime.PythonCore;
60+
import com.oracle.graal.python.runtime.PythonOptions;
4761
import com.oracle.truffle.api.CompilerAsserts;
4862
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
4963
import com.oracle.truffle.api.RootCallTarget;
@@ -129,4 +143,59 @@ private static void printStack(final ArrayList<String> stack) {
129143
System.err.println(listIterator.previous());
130144
}
131145
}
146+
147+
/**
148+
* This function is kind-of analogous to PyErr_PrintEx
149+
*/
150+
@TruffleBoundary
151+
public static void printExceptionTraceback(PythonContext context, PBaseException pythonException) {
152+
PythonCore core = context.getCore();
153+
154+
Object type = PythonObjectLibrary.getUncached().getLazyPythonClass(pythonException);
155+
PTraceback execute = GetExceptionTracebackNode.getUncached().execute(pythonException);
156+
Object tb = execute != null ? execute : PNone.NONE;
157+
158+
PythonModule sys = core.lookupBuiltinModule("sys");
159+
sys.setAttribute(BuiltinNames.LAST_TYPE, type);
160+
sys.setAttribute(BuiltinNames.LAST_VALUE, pythonException);
161+
sys.setAttribute(BuiltinNames.LAST_TRACEBACK, tb);
162+
163+
Object hook = sys.getAttribute(BuiltinNames.EXCEPTHOOK);
164+
if (context.getOption(PythonOptions.AlwaysRunExcepthook)) {
165+
if (hook != PNone.NO_VALUE) {
166+
try {
167+
// Note: it is important to pass frame 'null' because that will cause the
168+
// CallNode to tread the invoke like a foreign call and access the top frame ref
169+
// in the context.
170+
CallNode.getUncached().execute(null, hook, new Object[]{type, pythonException, tb}, PKeyword.EMPTY_KEYWORDS);
171+
} catch (PException internalError) {
172+
// More complex handling of errors in exception printing is done in our
173+
// Python code, if we get here, we just fall back to the launcher
174+
throw pythonException.getExceptionForReraise(pythonException.getTraceback());
175+
}
176+
} else {
177+
try {
178+
context.getEnv().err().write("sys.excepthook is missing\n".getBytes());
179+
} catch (IOException ioException) {
180+
ioException.printStackTrace();
181+
}
182+
}
183+
}
184+
}
185+
186+
@TruffleBoundary
187+
public static void printJavaStackTrace(PException e) {
188+
LazyTraceback traceback = e.getTraceback();
189+
while (traceback != null && traceback.getNextChain() != null) {
190+
traceback = traceback.getNextChain();
191+
}
192+
if (traceback != null) {
193+
PException exception = traceback.getException();
194+
if (exception.getCause() != null && exception.getCause().getStackTrace().length != 0) {
195+
exception.getCause().printStackTrace();
196+
} else {
197+
exception.printStackTrace();
198+
}
199+
}
200+
}
132201
}

0 commit comments

Comments
 (0)