Skip to content

Commit ec365d2

Browse files
committed
Handle interop messages for native exceptions
1 parent 9c63604 commit ec365d2

File tree

6 files changed

+148
-85
lines changed

6 files changed

+148
-85
lines changed

graalpython/com.oracle.graal.python.test/src/com/oracle/graal/python/test/builtin/modules/ConversionNodeTests.java

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2021, 2024, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* The Universal Permissive License (UPL), Version 1.0
@@ -46,7 +46,6 @@
4646
import org.junit.function.ThrowingRunnable;
4747

4848
import com.oracle.graal.python.PythonLanguage;
49-
import com.oracle.graal.python.builtins.objects.exception.PBaseException;
5049
import com.oracle.graal.python.builtins.objects.function.PArguments;
5150
import com.oracle.graal.python.builtins.objects.function.Signature;
5251
import com.oracle.graal.python.nodes.PRootNode;
@@ -109,15 +108,14 @@ public boolean isPythonInternal() {
109108
}
110109
} catch (PException e) {
111110
// materialize PException's error message since we are leaving Python
112-
if (e.getUnreifiedException() instanceof PBaseException managedException) {
113-
e.setMessage(managedException.getFormattedMessage());
114-
}
111+
e.materializeMessage();
115112
throw e;
116113
}
117114
}
118115

119116
protected void expectPythonMessage(String expectedMessage, ThrowingRunnable runnable) {
120117
PException exception = Assert.assertThrows(PException.class, runnable);
118+
exception.materializeMessage();
121119
Assert.assertEquals(expectedMessage, exception.getMessage());
122120
}
123121
}

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/cext/hpy/GraalHPyContext.java

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* The Universal Permissive License (UPL), Version 1.0
@@ -77,7 +77,6 @@
7777
import com.oracle.graal.python.builtins.objects.cext.hpy.llvm.GraalHPyLLVMContext;
7878
import com.oracle.graal.python.builtins.objects.dict.PDict;
7979
import com.oracle.graal.python.builtins.objects.ellipsis.PEllipsis;
80-
import com.oracle.graal.python.builtins.objects.exception.PBaseException;
8180
import com.oracle.graal.python.builtins.objects.frame.PFrame;
8281
import com.oracle.graal.python.builtins.objects.function.PArguments;
8382
import com.oracle.graal.python.builtins.objects.function.Signature;
@@ -96,8 +95,8 @@
9695
import com.oracle.graal.python.runtime.PythonOptions;
9796
import com.oracle.graal.python.runtime.PythonOptions.HPyBackendMode;
9897
import com.oracle.graal.python.runtime.exception.PException;
99-
import com.oracle.graal.python.util.PythonUtils;
10098
import com.oracle.graal.python.util.PythonSystemThreadTask;
99+
import com.oracle.graal.python.util.PythonUtils;
101100
import com.oracle.truffle.api.CompilerAsserts;
102101
import com.oracle.truffle.api.CompilerDirectives;
103102
import com.oracle.truffle.api.CompilerDirectives.CompilationFinal;
@@ -588,9 +587,7 @@ public void doRun() {
588587
* receive a Python exception. If it happens, consider that to be a problem
589588
* (however, it is not fatal problem).
590589
*/
591-
if (e.getUnreifiedException() instanceof PBaseException managedException) {
592-
e.setMessage(managedException.getFormattedMessage());
593-
}
590+
e.materializeMessage();
594591
LOGGER.warning("HPy reference cleaner thread received a Python exception: " + e);
595592
}
596593
}

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

Lines changed: 13 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* The Universal Permissive License (UPL), Version 1.0
@@ -46,29 +46,24 @@
4646
import com.oracle.graal.python.builtins.PythonBuiltinClassType;
4747
import com.oracle.graal.python.builtins.objects.PNone;
4848
import com.oracle.graal.python.builtins.objects.cext.PythonNativeClass;
49-
import com.oracle.graal.python.builtins.objects.common.SequenceStorageNodes.GetItemScalarNode;
5049
import com.oracle.graal.python.builtins.objects.frame.PFrame;
5150
import com.oracle.graal.python.builtins.objects.object.PythonObject;
5251
import com.oracle.graal.python.builtins.objects.traceback.LazyTraceback;
5352
import com.oracle.graal.python.builtins.objects.traceback.PTraceback;
5453
import com.oracle.graal.python.builtins.objects.tuple.PTuple;
5554
import com.oracle.graal.python.builtins.objects.type.PythonBuiltinClass;
5655
import com.oracle.graal.python.builtins.objects.type.TypeNodes;
57-
import com.oracle.graal.python.builtins.objects.type.TypeNodes.GetNameNode;
5856
import com.oracle.graal.python.lib.PyExceptionInstanceCheckNode;
5957
import com.oracle.graal.python.nodes.PRaiseNode;
6058
import com.oracle.graal.python.nodes.attributes.ReadAttributeFromPythonObjectNode;
6159
import com.oracle.graal.python.nodes.object.GetClassNode;
62-
import com.oracle.graal.python.nodes.object.GetClassNode.GetPythonObjectClassNode;
6360
import com.oracle.graal.python.nodes.util.CannotCastException;
6461
import com.oracle.graal.python.nodes.util.CastToJavaIntExactNode;
6562
import com.oracle.graal.python.runtime.GilNode;
63+
import com.oracle.graal.python.runtime.exception.ExceptionUtils;
6664
import com.oracle.graal.python.runtime.exception.PException;
67-
import com.oracle.graal.python.runtime.formatting.ErrorMessageFormatter;
68-
import com.oracle.graal.python.runtime.sequence.storage.SequenceStorage;
6965
import com.oracle.graal.python.util.PythonUtils;
7066
import com.oracle.truffle.api.CompilerAsserts;
71-
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
7267
import com.oracle.truffle.api.dsl.Bind;
7368
import com.oracle.truffle.api.dsl.Cached;
7469
import com.oracle.truffle.api.dsl.Cached.Exclusive;
@@ -235,36 +230,6 @@ public Object[] getMessageArgs() {
235230
return messageArgs != null ? messageArgs.clone() : PythonUtils.EMPTY_OBJECT_ARRAY;
236231
}
237232

238-
@TruffleBoundary
239-
public String getFormattedMessage() {
240-
final Object clazz = GetPythonObjectClassNode.executeUncached(this);
241-
String typeName = GetNameNode.doSlowPath(clazz).toJavaStringUncached();
242-
if (args == null) {
243-
if (messageArgs != null && messageArgs.length > 0) {
244-
return typeName + ": " + ErrorMessageFormatter.format(messageFormat.toJavaStringUncached(), getMessageArgs());
245-
} else if (hasMessageFormat) {
246-
return typeName + ": " + messageFormat.toJavaStringUncached();
247-
} else {
248-
return typeName;
249-
}
250-
} else {
251-
SequenceStorage storage = args.getSequenceStorage();
252-
if (storage.length() == 0) {
253-
return typeName;
254-
} else {
255-
StringBuilder builder = new StringBuilder(typeName);
256-
builder.append(": ");
257-
for (int i = 0; i < storage.length(); i++) {
258-
if (i > 0) {
259-
builder.append(", ");
260-
}
261-
builder.append(GetItemScalarNode.executeUncached(storage, i));
262-
}
263-
return builder.toString();
264-
}
265-
}
266-
}
267-
268233
@Override
269234
public String toString() {
270235
CompilerAsserts.neverPartOfCompilation();
@@ -384,7 +349,7 @@ boolean hasExceptionMessage() {
384349
String getExceptionMessage(@Shared("gil") @Cached GilNode gil) {
385350
boolean mustRelease = gil.acquire();
386351
try {
387-
return getFormattedMessage();
352+
return ExceptionUtils.getExceptionMessage(this);
388353
} finally {
389354
gil.release(mustRelease);
390355
}
@@ -425,32 +390,21 @@ int getExceptionExitStatus(
425390
}
426391

427392
@ExportMessage
428-
boolean hasExceptionCause(@Shared("gil") @Cached GilNode gil) {
429-
boolean mustRelease = gil.acquire();
430-
try {
431-
return cause != null || (!suppressContext && context != null);
432-
} finally {
433-
gil.release(mustRelease);
434-
}
393+
boolean hasExceptionCause() {
394+
return cause != null || !suppressContext && context != null;
435395
}
436396

437397
@ExportMessage
438398
Object getExceptionCause(
439399
@Bind("$node") Node inliningTarget,
440-
@Exclusive @Cached InlinedBranchProfile unsupportedProfile,
441-
@Shared("gil") @Cached GilNode gil) throws UnsupportedMessageException {
442-
boolean mustRelease = gil.acquire();
443-
try {
444-
if (cause != null) {
445-
return cause;
446-
}
447-
if (!suppressContext && context != null) {
448-
return context;
449-
}
450-
unsupportedProfile.enter(inliningTarget);
451-
throw UnsupportedMessageException.create();
452-
} finally {
453-
gil.release(mustRelease);
400+
@Exclusive @Cached InlinedBranchProfile unsupportedProfile) throws UnsupportedMessageException {
401+
if (cause != null) {
402+
return cause;
403+
}
404+
if (!suppressContext && context != null) {
405+
return context;
454406
}
407+
unsupportedProfile.enter(inliningTarget);
408+
throw UnsupportedMessageException.create();
455409
}
456410
}

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2017, 2024, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* The Universal Permissive License (UPL), Version 1.0
@@ -203,8 +203,8 @@ private AbstractTruffleException handlePythonException(AbstractTruffleException
203203
}
204204
}
205205
// Before we leave Python, format the message since outside the context
206-
if (e instanceof PException pe && pythonException instanceof PBaseException managedException) {
207-
pe.setMessage(managedException.getFormattedMessage());
206+
if (e instanceof PException pe) {
207+
pe.materializeMessage();
208208
}
209209
throw e;
210210
}

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

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* The Universal Permissive License (UPL), Version 1.0
@@ -55,6 +55,8 @@
5555
import com.oracle.graal.python.builtins.objects.exception.PBaseException;
5656
import com.oracle.graal.python.builtins.objects.function.PKeyword;
5757
import com.oracle.graal.python.builtins.objects.traceback.LazyTraceback;
58+
import com.oracle.graal.python.builtins.objects.type.TypeNodes;
59+
import com.oracle.graal.python.lib.PyObjectStrAsTruffleStringNode;
5860
import com.oracle.graal.python.nodes.BuiltinNames;
5961
import com.oracle.graal.python.nodes.ErrorMessages;
6062
import com.oracle.graal.python.nodes.bytecode.FrameInfo;
@@ -72,6 +74,7 @@
7274
import com.oracle.truffle.api.Truffle;
7375
import com.oracle.truffle.api.TruffleStackTrace;
7476
import com.oracle.truffle.api.TruffleStackTraceElement;
77+
import com.oracle.truffle.api.exception.AbstractTruffleException;
7578
import com.oracle.truffle.api.frame.Frame;
7679
import com.oracle.truffle.api.frame.FrameDescriptor;
7780
import com.oracle.truffle.api.frame.FrameInstance;
@@ -282,4 +285,21 @@ public static PException wrapJavaExceptionIfApplicable(Node location, Throwable
282285
}
283286
return null;
284287
}
288+
289+
@TruffleBoundary
290+
public static String getExceptionMessage(Object exception) {
291+
final Object type = GetClassNode.executeUncached(exception);
292+
String typeName = TypeNodes.GetNameNode.doSlowPath(type).toJavaStringUncached();
293+
String str;
294+
try {
295+
str = PyObjectStrAsTruffleStringNode.executeUncached(exception).toJavaStringUncached();
296+
} catch (AbstractTruffleException e) {
297+
str = "<exception str() failed>";
298+
}
299+
if (str.isEmpty()) {
300+
return typeName;
301+
} else {
302+
return typeName + ": " + str;
303+
}
304+
}
285305
}

0 commit comments

Comments
 (0)