Skip to content

Commit ac57445

Browse files
committed
Allow creating native subtypes of exceptions
1 parent 60278e7 commit ac57445

File tree

6 files changed

+82
-6
lines changed

6 files changed

+82
-6
lines changed

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

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -424,10 +424,18 @@ PyAPI_FUNC(PyTypeObject*) get_##NAME(RECEIVER obj) { \
424424
PyAPI_FUNC(PyObject*) get_##NAME(RECEIVER obj) { \
425425
return (PyObject*) obj->NAME; \
426426
}
427+
#define OBJECT_FIELD_SETTER(RECEIVER, NAME) \
428+
PyAPI_FUNC(void) set_##NAME(RECEIVER obj, PyObject* value) { \
429+
Py_XSETREF(obj->NAME, value); \
430+
}
427431
#define PRIMITIVE_FIELD_GETTER(RECEIVER, RESULT, NAME) \
428432
PyAPI_FUNC(RESULT) get_##NAME(RECEIVER obj) { \
429433
return obj->NAME; \
430434
}
435+
#define PRIMITIVE_FIELD_SETTER(RECEIVER, TYPE, NAME) \
436+
PyAPI_FUNC(void) set_##NAME(RECEIVER obj, TYPE value) { \
437+
obj->NAME = value; \
438+
}
431439
#define PRIMITIVE_SUBFIELD_GETTER(RECEIVER, FIELD, RESULT, NAME) \
432440
PyAPI_FUNC(RESULT) get_##NAME(RECEIVER obj) { \
433441
return obj->FIELD? obj->FIELD->NAME : NULL; \
@@ -522,6 +530,20 @@ PRIMITIVE_FIELD_GETTER(PyModuleDef*, Py_ssize_t, m_size)
522530
PRIMITIVE_FIELD_GETTER(PyModuleDef*, const char*, m_doc)
523531
PRIMITIVE_EMBEDDED_FIELD_GETTER(PyComplexObject*, cval, double, real)
524532
PRIMITIVE_EMBEDDED_FIELD_GETTER(PyComplexObject*, cval, double, imag)
533+
OBJECT_FIELD_GETTER(PyBaseExceptionObject*, args);
534+
OBJECT_FIELD_GETTER(PyBaseExceptionObject*, context);
535+
OBJECT_FIELD_GETTER(PyBaseExceptionObject*, cause);
536+
OBJECT_FIELD_GETTER(PyBaseExceptionObject*, traceback);
537+
PRIMITIVE_FIELD_GETTER(PyBaseExceptionObject*, char, suppress_context);
538+
OBJECT_FIELD_SETTER(PyBaseExceptionObject*, args);
539+
OBJECT_FIELD_SETTER(PyBaseExceptionObject*, context);
540+
PyAPI_FUNC(void) set_cause(PyBaseExceptionObject* obj, PyObject* value) {
541+
Py_XSETREF(obj->cause, value);
542+
obj->suppress_context = 1;
543+
}
544+
OBJECT_FIELD_SETTER(PyBaseExceptionObject*, traceback);
545+
PRIMITIVE_FIELD_SETTER(PyBaseExceptionObject*, char, suppress_context);
546+
525547

526548
char* get_ob_sval(PyObject* op) {
527549
return ((PyBytesObject *)(op))->ob_sval;

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

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -187,3 +187,17 @@ void initialize_exceptions() {
187187
PyExc_ResourceWarning = PY_EXCEPTION("ResourceWarning");
188188
}
189189

190+
PyObject* exception_subtype_new(PyTypeObject *type, PyObject *args) {
191+
PyBaseExceptionObject *self;
192+
193+
self = (PyBaseExceptionObject *)type->tp_alloc(type, 0);
194+
if (!self)
195+
return NULL;
196+
/* the dict is created on the fly in PyObject_GenericSetAttr */
197+
self->dict = NULL;
198+
self->traceback = self->cause = self->context = NULL;
199+
self->suppress_context = 0;
200+
self->args = args;
201+
Py_INCREF(args);
202+
return (PyObject *)self;
203+
}

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

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,8 @@
125125
import com.oracle.graal.python.builtins.objects.cext.capi.CExtNodes;
126126
import com.oracle.graal.python.builtins.objects.cext.capi.CExtNodes.PCallCapiFunction;
127127
import com.oracle.graal.python.builtins.objects.cext.capi.CExtNodesFactory;
128+
import com.oracle.graal.python.builtins.objects.cext.capi.ExternalFunctionNodes;
129+
import com.oracle.graal.python.builtins.objects.cext.capi.NativeCAPISymbol;
128130
import com.oracle.graal.python.builtins.objects.cext.capi.transitions.CApiTransitions.NativeToPythonNode;
129131
import com.oracle.graal.python.builtins.objects.cext.capi.transitions.CApiTransitions.PythonToNativeNode;
130132
import com.oracle.graal.python.builtins.objects.cext.capi.transitions.CApiTransitionsFactory.NativeToPythonNodeGen;
@@ -2920,15 +2922,26 @@ public final Object varArgExecute(VirtualFrame frame, Object self, Object[] argu
29202922
return execute(frame, arguments[0], argsWithoutSelf, keywords);
29212923
}
29222924

2923-
@Specialization(guards = "args.length == 0")
2925+
@Specialization(guards = {"!isNativeClass(cls)", "args.length == 0"})
29242926
Object initNoArgs(Object cls, @SuppressWarnings("unused") Object[] args, @SuppressWarnings("unused") PKeyword[] kwargs) {
29252927
return factory().createBaseException(cls);
29262928
}
29272929

2928-
@Specialization(guards = "args.length != 0")
2930+
@Specialization(guards = {"!isNativeClass(cls)", "args.length != 0"})
29292931
Object initArgs(Object cls, Object[] args, @SuppressWarnings("unused") PKeyword[] kwargs) {
29302932
return factory().createBaseException(cls, factory().createTuple(args));
29312933
}
2934+
2935+
@Specialization
2936+
Object doNativeSubtype(PythonNativeClass cls, Object[] args, @SuppressWarnings("unused") PKeyword[] kwargs,
2937+
@Cached PCallCapiFunction callCapiFunction,
2938+
@Cached PythonToNativeNode toNativeNode,
2939+
@Cached NativeToPythonNode toPythonNode,
2940+
@Cached ExternalFunctionNodes.DefaultCheckFunctionResultNode checkFunctionResultNode) {
2941+
Object argsTuple = args.length > 0 ? factory().createTuple(args) : factory().createEmptyTuple();
2942+
Object nativeResult = callCapiFunction.call(NativeCAPISymbol.FUN_EXCEPTION_SUBTYPE_NEW, toNativeNode.execute(cls), toNativeNode.execute(argsTuple));
2943+
return toPythonNode.execute(checkFunctionResultNode.execute(getContext(), NativeCAPISymbol.FUN_EXCEPTION_SUBTYPE_NEW.getTsName(), nativeResult));
2944+
}
29322945
}
29332946

29342947
@Builtin(name = "mappingproxy", constructsClass = PythonBuiltinClassType.PMappingproxy, isPublic = false, minNumOfPositionalArgs = 1, maxNumOfPositionalArgs = 2)

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/cext/capi/NativeCAPISymbol.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,16 @@ public enum NativeCAPISymbol implements NativeCExtSymbol {
197197
FUN_GET_MP_ASS_SUBSCRIPT("get_mp_ass_subscript"),
198198
FUN_GET_PY_COMPLEX_CVAL_REAL("get_cval_real"),
199199
FUN_GET_PY_COMPLEX_CVAL_IMAG("get_cval_imag"),
200+
FUN_GET_EXCEPTION_ARGS("get_args"),
201+
FUN_GET_EXCEPTION_CAUSE("get_cause"),
202+
FUN_GET_EXCEPTION_CONTEXT("get_context"),
203+
FUN_GET_EXCEPTION_SUPPRESS_CONTEXT("get_suppress_context"),
204+
FUN_GET_EXCEPTION_TRACEBACK("get_traceback"),
205+
FUN_SET_EXCEPTION_ARGS("set_args"),
206+
FUN_SET_EXCEPTION_CAUSE("set_cause"),
207+
FUN_SET_EXCEPTION_CONTEXT("set_context"),
208+
FUN_SET_EXCEPTION_SUPPRESS_CONTEXT("set_suppress_context"),
209+
FUN_SET_EXCEPTION_TRACEBACK("set_traceback"),
200210
FUN_GET_PYMODULEDEF_M_METHODS("get_PyModuleDef_m_methods"),
201211
FUN_GET_PYMODULEDEF_M_SLOTS("get_PyModuleDef_m_slots"),
202212
FUN_GET_BYTE_ARRAY_TYPE_ID("get_byte_array_typeid"),
@@ -295,6 +305,7 @@ public enum NativeCAPISymbol implements NativeCExtSymbol {
295305
FUN_TUPLE_SUBTYPE_NEW("tuple_subtype_new"),
296306
FUN_BYTES_SUBTYPE_NEW("bytes_subtype_new"),
297307
FUN_FLOAT_SUBTYPE_NEW("float_subtype_new"),
308+
FUN_EXCEPTION_SUBTYPE_NEW("exception_subtype_new"),
298309
FUN_SUBCLASS_CHECK("truffle_subclass_check"),
299310
FUN_BASETYPE_CHECK("truffle_BASETYPE_check"),
300311
FUN_MEMCPY_BYTES("truffle_memcpy_bytes"),

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

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@
5252
import com.oracle.graal.python.builtins.PythonBuiltinClassType;
5353
import com.oracle.graal.python.builtins.PythonBuiltins;
5454
import com.oracle.graal.python.builtins.objects.PNone;
55+
import com.oracle.graal.python.builtins.objects.cext.PythonAbstractNativeObject;
5556
import com.oracle.graal.python.builtins.objects.common.HashingStorage;
5657
import com.oracle.graal.python.builtins.objects.common.HashingStorageNodes.HashingStorageForEach;
5758
import com.oracle.graal.python.builtins.objects.common.HashingStorageNodes.HashingStorageForEachCallback;
@@ -117,7 +118,7 @@ protected List<? extends NodeFactory<? extends PythonBuiltinBaseNode>> getNodeFa
117118
public abstract static class BaseExceptionInitNode extends PythonVarargsBuiltinNode {
118119
@Child private SplitArgsNode splitArgsNode;
119120

120-
public final Object execute(PBaseException self, Object[] args) {
121+
public final Object execute(Object self, Object[] args) {
121122
return execute(null, self, args, PKeyword.EMPTY_KEYWORDS);
122123
}
123124

@@ -150,7 +151,7 @@ Object doWithArguments(PBaseException self, Object[] args, @SuppressWarnings("un
150151
@Specialization(replaces = {"doNoArguments", "doWithArguments"})
151152
Object doGeneric(PBaseException self, Object[] args, PKeyword[] keywords) {
152153
if (keywords.length != 0) {
153-
throw raise(PythonBuiltinClassType.TypeError, P_TAKES_NO_KEYWORD_ARGS, self);
154+
throw raise(TypeError, P_TAKES_NO_KEYWORD_ARGS, self);
154155
}
155156
if (args.length == 0) {
156157
self.setArgs(null);
@@ -159,6 +160,21 @@ Object doGeneric(PBaseException self, Object[] args, PKeyword[] keywords) {
159160
}
160161
return PNone.NONE;
161162
}
163+
164+
@Specialization
165+
Object doNative(PythonAbstractNativeObject self, Object[] args, PKeyword[] keywords,
166+
@Bind("this") Node inliningTarget,
167+
@Cached ExceptionNodes.SetArgsNode setArgsNode) {
168+
if (keywords.length != 0) {
169+
throw raise(TypeError, P_TAKES_NO_KEYWORD_ARGS, self);
170+
}
171+
if (args.length == 0) {
172+
setArgsNode.execute(inliningTarget, self, factory().createEmptyTuple());
173+
} else {
174+
setArgsNode.execute(inliningTarget, self, factory().createTuple(args));
175+
}
176+
return PNone.NONE;
177+
}
162178
}
163179

164180
@Builtin(name = "args", minNumOfPositionalArgs = 1, maxNumOfPositionalArgs = 2, isGetter = true, isSetter = true)

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -187,7 +187,7 @@ static boolean doNative(@SuppressWarnings("unused") Node inliningTarget, PythonA
187187
@Cached CApiTransitions.PythonToNativeNode toNative,
188188
@Cached CApiTransitions.NativeToPythonNode toPython,
189189
@Cached CExtNodes.PCallCapiFunction callGetter) {
190-
return (int) toPython.execute(callGetter.call(NativeMember.SUPPRESS_CONTEXT.getGetterFunctionName(), toNative.execute(noneToNoValue(exception)))) != 0;
190+
return (byte) callGetter.call(NativeMember.SUPPRESS_CONTEXT.getGetterFunctionName(), toNative.execute(noneToNoValue(exception))) != 0;
191191
}
192192

193193
@Specialization
@@ -217,7 +217,7 @@ static void doNative(@SuppressWarnings("unused") Node inliningTarget, PythonAbst
217217
@SuppressWarnings("unused") @Cached PyExceptionInstanceCheckNode check,
218218
@Cached CApiTransitions.PythonToNativeNode excToNative,
219219
@Cached CExtNodes.PCallCapiFunction callGetter) {
220-
callGetter.call(NativeMember.SUPPRESS_CONTEXT.getSetterFunctionName(), excToNative.execute(exception), value ? 1 : 0);
220+
callGetter.call(NativeMember.SUPPRESS_CONTEXT.getSetterFunctionName(), excToNative.execute(exception), (byte) (value ? 1 : 0));
221221
}
222222

223223
@Specialization

0 commit comments

Comments
 (0)