Skip to content

Commit 7bd2fea

Browse files
committed
[GR-13042] Remove arity matching macros in Python.h
PullRequest: graalpython/351
2 parents 7c2b139 + b4067e2 commit 7bd2fea

File tree

11 files changed

+618
-766
lines changed

11 files changed

+618
-766
lines changed

graalpython/com.oracle.graal.python.cext/include/Python.h

Lines changed: 0 additions & 198 deletions
Large diffs are not rendered by default.

graalpython/com.oracle.graal.python.cext/src/capi.h

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -328,6 +328,9 @@ extern PyObject* wrapped_null;
328328
/* DICT */
329329
void* PyTruffle_Tuple_GetItem(void* jtuple, Py_ssize_t position);
330330

331+
/* STR */
332+
PyObject* PyTruffle_Unicode_FromFormat(const char*, va_list, void**, int);
333+
331334
/* BYTES, BYTEARRAY */
332335
int bytes_buffer_getbuffer(PyBytesObject *self, Py_buffer *view, int flags);
333336
int bytearray_getbuffer(PyByteArrayObject *obj, Py_buffer *view, int flags);
@@ -338,4 +341,35 @@ int bytes_copy2mem(char* target, char* source, size_t nbytes);
338341
/* MEMORYVIEW, BUFFERDECORATOR */
339342
int bufferdecorator_getbuffer(PyBufferDecorator *self, Py_buffer *view, int flags);
340343

344+
#if 1
345+
/*
346+
* (tfel): On native Sulong, using va_list will force all arguments to native
347+
* memory, which hinders escape analysis and PE in a big way. To avoid this,
348+
* when we have function called with var args (rather than already with a
349+
* va_list), we allocate a managed array of void*, fill it with the arguments,
350+
* and pass that one on. In the target functions, we use the macros below to
351+
* access the variable arguments part depending on whether it is a va_list or a
352+
* managed void* array. The assumption is that once everything is compiled
353+
* together, the managed array with arguments will be escape analyzed away.
354+
*/
355+
#define CallWithPolyglotArgs(result, last, off, function, ...) \
356+
int __poly_argc = polyglot_get_arg_count(); \
357+
int __poly_args_s = sizeof(void*) * (__poly_argc - off); \
358+
void **__poly_args = truffle_managed_malloc(__poly_args_s); \
359+
for (int i = off; i < __poly_argc; i++) { \
360+
__poly_args[i - off] = polyglot_get_arg(i); \
361+
} \
362+
result = function(__VA_ARGS__, NULL, __poly_args, 0)
363+
#else
364+
/*
365+
* (tfel): Just skip the optimization with using a managed malloc and use
366+
* va_list always.
367+
*/
368+
#define CallWithPolyglotArgs(result, last, off, function, ...) \
369+
va_list __poly_args; \
370+
va_start(__poly_args, last); \
371+
result = function(__VA_ARGS__, __poly_args, NULL, 0); \
372+
va_end(__poly_args)
373+
#endif
374+
341375
#endif

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2018, 2019, 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
@@ -159,8 +159,8 @@ int PyErr_ExceptionMatches(PyObject *exc) {
159159
return PyErr_GivenExceptionMatches(PyErr_Occurred(), exc);
160160
}
161161

162-
PyObject* PyTruffle_Err_Format(PyObject* exception, const char* fmt, int s, void* v0, void* v1, void* v2, void* v3, void* v4, void* v5, void* v6, void* v7, void* v8, void* v9) {
163-
PyObject *formatted_msg = PyTruffle_Unicode_FromFormat(fmt, s, v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
162+
PyObject* PyErr_Format(PyObject* exception, const char* fmt, ...) {
163+
CallWithPolyglotArgs(PyObject* formatted_msg, fmt, 2, PyTruffle_Unicode_FromFormat, fmt);
164164
UPCALL_CEXT_VOID(_jls_PyErr_CreateAndSetException, native_to_java(exception), native_to_java(formatted_msg));
165165
return NULL;
166166
}

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

Lines changed: 426 additions & 498 deletions
Large diffs are not rendered by default.

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,10 @@ PyObject* PyObject_Str(PyObject* o) {
177177
return UPCALL_CEXT_O(_jls_PyObject_Str, native_to_java(o));
178178
}
179179

180+
PyObject* PyObject_ASCII(PyObject* o) {
181+
return UPCALL_O(PY_BUILTIN, polyglot_from_string("ascii", SRC_CS), native_to_java(o));
182+
}
183+
180184
UPCALL_ID(PyObject_Repr);
181185
PyObject* PyObject_Repr(PyObject* o) {
182186
return UPCALL_CEXT_O(_jls_PyObject_Repr, native_to_java(o));
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
/*
2+
* Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
3+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+
*
5+
* The Universal Permissive License (UPL), Version 1.0
6+
*
7+
* Subject to the condition set forth below, permission is hereby granted to any
8+
* person obtaining a copy of this software, associated documentation and/or
9+
* data (collectively the "Software"), free of charge and under any and all
10+
* copyright rights in the Software, and any and all patent rights owned or
11+
* freely licensable by each licensor hereunder covering either (i) the
12+
* unmodified Software as contributed to or provided by such licensor, or (ii)
13+
* the Larger Works (as defined below), to deal in both
14+
*
15+
* (a) the Software, and
16+
*
17+
* (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if
18+
* one is included with the Software each a "Larger Work" to which the Software
19+
* is contributed by such licensors),
20+
*
21+
* without restriction, including without limitation the rights to copy, create
22+
* derivative works of, display, perform, and distribute the Software and make,
23+
* use, sell, offer for sale, import, export, have made, and have sold the
24+
* Software and the Larger Work(s), and to sublicense the foregoing rights on
25+
* either these or other terms.
26+
*
27+
* This license is subject to the following condition:
28+
*
29+
* The above copyright notice and either this complete permission notice or at a
30+
* minimum a reference to the UPL must be included in all copies or substantial
31+
* portions of the Software.
32+
*
33+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
34+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
35+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
36+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
37+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
38+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
39+
* SOFTWARE.
40+
*/
41+
#include "capi.h"
42+
43+
44+
PyObject* _PyLong_FromTime_t(time_t sec) {
45+
return PyLong_FromLong((long)sec);
46+
}

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

Lines changed: 72 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -112,89 +112,105 @@ PyObject * PyUnicode_FromStringAndSize(const char *u, Py_ssize_t size) {
112112
return to_sulong(polyglot_from_string_n(u, size, SRC_CS));
113113
}
114114

115-
PyObject* PyTruffle_Unicode_FromFormat(const char* fmt, int s, void* v0, void* v1, void* v2, void* v3, void* v4, void* v5, void* v6, void* v7, void* v8, void* v9, void* v10, void* v11, void* v12, void* v13, void* v14, void* v15, void* v16, void* v17, void* v18, void* v19) {
116-
char** allocated_strings = calloc(sizeof(char*), s);
117-
# define ASSIGN(n, value) \
118-
switch(n) { \
119-
case 0: v0 = value; break; \
120-
case 1: v1 = value; break; \
121-
case 2: v2 = value; break; \
122-
case 3: v3 = value; break; \
123-
case 4: v4 = value; break; \
124-
case 5: v5 = value; break; \
125-
case 6: v6 = value; break; \
126-
case 7: v7 = value; break; \
127-
case 8: v8 = value; break; \
128-
case 9: v9 = value; break; \
129-
case 10: v10 = value; break; \
130-
case 11: v11 = value; break; \
131-
case 12: v12 = value; break; \
132-
case 13: v13 = value; break; \
133-
case 14: v14 = value; break; \
134-
case 15: v15 = value; break; \
135-
case 16: v16 = value; break; \
136-
case 17: v17 = value; break; \
137-
case 18: v18 = value; break; \
138-
case 19: v19 = value; break; \
139-
}
115+
#define AS_I64(__arg__) (polyglot_fits_in_i64((__arg__)) ? polyglot_as_i64((__arg__)) : (int64_t)(__arg__))
140116

117+
MUST_INLINE PyObject* PyTruffle_Unicode_FromFormat(const char *fmt, va_list va, void **args, int argc) {
141118
size_t fmt_size = strlen(fmt) + 1;
142119
// n.b. avoid using 'strdup' for compatiblity with MUSL libc
143120
char* fmtcpy = (char*) malloc(fmt_size*sizeof(char));
121+
memcpy(fmtcpy, fmt, fmt_size);
144122
char* c = fmtcpy;
145-
char* allocated;
146-
int cnt = 0;
147123

148-
memcpy(fmtcpy, fmt, fmt_size);
124+
int remaining_space = 2047;
125+
char* buffer = (char*)calloc(sizeof(char), remaining_space + 1);
126+
char* full_buffer = buffer;
149127

150-
while (c[0] && cnt < s) {
128+
void *variable = NULL;
129+
char *allocated = NULL; // points to the same as variable, if it has to be free'd
130+
131+
while (c[0]) {
151132
if (c[0] == '%') {
133+
// we've reached the next directive, write until here
134+
c[0] = '\0';
135+
int bytes_written;
136+
if (variable != NULL) {
137+
bytes_written = snprintf(buffer, remaining_space, fmtcpy, AS_I64(variable));
138+
if (allocated != NULL) {
139+
free(allocated);
140+
allocated = NULL;
141+
}
142+
variable = NULL;
143+
} else if (va != NULL) {
144+
bytes_written = vsnprintf(buffer, remaining_space, fmtcpy, va);
145+
} else {
146+
strncpy(buffer, fmtcpy, remaining_space);
147+
bytes_written = strlen(fmtcpy);
148+
}
149+
remaining_space -= bytes_written;
150+
buffer += bytes_written;
151+
fmtcpy = c;
152+
c[0] = '%';
153+
154+
// now decide if we need to do something special with this directive
155+
PyObject* (*converter)(PyObject*) = NULL;
152156
switch (c[1]) {
153-
case 'c':
154-
c[1] = 'd';
155-
break;
156157
case 'A':
157-
c[1] = 's';
158-
;
159-
allocated_strings[cnt] = allocated = as_char_pointer(UPCALL_O(PY_BUILTIN, polyglot_from_string("ascii", SRC_CS), native_to_java(polyglot_get_arg(cnt + 2))));
160-
ASSIGN(cnt, allocated);
161-
break;
158+
// The conversion cases, these all use a function to convert the
159+
// PyObject* to a char* and they fall through
160+
converter = PyObject_ASCII;
162161
case 'U':
163-
c[1] = 's';
164-
allocated_strings[cnt] = allocated = as_char_pointer(PyObject_Str(polyglot_get_arg(cnt + 2)));
165-
ASSIGN(cnt, allocated);
166-
break;
162+
if (converter == NULL) converter = PyObject_Str;
167163
case 'S':
168-
c[1] = 's';
169-
allocated_strings[cnt] = allocated = as_char_pointer(PyObject_Str(polyglot_get_arg(cnt + 2)));
170-
ASSIGN(cnt, allocated);
171-
break;
164+
if (converter == NULL) converter = PyObject_Str;
172165
case 'R':
166+
if (converter == NULL) converter = PyObject_Repr;
173167
c[1] = 's';
174-
allocated_strings[cnt] = allocated = as_char_pointer(PyObject_Repr(polyglot_get_arg(cnt + 2)));
175-
ASSIGN(cnt, allocated);
168+
allocated = variable = as_char_pointer(converter(args == NULL ? va_arg(va, PyObject*) : (PyObject*)(args[argc++])));
169+
break;
170+
case '%':
171+
// literal %
176172
break;
173+
case 'c':
174+
// This case should just treat it's argument as an integer
175+
c[1] = 'd';
176+
default:
177+
// if we're reading args from a void* array, read it now,
178+
// otherwise there's nothing to do
179+
if (args != NULL) {
180+
variable = args[argc++];
181+
}
177182
}
178-
cnt++;
183+
// skip over next char, we checked it
179184
c += 1;
180185
}
181186
c += 1;
182187
}
183188

184-
char buffer[2048] = {'\0'};
185-
snprintf(buffer, 2047, fmtcpy, v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19);
186-
187-
for (int i = 0; i < s; i++) {
188-
if (allocated_strings[i] != NULL) {
189-
free(allocated_strings[i]);
189+
// write the remaining buffer
190+
if (variable != NULL) {
191+
snprintf(buffer, remaining_space, fmtcpy, AS_I64(variable));
192+
if (allocated) {
193+
free(allocated);
190194
}
195+
} else if (va != NULL) {
196+
vsnprintf(buffer, remaining_space, fmtcpy, va);
197+
} else {
198+
strncpy(buffer, fmtcpy, remaining_space);
191199
}
192200

193-
return PyUnicode_FromString(buffer);
201+
PyObject* result = PyUnicode_FromString(full_buffer);
202+
free(full_buffer);
203+
return result;
204+
}
194205

195-
# undef ASSIGN
206+
PyObject* PyUnicode_FromFormatV(const char* format, va_list va) {
207+
return PyTruffle_Unicode_FromFormat(format, va, NULL, 0);
196208
}
197209

210+
PyObject* PyUnicode_FromFormat(const char* format, ...) {
211+
CallWithPolyglotArgs(PyObject* result, format, 1, PyTruffle_Unicode_FromFormat, format);
212+
return result;
213+
}
198214

199215
PyObject * PyUnicode_FromUnicode(const Py_UNICODE *u, Py_ssize_t size) {
200216
if (u == NULL) {

graalpython/com.oracle.graal.python.shell/src/com/oracle/graal/python/shell/GraalPythonCC.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -171,7 +171,7 @@ private void parseOptions(String[] args) {
171171
throw new RuntimeException("cannot mix source and compiled sources");
172172
}
173173
fileInputs.add(arg);
174-
} else if (arg.endsWith(".c") || arg.endsWith(".cpp") || arg.endsWith(".cxx")) {
174+
} else if (arg.endsWith(".c") || arg.endsWith(".cc") || arg.endsWith(".cpp") || arg.endsWith(".cxx")) {
175175
if (arg.endsWith(".cpp") || arg.endsWith(".cxx")) {
176176
isCpp = true;
177177
}

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/generator/GeneratorTryExceptNode.java

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@
4848
import com.oracle.graal.python.nodes.util.ExceptionStateNodes.SaveExceptionStateNode;
4949
import com.oracle.graal.python.runtime.exception.ExceptionHandledException;
5050
import com.oracle.graal.python.runtime.exception.PException;
51+
import com.oracle.truffle.api.CompilerAsserts;
5152
import com.oracle.truffle.api.frame.VirtualFrame;
5253
import com.oracle.truffle.api.nodes.ControlFlowException;
5354
import com.oracle.truffle.api.nodes.ExplodeLoop;
@@ -121,11 +122,8 @@ private void catchExceptionInGenerator(VirtualFrame frame, PException exception,
121122
}
122123
}
123124
} else if (matchingExceptNodeIndex <= exceptNodes.length) {
124-
// we already found the right except handler, jump back into
125-
// it directly
126-
ExceptNode exceptNode = exceptNodes[matchingExceptNodeIndex - 1];
127-
runExceptionHandler(frame, exception, exceptNode, exceptionState);
128-
wasHandled = true;
125+
// we already found the right except handler, jump back into it directly
126+
wasHandled = catchExceptionInGeneratorCached(frame, exceptNodes, exception, exceptionState, matchingExceptNodeIndex);
129127
}
130128
reset(frame);
131129
if (!wasHandled) {
@@ -135,6 +133,23 @@ private void catchExceptionInGenerator(VirtualFrame frame, PException exception,
135133
restoreExceptionState.execute(frame, exceptionState);
136134
}
137135

136+
@ExplodeLoop
137+
private boolean catchExceptionInGeneratorCached(VirtualFrame frame, ExceptNode[] exceptNodes, PException exception, ExceptionState exceptionState, int matchingExceptNodeIndex) {
138+
CompilerAsserts.compilationConstant(exceptNodes);
139+
assert matchingExceptNodeIndex <= exceptNodes.length;
140+
boolean wasHandled = false;
141+
for (int i = 0; i < exceptNodes.length; i++) {
142+
// we want a constant loop iteration count for ExplodeLoop to work,
143+
// so we always run through all except handlers
144+
if (i == matchingExceptNodeIndex - 1) {
145+
runExceptionHandler(frame, exception, exceptNodes[i], exceptionState);
146+
wasHandled = true;
147+
}
148+
}
149+
assert wasHandled : "cached exception handler does not handle exception";
150+
return wasHandled;
151+
}
152+
138153
private void runExceptionHandler(VirtualFrame frame, PException exception, ExceptNode exceptNode, ExceptionState exceptionState) {
139154
try {
140155
exceptNode.executeExcept(frame, exception);

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/statement/AssertNode.java

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ public class AssertNode extends StatementNode {
5151
@Child private ExpressionNode message;
5252
@Child private LookupAndCallUnaryNode callNode;
5353
@CompilationFinal private Boolean assertionsEnabled = null;
54+
@CompilationFinal private boolean javaExceptionsFailAssertions;
5455
@CompilationFinal private ContextReference<PythonContext> contextRef;
5556

5657
private final ConditionProfile profile = ConditionProfile.createBinaryProfile();
@@ -64,7 +65,9 @@ public AssertNode(CastToBooleanNode condition, ExpressionNode message) {
6465
public void executeVoid(VirtualFrame frame) {
6566
if (assertionsEnabled == null) {
6667
CompilerDirectives.transferToInterpreterAndInvalidate();
67-
assertionsEnabled = !PythonOptions.getOption(PythonLanguage.getContextRef().get(), PythonOptions.PythonOptimizeFlag);
68+
PythonContext context = PythonLanguage.getContextRef().get();
69+
assertionsEnabled = !PythonOptions.getOption(context, PythonOptions.PythonOptimizeFlag);
70+
javaExceptionsFailAssertions = PythonOptions.getOption(context, PythonOptions.CatchAllExceptions);
6871
}
6972
if (assertionsEnabled) {
7073
try {
@@ -75,8 +78,12 @@ public void executeVoid(VirtualFrame frame) {
7578
// Python exceptions just fall through
7679
throw e;
7780
} catch (Exception e) {
78-
// catch any other exception and convert to Python exception
79-
throw assertionFailed(frame);
81+
if (javaExceptionsFailAssertions) {
82+
// catch any other exception and convert to Python exception
83+
throw assertionFailed(frame);
84+
} else {
85+
throw e;
86+
}
8087
}
8188
}
8289
}

0 commit comments

Comments
 (0)