Skip to content

Commit 90ab65a

Browse files
committed
[GR-23274] Make test_atexit pass
PullRequest: graalpython/1435
2 parents abeee27 + 78c00d7 commit 90ab65a

File tree

10 files changed

+232
-156
lines changed

10 files changed

+232
-156
lines changed
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,15 @@
1+
*graalpython.lib-python.3.test.test_atexit.GeneralTest.test_args
2+
*graalpython.lib-python.3.test.test_atexit.GeneralTest.test_badargs
3+
*graalpython.lib-python.3.test.test_atexit.GeneralTest.test_bound_methods
4+
*graalpython.lib-python.3.test.test_atexit.GeneralTest.test_clear
5+
*graalpython.lib-python.3.test.test_atexit.GeneralTest.test_exit
6+
*graalpython.lib-python.3.test.test_atexit.GeneralTest.test_order
7+
*graalpython.lib-python.3.test.test_atexit.GeneralTest.test_print_tracebacks
8+
*graalpython.lib-python.3.test.test_atexit.GeneralTest.test_raise
9+
*graalpython.lib-python.3.test.test_atexit.GeneralTest.test_raise_unnormalized
10+
*graalpython.lib-python.3.test.test_atexit.GeneralTest.test_shutdown
11+
*graalpython.lib-python.3.test.test_atexit.GeneralTest.test_stress
12+
*graalpython.lib-python.3.test.test_atexit.GeneralTest.test_unregister
113
*graalpython.lib-python.3.test.test_atexit.SubinterpreterTest.test_callback_on_subinterpreter_teardown
214
*graalpython.lib-python.3.test.test_atexit.SubinterpreterTest.test_callbacks_leak
315
*graalpython.lib-python.3.test.test_atexit.SubinterpreterTest.test_callbacks_leak_refcycle

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

Lines changed: 58 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -45,18 +45,25 @@
4545
import com.oracle.graal.python.PythonLanguage;
4646
import com.oracle.graal.python.builtins.Builtin;
4747
import com.oracle.graal.python.builtins.CoreFunctions;
48+
import com.oracle.graal.python.builtins.PythonBuiltinClassType;
4849
import com.oracle.graal.python.builtins.PythonBuiltins;
4950
import com.oracle.graal.python.builtins.objects.PNone;
51+
import com.oracle.graal.python.builtins.objects.exception.PBaseException;
5052
import com.oracle.graal.python.builtins.objects.frame.PFrame;
5153
import com.oracle.graal.python.builtins.objects.function.PKeyword;
54+
import com.oracle.graal.python.builtins.objects.object.PythonObjectLibrary;
5255
import com.oracle.graal.python.nodes.call.CallNode;
5356
import com.oracle.graal.python.nodes.function.PythonBuiltinBaseNode;
57+
import com.oracle.graal.python.nodes.function.PythonBuiltinNode;
5458
import com.oracle.graal.python.nodes.function.builtins.PythonUnaryBuiltinNode;
5559
import com.oracle.graal.python.nodes.function.builtins.PythonVarargsBuiltinNode;
60+
import com.oracle.graal.python.nodes.object.IsBuiltinClassProfile;
5661
import com.oracle.graal.python.runtime.PythonContext;
62+
import com.oracle.graal.python.runtime.exception.ExceptionUtils;
5763
import com.oracle.graal.python.runtime.exception.PException;
5864
import com.oracle.graal.python.util.PythonUtils;
5965
import com.oracle.truffle.api.CompilerDirectives;
66+
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
6067
import com.oracle.truffle.api.TruffleLanguage;
6168
import com.oracle.truffle.api.TruffleLanguage.ContextReference;
6269
import com.oracle.truffle.api.dsl.GenerateNodeFactory;
@@ -75,17 +82,16 @@ protected List<? extends NodeFactory<? extends PythonBuiltinBaseNode>> getNodeFa
7582
@Builtin(name = "register", minNumOfPositionalArgs = 1, takesVarArgs = true, takesVarKeywordArgs = true)
7683
@GenerateNodeFactory
7784
abstract static class RegisterNode extends PythonVarargsBuiltinNode {
78-
private static class AtExitCallTarget extends RootNode {
85+
private static class AtExitRootNode extends RootNode {
7986
@Child private CallNode callNode = CallNode.create();
8087

8188
private final ContextReference<PythonContext> contextRef = lookupContextReference(PythonLanguage.class);
8289

83-
protected AtExitCallTarget(TruffleLanguage<?> language) {
90+
protected AtExitRootNode(TruffleLanguage<?> language) {
8491
super(language);
8592
}
8693

8794
@Override
88-
@SuppressWarnings("try")
8995
public Object execute(VirtualFrame frame) {
9096
PythonContext context = contextRef.get();
9197
context.setTopFrameInfo(PFrame.Reference.EMPTY);
@@ -99,18 +105,35 @@ public Object execute(VirtualFrame frame) {
99105
// from the context.
100106
try {
101107
return callNode.execute(null, callable, arguments, keywords);
108+
} catch (PException e) {
109+
handleException(context, e);
110+
throw e;
102111
} finally {
103112
context.popTopFrameInfo();
104113
context.setCaughtException(null);
105114
}
106115
}
116+
117+
@TruffleBoundary
118+
private static void handleException(PythonContext context, PException e) {
119+
PBaseException pythonException = e.getEscapedException();
120+
PythonObjectLibrary lib = PythonObjectLibrary.getUncached();
121+
if (!IsBuiltinClassProfile.profileClassSlowPath(lib.getLazyPythonClass(pythonException), PythonBuiltinClassType.SystemExit)) {
122+
lib.lookupAndCallRegularMethod(context.getCore().getStderr(), null, "write", "Error in atexit._run_exitfuncs:\n");
123+
try {
124+
ExceptionUtils.printExceptionTraceback(context, pythonException);
125+
} catch (PException pe) {
126+
lib.lookupAndCallRegularMethod(context.getCore().getStderr(), null, "write", "Failed to print traceback\n");
127+
}
128+
}
129+
}
107130
}
108131

109132
@Specialization
110133
Object register(Object callable, Object[] arguments, PKeyword[] keywords) {
111134
CompilerDirectives.transferToInterpreter();
112-
AtExitCallTarget atExitCallTarget = new AtExitCallTarget(getContext().getLanguage());
113-
getContext().registerShutdownHook(callable, arguments, keywords, PythonUtils.getOrCreateCallTarget(atExitCallTarget));
135+
AtExitRootNode atExitRootNode = new AtExitRootNode(getContext().getLanguage());
136+
getContext().registerAtexitHook(callable, arguments, keywords, PythonUtils.getOrCreateCallTarget(atExitRootNode));
114137
return callable;
115138
}
116139
}
@@ -120,7 +143,36 @@ Object register(Object callable, Object[] arguments, PKeyword[] keywords) {
120143
abstract static class UnregisterNode extends PythonUnaryBuiltinNode {
121144
@Specialization
122145
Object register(Object callable) {
123-
getContext().deregisterShutdownHook(callable);
146+
getContext().unregisterAtexitHook(callable);
147+
return PNone.NONE;
148+
}
149+
}
150+
151+
@Builtin(name = "_clear")
152+
@GenerateNodeFactory
153+
abstract static class ClearNode extends PythonBuiltinNode {
154+
@Specialization
155+
Object clear() {
156+
getContext().clearAtexitHooks();
157+
return PNone.NONE;
158+
}
159+
}
160+
161+
@Builtin(name = "_ncallbacks")
162+
@GenerateNodeFactory
163+
abstract static class NCallbacksNode extends PythonBuiltinNode {
164+
@Specialization
165+
int get() {
166+
return getContext().getAtexitHookCount();
167+
}
168+
}
169+
170+
@Builtin(name = "_run_exitfuncs")
171+
@GenerateNodeFactory
172+
abstract static class RunExitfuncsNode extends PythonBuiltinNode {
173+
@Specialization
174+
Object run() {
175+
getContext().runAtexitHooks();
124176
return PNone.NONE;
125177
}
126178
}

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -953,7 +953,7 @@ private Object doOpenFile(String pathname, Set<StandardOpenOption> options, File
953953
options.remove(StandardOpenOption.CREATE_NEW);
954954
options.remove(StandardOpenOption.DELETE_ON_CLOSE);
955955
options.add(StandardOpenOption.CREATE);
956-
getContext().registerShutdownHook(new FileDeleteShutdownHook(truffleFile));
956+
getContext().registerAtexitHook(new FileDeleteShutdownHook(truffleFile));
957957
}
958958

959959
fc = truffleFile.newByteChannel(options, attributes);

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: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,8 @@
4040
*/
4141
package com.oracle.graal.python.nodes;
4242

43+
import java.io.IOException;
44+
4345
import com.oracle.graal.python.PythonLanguage;
4446
import com.oracle.graal.python.builtins.objects.PNone;
4547
import com.oracle.graal.python.builtins.objects.exception.GetExceptionTracebackNode;
@@ -82,7 +84,7 @@ static void writeUnraisable(VirtualFrame frame, PBaseException exception, String
8284
Object unraisablehook = getUnraisableHook.executeObject(frame, sysModule);
8385
Object argumentsFactory = getArgumentsFactory.executeObject(frame, sysModule);
8486
Object exceptionType = lib.getLazyPythonClass(exception);
85-
Object traceback = getExceptionTracebackNode.execute(frame, exception);
87+
Object traceback = getExceptionTracebackNode.execute(exception);
8688
if (traceback == null) {
8789
traceback = PNone.NONE;
8890
}
@@ -94,21 +96,25 @@ static void writeUnraisable(VirtualFrame frame, PBaseException exception, String
9496
factory.createTuple(new Object[]{exceptionType, exception, traceback, messageObj, object != null ? object : PNone.NONE}));
9597
callUnraisableHook.execute(frame, unraisablehook, hookArguments);
9698
} catch (PException e) {
97-
ignoreException(message);
99+
ignoreException(contextRef.get(), message);
98100
}
99101
}
100102

101103
@TruffleBoundary
102-
private static void ignoreException(String message) {
103-
if (message != null) {
104-
System.err.println(formatMessage(message));
105-
} else {
106-
System.err.println("Exception ignored in sys.unraisablehook");
104+
private static void ignoreException(PythonContext context, String message) {
105+
try {
106+
if (message != null) {
107+
context.getEnv().err().write(formatMessage(message).getBytes());
108+
} else {
109+
context.getEnv().err().write("Exception ignored in sys.unraisablehook".getBytes());
110+
}
111+
} catch (IOException ioException) {
112+
ioException.printStackTrace();
107113
}
108114
}
109115

110116
@TruffleBoundary
111-
private static Object formatMessage(String message) {
117+
private static String formatMessage(String message) {
112118
return "Exception ignored " + message;
113119
}
114120

0 commit comments

Comments
 (0)