Skip to content

Commit 73bed78

Browse files
committed
[GR-67957] Avoid _call_with_frames_removed
PullRequest: graalpython/3921
2 parents ee36da4 + 71b5656 commit 73bed78

File tree

16 files changed

+187
-142
lines changed

16 files changed

+187
-142
lines changed

graalpython/com.oracle.graal.python.cext/src/pylifecycle.c

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -74,9 +74,16 @@ _Py_IsFinalizing(void)
7474
}
7575

7676
void _Py_NO_RETURN _Py_FatalErrorFunc(const char *func, const char *msg) {
77-
GraalPyPrivate_FatalErrorFunc(func, msg, -1);
78-
/* If the above upcall returns, then we just fall through to the 'abort' call. */
79-
abort();
77+
const char *prefix1 = "", *prefix2 = "";
78+
if (func) {
79+
prefix1 = func;
80+
prefix2 = ": ";
81+
}
82+
if (!msg) {
83+
msg = "<message not set>";
84+
}
85+
fprintf(stderr, "Fatal Python error: %s%s%s\n", prefix1, prefix2, msg);
86+
abort();
8087
}
8188

8289
_PyRuntimeState _PyRuntime

graalpython/com.oracle.graal.python.test/src/tests/test_repl.py

Lines changed: 36 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -37,18 +37,19 @@
3737
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
3838
# SOFTWARE.
3939

40-
import sys
40+
import os
4141
import platform
42+
import re
43+
import select
44+
import subprocess
45+
import sys
46+
import tempfile
4247
import unittest
48+
from dataclasses import dataclass
49+
from textwrap import dedent
4350

44-
if (sys.platform != 'win32' and (sys.platform != 'linux' or platform.machine() != 'aarch64')) and (sys.implementation.name != 'graalpy' or __graalpython__.posix_module_backend() != 'java'):
45-
import os
46-
import re
47-
import select
48-
import subprocess
49-
import tempfile
50-
import termios
51-
from textwrap import dedent
51+
if (sys.platform != 'win32' and (sys.platform != 'linux' or platform.machine() != 'aarch64')) and (
52+
sys.implementation.name != 'graalpy' or __graalpython__.posix_module_backend() != 'java'):
5253

5354
# The terminal tests can be flaky
5455
def autoretry(fn):
@@ -63,16 +64,25 @@ def decorated(*args, **kwargs):
6364
print("Retrying test")
6465
continue
6566
fn(*args, **kwargs)
67+
6668
return decorated
6769

6870

71+
@dataclass
72+
class ExpectedInOutItem:
73+
prompt: str
74+
input: str
75+
output: str
76+
77+
6978
@autoretry
7079
def validate_repl(stdin, python_args=(), ignore_preamble=True):
7180
env = os.environ.copy()
7281
env['TERM'] = 'ansi'
7382
env['PYTHONIOENCODING'] = 'utf-8'
7483
pty_parent, pty_child = os.openpty()
7584
try:
85+
import termios
7686
termios.tcsetwinsize(pty_parent, (60, 80))
7787
proc = subprocess.Popen(
7888
[sys.executable, '-I', *python_args],
@@ -82,36 +92,35 @@ def validate_repl(stdin, python_args=(), ignore_preamble=True):
8292
stderr=pty_child,
8393
)
8494
out = ''
85-
input_and_output = []
95+
input_and_output: list[ExpectedInOutItem] = []
8696
expected_preamble = ''
87-
in_matches = list(re.finditer(r'^(>>>|\.\.\.) (.*)', stdin, flags=re.MULTILINE))
97+
in_matches = list(re.finditer(r'^(>>>|\.\.\.) ?(.*)', stdin, flags=re.MULTILINE))
8898
for i, match in enumerate(in_matches):
8999
if i == 0:
90100
expected_preamble = stdin[:match.start() - 1] if match.start() else ''
91-
input_and_output.append((
92-
match.group(1),
93-
match.group(2),
94-
stdin[match.end():in_matches[i + 1].start() - 1 if i + 1 < len(in_matches) else -1],
95-
))
101+
prompt = match.group(1)
102+
expected_input = match.group(2)
103+
expected_output = stdin[match.end():in_matches[i + 1].start() - 1 if i + 1 < len(in_matches) else -1]
104+
input_and_output.append(ExpectedInOutItem(prompt, expected_input, expected_output))
96105
index = -1
97106
whole_out = ''
98107
while True:
99108
rlist, _, _ = select.select([pty_parent], [], [], 60)
100109
assert pty_parent in rlist, f"Timed out waiting for REPL output. Output: {whole_out}{out}"
101110
out += os.read(pty_parent, 1024).decode('utf-8')
102111
out = re.sub(r'\x1b\[(?:\?2004[hl]|\d+[A-G])', '', out)
103-
out = out.replace('\r\n', '\n')
112+
out = re.sub(r'\r+\n', '\n', out)
104113
if out == '>>> ' or out.endswith(('\n>>> ', '\n... ')):
105114
prompt = out[:3]
106115
actual = out[:-5]
107116
if index >= 0:
108-
expected_prompt, current_in, expected_out = input_and_output[index]
109-
assert prompt == expected_prompt
110-
expected = f'{expected_prompt} {current_in}{expected_out}'
117+
current = input_and_output[index]
118+
assert prompt == current.prompt, f"Actual prompt: {prompt}\nExpected prompt: {current.prompt}"
119+
expected = f'{current.prompt} {current.input}{current.output}'
111120
else:
112121
expected = expected_preamble
113122
if index >= 0 or not ignore_preamble:
114-
assert actual == expected, f'Actual:\n{actual!r}\nExpected:\n{expected!r}'
123+
assert actual == expected, f'Actual:\n{actual!r}\nExpected:\n{expected!r}\nWhole output:\n{whole_out}{out}'
115124
index += 1
116125
whole_out += out[:-4]
117126
out = out[-4:]
@@ -123,7 +132,7 @@ def validate_repl(stdin, python_args=(), ignore_preamble=True):
123132
assert not out.strip(), f"Garbage after EOF:\n{out!r}"
124133
return
125134
else:
126-
_, next_in, _ = input_and_output[index]
135+
next_in = input_and_output[index].input
127136
os.write(pty_parent, next_in.encode('utf-8') + b'\r')
128137
finally:
129138
os.close(pty_child)
@@ -147,21 +156,21 @@ def test_continuation():
147156
>>> def foo():
148157
... a = 1
149158
... return a
150-
...
159+
...
151160
>>> class Foo:
152161
... def meth(self):
153162
... return 1
154-
...
163+
...
155164
>>> from functools import wraps
156165
>>> @wraps
157166
... def foo(fn):
158167
... return fn
159-
...
168+
...
160169
>>> from contextlib import contextmanager
161170
>>> @contextmanager
162171
... class Foo:
163172
... pass
164-
...
173+
...
165174
>>> """
166175
... asdf
167176
... """
@@ -182,7 +191,7 @@ def test_exceptions():
182191
>>> class BrokenRepr:
183192
... def __repr__(self):
184193
... asdf
185-
...
194+
...
186195
>>> BrokenRepr()
187196
Traceback (most recent call last):
188197
File "<stdin>", line 1, in <module>

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

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -91,14 +91,14 @@
9191
import com.oracle.graal.python.builtins.objects.object.PythonObject;
9292
import com.oracle.graal.python.builtins.objects.str.PString;
9393
import com.oracle.graal.python.compiler.Compiler;
94+
import com.oracle.graal.python.lib.PyObjectGetAttr;
9495
import com.oracle.graal.python.lib.PyObjectLookupAttr;
9596
import com.oracle.graal.python.lib.PyObjectSetAttr;
9697
import com.oracle.graal.python.lib.PyObjectStrAsTruffleStringNode;
9798
import com.oracle.graal.python.nodes.ErrorMessages;
9899
import com.oracle.graal.python.nodes.PConstructAndRaiseNode;
99100
import com.oracle.graal.python.nodes.PGuards;
100101
import com.oracle.graal.python.nodes.PRaiseNode;
101-
import com.oracle.graal.python.nodes.attributes.ReadAttributeFromPythonObjectNode;
102102
import com.oracle.graal.python.nodes.attributes.WriteAttributeToPythonObjectNode;
103103
import com.oracle.graal.python.nodes.call.CallDispatchers;
104104
import com.oracle.graal.python.nodes.function.PythonBuiltinBaseNode;
@@ -274,9 +274,7 @@ protected PBytes getMagicNumberPBytes() {
274274
}
275275
}
276276

277-
@Builtin(name = "__create_dynamic__", minNumOfPositionalArgs = 2)
278-
@GenerateNodeFactory
279-
public abstract static class CreateDynamic extends PythonBinaryBuiltinNode {
277+
public abstract static class CreateDynamic extends Node {
280278

281279
@Child private CheckFunctionResultNode checkResultNode;
282280

@@ -287,13 +285,18 @@ Object run(VirtualFrame frame, PythonObject moduleSpec, @SuppressWarnings("unuse
287285
@Bind Node inliningTarget,
288286
@Bind PythonContext context,
289287
@Cached("createFor($node)") IndirectCallData indirectCallData,
290-
@Cached ReadAttributeFromPythonObjectNode readNameNode,
291-
@Cached ReadAttributeFromPythonObjectNode readOriginNode,
288+
@Cached PyObjectGetAttr getAttr,
292289
@Cached CastToTruffleStringNode castToTruffleStringNode,
293290
@Cached TruffleString.EqualNode eqNode,
294-
@Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) {
295-
TruffleString name = castToTruffleStringNode.execute(inliningTarget, readNameNode.execute(moduleSpec, T_NAME));
296-
TruffleString path = castToTruffleStringNode.execute(inliningTarget, readOriginNode.execute(moduleSpec, T_ORIGIN));
291+
@Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode,
292+
@Cached PRaiseNode raiseNode) {
293+
TruffleString name, path;
294+
try {
295+
name = castToTruffleStringNode.execute(inliningTarget, getAttr.execute(inliningTarget, moduleSpec, T_NAME));
296+
path = castToTruffleStringNode.execute(inliningTarget, getAttr.execute(inliningTarget, moduleSpec, T_ORIGIN));
297+
} catch (CannotCastException e) {
298+
throw raiseNode.raise(inliningTarget, TypeError, ErrorMessages.BAD_ARG_TYPE_FOR_BUILTIN_OP);
299+
}
297300

298301
PythonLanguage language = context.getLanguage(inliningTarget);
299302
Object state = IndirectCallContext.enter(frame, language, context, indirectCallData);

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/cext/PythonCextPyLifecycleBuiltins.java

Lines changed: 0 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -41,17 +41,11 @@
4141
package com.oracle.graal.python.builtins.modules.cext;
4242

4343
import static com.oracle.graal.python.builtins.modules.cext.PythonCextBuiltins.CApiCallPath.Direct;
44-
import static com.oracle.graal.python.builtins.modules.cext.PythonCextBuiltins.CApiCallPath.Ignored;
45-
import static com.oracle.graal.python.builtins.objects.cext.capi.transitions.ArgDescriptor.ConstCharPtrAsTruffleString;
4644
import static com.oracle.graal.python.builtins.objects.cext.capi.transitions.ArgDescriptor.Int;
47-
import static com.oracle.graal.python.builtins.objects.cext.capi.transitions.ArgDescriptor.Void;
4845
import static com.oracle.graal.python.builtins.objects.cext.capi.transitions.ArgDescriptor.func_voidvoid;
4946

5047
import com.oracle.graal.python.builtins.modules.cext.PythonCextBuiltins.CApiBuiltin;
51-
import com.oracle.graal.python.builtins.modules.cext.PythonCextBuiltins.CApiTernaryBuiltinNode;
5248
import com.oracle.graal.python.builtins.modules.cext.PythonCextBuiltins.CApiUnaryBuiltinNode;
53-
import com.oracle.graal.python.builtins.objects.PNone;
54-
import com.oracle.graal.python.builtins.objects.cext.common.CExtCommonNodes;
5549
import com.oracle.graal.python.runtime.PythonContext;
5650
import com.oracle.graal.python.util.ShutdownHook;
5751
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
@@ -60,7 +54,6 @@
6054
import com.oracle.truffle.api.interop.InteropLibrary;
6155
import com.oracle.truffle.api.interop.UnsupportedMessageException;
6256
import com.oracle.truffle.api.interop.UnsupportedTypeException;
63-
import com.oracle.truffle.api.strings.TruffleString;
6457

6558
public final class PythonCextPyLifecycleBuiltins {
6659

@@ -83,23 +76,4 @@ public void call(@SuppressWarnings("unused") PythonContext context) {
8376
return 0;
8477
}
8578
}
86-
87-
@CApiBuiltin(ret = Void, args = {ConstCharPtrAsTruffleString, ConstCharPtrAsTruffleString, Int}, call = Ignored)
88-
abstract static class GraalPyPrivate_FatalErrorFunc extends CApiTernaryBuiltinNode {
89-
90-
@Specialization
91-
@TruffleBoundary
92-
Object doStrings(TruffleString func, TruffleString msg, int status) {
93-
CExtCommonNodes.fatalError(this, getContext(), func, msg, status);
94-
return PNone.NONE;
95-
}
96-
97-
@Specialization
98-
@TruffleBoundary
99-
Object doGeneric(Object funcObj, Object msgObj, int status) {
100-
TruffleString func = funcObj == PNone.NO_VALUE ? null : (TruffleString) funcObj;
101-
TruffleString msg = msgObj == PNone.NO_VALUE ? null : (TruffleString) msgObj;
102-
return doStrings(func, msg, status);
103-
}
104-
}
10579
}

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/cext/PythonCextUnicodeBuiltins.java

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,6 @@
116116
import com.oracle.graal.python.builtins.objects.cext.capi.CExtNodes.UnicodeFromFormatNode;
117117
import com.oracle.graal.python.builtins.objects.cext.capi.PySequenceArrayWrapper;
118118
import com.oracle.graal.python.builtins.objects.cext.capi.UnicodeObjectNodes.UnicodeAsWideCharNode;
119-
import com.oracle.graal.python.builtins.objects.cext.common.CExtCommonNodes;
120119
import com.oracle.graal.python.builtins.objects.cext.common.CExtCommonNodes.EncodeNativeStringNode;
121120
import com.oracle.graal.python.builtins.objects.cext.common.CExtCommonNodes.GetByteArrayNode;
122121
import com.oracle.graal.python.builtins.objects.cext.common.CExtCommonNodes.ReadUnicodeArrayNode;
@@ -158,11 +157,11 @@
158157
import com.oracle.graal.python.nodes.util.CannotCastException;
159158
import com.oracle.graal.python.nodes.util.CastToJavaStringNode;
160159
import com.oracle.graal.python.nodes.util.CastToTruffleStringNode;
161-
import com.oracle.graal.python.runtime.PythonContext;
162160
import com.oracle.graal.python.runtime.exception.PException;
163161
import com.oracle.graal.python.runtime.exception.PythonErrorType;
164162
import com.oracle.graal.python.runtime.object.PFactory;
165163
import com.oracle.graal.python.util.OverflowException;
164+
import com.oracle.truffle.api.CompilerDirectives;
166165
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
167166
import com.oracle.truffle.api.dsl.Bind;
168167
import com.oracle.truffle.api.dsl.Cached;
@@ -388,15 +387,14 @@ static Object overflow(Object val, int alt, int prec, int type,
388387
@Specialization(guards = "!isOF(prec)")
389388
static Object formatLong(Object val, int alt, int prec, int type,
390389
@Bind Node inliningTarget,
391-
@Bind PythonContext context,
392390
@Cached OctNode toOctBase,
393391
@Cached HexNode toHexBase,
394392
@Cached PyNumberIndexNode indexNode,
395393
@Cached StringBuiltins.StrNewNode strNode,
396394
@Cached CastToJavaStringNode cast,
397395
@Cached TruffleString.FromCharArrayUTF16Node fromCharArrayNode) {
398396
int numnondigits = 0;
399-
TruffleString result = null;
397+
TruffleString result;
400398
switch (type) {
401399
case 'd', 'i', 'u' ->
402400
/* int and int subclasses should print numerically when a numeric */
@@ -410,7 +408,10 @@ static Object formatLong(Object val, int alt, int prec, int type,
410408
numnondigits = 2;
411409
result = (TruffleString) PyNumber_ToBase.toBase16(val, 16, inliningTarget, indexNode, toHexBase);
412410
}
413-
default -> CExtCommonNodes.fatalErrorString(inliningTarget, context, null, null, -1);
411+
default -> {
412+
CompilerDirectives.transferToInterpreterAndInvalidate();
413+
throw PRaiseNode.raiseStatic(inliningTarget, SystemError, ErrorMessages.BAD_ARG_TO_INTERNAL_FUNC);
414+
}
414415
}
415416

416417
char[] buf = getCharArray(cast.execute(result));

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/cext/common/CExtCommonNodes.java

Lines changed: 1 addition & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -51,14 +51,12 @@
5151
import static com.oracle.graal.python.util.PythonUtils.TS_ENCODING;
5252
import static com.oracle.graal.python.util.PythonUtils.tsLiteral;
5353

54-
import java.io.PrintWriter;
5554
import java.nio.charset.CharacterCodingException;
5655
import java.nio.charset.Charset;
5756
import java.nio.charset.CodingErrorAction;
5857
import java.nio.charset.StandardCharsets;
5958
import java.util.logging.Level;
6059

61-
import com.oracle.truffle.api.dsl.Cached.Exclusive;
6260
import org.graalvm.collections.Pair;
6361

6462
import com.oracle.graal.python.PythonLanguage;
@@ -96,14 +94,12 @@
9694
import com.oracle.graal.python.nodes.SpecialMethodNames;
9795
import com.oracle.graal.python.nodes.util.CannotCastException;
9896
import com.oracle.graal.python.nodes.util.CastToTruffleStringNode;
99-
import com.oracle.graal.python.runtime.PosixSupportLibrary;
10097
import com.oracle.graal.python.runtime.PythonContext;
10198
import com.oracle.graal.python.runtime.PythonContext.GetThreadStateNode;
10299
import com.oracle.graal.python.runtime.PythonContext.PythonThreadState;
103100
import com.oracle.graal.python.runtime.PythonOptions;
104101
import com.oracle.graal.python.runtime.exception.PException;
105102
import com.oracle.graal.python.runtime.exception.PythonErrorType;
106-
import com.oracle.graal.python.runtime.exception.PythonExitException;
107103
import com.oracle.graal.python.runtime.object.PFactory;
108104
import com.oracle.graal.python.util.OverflowException;
109105
import com.oracle.graal.python.util.PythonUtils;
@@ -115,6 +111,7 @@
115111
import com.oracle.truffle.api.TruffleLogger;
116112
import com.oracle.truffle.api.dsl.Bind;
117113
import com.oracle.truffle.api.dsl.Cached;
114+
import com.oracle.truffle.api.dsl.Cached.Exclusive;
118115
import com.oracle.truffle.api.dsl.Cached.Shared;
119116
import com.oracle.truffle.api.dsl.Fallback;
120117
import com.oracle.truffle.api.dsl.GenerateCached;
@@ -140,35 +137,6 @@
140137
import com.oracle.truffle.nfi.api.SignatureLibrary;
141138

142139
public abstract class CExtCommonNodes {
143-
@TruffleBoundary
144-
public static void fatalError(Node location, PythonContext context, TruffleString prefix, TruffleString msg, int status) {
145-
fatalErrorString(location, context, prefix != null ? prefix.toJavaStringUncached() : null, msg.toJavaStringUncached(), status);
146-
}
147-
148-
@TruffleBoundary
149-
public static void fatalErrorString(Node location, PythonContext context, String prefix, String msg, int status) {
150-
PrintWriter stderr = new PrintWriter(context.getStandardErr());
151-
stderr.print("Fatal Python error: ");
152-
if (prefix != null) {
153-
stderr.print(prefix);
154-
stderr.print(": ");
155-
}
156-
if (msg != null) {
157-
stderr.print(msg);
158-
} else {
159-
stderr.print("<message not set>");
160-
}
161-
stderr.println();
162-
stderr.flush();
163-
164-
if (status < 0) {
165-
PosixSupportLibrary posixLib = PosixSupportLibrary.getUncached();
166-
Object posixSupport = context.getPosixSupport();
167-
posixLib.abort(posixSupport);
168-
// abort does not return
169-
}
170-
throw new PythonExitException(location, status);
171-
}
172140

173141
@GenerateUncached
174142
@GenerateInline

0 commit comments

Comments
 (0)