Commit 23fe2a16 authored by Kevin Modzelewski's avatar Kevin Modzelewski

Merge branch 'tpp_hasnext'

parents 4714b860 b2d54051
......@@ -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 */
......
t = 0
for i in range(1000000):
t = t + i
for i in xrange(1000000):
t = t + i
print t
......@@ -376,6 +376,7 @@ private:
case AST_LangPrimitive::SET_EXC_INFO:
case AST_LangPrimitive::UNCACHE_EXC_INFO:
return NONE;
case AST_LangPrimitive::HASNEXT:
case AST_LangPrimitive::NONZERO:
return BOOL;
default:
......
......@@ -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;
}
......
......@@ -237,6 +237,7 @@ public:
const std::vector<CompilerVariable*>& args,
const std::vector<const std::string*>* keyword_names) override;
ConcreteCompilerVariable* nonzero(IREmitter& emitter, const OpInfo& info, ConcreteCompilerVariable* var) override;
ConcreteCompilerVariable* hasnext(IREmitter& emitter, const OpInfo& info, ConcreteCompilerVariable* var) override;
void setattr(IREmitter& emitter, const OpInfo& info, ConcreteCompilerVariable* var, const std::string* attr,
CompilerVariable* v) override {
......@@ -707,6 +708,23 @@ ConcreteCompilerVariable* UnknownType::nonzero(IREmitter& emitter, const OpInfo&
return boolFromI1(emitter, rtn_val);
}
ConcreteCompilerVariable* UnknownType::hasnext(IREmitter& emitter, const OpInfo& info, ConcreteCompilerVariable* var) {
bool do_patchpoint = ENABLE_ICS && !info.isInterpreted();
llvm::Value* rtn_val;
if (do_patchpoint) {
ICSetupInfo* pp = createHasnextIC(info.getTypeRecorder());
std::vector<llvm::Value*> llvm_args;
llvm_args.push_back(var->getValue());
llvm::Value* uncasted = emitter.createIC(pp, (void*)pyston::hasnext, llvm_args, info.unw_info);
rtn_val = emitter.getBuilder()->CreateTrunc(uncasted, g.i1);
} else {
rtn_val = emitter.createCall(info.unw_info, g.funcs.hasnext, var->getValue());
}
return boolFromI1(emitter, rtn_val);
}
CompilerVariable* makeFunction(IREmitter& emitter, CLFunction* f, CompilerVariable* closure, bool isGenerator,
const std::vector<ConcreteCompilerVariable*>& defaults) {
// Unlike the CLFunction*, which can be shared between recompilations, the Box* around it
......@@ -1719,6 +1737,18 @@ public:
return UNKNOWN->nonzero(emitter, info, var);
}
ConcreteCompilerVariable* hasnext(IREmitter& emitter, const OpInfo& info, ConcreteCompilerVariable* var) override {
static const std::string attr("__hasnext__");
ConcreteCompilerVariable* called_constant
= tryCallattrConstant(emitter, info, var, &attr, true, ArgPassSpec(0, 0, 0, 0), {}, NULL, NULL);
if (called_constant)
return called_constant;
return UNKNOWN->hasnext(emitter, info, var);
}
static NormalObjectType* fromClass(BoxedClass* cls) {
NormalObjectType*& rtn = made[cls];
if (rtn == NULL) {
......
......@@ -100,6 +100,10 @@ public:
printf("nonzero not defined for %s\n", debugName().c_str());
abort();
}
virtual ConcreteCompilerVariable* hasnext(IREmitter& emitter, const OpInfo& info, VAR* var) {
printf("hasnext not defined for %s\n", debugName().c_str());
abort();
}
virtual CompilerVariable* getattr(IREmitter& emitter, const OpInfo& info, VAR* var, const std::string* attr,
bool cls_only) {
printf("getattr not defined for %s\n", debugName().c_str());
......@@ -256,6 +260,7 @@ public:
virtual BoxedClass* guaranteedClass() = 0;
virtual ConcreteCompilerVariable* nonzero(IREmitter& emitter, const OpInfo& info) = 0;
virtual ConcreteCompilerVariable* hasnext(IREmitter& emitter, const OpInfo& info) = 0;
virtual CompilerVariable* getattr(IREmitter& emitter, const OpInfo& info, const std::string* attr, bool cls_only)
= 0;
virtual void setattr(IREmitter& emitter, const OpInfo& info, const std::string* attr, CompilerVariable* v) = 0;
......@@ -327,6 +332,9 @@ public:
ConcreteCompilerVariable* nonzero(IREmitter& emitter, const OpInfo& info) override {
return type->nonzero(emitter, info, this);
}
ConcreteCompilerVariable* hasnext(IREmitter& emitter, const OpInfo& info) override {
return type->hasnext(emitter, info, this);
}
CompilerVariable* getattr(IREmitter& emitter, const OpInfo& info, const std::string* attr, bool cls_only) override {
return type->getattr(emitter, info, this, attr, cls_only);
}
......
......@@ -576,13 +576,16 @@ private:
CompilerVariable* obj = evalExpr(node->args[0], unw_info);
ConcreteCompilerVariable* rtn = obj->nonzero(emitter, getOpInfoForNode(node, unw_info));
assert(rtn->getType() == BOOL);
llvm::Value* v = i1FromBool(emitter, rtn);
assert(v->getType() == g.i1);
obj->decvref(emitter);
return rtn;
}
case AST_LangPrimitive::HASNEXT: {
assert(node->args.size() == 1);
CompilerVariable* obj = evalExpr(node->args[0], unw_info);
return boolFromI1(emitter, v);
ConcreteCompilerVariable* rtn = obj->hasnext(emitter, getOpInfoForNode(node, unw_info));
obj->decvref(emitter);
return rtn;
}
case AST_LangPrimitive::SET_EXC_INFO: {
assert(node->args.size() == 3);
......
......@@ -336,4 +336,8 @@ ICSetupInfo* createNonzeroIC(TypeRecorder* type_recorder) {
return ICSetupInfo::initialize(true, 2, 64, ICSetupInfo::Nonzero, type_recorder);
}
ICSetupInfo* createHasnextIC(TypeRecorder* type_recorder) {
return ICSetupInfo::initialize(true, 2, 64, ICSetupInfo::Hasnext, type_recorder);
}
} // namespace pyston
......@@ -105,6 +105,7 @@ public:
Delitem,
Binexp,
Nonzero,
Hasnext,
};
private:
......@@ -146,6 +147,7 @@ ICSetupInfo* createSetitemIC(TypeRecorder* type_recorder);
ICSetupInfo* createDelitemIC(TypeRecorder* type_recorder);
ICSetupInfo* createBinexpIC(TypeRecorder* type_recorder);
ICSetupInfo* createNonzeroIC(TypeRecorder* type_recorder);
ICSetupInfo* createHasnextIC(TypeRecorder* type_recorder);
} // namespace pyston
......
......@@ -209,6 +209,7 @@ void initGlobalFuncs(GlobalState& g) {
GET(isinstance);
GET(yield);
GET(getiterHelper);
GET(hasnext);
GET(unpackIntoArray);
GET(raiseAttributeError);
......
......@@ -38,7 +38,7 @@ struct GlobalFuncs {
*decodeUTF8StringPtr;
llvm::Value* getattr, *setattr, *delattr, *delitem, *delGlobal, *nonzero, *binop, *compare, *augbinop, *unboxedLen,
*getitem, *getclsattr, *getGlobal, *setitem, *unaryop, *import, *importFrom, *importStar, *repr, *str,
*isinstance, *yield, *getiterHelper;
*isinstance, *yield, *getiterHelper, *hasnext;
llvm::Value* unpackIntoArray, *raiseAttributeError, *raiseAttributeErrorStr, *raiseNotIterableError,
*assertNameDefined, *assertFail;
......
......@@ -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);
......
......@@ -90,6 +90,7 @@ void force() {
FORCE(isinstance);
FORCE(yield);
FORCE(getiterHelper);
FORCE(hasnext);
FORCE(unpackIntoArray);
FORCE(raiseAttributeError);
......
......@@ -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