void raise3(Box* arg0, Box* arg1, Box* arg2) { // TODO switch this to PyErr_Normalize if (arg2 == None) arg2 = getTraceback(); if (isSubclass(arg0->cls, type_cls)) { BoxedClass* c = static_cast<BoxedClass*>(arg0); if (isSubclass(c, BaseException)) { Box* exc_obj; if (isSubclass(arg1->cls, BaseException)) { exc_obj = arg1; c = exc_obj->cls; } else if (arg1 != None) { exc_obj = runtimeCall(c, ArgPassSpec(1), arg1, NULL, NULL, NULL, NULL); } else { exc_obj = runtimeCall(c, ArgPassSpec(0), NULL, NULL, NULL, NULL, NULL); } raiseRaw(ExcInfo(c, exc_obj, arg2)); } } if (isSubclass(arg0->cls, BaseException)) { if (arg1 != None) raiseExcHelper(TypeError, "instance exception may not have a separate value"); raiseRaw(ExcInfo(arg0->cls, arg0, arg2)); } raiseExcHelper(TypeError, "exceptions must be old-style classes or derived from BaseException, not %s", getTypeName(arg0)); }
BoxIterator& BoxIterator::operator++() { static std::string hasnext_str("__hasnext__"); static std::string next_str("next"); Box* hasnext = callattrInternal(iter, &hasnext_str, CLASS_ONLY, NULL, ArgPassSpec(0), NULL, NULL, NULL, NULL, NULL); if (nonzero(hasnext)) { value = callattrInternal(iter, &next_str, CLASS_ONLY, NULL, ArgPassSpec(0), NULL, NULL, NULL, NULL, NULL); } else { iter = nullptr; value = nullptr; } return *this; }
static Box* property_copy(BoxedProperty* old, Box* get, Box* set, Box* del) { RELEASE_ASSERT(isSubclass(old->cls, property_cls), ""); if (!get || get == Py_None) get = old->prop_get; if (!set || set == Py_None) set = old->prop_set; if (!del || del == Py_None) del = old->prop_del; // Optimization for the case when the old propery is not subclassed if (old->cls == property_cls) { BoxedProperty* prop = new BoxedProperty(get, set, del, old->prop_doc); prop->getter_doc = false; if ((old->getter_doc && get != Py_None) || !old->prop_doc) propertyDocCopy(prop, get); return prop; } else { if (!get) get = Py_None; if (!set) set = Py_None; if (!del) del = Py_None; Box* doc; if ((old->getter_doc && get != Py_None) || !old->prop_doc) doc = Py_None; else doc = old->prop_doc; return runtimeCall(old->cls, ArgPassSpec(4), get, set, del, &doc, NULL); } }
// Have a special helper function for syntax errors, since we want to include the location // of the syntax error in the traceback, even though it is not part of the execution: void raiseSyntaxError(const char* msg, int lineno, int col_offset, llvm::StringRef file, llvm::StringRef func) { Box* exc = runtimeCall(SyntaxError, ArgPassSpec(1), boxString(msg), NULL, NULL, NULL, NULL); auto tb = new BoxedTraceback(LineInfo(lineno, col_offset, boxString(file), boxString(func)), None); assert(!PyErr_Occurred()); throw ExcInfo(exc->cls, exc, tb); }
extern "C" PyObject* PyObject_Call(PyObject* callable_object, PyObject* args, PyObject* kw) { try { return runtimeCall(callable_object, ArgPassSpec(0, 0, true, true), args, kw, NULL, NULL, NULL); } catch (Box* b) { Py_FatalError("unimplemented"); } }
// Have a special helper function for syntax errors, since we want to include the location // of the syntax error in the traceback, even though it is not part of the execution: void raiseSyntaxError(const char* msg, int lineno, int col_offset, const std::string& file, const std::string& func) { Box* exc = runtimeCall(SyntaxError, ArgPassSpec(1), boxStrConstant(msg), NULL, NULL, NULL, NULL); auto tb = getTraceback(); std::vector<const LineInfo*> entries = tb->lines; entries.push_back(new LineInfo(lineno, col_offset, file, func)); raiseRaw(ExcInfo(exc->cls, exc, new BoxedTraceback(std::move(entries)))); }
static Box* sysExit(Box* arg) { assert(arg); Box* exc = runtimeCall(SystemExit, ArgPassSpec(1), arg, NULL, NULL, NULL, NULL); // TODO this should be handled by the SystemExit constructor exc->giveAttr("code", arg); raiseExc(exc); }
extern "C" PyObject* PyFrozenSet_New(PyObject* iterable) noexcept { try { return runtimeCall(frozenset_cls, ArgPassSpec(iterable ? 1 : 0), iterable, NULL, NULL, NULL, NULL); } catch (ExcInfo e) { setCAPIException(e); return NULL; } }
llvm::iterator_range<BoxIterator> Box::pyElements() { static std::string iter_str("__iter__"); Box* iter = callattr(const_cast<Box*>(this), &iter_str, true, ArgPassSpec(0), NULL, NULL, NULL, NULL, NULL); if (iter) { return llvm::iterator_range<BoxIterator>(++BoxIterator(iter), BoxIterator(nullptr)); } raiseExcHelper(TypeError, "'%s' object is not iterable", getTypeName(this)->c_str()); }
extern "C" PyObject* PySet_New(PyObject* iterable) noexcept { if (!iterable) return new BoxedSet(); // Fast path for empty set. try { return runtimeCall(set_cls, ArgPassSpec(iterable ? 1 : 0), iterable, NULL, NULL, NULL, NULL); } catch (ExcInfo e) { setCAPIException(e); return NULL; } }
static Box* propertySet(Box* self, Box* obj, Box* val) { RELEASE_ASSERT(isSubclass(self->cls, property_cls), ""); BoxedProperty* prop = static_cast<BoxedProperty*>(self); Box* func; if (val == NULL) { func = prop->prop_del; } else { func = prop->prop_set; } if (func == NULL) { raiseExcHelper(AttributeError, val == NULL ? "can't delete attribute" : "can't set attribute"); } if (val == NULL) { autoDecref(runtimeCall(func, ArgPassSpec(1), obj, NULL, NULL, NULL, NULL)); } else { autoDecref(runtimeCall(func, ArgPassSpec(2), obj, val, NULL, NULL, NULL)); } return incref(Py_None); }
static void* thread_start(Box* target, Box* varargs, Box* kwargs) { assert(target); assert(varargs); try { runtimeCall(target, ArgPassSpec(0, 0, true, kwargs != NULL), varargs, kwargs, NULL, NULL, NULL); } catch (Box* b) { std::string msg = formatException(b); printLastTraceback(); fprintf(stderr, "%s\n", msg.c_str()); } return NULL; }
void raiseExcHelper(BoxedClass* cls, const char* msg, ...) { if (msg != NULL) { va_list ap; va_start(ap, msg); // printf("Raising: "); // vprintf(msg, ap); // printf("\n"); // va_start(ap, msg); char buf[1024]; vsnprintf(buf, sizeof(buf), msg, ap); va_end(ap); BoxedString* message = boxStrConstant(buf); Box* exc_obj = runtimeCall(cls, ArgPassSpec(1), message, NULL, NULL, NULL, NULL); raiseExc(exc_obj); } else { Box* exc_obj = runtimeCall(cls, ArgPassSpec(0), NULL, NULL, NULL, NULL, NULL); raiseExc(exc_obj); } }
static Box* propertyGet(Box* self, Box* obj, Box* type) { RELEASE_ASSERT(isSubclass(self->cls, property_cls), ""); BoxedProperty* prop = static_cast<BoxedProperty*>(self); if (obj == NULL || obj == Py_None) { return incref(self); } if (prop->prop_get == NULL) { raiseExcHelper(AttributeError, "unreadable attribute"); } return runtimeCall(prop->prop_get, ArgPassSpec(1), obj, NULL, NULL, NULL, NULL); }
extern "C" PyObject* PyObject_CallObject(PyObject* obj, PyObject* args) { RELEASE_ASSERT(args, ""); // actually it looks like this is allowed to be NULL RELEASE_ASSERT(args->cls == tuple_cls, ""); // TODO do something like this? not sure if this is safe; will people expect that calling into a known function // won't end up doing a GIL check? // threading::GLDemoteRegion _gil_demote; try { Box* r = runtimeCall(obj, ArgPassSpec(0, 0, true, false), args, NULL, NULL, NULL, NULL); return r; } catch (Box* b) { Py_FatalError("unimplemented"); } }
extern "C" int PyDict_SetItem(PyObject* mp, PyObject* _key, PyObject* _item) { Box* b = static_cast<Box*>(mp); Box* key = static_cast<Box*>(_key); Box* item = static_cast<Box*>(_item); static std::string setitem_str("__setitem__"); Box* r; try { // TODO should demote GIL? r = callattrInternal(b, &setitem_str, CLASS_ONLY, NULL, ArgPassSpec(2), key, item, NULL, NULL, NULL); } catch (Box* b) { fprintf(stderr, "Error: uncaught error would be propagated to C code!\n"); Py_FatalError("unimplemented"); } RELEASE_ASSERT(r, ""); return 0; }
static PyObject* superGet(PyObject* _self, PyObject* obj, PyObject* type) noexcept(S == CAPI) { BoxedSuper* self = static_cast<BoxedSuper*>(_self); if (obj == NULL || obj == None || self->obj != NULL) { /* Not binding to an object, or already bound */ return self; } if (self->cls != super_cls) { /* If self is an instance of a (strict) subclass of super, call its type */ return runtimeCallInternal<S, NOT_REWRITABLE>(self->cls, NULL, ArgPassSpec(2), self->type, obj, NULL, NULL, NULL); } else { /* Inline the common case */ BoxedClass* obj_type = superCheck<S>(self->type, obj); if (obj_type == NULL) return NULL; return new BoxedSuper(self->type, obj, obj_type); } }
void runCollection() { static StatCounter sc("gc_collections"); sc.log(); ncollections++; if (VERBOSITY("gc") >= 2) printf("Collection #%d\n", ncollections); Timer _t("collecting", /*min_usec=*/10000); markPhase(); std::list<Box*, StlCompatAllocator<Box*>> weakly_referenced; sweepPhase(weakly_referenced); for (auto o : weakly_referenced) { PyWeakReference** list = (PyWeakReference**)PyObject_GET_WEAKREFS_LISTPTR(o); while (PyWeakReference* head = *list) { assert(isValidGCObject(head)); if (head->wr_object != Py_None) { _PyWeakref_ClearRef(head); if (head->wr_callback) { runtimeCall(head->wr_callback, ArgPassSpec(1), reinterpret_cast<Box*>(head), NULL, NULL, NULL, NULL); head->wr_callback = NULL; } } } } if (VERBOSITY("gc") >= 2) printf("Collection #%d done\n\n", ncollections); long us = _t.end(); static StatCounter sc_us("gc_collections_us"); sc_us.log(us); // dumpHeapStatistics(); }
static void* thread_start(Box* target, Box* varargs, Box* kwargs) { assert(target); assert(varargs); #if STAT_TIMERS // TODO: maybe we should just not log anything for threads... static uint64_t* timer_counter = Stats::getStatCounter("us_timer_thread_start"); StatTimer timer(timer_counter, 0, true); timer.pushTopLevel(getCPUTicks()); #endif try { runtimeCall(target, ArgPassSpec(0, 0, true, kwargs != NULL), varargs, kwargs, NULL, NULL, NULL); } catch (ExcInfo e) { e.printExcAndTraceback(); } #if STAT_TIMERS timer.popTopLevel(getCPUTicks()); #endif return NULL; }
static Box* sysExit(Box* arg) { assert(arg); Box* exc = runtimeCall(SystemExit, ArgPassSpec(1), arg, NULL, NULL, NULL, NULL); raiseExc(exc); }
// TODO this should be auto-generated as a slot wrapper: Box* BoxedMethodDescriptor::__call__(BoxedMethodDescriptor* self, Box* obj, BoxedTuple* varargs, Box** _args) { BoxedDict* kwargs = static_cast<BoxedDict*>(_args[0]); return BoxedMethodDescriptor::tppCall(self, NULL, ArgPassSpec(1, 0, true, true), obj, varargs, kwargs, NULL, NULL); }
void raiseExcHelper(BoxedClass* cls, Box* arg) { Box* exc_obj = runtimeCall(cls, ArgPassSpec(1), arg, NULL, NULL, NULL, NULL); raiseExc(exc_obj); }
void prependToSysPath(const std::string& path) { BoxedList* sys_path = getSysPath(); static std::string attr = "insert"; callattr(sys_path, &attr, false, ArgPassSpec(2), boxInt(0), new BoxedString(path), NULL, NULL, NULL); }