Commit c7c10250 authored by Kevin Modzelewski's avatar Kevin Modzelewski

Add a bunch more C API stuff

Most involved was the recursion checking stuff: switch to
providing the C API thread state rather than our internal
one, since they are mostly the same.

The recursion checking code doesn't mean much while most stuff
doesn't use it, but hey at least it's supported now.
parent 9b3c6d65
...@@ -52,7 +52,8 @@ PyAPI_FUNC(int) Py_GetRecursionLimit(void); ...@@ -52,7 +52,8 @@ PyAPI_FUNC(int) Py_GetRecursionLimit(void);
_Py_CheckRecursiveCall(where)) _Py_CheckRecursiveCall(where))
#define Py_LeaveRecursiveCall() \ #define Py_LeaveRecursiveCall() \
(--PyThreadState_GET()->recursion_depth) (--PyThreadState_GET()->recursion_depth)
PyAPI_FUNC(int) _Py_CheckRecursiveCall(char *where); // Pyston change: changed this to const char*
PyAPI_FUNC(int) _Py_CheckRecursiveCall(const char *where);
PyAPI_DATA(int) _Py_CheckRecursionLimit; PyAPI_DATA(int) _Py_CheckRecursionLimit;
#ifdef USE_STACKCHECK #ifdef USE_STACKCHECK
# define _Py_MakeRecCheck(x) (++(x) > --_Py_CheckRecursionLimit) # define _Py_MakeRecCheck(x) (++(x) > --_Py_CheckRecursionLimit)
......
...@@ -37,7 +37,8 @@ PyAPI_DATA(PyTypeObject*) int_cls; ...@@ -37,7 +37,8 @@ PyAPI_DATA(PyTypeObject*) int_cls;
#define PyInt_Type (*int_cls) #define PyInt_Type (*int_cls)
// Pyston changes: these aren't direct macros any more [they potentially could be though] // Pyston changes: these aren't direct macros any more [they potentially could be though]
PyAPI_FUNC(bool) PyInt_Check(PyObject*); PyAPI_FUNC(bool) _PyInt_Check(PyObject*);
#define PyInt_Check(op) _PyInt_Check((PyObject*)op)
#if 0 #if 0
#define PyInt_Check(op) \ #define PyInt_Check(op) \
PyType_FastSubclass((op)->ob_type, Py_TPFLAGS_INT_SUBCLASS) PyType_FastSubclass((op)->ob_type, Py_TPFLAGS_INT_SUBCLASS)
......
...@@ -100,6 +100,8 @@ PyAPI_FUNC(void) PyErr_NormalizeException(PyObject**, PyObject**, PyObject**); ...@@ -100,6 +100,8 @@ PyAPI_FUNC(void) PyErr_NormalizeException(PyObject**, PyObject**, PyObject**);
/* */ /* */
// Pyston change: made these function calls for now
#if 0
#define PyExceptionClass_Check(x) \ #define PyExceptionClass_Check(x) \
(PyClass_Check((x)) || (PyType_Check((x)) && \ (PyClass_Check((x)) || (PyType_Check((x)) && \
PyType_FastSubclass((PyTypeObject*)(x), Py_TPFLAGS_BASE_EXC_SUBCLASS))) PyType_FastSubclass((PyTypeObject*)(x), Py_TPFLAGS_BASE_EXC_SUBCLASS)))
...@@ -117,7 +119,12 @@ PyAPI_FUNC(void) PyErr_NormalizeException(PyObject**, PyObject**, PyObject**); ...@@ -117,7 +119,12 @@ PyAPI_FUNC(void) PyErr_NormalizeException(PyObject**, PyObject**, PyObject**);
((PyInstance_Check((x)) \ ((PyInstance_Check((x)) \
? (PyObject*)((PyInstanceObject*)(x))->in_class \ ? (PyObject*)((PyInstanceObject*)(x))->in_class \
: (PyObject*)((x)->ob_type))) : (PyObject*)((x)->ob_type)))
#endif
// (We might have to make these wrapper macros that do appropriate casting to PyObject)
PyAPI_FUNC(int) PyExceptionClass_Check(PyObject*);
PyAPI_FUNC(int) PyExceptionInstance_Check(PyObject*);
PyAPI_FUNC(const char*) PyExceptionClass_Name(PyObject*);
PyAPI_FUNC(PyObject*) PyExceptionInstance_Class(PyObject*);
/* Predefined exceptions */ /* Predefined exceptions */
......
...@@ -110,8 +110,13 @@ typedef struct _ts { ...@@ -110,8 +110,13 @@ typedef struct _ts {
} PyThreadState; } PyThreadState;
#endif #endif
struct _PyThreadState; typedef struct _ts {
typedef struct _PyThreadState PyThreadState; int recursion_depth;
PyObject *curexc_type;
PyObject *curexc_value;
PyObject *curexc_traceback;
} PyThreadState;
PyAPI_FUNC(PyInterpreterState *) PyInterpreterState_New(void); PyAPI_FUNC(PyInterpreterState *) PyInterpreterState_New(void);
...@@ -135,7 +140,10 @@ PyAPI_FUNC(int) PyThreadState_SetAsyncExc(long, PyObject *); ...@@ -135,7 +140,10 @@ PyAPI_FUNC(int) PyThreadState_SetAsyncExc(long, PyObject *);
/* Variable and macro for in-line access to current thread state */ /* Variable and macro for in-line access to current thread state */
PyAPI_DATA(PyThreadState *) _PyThreadState_Current; // Pyston change: use our internal name for this
//PyAPI_DATA(PyThreadState *) _PyThreadState_Current;
PyAPI_DATA(__thread PyThreadState) cur_thread_state;
#define _PyThreadState_Current (&cur_thread_state)
#ifdef Py_DEBUG #ifdef Py_DEBUG
#define PyThreadState_GET() PyThreadState_Get() #define PyThreadState_GET() PyThreadState_Get()
......
...@@ -65,7 +65,8 @@ PyAPI_DATA(PyTypeObject*) str_cls; ...@@ -65,7 +65,8 @@ PyAPI_DATA(PyTypeObject*) str_cls;
#define PyString_Type (*str_cls) #define PyString_Type (*str_cls)
// Pyston changes: these aren't direct macros any more [they potentially could be though] // Pyston changes: these aren't direct macros any more [they potentially could be though]
PyAPI_FUNC(bool) PyString_Check(PyObject*); PyAPI_FUNC(bool) _PyString_Check(PyObject*);
#define PyString_Check(op) _PyString_Check((PyObject*)op)
#if 0 #if 0
#define PyString_Check(op) \ #define PyString_Check(op) \
PyType_FastSubclass(Py_TYPE(op), Py_TPFLAGS_STRING_SUBCLASS) PyType_FastSubclass(Py_TYPE(op), Py_TPFLAGS_STRING_SUBCLASS)
......
...@@ -20,6 +20,7 @@ ...@@ -20,6 +20,7 @@
#include "capi/types.h" #include "capi/types.h"
#include "core/threading.h" #include "core/threading.h"
#include "core/types.h" #include "core/types.h"
#include "runtime/classobj.h"
#include "runtime/import.h" #include "runtime/import.h"
#include "runtime/objmodel.h" #include "runtime/objmodel.h"
#include "runtime/types.h" #include "runtime/types.h"
...@@ -65,6 +66,205 @@ static PyObject* objargs_mktuple(va_list va) noexcept { ...@@ -65,6 +66,205 @@ static PyObject* objargs_mktuple(va_list va) noexcept {
return result; return result;
} }
/* isinstance(), issubclass() */
/* abstract_get_bases() has logically 4 return states, with a sort of 0th
* state that will almost never happen.
*
* 0. creating the __bases__ static string could get a MemoryError
* 1. getattr(cls, '__bases__') could raise an AttributeError
* 2. getattr(cls, '__bases__') could raise some other exception
* 3. getattr(cls, '__bases__') could return a tuple
* 4. getattr(cls, '__bases__') could return something other than a tuple
*
* Only state #3 is a non-error state and only it returns a non-NULL object
* (it returns the retrieved tuple).
*
* Any raised AttributeErrors are masked by clearing the exception and
* returning NULL. If an object other than a tuple comes out of __bases__,
* then again, the return value is NULL. So yes, these two situations
* produce exactly the same results: NULL is returned and no error is set.
*
* If some exception other than AttributeError is raised, then NULL is also
* returned, but the exception is not cleared. That's because we want the
* exception to be propagated along.
*
* Callers are expected to test for PyErr_Occurred() when the return value
* is NULL to decide whether a valid exception should be propagated or not.
* When there's no exception to propagate, it's customary for the caller to
* set a TypeError.
*/
static PyObject* abstract_get_bases(PyObject* cls) noexcept {
PyObject* bases;
/*
static PyObject* __bases__ = NULL;
if (__bases__ == NULL) {
__bases__ = PyString_InternFromString("__bases__");
if (__bases__ == NULL)
return NULL;
}
*/
PyObject* __bases__ = boxStrConstant("__bases__");
bases = PyObject_GetAttr(cls, __bases__);
if (bases == NULL) {
if (PyErr_ExceptionMatches(PyExc_AttributeError))
PyErr_Clear();
return NULL;
}
if (!PyTuple_Check(bases)) {
Py_DECREF(bases);
return NULL;
}
return bases;
}
static int abstract_issubclass(PyObject* derived, PyObject* cls) noexcept {
PyObject* bases = NULL;
Py_ssize_t i, n;
int r = 0;
while (1) {
if (derived == cls)
return 1;
bases = abstract_get_bases(derived);
if (bases == NULL) {
if (PyErr_Occurred())
return -1;
return 0;
}
n = PyTuple_GET_SIZE(bases);
if (n == 0) {
Py_DECREF(bases);
return 0;
}
/* Avoid recursivity in the single inheritance case */
if (n == 1) {
derived = PyTuple_GET_ITEM(bases, 0);
Py_DECREF(bases);
continue;
}
for (i = 0; i < n; i++) {
r = abstract_issubclass(PyTuple_GET_ITEM(bases, i), cls);
if (r != 0)
break;
}
Py_DECREF(bases);
return r;
}
}
static int check_class(PyObject* cls, const char* error) noexcept {
PyObject* bases = abstract_get_bases(cls);
if (bases == NULL) {
/* Do not mask errors. */
if (!PyErr_Occurred())
PyErr_SetString(PyExc_TypeError, error);
return 0;
}
Py_DECREF(bases);
return -1;
}
static int recursive_isinstance(PyObject* inst, PyObject* cls) noexcept {
PyObject* icls;
int retval = 0;
/*
static PyObject* __class__ = NULL;
if (__class__ == NULL) {
__class__ = PyString_InternFromString("__class__");
if (__class__ == NULL)
return -1;
}
*/
PyObject* __class__ = boxStrConstant("__class__");
if (PyClass_Check(cls) && PyInstance_Check(inst)) {
PyObject* inclass = static_cast<BoxedInstance*>(inst)->inst_cls;
retval = PyClass_IsSubclass(inclass, cls);
} else if (PyType_Check(cls)) {
retval = PyObject_TypeCheck(inst, (PyTypeObject*)cls);
if (retval == 0) {
PyObject* c = PyObject_GetAttr(inst, __class__);
if (c == NULL) {
PyErr_Clear();
} else {
if (c != (PyObject*)(inst->cls) && PyType_Check(c))
retval = PyType_IsSubtype((PyTypeObject*)c, (PyTypeObject*)cls);
Py_DECREF(c);
}
}
} else {
if (!check_class(cls, "isinstance() arg 2 must be a class, type,"
" or tuple of classes and types"))
return -1;
icls = PyObject_GetAttr(inst, __class__);
if (icls == NULL) {
PyErr_Clear();
retval = 0;
} else {
retval = abstract_issubclass(icls, cls);
Py_DECREF(icls);
}
}
return retval;
}
extern "C" int PyObject_IsInstance(PyObject* inst, PyObject* cls) {
static PyObject* name = NULL;
/* Quick test for an exact match */
if (Py_TYPE(inst) == (PyTypeObject*)cls)
return 1;
if (PyTuple_Check(cls)) {
Py_ssize_t i;
Py_ssize_t n;
int r = 0;
if (Py_EnterRecursiveCall(" in __instancecheck__"))
return -1;
n = PyTuple_GET_SIZE(cls);
for (i = 0; i < n; ++i) {
PyObject* item = PyTuple_GET_ITEM(cls, i);
r = PyObject_IsInstance(inst, item);
if (r != 0)
/* either found it, or got an error */
break;
}
Py_LeaveRecursiveCall();
return r;
}
if (!(PyClass_Check(cls) || PyInstance_Check(cls))) {
PyObject* checker;
checker = _PyObject_LookupSpecial(cls, "__instancecheck__", &name);
if (checker != NULL) {
PyObject* res;
int ok = -1;
if (Py_EnterRecursiveCall(" in __instancecheck__")) {
Py_DECREF(checker);
return ok;
}
res = PyObject_CallFunctionObjArgs(checker, inst, NULL);
Py_LeaveRecursiveCall();
Py_DECREF(checker);
if (res != NULL) {
ok = PyObject_IsTrue(res);
Py_DECREF(res);
}
return ok;
} else if (PyErr_Occurred())
return -1;
}
return recursive_isinstance(inst, cls);
}
extern "C" PyObject* PyObject_CallFunctionObjArgs(PyObject* callable, ...) { extern "C" PyObject* PyObject_CallFunctionObjArgs(PyObject* callable, ...) {
PyObject* args, *tmp; PyObject* args, *tmp;
va_list vargs; va_list vargs;
...@@ -83,4 +283,74 @@ extern "C" PyObject* PyObject_CallFunctionObjArgs(PyObject* callable, ...) { ...@@ -83,4 +283,74 @@ extern "C" PyObject* PyObject_CallFunctionObjArgs(PyObject* callable, ...) {
return tmp; return tmp;
} }
static int recursive_issubclass(PyObject* derived, PyObject* cls) noexcept {
int retval;
if (PyType_Check(cls) && PyType_Check(derived)) {
/* Fast path (non-recursive) */
return PyType_IsSubtype((PyTypeObject*)derived, (PyTypeObject*)cls);
}
if (!PyClass_Check(derived) || !PyClass_Check(cls)) {
if (!check_class(derived, "issubclass() arg 1 must be a class"))
return -1;
if (!check_class(cls, "issubclass() arg 2 must be a class"
" or tuple of classes"))
return -1;
retval = abstract_issubclass(derived, cls);
} else {
/* shortcut */
if (!(retval = (derived == cls)))
retval = PyClass_IsSubclass(derived, cls);
}
return retval;
}
extern "C" int PyObject_IsSubclass(PyObject* derived, PyObject* cls) {
static PyObject* name = NULL;
if (PyTuple_Check(cls)) {
Py_ssize_t i;
Py_ssize_t n;
int r = 0;
if (Py_EnterRecursiveCall(" in __subclasscheck__"))
return -1;
n = PyTuple_GET_SIZE(cls);
for (i = 0; i < n; ++i) {
PyObject* item = PyTuple_GET_ITEM(cls, i);
r = PyObject_IsSubclass(derived, item);
if (r != 0)
/* either found it, or got an error */
break;
}
Py_LeaveRecursiveCall();
return r;
}
if (!(PyClass_Check(cls) || PyInstance_Check(cls))) {
PyObject* checker;
checker = _PyObject_LookupSpecial(cls, "__subclasscheck__", &name);
if (checker != NULL) {
PyObject* res;
int ok = -1;
if (Py_EnterRecursiveCall(" in __subclasscheck__")) {
Py_DECREF(checker);
return ok;
}
res = PyObject_CallFunctionObjArgs(checker, derived, NULL);
Py_LeaveRecursiveCall();
Py_DECREF(checker);
if (res != NULL) {
ok = PyObject_IsTrue(res);
Py_DECREF(res);
}
return ok;
} else if (PyErr_Occurred()) {
return -1;
}
}
return recursive_issubclass(derived, cls);
}
} }
...@@ -118,21 +118,69 @@ extern "C" PyObject* PyErr_SetFromErrnoWithUnicodeFilename(PyObject* exc, const ...@@ -118,21 +118,69 @@ extern "C" PyObject* PyErr_SetFromErrnoWithUnicodeFilename(PyObject* exc, const
#endif /* MS_WINDOWS */ #endif /* MS_WINDOWS */
extern "C" void PyErr_Fetch(PyObject** p_type, PyObject** p_value, PyObject** p_traceback) { extern "C" void PyErr_Fetch(PyObject** p_type, PyObject** p_value, PyObject** p_traceback) {
auto* tstate = &threading::cur_thread_state; PyThreadState* tstate = PyThreadState_GET();
*p_type = tstate->exc_type; *p_type = tstate->curexc_type;
*p_value = tstate->exc_value; *p_value = tstate->curexc_value;
*p_traceback = tstate->exc_traceback; *p_traceback = tstate->curexc_traceback;
tstate->exc_type = NULL; tstate->curexc_type = NULL;
tstate->exc_value = NULL; tstate->curexc_value = NULL;
tstate->exc_traceback = NULL; tstate->curexc_traceback = NULL;
} }
extern "C" PyObject* PyErr_SetFromErrno(PyObject* exc) { extern "C" PyObject* PyErr_SetFromErrno(PyObject* exc) {
return PyErr_SetFromErrnoWithFilenameObject(exc, NULL); return PyErr_SetFromErrnoWithFilenameObject(exc, NULL);
} }
/* Call when an exception has occurred but there is no way for Python
to handle it. Examples: exception in __del__ or during GC. */
extern "C" void PyErr_WriteUnraisable(PyObject* obj) {
PyObject* f, *t, *v, *tb;
PyErr_Fetch(&t, &v, &tb);
f = PySys_GetObject("stderr");
if (f != NULL) {
PyFile_WriteString("Exception ", f);
if (t) {
PyObject* moduleName;
const char* className;
assert(PyExceptionClass_Check(t));
className = PyExceptionClass_Name(t);
if (className != NULL) {
const char* dot = strrchr(className, '.');
if (dot != NULL)
className = dot + 1;
}
moduleName = PyObject_GetAttrString(t, "__module__");
if (moduleName == NULL)
PyFile_WriteString("<unknown>", f);
else {
char* modstr = PyString_AsString(moduleName);
if (modstr && strcmp(modstr, "exceptions") != 0) {
PyFile_WriteString(modstr, f);
PyFile_WriteString(".", f);
}
}
if (className == NULL)
PyFile_WriteString("<unknown>", f);
else
PyFile_WriteString(className, f);
if (v && v != Py_None) {
PyFile_WriteString(": ", f);
PyFile_WriteObject(v, f, 0);
}
Py_XDECREF(moduleName);
}
PyFile_WriteString(" in ", f);
PyFile_WriteObject(obj, f, 0);
PyFile_WriteString(" ignored\n", f);
PyErr_Clear(); /* Just in case */
}
Py_XDECREF(t);
Py_XDECREF(v);
Py_XDECREF(tb);
}
extern "C" void PyErr_Display(PyObject* exception, PyObject* value, PyObject* tb) { extern "C" void PyErr_Display(PyObject* exception, PyObject* value, PyObject* tb) {
Py_FatalError("unimplemented"); Py_FatalError("unimplemented");
} }
......
...@@ -34,8 +34,10 @@ ...@@ -34,8 +34,10 @@
namespace pyston { namespace pyston {
namespace threading { namespace threading {
__thread ThreadState cur_thread_state extern "C" {
= { NULL, NULL, NULL }; // not sure if we need to explicitly request zero-initialization __thread PyThreadState cur_thread_state
= { 0, NULL, NULL, NULL }; // not sure if we need to explicitly request zero-initialization
}
PthreadFastMutex threading_lock; PthreadFastMutex threading_lock;
...@@ -75,9 +77,9 @@ public: ...@@ -75,9 +77,9 @@ public:
std::vector<StackInfo> previous_stacks; std::vector<StackInfo> previous_stacks;
pthread_t pthread_id; pthread_t pthread_id;
ThreadState* public_thread_state; PyThreadState* public_thread_state;
ThreadStateInternal(void* stack_start, pthread_t pthread_id, ThreadState* public_thread_state) ThreadStateInternal(void* stack_start, pthread_t pthread_id, PyThreadState* public_thread_state)
: saved(false), stack_start(stack_start), pthread_id(pthread_id), public_thread_state(public_thread_state) {} : saved(false), stack_start(stack_start), pthread_id(pthread_id), public_thread_state(public_thread_state) {}
void saveCurrent() { void saveCurrent() {
...@@ -111,12 +113,12 @@ public: ...@@ -111,12 +113,12 @@ public:
void accept(gc::GCVisitor* v) { void accept(gc::GCVisitor* v) {
auto pub_state = public_thread_state; auto pub_state = public_thread_state;
if (pub_state->exc_type) if (pub_state->curexc_type)
v->visit(pub_state->exc_type); v->visit(pub_state->curexc_type);
if (pub_state->exc_value) if (pub_state->curexc_value)
v->visit(pub_state->exc_value); v->visit(pub_state->curexc_value);
if (pub_state->exc_traceback) if (pub_state->curexc_traceback)
v->visit(pub_state->exc_traceback); v->visit(pub_state->curexc_traceback);
for (auto& stack_info : previous_stacks) { for (auto& stack_info : previous_stacks) {
v->visit(stack_info.next_generator); v->visit(stack_info.next_generator);
......
...@@ -36,11 +36,6 @@ namespace threading { ...@@ -36,11 +36,6 @@ namespace threading {
// Whether or not a second thread was ever started: // Whether or not a second thread was ever started:
bool threadWasStarted(); bool threadWasStarted();
struct ThreadState {
Box* exc_type, *exc_value, *exc_traceback;
};
extern __thread ThreadState cur_thread_state;
// returns a thread id (currently, the pthread_t id) // returns a thread id (currently, the pthread_t id)
intptr_t start_thread(void* (*start_func)(Box*, Box*, Box*), Box* arg1, Box* arg2, Box* arg3); intptr_t start_thread(void* (*start_func)(Box*, Box*, Box*), Box* arg1, Box* arg2, Box* arg3);
...@@ -49,7 +44,7 @@ void registerMainThread(); ...@@ -49,7 +44,7 @@ void registerMainThread();
void finishMainThread(); void finishMainThread();
// Hook for the GC; will visit all the threads (including the current one), visiting their // Hook for the GC; will visit all the threads (including the current one), visiting their
// stacks and thread-local ThreadState objects // stacks and thread-local PyThreadState objects
void visitAllStacks(gc::GCVisitor* v); void visitAllStacks(gc::GCVisitor* v);
// Some hooks to keep track of the list of stacks that this thread has been using. // Some hooks to keep track of the list of stacks that this thread has been using.
......
...@@ -32,10 +32,9 @@ BoxedModule* sys_module; ...@@ -32,10 +32,9 @@ BoxedModule* sys_module;
BoxedDict* sys_modules_dict; BoxedDict* sys_modules_dict;
Box* sysExcInfo() { Box* sysExcInfo() {
return new BoxedTuple( return new BoxedTuple({ cur_thread_state.curexc_type ? cur_thread_state.curexc_type : None,
{ threading::cur_thread_state.exc_type ? threading::cur_thread_state.exc_type : None, cur_thread_state.curexc_value ? cur_thread_state.curexc_value : None,
threading::cur_thread_state.exc_value ? threading::cur_thread_state.exc_value : None, cur_thread_state.curexc_traceback ? cur_thread_state.curexc_traceback : None });
threading::cur_thread_state.exc_traceback ? threading::cur_thread_state.exc_traceback : None });
} }
static Box* sysExit(Box* arg) { static Box* sysExit(Box* arg) {
......
...@@ -32,9 +32,11 @@ BoxedClass* method_cls; ...@@ -32,9 +32,11 @@ BoxedClass* method_cls;
#define MAKE_CHECK(NAME, cls_name) \ #define MAKE_CHECK(NAME, cls_name) \
extern "C" bool Py##NAME##_Check(PyObject* op) { return isSubclass(op->cls, cls_name); } extern "C" bool Py##NAME##_Check(PyObject* op) { return isSubclass(op->cls, cls_name); }
#define MAKE_CHECK2(NAME, cls_name) \
extern "C" bool _Py##NAME##_Check(PyObject* op) { return isSubclass(op->cls, cls_name); }
MAKE_CHECK(Int, int_cls) MAKE_CHECK2(Int, int_cls)
MAKE_CHECK(String, str_cls) MAKE_CHECK2(String, str_cls)
MAKE_CHECK(Long, long_cls) MAKE_CHECK(Long, long_cls)
MAKE_CHECK(List, list_cls) MAKE_CHECK(List, list_cls)
MAKE_CHECK(Tuple, tuple_cls) MAKE_CHECK(Tuple, tuple_cls)
...@@ -47,6 +49,7 @@ MAKE_CHECK(Unicode, unicode_cls) ...@@ -47,6 +49,7 @@ MAKE_CHECK(Unicode, unicode_cls)
#endif #endif
#undef MAKE_CHECK #undef MAKE_CHECK
#undef MAKE_CHECK2
extern "C" bool _PyIndex_Check(PyObject* op) { extern "C" bool _PyIndex_Check(PyObject* op) {
// TODO this is wrong (the CPython version checks for things that can be coerced to a number): // TODO this is wrong (the CPython version checks for things that can be coerced to a number):
...@@ -644,10 +647,10 @@ extern "C" void PyErr_NormalizeException(PyObject** exc, PyObject** val, PyObjec ...@@ -644,10 +647,10 @@ extern "C" void PyErr_NormalizeException(PyObject** exc, PyObject** val, PyObjec
} }
void checkAndThrowCAPIException() { void checkAndThrowCAPIException() {
Box* value = threading::cur_thread_state.exc_value; Box* value = cur_thread_state.curexc_value;
if (value) { if (value) {
RELEASE_ASSERT(threading::cur_thread_state.exc_traceback == NULL, "unsupported"); RELEASE_ASSERT(cur_thread_state.curexc_traceback == NULL, "unsupported");
Box* _type = threading::cur_thread_state.exc_type; Box* _type = cur_thread_state.curexc_type;
BoxedClass* type = static_cast<BoxedClass*>(_type); BoxedClass* type = static_cast<BoxedClass*>(_type);
assert(isInstance(_type, type_cls) && isSubclass(static_cast<BoxedClass*>(type), BaseException) assert(isInstance(_type, type_cls) && isSubclass(static_cast<BoxedClass*>(type), BaseException)
&& "Only support throwing subclass of BaseException for now"); && "Only support throwing subclass of BaseException for now");
...@@ -655,13 +658,12 @@ void checkAndThrowCAPIException() { ...@@ -655,13 +658,12 @@ void checkAndThrowCAPIException() {
// This is similar to PyErr_NormalizeException: // This is similar to PyErr_NormalizeException:
if (!isInstance(value, type)) { if (!isInstance(value, type)) {
if (value->cls == tuple_cls) { if (value->cls == tuple_cls) {
value = runtimeCall(threading::cur_thread_state.exc_type, ArgPassSpec(0, 0, true, false), value, NULL, value = runtimeCall(cur_thread_state.curexc_type, ArgPassSpec(0, 0, true, false), value, NULL, NULL,
NULL, NULL, NULL); NULL, NULL);
} else if (value == None) { } else if (value == None) {
value = runtimeCall(threading::cur_thread_state.exc_type, ArgPassSpec(0), NULL, NULL, NULL, NULL, NULL); value = runtimeCall(cur_thread_state.curexc_type, ArgPassSpec(0), NULL, NULL, NULL, NULL, NULL);
} else { } else {
value value = runtimeCall(cur_thread_state.curexc_type, ArgPassSpec(1), value, NULL, NULL, NULL, NULL);
= runtimeCall(threading::cur_thread_state.exc_type, ArgPassSpec(1), value, NULL, NULL, NULL, NULL);
} }
} }
...@@ -673,9 +675,9 @@ void checkAndThrowCAPIException() { ...@@ -673,9 +675,9 @@ void checkAndThrowCAPIException() {
} }
extern "C" void PyErr_Restore(PyObject* type, PyObject* value, PyObject* traceback) { extern "C" void PyErr_Restore(PyObject* type, PyObject* value, PyObject* traceback) {
threading::cur_thread_state.exc_type = type; cur_thread_state.curexc_type = type;
threading::cur_thread_state.exc_value = value; cur_thread_state.curexc_value = value;
threading::cur_thread_state.exc_traceback = traceback; cur_thread_state.curexc_traceback = traceback;
} }
extern "C" void PyErr_Clear() { extern "C" void PyErr_Clear() {
...@@ -702,12 +704,112 @@ extern "C" int PyErr_CheckSignals() { ...@@ -702,12 +704,112 @@ extern "C" int PyErr_CheckSignals() {
Py_FatalError("unimplemented"); Py_FatalError("unimplemented");
} }
extern "C" int PyErr_ExceptionMatches(PyObject* exc) { extern "C" int PyExceptionClass_Check(PyObject* o) {
Py_FatalError("unimplemented");
}
extern "C" int PyExceptionInstance_Check(PyObject* o) {
Py_FatalError("unimplemented");
}
extern "C" const char* PyExceptionClass_Name(PyObject* o) {
Py_FatalError("unimplemented");
}
extern "C" PyObject* PyExceptionInstance_Class(PyObject* o) {
Py_FatalError("unimplemented"); Py_FatalError("unimplemented");
} }
#define Py_DEFAULT_RECURSION_LIMIT 1000
static int recursion_limit = Py_DEFAULT_RECURSION_LIMIT;
extern "C" {
int _Py_CheckRecursionLimit = Py_DEFAULT_RECURSION_LIMIT;
}
/* the macro Py_EnterRecursiveCall() only calls _Py_CheckRecursiveCall()
if the recursion_depth reaches _Py_CheckRecursionLimit.
If USE_STACKCHECK, the macro decrements _Py_CheckRecursionLimit
to guarantee that _Py_CheckRecursiveCall() is regularly called.
Without USE_STACKCHECK, there is no need for this. */
extern "C" int _Py_CheckRecursiveCall(const char* where) {
PyThreadState* tstate = PyThreadState_GET();
#ifdef USE_STACKCHECK
if (PyOS_CheckStack()) {
--tstate->recursion_depth;
PyErr_SetString(PyExc_MemoryError, "Stack overflow");
return -1;
}
#endif
if (tstate->recursion_depth > recursion_limit) {
--tstate->recursion_depth;
PyErr_Format(PyExc_RuntimeError, "maximum recursion depth exceeded%s", where);
return -1;
}
_Py_CheckRecursionLimit = recursion_limit;
return 0;
}
extern "C" int Py_GetRecursionLimit(void) {
return recursion_limit;
}
extern "C" void Py_SetRecursionLimit(int new_limit) {
recursion_limit = new_limit;
_Py_CheckRecursionLimit = recursion_limit;
}
extern "C" int PyErr_GivenExceptionMatches(PyObject* err, PyObject* exc) {
if (err == NULL || exc == NULL) {
/* maybe caused by "import exceptions" that failed early on */
return 0;
}
if (PyTuple_Check(exc)) {
Py_ssize_t i, n;
n = PyTuple_Size(exc);
for (i = 0; i < n; i++) {
/* Test recursively */
if (PyErr_GivenExceptionMatches(err, PyTuple_GET_ITEM(exc, i))) {
return 1;
}
}
return 0;
}
/* err might be an instance, so check its class. */
if (PyExceptionInstance_Check(err))
err = PyExceptionInstance_Class(err);
if (PyExceptionClass_Check(err) && PyExceptionClass_Check(exc)) {
int res = 0, reclimit;
PyObject* exception, *value, *tb;
PyErr_Fetch(&exception, &value, &tb);
/* Temporarily bump the recursion limit, so that in the most
common case PyObject_IsSubclass will not raise a recursion
error we have to ignore anyway. Don't do it when the limit
is already insanely high, to avoid overflow */
reclimit = Py_GetRecursionLimit();
if (reclimit < (1 << 30))
Py_SetRecursionLimit(reclimit + 5);
res = PyObject_IsSubclass(err, exc);
Py_SetRecursionLimit(reclimit);
/* This function must not fail, so print the error here */
if (res == -1) {
PyErr_WriteUnraisable(err);
res = 0;
}
PyErr_Restore(exception, value, tb);
return res;
}
return err == exc;
}
extern "C" int PyErr_ExceptionMatches(PyObject* exc) {
return PyErr_GivenExceptionMatches(PyErr_Occurred(), exc);
}
extern "C" PyObject* PyErr_Occurred() { extern "C" PyObject* PyErr_Occurred() {
return threading::cur_thread_state.exc_type; return cur_thread_state.curexc_type;
} }
extern "C" int PyErr_WarnEx(PyObject* category, const char* text, Py_ssize_t stacklevel) { extern "C" int PyErr_WarnEx(PyObject* category, const char* text, Py_ssize_t stacklevel) {
......
...@@ -57,6 +57,10 @@ static Box* classLookup(BoxedClassobj* cls, const std::string& attr) { ...@@ -57,6 +57,10 @@ static Box* classLookup(BoxedClassobj* cls, const std::string& attr) {
return NULL; return NULL;
} }
extern "C" int PyClass_IsSubclass(PyObject* klass, PyObject* base) {
Py_FatalError("unimplemented");
}
Box* classobjNew(Box* _cls, Box* _name, Box* _bases, Box** _args) { Box* classobjNew(Box* _cls, Box* _name, Box* _bases, Box** _args) {
if (!isSubclass(_cls->cls, type_cls)) if (!isSubclass(_cls->cls, type_cls))
raiseExcHelper(TypeError, "classobj.__new__(X): X is not a type object (%s)", getTypeName(_cls)->c_str()); raiseExcHelper(TypeError, "classobj.__new__(X): X is not a type object (%s)", getTypeName(_cls)->c_str());
......
...@@ -195,6 +195,10 @@ extern "C" FILE* PyFile_AsFile(PyObject* f) { ...@@ -195,6 +195,10 @@ extern "C" FILE* PyFile_AsFile(PyObject* f) {
Py_FatalError("unimplemented"); Py_FatalError("unimplemented");
} }
extern "C" int PyFile_WriteObject(PyObject* v, PyObject* f, int flags) {
Py_FatalError("unimplemented");
}
extern "C" int PyFile_WriteString(const char* s, PyObject* f) { extern "C" int PyFile_WriteString(const char* s, PyObject* f) {
Py_FatalError("unimplemented"); Py_FatalError("unimplemented");
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment