Commit 8baec850 authored by Kevin Modzelewski's avatar Kevin Modzelewski

Add a simple tpp_hasnext

And change for loops to instead of calling __hasnext__ directly, to
call objmodel::hasnext() which calls tpp_hasnext.
parent d1c5d853
......@@ -36,6 +36,7 @@ struct wrapperbase {
/* Flags for above struct */
#define PyWrapperFlag_KEYWORDS 1 /* wrapper function takes keyword args */
#define PyWrapperFlag_PYSTON 2 /* wrapper function is a Pyston function*/
/* Various kinds of descriptor objects */
......
......@@ -459,7 +459,8 @@ struct _typeobject {
void* _gcvisit_func;
void* _dtor;
int _attrs_offset;
bool _flags[2];
bool _flags[3];
void* _tpp_hasnext;
};
/* The *real* layout of a type object when allocated on the heap */
......
......@@ -231,6 +231,18 @@ static PyObject* wrap_inquirypred(PyObject* self, PyObject* args, void* wrapped)
return PyBool_FromLong((long)res);
}
static PyObject* wrapInquirypred(PyObject* self, PyObject* args, void* wrapped) {
inquiry func = (inquiry)wrapped;
int res;
if (!check_num_args(args, 0))
throwCAPIException();
res = (*func)(self);
assert(res == 0 || res == 1);
assert(!PyErr_Occurred());
return PyBool_FromLong((long)res);
}
static PyObject* wrap_binaryfunc(PyObject* self, PyObject* args, void* wrapped) noexcept {
binaryfunc func = (binaryfunc)wrapped;
PyObject* other;
......@@ -695,6 +707,14 @@ static PyObject* slot_tp_iternext(PyObject* self) noexcept {
return call_method(self, "next", &next_str, "()");
}
static bool slotTppHasnext(PyObject* self) {
static PyObject* hasnext_str;
Box* r = call_method(self, "__hasnext__", &hasnext_str, "()");
if (!r)
throwCAPIException();
return nonzero(r);
}
static PyObject* slot_tp_descr_get(PyObject* self, PyObject* obj, PyObject* type) noexcept {
PyTypeObject* tp = Py_TYPE(self);
PyObject* get;
......@@ -1208,6 +1228,8 @@ static void** slotptr(BoxedClass* type, int offset) noexcept {
// Copied from CPython:
#define TPSLOT(NAME, SLOT, FUNCTION, WRAPPER, DOC) \
{ NAME, offsetof(PyTypeObject, SLOT), (void*)(FUNCTION), WRAPPER, PyDoc_STR(DOC), 0 }
#define TPPSLOT(NAME, SLOT, FUNCTION, WRAPPER, DOC) \
{ NAME, offsetof(PyTypeObject, SLOT), (void*)(FUNCTION), WRAPPER, PyDoc_STR(DOC), PyWrapperFlag_PYSTON }
#define FLSLOT(NAME, SLOT, FUNCTION, WRAPPER, DOC, FLAGS) \
{ NAME, offsetof(PyTypeObject, SLOT), (void*)(FUNCTION), WRAPPER, PyDoc_STR(DOC), FLAGS }
#define ETSLOT(NAME, SLOT, FUNCTION, WRAPPER, DOC) \
......@@ -1262,6 +1284,7 @@ static slotdef slotdefs[]
"see help(type(x)) for signature",
PyWrapperFlag_KEYWORDS),
TPSLOT("__new__", tp_new, slot_tp_new, NULL, ""),
TPPSLOT("__hasnext__", tpp_hasnext, slotTppHasnext, wrapInquirypred, "hasnext"),
BINSLOT("__add__", nb_add, slot_nb_add, "+"), // [force clang-format to line break]
RBINSLOT("__radd__", nb_add, slot_nb_add, "+"), //
......@@ -1452,7 +1475,8 @@ static const slotdef* update_one_slot(BoxedClass* type, const slotdef* p) noexce
if (tptr == NULL || tptr == ptr)
generic = p->function;
d = (BoxedWrapperDescriptor*)descr;
if (d->wrapper->wrapper == p->wrapper && PyType_IsSubtype(type, d->type)) {
if (d->wrapper->wrapper == p->wrapper && PyType_IsSubtype(type, d->type)
&& ((d->wrapper->flags & PyWrapperFlag_PYSTON) == (p->flags & PyWrapperFlag_PYSTON))) {
if (specific == NULL || specific == d->wrapped)
specific = d->wrapped;
else
......
......@@ -120,11 +120,13 @@ public:
assert(self->descr->wrapper->offset > 0);
Box* rtn;
if (flags & PyWrapperFlag_KEYWORDS) {
if (flags == PyWrapperFlag_KEYWORDS) {
wrapperfunc_kwds wk = (wrapperfunc_kwds)wrapper;
rtn = (*wk)(self->obj, args, self->descr->wrapped, kwds);
} else {
} else if (flags == 0) {
rtn = (*wrapper)(self->obj, args, self->descr->wrapped);
} else {
RELEASE_ASSERT(0, "%d", flags);
}
checkAndThrowCAPIException();
......
......@@ -570,8 +570,12 @@ Value ASTInterpreter::visit_langPrimitive(AST_LangPrimitive* node) {
assert(node->args.empty());
getFrameInfo()->exc = ExcInfo(NULL, NULL, NULL);
v = None;
} else if (node->opcode == AST_LangPrimitive::HASNEXT) {
assert(node->args.size() == 1);
Value obj = visit_expr(node->args[0]);
v = boxBool(hasnext(obj.o));
} else
RELEASE_ASSERT(0, "not implemented");
RELEASE_ASSERT(0, "unknown opcode %d", node->opcode);
return v;
}
......
......@@ -1031,6 +1031,7 @@ public:
NONZERO,
SET_EXC_INFO,
UNCACHE_EXC_INFO,
HASNEXT,
} opcode;
std::vector<AST_expr*> args;
......
......@@ -1868,10 +1868,6 @@ public:
InternedString itername = internString(itername_buf);
pushAssign(itername, iter_call);
auto hasnext_attr = [&]() {
return makeLoadAttribute(makeName(itername, AST_TYPE::Load, node->lineno), internString("__hasnext__"),
true);
};
AST_expr* next_attr
= makeLoadAttribute(makeName(itername, AST_TYPE::Load, node->lineno), internString("next"), true);
......@@ -1882,7 +1878,8 @@ public:
curblock->connectTo(test_block);
curblock = test_block;
AST_expr* test_call = makeCall(hasnext_attr());
AST_LangPrimitive* test_call = new AST_LangPrimitive(AST_LangPrimitive::HASNEXT);
test_call->args.push_back(makeName(itername, AST_TYPE::Load, node->lineno));
AST_Branch* test_br = makeBranch(remapExpr(test_call));
push_back(test_br);
......@@ -1924,7 +1921,8 @@ public:
popRegion();
if (curblock) {
AST_expr* end_call = makeCall((hasnext_attr()));
AST_LangPrimitive* end_call = new AST_LangPrimitive(AST_LangPrimitive::HASNEXT);
end_call->args.push_back(makeName(itername, AST_TYPE::Load, node->lineno));
AST_Branch* end_br = makeBranch(remapExpr(end_call));
push_back(end_br);
......
......@@ -205,5 +205,6 @@ void setupXrange() {
xrange_cls->freeze();
xrange_iterator_cls->freeze();
xrange_iterator_cls->tpp_hasnext = BoxedXrangeIterator::xrangeIteratorHasnextUnboxed;
}
}
......@@ -871,6 +871,7 @@ void setupList() {
list_iterator_cls->giveAttr("next", new BoxedFunction(boxRTFunction((void*)listiterNext, UNKNOWN, 1)));
list_iterator_cls->freeze();
list_iterator_cls->tpp_hasnext = listiterHasnextUnboxed;
list_reverse_iterator_cls->giveAttr("__name__", boxStrConstant("listreverseiterator"));
......
......@@ -537,11 +537,21 @@ BoxedDict* Box::getDict() {
return d;
}
static StatCounter box_getattr_slowpath("slowpath_box_getattr");
Box* Box::getattr(const std::string& attr, GetattrRewriteArgs* rewrite_args) {
if (rewrite_args)
rewrite_args->obj->addAttrGuard(BOX_CLS_OFFSET, (intptr_t)cls);
#if 0
if (attr[0] == '_' && attr[1] == '_') {
std::string per_name_stat_name = "slowpath_box_getattr." + std::string(attr);
int id = Stats::getStatId(per_name_stat_name);
Stats::log(id);
}
#endif
box_getattr_slowpath.log();
// Have to guard on the memory layout of this object.
// Right now, guard on the specific Python-class, which in turn
// specifies the C structure.
......@@ -3692,6 +3702,10 @@ Box* getiter(Box* o) {
return getiterHelper(o);
}
extern "C" bool hasnext(Box* o) {
return o->cls->tpp_hasnext(o);
}
llvm::iterator_range<BoxIterator> Box::pyElements() {
return BoxIterator::getRange(this);
}
......
......@@ -90,6 +90,7 @@ Box* getiter(Box* o);
extern "C" Box* getPystonIter(Box* o);
extern "C" Box* getiterHelper(Box* o);
extern "C" Box* createBoxedIterWrapperIfNeeded(Box* o);
extern "C" bool hasnext(Box* o);
extern "C" void dump(void* p);
......
......@@ -190,6 +190,9 @@ public:
// that we can't rely on for extension classes.
bool is_pyston_class;
typedef bool (*pyston_inquiry)(Box*);
pyston_inquiry tpp_hasnext;
bool hasGenericGetattr() { return tp_getattr == NULL; }
void freeze();
......
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