Skip to content

Commit 6266719

Browse files
committed
[GR-15310] Avoid iterating frames on the fast path unless Python code requests the full traceback.
PullRequest: graalpython/526
2 parents 3f48559 + f76c593 commit 6266719

File tree

116 files changed

+3946
-2083
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

116 files changed

+3946
-2083
lines changed
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
# Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
2+
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
3+
#
4+
# The Universal Permissive License (UPL), Version 1.0
5+
#
6+
# Subject to the condition set forth below, permission is hereby granted to any
7+
# person obtaining a copy of this software, associated documentation and/or
8+
# data (collectively the "Software"), free of charge and under any and all
9+
# copyright rights in the Software, and any and all patent rights owned or
10+
# freely licensable by each licensor hereunder covering either (i) the
11+
# unmodified Software as contributed to or provided by such licensor, or (ii)
12+
# the Larger Works (as defined below), to deal in both
13+
#
14+
# (a) the Software, and
15+
#
16+
# (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if
17+
# one is included with the Software each a "Larger Work" to which the Software
18+
# is contributed by such licensors),
19+
#
20+
# without restriction, including without limitation the rights to copy, create
21+
# derivative works of, display, perform, and distribute the Software and make,
22+
# use, sell, offer for sale, import, export, have made, and have sold the
23+
# Software and the Larger Work(s), and to sublicense the foregoing rights on
24+
# either these or other terms.
25+
#
26+
# This license is subject to the following condition:
27+
#
28+
# The above copyright notice and either this complete permission notice or at a
29+
# minimum a reference to the UPL must be included in all copies or substantial
30+
# portions of the Software.
31+
#
32+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
33+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
34+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
35+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
36+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
37+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
38+
# SOFTWARE.
39+
40+
import sys
41+
42+
exc_types = (ValueError, TypeError, IndexError, KeyError, SystemError, RuntimeError, NameError, ArithmeticError)
43+
n_exc_types = len(exc_types)
44+
45+
def count(num):
46+
typ, val, tb = (None, None, None)
47+
cnt = 0
48+
for i in range(num):
49+
typ, val, tb = (None, None, None)
50+
try:
51+
raise exc_types[i % n_exc_types]
52+
except BaseException as e:
53+
cnt += 1
54+
assert type(e) == exc_types[i % n_exc_types]
55+
56+
return cnt
57+
58+
59+
def measure(num):
60+
result = count(num)
61+
print("last value: %s " % result)
62+
63+
64+
def __benchmark__(num=1000000):
65+
measure(num)
66+

graalpython/com.oracle.graal.python.tck/src/com/oracle/graal/python/tck/PythonProvider.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -251,7 +251,7 @@ public Collection<? extends Snippet> createStatements(Context context) {
251251
" try:\n" +
252252
" raise BaseException()\n" +
253253
" e = None\n" +
254-
" except BaseException as e:\n" +
254+
" except BaseException as ex:\n" +
255255
" e = True\n" +
256256
" else:\n" +
257257
" e = None\n" +
@@ -261,7 +261,7 @@ public Collection<? extends Snippet> createStatements(Context context) {
261261
" e = None\n" +
262262
" try:\n" +
263263
" e = None\n" +
264-
" except BaseException as e:\n" +
264+
" except BaseException as ex:\n" +
265265
" e = None\n" +
266266
" else:\n" +
267267
" e = True\n" +

graalpython/com.oracle.graal.python.test/src/com/oracle/graal/python/test/grammar/TestParserTranslator.java

Lines changed: 36 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -58,11 +58,14 @@
5858
import com.oracle.graal.python.builtins.objects.PNone;
5959
import com.oracle.graal.python.builtins.objects.complex.PComplex;
6060
import com.oracle.graal.python.builtins.objects.dict.PDict;
61+
import com.oracle.graal.python.builtins.objects.frame.PFrame;
6162
import com.oracle.graal.python.builtins.objects.function.PArguments;
63+
import com.oracle.graal.python.builtins.objects.function.Signature;
6264
import com.oracle.graal.python.builtins.objects.list.PList;
6365
import com.oracle.graal.python.builtins.objects.set.PSet;
6466
import com.oracle.graal.python.builtins.objects.tuple.PTuple;
6567
import com.oracle.graal.python.nodes.PNode;
68+
import com.oracle.graal.python.nodes.PRootNode;
6669
import com.oracle.graal.python.nodes.attributes.DeleteAttributeNode;
6770
import com.oracle.graal.python.nodes.attributes.GetAttributeNode;
6871
import com.oracle.graal.python.nodes.attributes.SetAttributeNode;
@@ -74,7 +77,7 @@
7477
import com.oracle.graal.python.nodes.expression.CastToBooleanNode.NotNode;
7578
import com.oracle.graal.python.nodes.expression.ContainsNode;
7679
import com.oracle.graal.python.nodes.expression.ExpressionNode;
77-
import com.oracle.graal.python.nodes.expression.IsNode;
80+
import com.oracle.graal.python.nodes.expression.IsExpressionNode;
7881
import com.oracle.graal.python.nodes.expression.OrNode;
7982
import com.oracle.graal.python.nodes.expression.TernaryArithmetic;
8083
import com.oracle.graal.python.nodes.expression.UnaryArithmetic;
@@ -105,16 +108,18 @@
105108
import com.oracle.graal.python.nodes.subscript.DeleteItemNode;
106109
import com.oracle.graal.python.nodes.subscript.GetItemNode;
107110
import com.oracle.graal.python.nodes.subscript.SetItemNode;
111+
import com.oracle.graal.python.runtime.ExecutionContext.CalleeContext;
112+
import com.oracle.graal.python.runtime.ExecutionContext.IndirectCalleeContext;
108113
import com.oracle.graal.python.runtime.PythonContext;
109114
import com.oracle.graal.python.runtime.PythonParser.ParserMode;
110115
import com.oracle.graal.python.test.PythonTests;
111116
import com.oracle.truffle.api.RootCallTarget;
112117
import com.oracle.truffle.api.Truffle;
113-
import com.oracle.truffle.api.TruffleLanguage;
114118
import com.oracle.truffle.api.frame.VirtualFrame;
115119
import com.oracle.truffle.api.nodes.Node;
116120
import com.oracle.truffle.api.nodes.NodeUtil;
117121
import com.oracle.truffle.api.nodes.RootNode;
122+
import com.oracle.truffle.api.profiles.BranchProfile;
118123
import com.oracle.truffle.api.source.Source;
119124

120125
public class TestParserTranslator {
@@ -125,26 +130,48 @@ public TestParserTranslator() {
125130
context = PythonLanguage.getContextRef().get();
126131
}
127132

128-
private static class JUnitRootNode extends RootNode {
129-
133+
private static class JUnitRootNode extends PRootNode {
134+
private final BranchProfile profile = BranchProfile.create();
130135
@Child private ExpressionNode body;
136+
@Child private CalleeContext calleeContext = CalleeContext.create();
131137

132-
public JUnitRootNode(TruffleLanguage<?> language, ExpressionNode body) {
138+
public JUnitRootNode(PythonLanguage language, ExpressionNode body) {
133139
super(language);
134140
this.body = body;
135141
}
136142

137143
@Override
138144
public Object execute(VirtualFrame frame) {
139-
return body.execute(frame);
145+
CalleeContext.enter(frame, profile);
146+
try {
147+
return body.execute(frame);
148+
} finally {
149+
calleeContext.exit(frame, this);
150+
}
151+
}
152+
153+
@Override
154+
public Signature getSignature() {
155+
return Signature.EMPTY;
156+
}
157+
158+
@Override
159+
public boolean isPythonInternal() {
160+
return false;
140161
}
141162

142163
}
143164

144165
private Object runInRoot(ExpressionNode expr) {
145166
JUnitRootNode jUnitRootNode = new JUnitRootNode(context.getLanguage(), expr);
146167
RootCallTarget callTarget = Truffle.getRuntime().createCallTarget(jUnitRootNode);
147-
return callTarget.call(PArguments.create());
168+
Object[] arguments = PArguments.create();
169+
PFrame.Reference frameInfo = IndirectCalleeContext.enter(context, arguments, callTarget);
170+
try {
171+
return callTarget.call(arguments);
172+
} finally {
173+
IndirectCalleeContext.exit(context, frameInfo);
174+
}
148175
}
149176

150177
RootNode parse(String src) {
@@ -391,9 +418,9 @@ public void parseComparisons() {
391418
parseAs("x in y", ContainsNode.class);
392419
CastToBooleanNode notNode = parseAs("x not in y", CastToBooleanNode.NotNode.class);
393420
getChild(notNode, 0, ContainsNode.class);
394-
parseAs("x is y", IsNode.class);
421+
parseAs("x is y", IsExpressionNode.class);
395422
notNode = parseAs("x is not y", CastToBooleanNode.NotNode.class);
396-
getChild(notNode, 0, IsNode.class);
423+
getChild(notNode, 0, IsExpressionNode.class);
397424

398425
AndNode parseAs = parseAs("x < y() <= z", AndNode.class);
399426
PNode leftNode = parseAs.getLeftNode();

graalpython/com.oracle.graal.python.test/src/com/oracle/graal/python/test/runtime/PythonModuleTests.java

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2017, 2018, Oracle and/or its affiliates.
2+
* Copyright (c) 2017, 2019, Oracle and/or its affiliates.
33
* Copyright (c) 2013, Regents of the University of California
44
*
55
* All rights reserved.
@@ -52,7 +52,6 @@ public class PythonModuleTests {
5252
private PythonContext context;
5353

5454
private static class PythonModuleTestRootNode extends RootNode {
55-
5655
@Child private CallNode body;
5756

5857
public PythonModuleTestRootNode(PythonLanguage language, CallNode body) {
@@ -66,7 +65,7 @@ public Object execute(VirtualFrame frame) {
6665
Object[] arguments = frame.getArguments();
6766
Object[] argsWithoutSelf = new Object[arguments.length - 1];
6867
System.arraycopy(arguments, 1, argsWithoutSelf, 0, argsWithoutSelf.length);
69-
return body.execute(frame, arguments[0], argsWithoutSelf);
68+
return body.execute(null, arguments[0], argsWithoutSelf);
7069
}
7170
}
7271

graalpython/com.oracle.graal.python.test/src/tests/cpyext/test_exceptionobject.py

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,52 @@ def test_exc_info(self):
7676
else:
7777
assert False
7878

79+
def test_set_exc_info(self):
80+
TestSetExcInfo = CPyExtType("TestSetExcInfo",
81+
"""
82+
PyObject* set_exc_info(PyObject* self, PyObject* args) {
83+
PyObject* typ = PyTuple_GetItem(args, 0);
84+
PyObject* val = PyTuple_GetItem(args, 1);
85+
PyObject* tb = PyTuple_GetItem(args, 2);
86+
PyObject* typ1 = NULL;
87+
PyObject* val1 = NULL;
88+
PyObject* tb1 = NULL;
89+
90+
Py_XINCREF(typ);
91+
Py_XINCREF(val);
92+
Py_XINCREF(tb);
93+
PyErr_SetExcInfo(typ, val, tb);
94+
95+
PyErr_GetExcInfo(&typ1, &val1, &tb1);
96+
// ignore the traceback for now
97+
if(typ == typ1 && val == val1) {
98+
return Py_True;
99+
}
100+
return Py_False;
101+
}
102+
""",
103+
tp_methods='{"set_exc_info", (PyCFunction)set_exc_info, METH_O, ""}'
104+
)
105+
tester = TestSetExcInfo()
106+
try:
107+
raise IndexError
108+
except:
109+
typ, val, tb = sys.exc_info()
110+
assert typ == IndexError
111+
112+
113+
114+
# overwrite exception info
115+
expected = (ValueError, ValueError(), None)
116+
res = tester.set_exc_info(expected)
117+
assert res
118+
119+
# TODO uncomment once supported
120+
# actual = sys.exc_info()
121+
# assert actual == expected
122+
else:
123+
assert False
124+
79125
class TestExceptionobjectFunctions(CPyExtTestCase):
80126
def compile_module(self, name):
81127
type(self).mro()[1].__dict__["test_%s" % name].create_module(name)

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

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ def fun4(test_obj):
2929
fun3(test_obj, ValueError)
3030

3131
class ExceptionTests(unittest.TestCase):
32-
32+
3333
def test_exc_info(self):
3434
typ, val, tb = (None,) * 3
3535
try:
@@ -115,7 +115,7 @@ def test_new_oserror(self):
115115
self.assertTrue(type(OSError(2)) is OSError)
116116
self.assertTrue(type(OSError(errno.EISDIR)) is OSError)
117117
self.assertTrue(type(OSError(2, "a message")) is FileNotFoundError)
118-
118+
119119
self.assertTrue(type(OSError(errno.EISDIR, "a message")) is IsADirectoryError)
120120
self.assertTrue(type(OSError(errno.EAGAIN, "a message")) is BlockingIOError)
121121
self.assertTrue(type(OSError(errno.EALREADY, "a message")) is BlockingIOError)
@@ -163,3 +163,15 @@ def test_oserror_four_attribute(self):
163163
self.assertEqual(e.strerror, "message")
164164
self.assertEqual(e.filename, "file1")
165165
self.assertEqual(e.filename2, "file2")
166+
167+
def test_exception_cleared(self):
168+
try:
169+
raise ValueError
170+
except ValueError as e:
171+
pass
172+
try:
173+
e
174+
except UnboundLocalError:
175+
pass
176+
else:
177+
assert False, "named exception should be unbound after except block"

graalpython/com.oracle.graal.python.test/src/tests/test_generator-expression-next.py

Lines changed: 0 additions & 33 deletions
This file was deleted.

graalpython/com.oracle.graal.python.test/src/tests/test_generator-expression-sum-2.py

Lines changed: 0 additions & 37 deletions
This file was deleted.

0 commit comments

Comments
 (0)