Commit 83f68abd authored by Marius Wachtler's avatar Marius Wachtler

use a template to remove rewriter checks inside our most important runtime funcs

when we know that the rewrite_args are NULL

                                origin/rewritable~:   origin/rewritable:
           django_template3.py             2.7s (4)             2.7s (4)  -1.3%
                 pyxl_bench.py             2.2s (4)             2.2s (4)  -1.7%
     sqlalchemy_imperative2.py             2.7s (4)             2.6s (4)  -2.4%
                       geomean                 2.5s                 2.5s  -1.8%
parent 2a0955bb
......@@ -758,7 +758,7 @@ exit:
}
extern "C" Py_ssize_t PyObject_Size(PyObject* o) noexcept {
BoxedInt* r = lenInternal<ExceptionStyle::CAPI>(o, NULL);
BoxedInt* r = lenInternal<ExceptionStyle::CAPI, NOT_REWRITABLE>(o, NULL);
if (!r)
return -1;
return r->n;
......@@ -2252,7 +2252,7 @@ extern "C" PyObject* PyNumber_Int(PyObject* o) noexcept {
// Pyston change: this should be an optimization
// PyObject* trunc_func = PyObject_GetAttrString(o, "__trunc__");
static BoxedString* trunc_str = internStringImmortal("__trunc__");
PyObject* trunc_func = getattrInternal<ExceptionStyle::CAPI>(o, trunc_str, NULL);
PyObject* trunc_func = getattrInternal<ExceptionStyle::CAPI>(o, trunc_str);
if (trunc_func) {
PyObject* truncated = PyEval_CallObject(trunc_func, NULL);
......
......@@ -486,7 +486,7 @@ extern "C" int PyObject_GenericSetAttr(PyObject* obj, PyObject* name, PyObject*
if (value == NULL)
delattrGeneric(obj, str, NULL);
else
setattrGeneric(obj, str, value, NULL);
setattrGeneric<NOT_REWRITABLE>(obj, str, value, NULL);
} catch (ExcInfo e) {
setCAPIException(e);
return -1;
......@@ -534,7 +534,7 @@ extern "C" int PyObject_SetAttrString(PyObject* v, const char* name, PyObject* w
extern "C" PyObject* PyObject_GetAttrString(PyObject* o, const char* attr) noexcept {
try {
Box* r = getattrInternal<ExceptionStyle::CXX>(o, internStringMortal(attr), NULL);
Box* r = getattrInternal<ExceptionStyle::CXX>(o, internStringMortal(attr));
if (!r)
PyErr_Format(PyExc_AttributeError, "'%.50s' object has no attribute '%.400s'", o->cls->tp_name, attr);
return r;
......
......@@ -484,7 +484,7 @@ static PyObject* lookup_maybe(PyObject* self, const char* attrstr, PyObject** at
return NULL;
}
Box* obj = typeLookup(self->cls, (BoxedString*)*attrobj, NULL);
Box* obj = typeLookup(self->cls, (BoxedString*)*attrobj);
if (obj) {
try {
return processDescriptor(obj, self, self->cls);
......@@ -809,7 +809,7 @@ static PyObject* slot_tp_descr_get(PyObject* self, PyObject* obj, PyObject* type
PyObject* get;
static BoxedString* get_str = internStringImmortal("__get__");
get = typeLookup(tp, get_str, NULL);
get = typeLookup(tp, get_str);
if (get == NULL) {
/* Avoid further slowdowns */
if (tp->tp_descr_get == slot_tp_descr_get)
......@@ -883,11 +883,16 @@ static PyObject* call_attribute(PyObject* self, PyObject* attr, PyObject* name)
/* Pyston change: static */ PyObject* slot_tp_getattr_hook(PyObject* self, PyObject* name) noexcept {
assert(name->cls == str_cls);
return slotTpGetattrHookInternal<CAPI>(self, (BoxedString*)name, NULL);
return slotTpGetattrHookInternal<CAPI, NOT_REWRITABLE>(self, (BoxedString*)name, NULL);
}
template <ExceptionStyle S>
template <ExceptionStyle S, Rewritable rewritable>
Box* slotTpGetattrHookInternal(Box* self, BoxedString* name, GetattrRewriteArgs* rewrite_args) noexcept(S == CAPI) {
if (rewritable == NOT_REWRITABLE) {
assert(!rewrite_args);
rewrite_args = NULL;
}
STAT_TIMER(t0, "us_timer_slot_tpgetattrhook", SLOT_AVOIDABILITY(self));
PyObject* getattr, *getattribute, * res = NULL;
......@@ -905,7 +910,7 @@ Box* slotTpGetattrHookInternal(Box* self, BoxedString* name, GetattrRewriteArgs*
// - if we never get to the "call __getattr__" portion and the "calling __getattribute__"
// portion still has its guards pass, then that section is still behaviorally correct, and
// I think should be close to as fast as the normal rewritten version we would generate.
getattr = typeLookup(self->cls, _getattr_str, NULL);
getattr = typeLookup(self->cls, _getattr_str);
if (getattr == NULL) {
if (rewrite_args) {
......@@ -943,7 +948,7 @@ Box* slotTpGetattrHookInternal(Box* self, BoxedString* name, GetattrRewriteArgs*
grewrite_args.assertReturnConvention(ReturnConvention::NO_RETURN);
}
} else {
getattribute = typeLookup(self->cls, _getattribute_str, NULL);
getattribute = typeLookup(self->cls, _getattribute_str);
}
// Not sure why CPython checks if getattribute is NULL since I don't think that should happen.
......@@ -966,7 +971,7 @@ Box* slotTpGetattrHookInternal(Box* self, BoxedString* name, GetattrRewriteArgs*
GetattrRewriteArgs grewrite_args(rewrite_args->rewriter, rewrite_args->obj, rewrite_args->destination);
try {
assert(!PyType_Check(self)); // There would be a getattribute
res = getattrInternalGeneric<false>(self, name, &grewrite_args, false, false, NULL, NULL);
res = getattrInternalGeneric<false, rewritable>(self, name, &grewrite_args, false, false, NULL, NULL);
} catch (ExcInfo e) {
if (!e.matches(AttributeError)) {
if (S == CAPI) {
......@@ -1013,7 +1018,7 @@ Box* slotTpGetattrHookInternal(Box* self, BoxedString* name, GetattrRewriteArgs*
} else {
try {
assert(!PyType_Check(self)); // There would be a getattribute
res = getattrInternalGeneric<false>(self, name, NULL, false, false, NULL, NULL);
res = getattrInternalGeneric<false, rewritable>(self, name, NULL, false, false, NULL, NULL);
} catch (ExcInfo e) {
if (!e.matches(AttributeError)) {
if (S == CAPI) {
......@@ -1068,8 +1073,8 @@ Box* slotTpGetattrHookInternal(Box* self, BoxedString* name, GetattrRewriteArgs*
assert(PyString_CHECK_INTERNED(name) == SSTATE_INTERNED_IMMORTAL);
crewrite_args.arg1 = rewrite_args->rewriter->loadConst((intptr_t)name, Location::forArg(1));
res = callattrInternal<S>(self, _getattr_str, LookupScope::CLASS_ONLY, &crewrite_args, ArgPassSpec(1), name,
NULL, NULL, NULL, NULL);
res = callattrInternal<S, REWRITABLE>(self, _getattr_str, LookupScope::CLASS_ONLY, &crewrite_args,
ArgPassSpec(1), name, NULL, NULL, NULL, NULL);
assert(res || S == CAPI);
if (!crewrite_args.isSuccessful())
......@@ -1083,16 +1088,22 @@ Box* slotTpGetattrHookInternal(Box* self, BoxedString* name, GetattrRewriteArgs*
// the rewrite_args and non-rewrite_args case the same.
// Actually, we might have gotten to the point that doing a runtimeCall on an instancemethod is as
// fast as a callattr, but that hasn't typically been the case.
res = callattrInternal<S>(self, _getattr_str, LookupScope::CLASS_ONLY, NULL, ArgPassSpec(1), name, NULL, NULL,
NULL, NULL);
res = callattrInternal<S, NOT_REWRITABLE>(self, _getattr_str, LookupScope::CLASS_ONLY, NULL, ArgPassSpec(1),
name, NULL, NULL, NULL, NULL);
assert(res || S == CAPI);
}
return res;
}
// Force instantiation of the template
template Box* slotTpGetattrHookInternal<CAPI>(Box* self, BoxedString* name, GetattrRewriteArgs* rewrite_args);
template Box* slotTpGetattrHookInternal<CXX>(Box* self, BoxedString* name, GetattrRewriteArgs* rewrite_args);
template Box* slotTpGetattrHookInternal<CAPI, REWRITABLE>(Box* self, BoxedString* name,
GetattrRewriteArgs* rewrite_args);
template Box* slotTpGetattrHookInternal<CXX, REWRITABLE>(Box* self, BoxedString* name,
GetattrRewriteArgs* rewrite_args);
template Box* slotTpGetattrHookInternal<CAPI, NOT_REWRITABLE>(Box* self, BoxedString* name,
GetattrRewriteArgs* rewrite_args);
template Box* slotTpGetattrHookInternal<CXX, NOT_REWRITABLE>(Box* self, BoxedString* name,
GetattrRewriteArgs* rewrite_args);
/* Pyston change: static */ PyObject* slot_tp_new(PyTypeObject* self, PyObject* args, PyObject* kwds) noexcept {
STAT_TIMER(t0, "us_timer_slot_tpnew", SLOT_AVOIDABILITY(self));
......@@ -1100,7 +1111,7 @@ template Box* slotTpGetattrHookInternal<CXX>(Box* self, BoxedString* name, Getat
try {
// TODO: runtime ICs?
static BoxedString* _new_str = internStringImmortal("__new__");
Box* new_attr = typeLookup(self, _new_str, NULL);
Box* new_attr = typeLookup(self, _new_str);
assert(new_attr);
new_attr = processDescriptor(new_attr, None, self);
......@@ -1115,7 +1126,7 @@ static PyObject* slot_tp_del(PyObject* self) noexcept {
static BoxedString* del_str = internStringImmortal("__del__");
try {
// TODO: runtime ICs?
Box* del_attr = typeLookup(self->cls, del_str, NULL);
Box* del_attr = typeLookup(self->cls, del_str);
assert(del_attr);
CallattrFlags flags{.cls_only = false,
......@@ -1155,7 +1166,7 @@ static PyObject* slot_tp_del(PyObject* self) noexcept {
PyObject* slot_sq_item(PyObject* self, Py_ssize_t i) noexcept {
STAT_TIMER(t0, "us_timer_slot_sqitem", SLOT_AVOIDABILITY(self));
return getitemInternal<CAPI>(self, boxInt(i), NULL);
return getitemInternal<CAPI>(self, boxInt(i));
}
/* Pyston change: static */ Py_ssize_t slot_sq_length(PyObject* self) noexcept {
......@@ -1823,7 +1834,7 @@ static const slotdef* update_one_slot(BoxedClass* type, const slotdef* p) noexce
}
do {
descr = typeLookup(type, p->name_strobj, NULL);
descr = typeLookup(type, p->name_strobj);
if (p->flags & PyWrapperFlag_BOOL) {
// We are supposed to iterate over each slotdef; for now just assert that
......
......@@ -55,7 +55,7 @@ PyObject* tp_new_wrapper(PyTypeObject* self, BoxedTuple* args, Box* kwds) noexce
int slot_tp_init(PyObject* self, PyObject* args, PyObject* kwds) noexcept;
class GetattrRewriteArgs;
template <ExceptionStyle S>
template <ExceptionStyle S, Rewritable rewritable>
Box* slotTpGetattrHookInternal(Box* self, BoxedString* attr, GetattrRewriteArgs* rewrite_args) noexcept(S == CAPI);
}
......
......@@ -1563,7 +1563,7 @@ public:
CompilerType* getattrType(BoxedString* attr, bool cls_only) override {
// Any changes here need to be mirrored in getattr()
if (canStaticallyResolveGetattrs()) {
Box* rtattr = typeLookup(cls, attr, nullptr);
Box* rtattr = typeLookup(cls, attr);
if (rtattr == NULL)
return UNDEF;
......@@ -1588,7 +1588,7 @@ public:
bool cls_only) override {
// Any changes here need to be mirrored in getattrType()
if (canStaticallyResolveGetattrs()) {
Box* rtattr = typeLookup(cls, attr, nullptr);
Box* rtattr = typeLookup(cls, attr);
if (rtattr == NULL) {
ExceptionStyle exception_style = info.preferredExceptionStyle();
llvm::Value* raise_func = exception_style == CXX ? g.funcs.raiseAttributeErrorStr
......
......@@ -2625,7 +2625,7 @@ CFG* computeCFG(SourceInfo* source, std::vector<AST_stmt*> body) {
if (source->scoping->areGlobalsFromModule()) {
static BoxedString* name_str = internStringImmortal("__name__");
Box* module_name = source->parent_module->getattr(name_str, NULL);
Box* module_name = source->parent_module->getattr(name_str);
assert(module_name->cls == str_cls);
module_assign->value = new AST_Str(static_cast<BoxedString*>(module_name)->s());
} else {
......
......@@ -51,6 +51,11 @@ enum ExceptionStyle {
CXX,
};
enum Rewritable {
REWRITABLE,
NOT_REWRITABLE,
};
template <typename T> struct ExceptionSwitchable {
public:
T capi_val;
......@@ -545,8 +550,9 @@ public:
// getattr() does the equivalent of PyDict_GetItem(obj->dict, attr): it looks up the attribute's value on the
// object's attribute storage. it doesn't look at other objects or do any descriptor logic.
template <Rewritable rewritable = REWRITABLE>
Box* getattr(BoxedString* attr, GetattrRewriteArgs* rewrite_args);
Box* getattr(BoxedString* attr) { return getattr(attr, NULL); }
Box* getattr(BoxedString* attr) { return getattr<NOT_REWRITABLE>(attr, NULL); }
bool hasattr(BoxedString* attr) { return getattr(attr) != NULL; }
void delattr(BoxedString* attr, DelattrRewriteArgs* rewrite_args);
......
......@@ -83,7 +83,7 @@ extern "C" Box* vars(Box* obj) {
return fastLocalsToBoxedLocals();
static BoxedString* dict_str = internStringImmortal("__dict__");
Box* rtn = getattrInternal<ExceptionStyle::CAPI>(obj, dict_str, NULL);
Box* rtn = getattrInternal<ExceptionStyle::CAPI>(obj, dict_str);
if (!rtn)
raiseExcHelper(TypeError, "vars() argument must have __dict__ attribute");
return rtn;
......@@ -580,7 +580,7 @@ Box* getattrFuncInternal(BoxedFunctionBase* func, CallRewriteArgs* rewrite_args,
r_rtn = rewrite_args->rewriter->loadConst(0);
}
} else {
rtn = getattrInternal<CAPI>(obj, str, NULL);
rtn = getattrInternal<CAPI>(obj, str);
}
if (rewrite_args) {
......@@ -691,7 +691,7 @@ Box* hasattrFuncInternal(BoxedFunctionBase* func, CallRewriteArgs* rewrite_args,
r_rtn = rewrite_args->rewriter->loadConst(0);
}
} else {
rtn = getattrInternal<CAPI>(obj, str, NULL);
rtn = getattrInternal<CAPI>(obj, str);
}
if (rewrite_args) {
......@@ -1252,7 +1252,7 @@ Box* ellipsisRepr(Box* self) {
return boxString("Ellipsis");
}
Box* divmod(Box* lhs, Box* rhs) {
return binopInternal(lhs, rhs, AST_TYPE::DivMod, false, NULL);
return binopInternal<NOT_REWRITABLE>(lhs, rhs, AST_TYPE::DivMod, false, NULL);
}
Box* powFunc(Box* x, Box* y, Box* z) {
......@@ -1326,7 +1326,7 @@ Box* getreversed(Box* o) {
return r;
static BoxedString* getitem_str = internStringImmortal("__getitem__");
if (!typeLookup(o->cls, getitem_str, NULL)) {
if (!typeLookup(o->cls, getitem_str)) {
raiseExcHelper(TypeError, "'%s' object is not iterable", getTypeName(o));
}
int64_t len = unboxedLen(o); // this will throw an exception if __len__ isn't there
......
......@@ -220,7 +220,7 @@ extern "C" PyObject* PyObject_GetAttr(PyObject* o, PyObject* attr) noexcept {
BoxedString* s = static_cast<BoxedString*>(attr);
internStringMortalInplace(s);
Box* r = getattrInternal<ExceptionStyle::CAPI>(o, s, NULL);
Box* r = getattrInternal<ExceptionStyle::CAPI>(o, s);
if (!r && !PyErr_Occurred()) {
PyErr_Format(PyExc_AttributeError, "'%.50s' object has no attribute '%.400s'", o->cls->tp_name,
......@@ -234,7 +234,7 @@ extern "C" PyObject* PyObject_GenericGetAttr(PyObject* o, PyObject* name) noexce
try {
BoxedString* s = static_cast<BoxedString*>(name);
internStringMortalInplace(s);
Box* r = getattrInternalGeneric<false>(o, s, NULL, false, false, NULL, NULL);
Box* r = getattrInternalGeneric<false, NOT_REWRITABLE>(o, s, NULL, false, false, NULL, NULL);
if (!r)
PyErr_Format(PyExc_AttributeError, "'%.50s' object has no attribute '%.400s'", o->cls->tp_name,
PyString_AS_STRING(name));
......@@ -458,7 +458,7 @@ done:
extern "C" PyObject* PyObject_GetItem(PyObject* o, PyObject* key) noexcept {
return getitemInternal<ExceptionStyle::CAPI>(o, key, NULL);
return getitemInternal<ExceptionStyle::CAPI>(o, key);
}
extern "C" int PyObject_SetItem(PyObject* o, PyObject* key, PyObject* v) noexcept {
......@@ -580,11 +580,11 @@ extern "C" int PyObject_Not(PyObject* o) noexcept {
extern "C" PyObject* PyObject_Call(PyObject* callable_object, PyObject* args, PyObject* kw) noexcept {
if (kw)
return runtimeCallInternal<ExceptionStyle::CAPI>(callable_object, NULL, ArgPassSpec(0, 0, true, true), args, kw,
NULL, NULL, NULL);
return runtimeCallInternal<ExceptionStyle::CAPI, NOT_REWRITABLE>(
callable_object, NULL, ArgPassSpec(0, 0, true, true), args, kw, NULL, NULL, NULL);
else
return runtimeCallInternal<ExceptionStyle::CAPI>(callable_object, NULL, ArgPassSpec(0, 0, true, false), args,
NULL, NULL, NULL, NULL);
return runtimeCallInternal<ExceptionStyle::CAPI, NOT_REWRITABLE>(
callable_object, NULL, ArgPassSpec(0, 0, true, false), args, NULL, NULL, NULL, NULL);
}
extern "C" int PyObject_GetBuffer(PyObject* obj, Py_buffer* view, int flags) noexcept {
......
......@@ -29,12 +29,17 @@ extern "C" {
BoxedClass* classobj_cls, *instance_cls;
}
template <Rewritable rewritable>
static Box* classLookup(BoxedClassobj* cls, BoxedString* attr, GetattrRewriteArgs* rewrite_args) {
if (rewritable == NOT_REWRITABLE) {
assert(!rewrite_args);
rewrite_args = NULL;
}
static Box* classLookup(BoxedClassobj* cls, BoxedString* attr, GetattrRewriteArgs* rewrite_args = NULL) {
if (rewrite_args)
assert(!rewrite_args->isSuccessful());
Box* r = cls->getattr(attr, rewrite_args);
Box* r = cls->getattr<rewritable>(attr, rewrite_args);
if (r) {
if (rewrite_args)
rewrite_args->assertReturnConvention(ReturnConvention::HAS_RETURN);
......@@ -51,7 +56,7 @@ static Box* classLookup(BoxedClassobj* cls, BoxedString* attr, GetattrRewriteArg
for (auto b : *cls->bases) {
RELEASE_ASSERT(b->cls == classobj_cls, "");
Box* r = classLookup(static_cast<BoxedClassobj*>(b), attr, rewrite_args);
Box* r = classLookup<NOT_REWRITABLE>(static_cast<BoxedClassobj*>(b), attr, rewrite_args);
if (r)
return r;
}
......@@ -59,6 +64,10 @@ static Box* classLookup(BoxedClassobj* cls, BoxedString* attr, GetattrRewriteArg
return NULL;
}
static Box* classLookup(BoxedClassobj* cls, BoxedString* attr) {
return classLookup<NOT_REWRITABLE>(cls, attr, NULL);
}
extern "C" PyObject* _PyInstance_Lookup(PyObject* pinst, PyObject* pname) noexcept {
RELEASE_ASSERT(PyInstance_Check(pinst), "");
BoxedInstance* inst = (BoxedInstance*)pinst;
......@@ -68,7 +77,7 @@ extern "C" PyObject* _PyInstance_Lookup(PyObject* pinst, PyObject* pname) noexce
try {
internStringMortalInplace(name);
Box* v = inst->getattr(name, NULL);
Box* v = inst->getattr(name);
if (v == NULL)
v = classLookup(inst->inst_cls, name);
return v;
......@@ -326,9 +335,15 @@ Box* classobjRepr(Box* _obj) {
}
// Analogous to CPython's instance_getattr2
template <Rewritable rewritable>
static Box* instanceGetattributeSimple(BoxedInstance* inst, BoxedString* attr_str,
GetattrRewriteArgs* rewrite_args = NULL) {
Box* r = inst->getattr(attr_str, rewrite_args);
if (rewritable == NOT_REWRITABLE) {
assert(!rewrite_args);
rewrite_args = NULL;
}
Box* r = inst->getattr<rewritable>(attr_str, rewrite_args);
if (r) {
if (rewrite_args)
rewrite_args->assertReturnConvention(ReturnConvention::HAS_RETURN);
......@@ -350,7 +365,7 @@ static Box* instanceGetattributeSimple(BoxedInstance* inst, BoxedString* attr_st
}
GetattrRewriteArgs grewriter_inst_args(rewrite_args ? rewrite_args->rewriter : NULL, r_inst_cls,
rewrite_args ? rewrite_args->rewriter->getReturnDestination() : Location());
r = classLookup(inst->inst_cls, attr_str, rewrite_args ? &grewriter_inst_args : NULL);
r = classLookup<rewritable>(inst->inst_cls, attr_str, rewrite_args ? &grewriter_inst_args : NULL);
if (!grewriter_inst_args.isSuccessful())
rewrite_args = NULL;
......@@ -371,9 +386,15 @@ static Box* instanceGetattributeSimple(BoxedInstance* inst, BoxedString* attr_st
return NULL;
}
template <Rewritable rewritable>
static Box* instanceGetattributeWithFallback(BoxedInstance* inst, BoxedString* attr_str,
GetattrRewriteArgs* rewrite_args = NULL) {
Box* attr_obj = instanceGetattributeSimple(inst, attr_str, rewrite_args);
if (rewritable == NOT_REWRITABLE) {
assert(!rewrite_args);
rewrite_args = NULL;
}
Box* attr_obj = instanceGetattributeSimple<rewritable>(inst, attr_str, rewrite_args);
if (attr_obj) {
if (rewrite_args && rewrite_args->isSuccessful())
......@@ -399,14 +420,21 @@ static Box* instanceGetattributeWithFallback(BoxedInstance* inst, BoxedString* a
if (getattr) {
getattr = processDescriptor(getattr, inst, inst->inst_cls);
return runtimeCallInternal<CXX>(getattr, NULL, ArgPassSpec(1), attr_str, NULL, NULL, NULL, NULL);
return runtimeCallInternal<CXX, NOT_REWRITABLE>(getattr, NULL, ArgPassSpec(1), attr_str, NULL, NULL, NULL,
NULL);
}
return NULL;
}
template <Rewritable rewritable>
static Box* _instanceGetattribute(Box* _inst, BoxedString* attr_str, bool raise_on_missing,
GetattrRewriteArgs* rewrite_args = NULL) {
GetattrRewriteArgs* rewrite_args) {
if (rewritable == NOT_REWRITABLE) {
assert(!rewrite_args);
rewrite_args = NULL;
}
RELEASE_ASSERT(_inst->cls == instance_cls, "");
BoxedInstance* inst = static_cast<BoxedInstance*>(_inst);
......@@ -419,7 +447,7 @@ static Box* _instanceGetattribute(Box* _inst, BoxedString* attr_str, bool raise_
return inst->inst_cls;
}
Box* attr = instanceGetattributeWithFallback(inst, attr_str, rewrite_args);
Box* attr = instanceGetattributeWithFallback<rewritable>(inst, attr_str, rewrite_args);
if (attr) {
return attr;
} else if (!raise_on_missing) {
......@@ -429,6 +457,9 @@ static Box* _instanceGetattribute(Box* _inst, BoxedString* attr_str, bool raise_
attr_str->data());
}
}
static Box* _instanceGetattribute(Box* _inst, BoxedString* attr_str, bool raise_on_missing) {
return _instanceGetattribute<NOT_REWRITABLE>(_inst, attr_str, raise_on_missing, NULL);
}
// Analogous to CPython's instance_getattr
Box* instance_getattro(Box* cls, Box* attr) noexcept {
......@@ -444,13 +475,13 @@ Box* instanceGetattroInternal(Box* cls, Box* _attr, GetattrRewriteArgs* rewrite_
if (S == CAPI) {
try {
return _instanceGetattribute(cls, attr, true, rewrite_args);
return _instanceGetattribute<REWRITABLE>(cls, attr, true, rewrite_args);
} catch (ExcInfo e) {
setCAPIException(e);
return NULL;
}
} else {
return _instanceGetattribute(cls, attr, true, rewrite_args);
return _instanceGetattribute<REWRITABLE>(cls, attr, true, rewrite_args);
}
}
......@@ -1137,7 +1168,7 @@ static void instance_dealloc(Box* _inst) noexcept {
static BoxedString* del_str = internStringImmortal("__del__");
// TODO: any exceptions here should get caught + printed, instead of causing a std::terminate:
Box* func = instanceGetattributeSimple(inst, del_str);
Box* func = instanceGetattributeSimple<NOT_REWRITABLE>(inst, del_str, NULL);
if (func)
runtimeCall(func, ArgPassSpec(0), NULL, NULL, NULL, NULL, NULL);
}
......
......@@ -842,7 +842,8 @@ template <ExceptionStyle S> static Box* try_special_method(Box* self) noexcept(S
static BoxedString* float_str = internStringImmortal("__float__");
if (PyObject_HasAttr((PyObject*)self, float_str)) {
Box* r_f = callattrInternal<S>(self, float_str, CLASS_ONLY, NULL, ArgPassSpec(0), NULL, NULL, NULL, NULL, NULL);
Box* r_f = callattrInternal<S, NOT_REWRITABLE>(self, float_str, CLASS_ONLY, NULL, ArgPassSpec(0), NULL, NULL,
NULL, NULL, NULL);
if (!PyFloat_Check(r_f)) {
if (S == CAPI) {
if (!PyErr_Occurred())
......@@ -857,8 +858,8 @@ template <ExceptionStyle S> static Box* try_special_method(Box* self) noexcept(S
static BoxedString* complex_str = internStringImmortal("__complex__");
if (PyObject_HasAttr((PyObject*)self, complex_str)) {
Box* r
= callattrInternal<S>(self, complex_str, CLASS_OR_INST, NULL, ArgPassSpec(0), NULL, NULL, NULL, NULL, NULL);
Box* r = callattrInternal<S, NOT_REWRITABLE>(self, complex_str, CLASS_OR_INST, NULL, ArgPassSpec(0), NULL, NULL,
NULL, NULL, NULL);
if (!r) {
if (S == CAPI) {
if (!PyErr_Occurred())
......
......@@ -47,7 +47,7 @@ static void propertyDocCopy(BoxedProperty* prop, Box* fget) {
static BoxedString* doc_str = internStringImmortal("__doc__");
try {
get_doc = getattrInternal<ExceptionStyle::CXX>(fget, doc_str, NULL);
get_doc = getattrInternal<ExceptionStyle::CXX>(fget, doc_str);
} catch (ExcInfo e) {
if (!e.matches(Exception)) {
throw e;
......
......@@ -327,12 +327,12 @@ extern "C" PyObject* PyDict_GetItem(PyObject* dict, PyObject* key) noexcept {
/* preserve the existing exception */
PyObject* err_type, *err_value, *err_tb;
PyErr_Fetch(&err_type, &err_value, &err_tb);
Box* b = getitemInternal<CAPI>(dict, key, NULL);
Box* b = getitemInternal<CAPI>(dict, key);
/* ignore errors */
PyErr_Restore(err_type, err_value, err_tb);
return b;
} else {
Box* b = getitemInternal<CAPI>(dict, key, NULL);
Box* b = getitemInternal<CAPI>(dict, key);
if (b == NULL)
PyErr_Clear();
return b;
......@@ -691,7 +691,7 @@ Box* dictUpdate(BoxedDict* self, BoxedTuple* args, BoxedDict* kwargs) {
if (args->size()) {
Box* arg = args->elts[0];
static BoxedString* keys_str = internStringImmortal("keys");
if (getattrInternal<ExceptionStyle::CXX>(arg, keys_str, NULL)) {
if (getattrInternal<ExceptionStyle::CXX>(arg, keys_str)) {
dictMerge(self, arg);
} else {
dictMergeFromSeq2(self, arg);
......
......@@ -794,7 +794,8 @@ template <ExceptionStyle S> static BoxedFloat* _floatNew(Box* a) noexcept(S == C
return res;
} else {
static BoxedString* float_str = internStringImmortal("__float__");
Box* r = callattrInternal<S>(a, float_str, CLASS_ONLY, NULL, ArgPassSpec(0), NULL, NULL, NULL, NULL, NULL);
Box* r = callattrInternal<S, NOT_REWRITABLE>(a, float_str, CLASS_ONLY, NULL, ArgPassSpec(0), NULL, NULL, NULL,
NULL, NULL);
if (!r) {
if (S == CAPI) {
......
......@@ -381,7 +381,7 @@ static Box* importSub(const std::string& name, BoxedString* full_name, Box* pare
path_list = NULL;
} else {
static BoxedString* path_str = internStringImmortal("__path__");
path_list = static_cast<BoxedList*>(getattrInternal<ExceptionStyle::CXX>(parent_module, path_str, NULL));
path_list = static_cast<BoxedList*>(getattrInternal<ExceptionStyle::CXX>(parent_module, path_str));
if (path_list == NULL || path_list->cls != list_cls) {
return None;
}
......@@ -558,7 +558,7 @@ static void ensureFromlist(Box* module, Box* fromlist, std::string& buf, bool re
static BoxedString* path_str = internStringImmortal("__path__");
Box* pathlist = NULL;
try {
pathlist = getattrInternal<ExceptionStyle::CXX>(module, path_str, NULL);
pathlist = getattrInternal<ExceptionStyle::CXX>(module, path_str);
} catch (ExcInfo e) {
if (!e.matches(AttributeError))
throw e;
......@@ -580,14 +580,14 @@ static void ensureFromlist(Box* module, Box* fromlist, std::string& buf, bool re
continue;
static BoxedString* all_str = internStringImmortal("__all__");
Box* all = getattrInternal<ExceptionStyle::CXX>(module, all_str, NULL);
Box* all = getattrInternal<ExceptionStyle::CXX>(module, all_str);
if (all) {
ensureFromlist(module, all, buf, true);
}
continue;
}
Box* attr = getattrInternal<ExceptionStyle::CXX>(module, s, NULL);
Box* attr = getattrInternal<ExceptionStyle::CXX>(module, s);
if (attr != NULL)
continue;
......
......@@ -837,7 +837,7 @@ private:
public:
PyCmpComparer(Box* cmp) : cmp(cmp) {}
bool operator()(Box* lhs, Box* rhs) {
Box* r = runtimeCallInternal<CXX>(cmp, NULL, ArgPassSpec(2), lhs, rhs, NULL, NULL, NULL);
Box* r = runtimeCallInternal<CXX, NOT_REWRITABLE>(cmp, NULL, ArgPassSpec(2), lhs, rhs, NULL, NULL, NULL);
if (!PyInt_Check(r))
raiseExcHelper(TypeError, "comparison function must return int, not %.200s", r->cls->tp_name);
return static_cast<BoxedInt*>(r)->n < 0;
......@@ -1141,7 +1141,7 @@ Box* _listCmp(BoxedList* lhs, BoxedList* rhs, AST_TYPE::AST_TYPE op_type) {
} else if (op_type == AST_TYPE::NotEq) {
return boxBool(true);
} else {
Box* r = compareInternal(lhs->elts->elts[i], rhs->elts->elts[i], op_type, NULL);
Box* r = compareInternal<NOT_REWRITABLE>(lhs->elts->elts[i], rhs->elts->elts[i], op_type, NULL);
return r;
}
}
......
This diff is collapsed.
......@@ -113,22 +113,28 @@ extern "C" Box* getiterHelper(Box* o);
extern "C" Box* createBoxedIterWrapperIfNeeded(Box* o);
struct SetattrRewriteArgs;
template <Rewritable rewritable>
void setattrGeneric(Box* obj, BoxedString* attr, Box* val, SetattrRewriteArgs* rewrite_args);
struct BinopRewriteArgs;
extern "C" Box* binopInternal(Box* lhs, Box* rhs, int op_type, bool inplace, BinopRewriteArgs* rewrite_args);
template <Rewritable rewritable>
Box* binopInternal(Box* lhs, Box* rhs, int op_type, bool inplace, BinopRewriteArgs* rewrite_args);
struct CallRewriteArgs;
template <ExceptionStyle S>
template <ExceptionStyle S, Rewritable rewritable>
Box* runtimeCallInternal(Box* obj, CallRewriteArgs* rewrite_args, ArgPassSpec argspec, Box* arg1, Box* arg2, Box* arg3,
Box** args, const std::vector<BoxedString*>* keyword_names) noexcept(S == CAPI);
struct GetitemRewriteArgs;
template <ExceptionStyle S>
template <ExceptionStyle S, Rewritable rewritable = REWRITABLE>
Box* getitemInternal(Box* target, Box* slice, GetitemRewriteArgs* rewrite_args) noexcept(S == CAPI);
template <ExceptionStyle S> inline Box* getitemInternal(Box* target, Box* slice) noexcept(S == CAPI) {
return getitemInternal<S, NOT_REWRITABLE>(target, slice, NULL);
}
struct LenRewriteArgs;
template <ExceptionStyle S> BoxedInt* lenInternal(Box* obj, LenRewriteArgs* rewrite_args) noexcept(S == CAPI);
template <ExceptionStyle S, Rewritable rewritable>
BoxedInt* lenInternal(Box* obj, LenRewriteArgs* rewrite_args) noexcept(S == CAPI);
Box* lenCallInternal(BoxedFunctionBase* f, CallRewriteArgs* rewrite_args, ArgPassSpec argspec, Box* arg1, Box* arg2,
Box* arg3, Box** args, const std::vector<BoxedString*>* keyword_names);
......@@ -142,23 +148,27 @@ enum LookupScope {
CLASS_OR_INST = 3,
};
struct CallattrRewriteArgs;
template <ExceptionStyle S>
template <ExceptionStyle S, Rewritable rewritable>
Box* callattrInternal(Box* obj, BoxedString* attr, LookupScope, CallattrRewriteArgs* rewrite_args, ArgPassSpec argspec,
Box* arg1, Box* arg2, Box* arg3, Box** args,
const std::vector<BoxedString*>* keyword_names) noexcept(S == CAPI);
extern "C" void delattr_internal(Box* obj, BoxedString* attr, bool allow_custom, DelattrRewriteArgs* rewrite_args);
struct CompareRewriteArgs;
template <Rewritable rewritable>
Box* compareInternal(Box* lhs, Box* rhs, int op_type, CompareRewriteArgs* rewrite_args);
// This is the equivalent of PyObject_GetAttr. Unlike getattrInternalGeneric, it checks for custom __getattr__ or
// __getattribute__ methods.
template <ExceptionStyle S>
template <ExceptionStyle S, Rewritable rewritable = REWRITABLE>
Box* getattrInternal(Box* obj, BoxedString* attr, GetattrRewriteArgs* rewrite_args) noexcept(S == CAPI);
template <ExceptionStyle S> inline Box* getattrInternal(Box* obj, BoxedString* attr) noexcept(S == CAPI) {
return getattrInternal<S, NOT_REWRITABLE>(obj, attr, NULL);
}
// This is the equivalent of PyObject_GenericGetAttr, which performs the default lookup rules for getattr() (check for
// data descriptor, check for instance attribute, check for non-data descriptor). It does not check for __getattr__ or
// __getattribute__.
template <bool IsType>
template <bool IsType, Rewritable rewritable>
Box* getattrInternalGeneric(Box* obj, BoxedString* attr, GetattrRewriteArgs* rewrite_args, bool cls_only, bool for_call,
Box** bind_obj_out, RewriterVar** r_bind_obj_out);
......@@ -166,7 +176,11 @@ extern "C" PyObject* type_getattro(PyObject* o, PyObject* name) noexcept;
// This is the equivalent of _PyType_Lookup(), which calls Box::getattr() on each item in the object's MRO in the
// appropriate order. It does not do any descriptor logic.
template <Rewritable rewritable = REWRITABLE>
Box* typeLookup(BoxedClass* cls, BoxedString* attr, GetattrRewriteArgs* rewrite_args);
inline Box* typeLookup(BoxedClass* cls, BoxedString* attr) {
return typeLookup<NOT_REWRITABLE>(cls, attr, NULL);
}
extern "C" void raiseAttributeErrorStr(const char* typeName, llvm::StringRef attr) __attribute__((__noreturn__));
extern "C" void raiseAttributeError(Box* obj, llvm::StringRef attr) __attribute__((__noreturn__));
......
......@@ -127,7 +127,7 @@ Box* superGetattribute(Box* _s, Box* _attr) {
}
}
Box* r = typeLookup(s->cls, attr, NULL);
Box* r = typeLookup(s->cls, attr);
// TODO implement this
RELEASE_ASSERT(r, "should call the equivalent of objectGetattr here");
return processDescriptor(r, s, s->cls);
......
......@@ -770,8 +770,8 @@ static Box* objectNewNoArgs(BoxedClass* cls) noexcept {
#ifndef NDEBUG
static BoxedString* new_str = internStringImmortal("__new__");
static BoxedString* init_str = internStringImmortal("__init__");
assert(typeLookup(cls, new_str, NULL) == typeLookup(object_cls, new_str, NULL)
&& typeLookup(cls, init_str, NULL) != typeLookup(object_cls, init_str, NULL));
assert(typeLookup(cls, new_str) == typeLookup(object_cls, new_str)
&& typeLookup(cls, init_str) != typeLookup(object_cls, init_str));
#endif
return new (cls) Box();
}
......@@ -934,7 +934,7 @@ static Box* typeCallInner(CallRewriteArgs* rewrite_args, ArgPassSpec argspec, Bo
}
}
} else {
new_attr = typeLookup(cls, new_str, NULL);
new_attr = typeLookup(cls, new_str);
try {
if (new_attr->cls != function_cls) // optimization
new_attr = processDescriptor(new_attr, None, cls);
......@@ -982,7 +982,7 @@ static Box* typeCallInner(CallRewriteArgs* rewrite_args, ArgPassSpec argspec, Bo
static std::vector<Box*> class_making_news;
if (class_making_news.empty()) {
for (BoxedClass* allowed_cls : { object_cls, enumerate_cls, xrange_cls, tuple_cls, list_cls, dict_cls }) {
auto new_obj = typeLookup(allowed_cls, new_str, NULL);
auto new_obj = typeLookup(allowed_cls, new_str);
gc::registerPermanentRoot(new_obj, /* allow_duplicates= */ true);
class_making_news.push_back(new_obj);
}
......@@ -1062,7 +1062,7 @@ static Box* typeCallInner(CallRewriteArgs* rewrite_args, ArgPassSpec argspec, Bo
}
}
} else {
init_attr = typeLookup(cls, init_str, NULL);
init_attr = typeLookup(cls, init_str);
}
}
......@@ -1112,7 +1112,8 @@ static Box* typeCallInner(CallRewriteArgs* rewrite_args, ArgPassSpec argspec, Bo
if (new_npassed_args >= 4)
srewrite_args.args = rewrite_args->args;
made = runtimeCallInternal<S>(new_attr, &srewrite_args, new_argspec, cls, arg2, arg3, args, keyword_names);
made = runtimeCallInternal<S, REWRITABLE>(new_attr, &srewrite_args, new_argspec, cls, arg2, arg3, args,
keyword_names);
if (!made) {
assert(S == CAPI);
......@@ -1135,7 +1136,8 @@ static Box* typeCallInner(CallRewriteArgs* rewrite_args, ArgPassSpec argspec, Bo
made = objectNewNoArgs(cls);
assert(made);
} else
made = runtimeCallInternal<S>(new_attr, NULL, new_argspec, cls, arg2, arg3, args, keyword_names);
made = runtimeCallInternal<S, NOT_REWRITABLE>(new_attr, NULL, new_argspec, cls, arg2, arg3, args,
keyword_names);
if (!made) {
assert(S == CAPI);
......@@ -1248,8 +1250,8 @@ static Box* typeCallInner(CallRewriteArgs* rewrite_args, ArgPassSpec argspec, Bo
srewrite_args.args_guarded = rewrite_args->args_guarded;
srewrite_args.func_guarded = true;
initrtn
= runtimeCallInternal<S>(init_attr, &srewrite_args, argspec, made, arg2, arg3, args, keyword_names);
initrtn = runtimeCallInternal<S, REWRITABLE>(init_attr, &srewrite_args, argspec, made, arg2, arg3, args,
keyword_names);
if (!srewrite_args.out_success) {
rewrite_args = NULL;
......@@ -1258,7 +1260,8 @@ static Box* typeCallInner(CallRewriteArgs* rewrite_args, ArgPassSpec argspec, Bo
rewrite_args->rewriter->call(true, (void*)assertInitNone, srewrite_args.out_rtn);
}
} else {
initrtn = runtimeCallInternal<S>(init_attr, NULL, argspec, made, arg2, arg3, args, keyword_names);
initrtn = runtimeCallInternal<S, NOT_REWRITABLE>(init_attr, NULL, argspec, made, arg2, arg3, args,
keyword_names);
}
if (!initrtn) {
......@@ -1823,7 +1826,8 @@ extern "C" Box* sliceNew(Box* cls, Box* start, Box* stop, Box** args) {
static Box* instancemethodCall(BoxedInstanceMethod* self, Box* args, Box* kwargs) {
// Not the most effficient, but it works:
return runtimeCallInternal<CXX>(self, NULL, ArgPassSpec(0, 0, true, true), args, kwargs, NULL, NULL, NULL);
return runtimeCallInternal<CXX, NOT_REWRITABLE>(self, NULL, ArgPassSpec(0, 0, true, true), args, kwargs, NULL, NULL,
NULL);
// TODO add a tpp_call
}
......@@ -1872,7 +1876,7 @@ static Box* instancemethodRepr(Box* b) {
const char* sfuncname = "?", * sklassname = "?";
static BoxedString* name_str = internStringImmortal("__name__");
funcname = getattrInternal<CXX>(func, name_str, NULL);
funcname = getattrInternal<CXX>(func, name_str);
if (funcname != NULL) {
if (!PyString_Check(funcname)) {
......@@ -1884,7 +1888,7 @@ static Box* instancemethodRepr(Box* b) {
if (klass == NULL) {
klassname = NULL;
} else {
klassname = getattrInternal<CXX>(klass, name_str, NULL);
klassname = getattrInternal<CXX>(klass, name_str);
if (klassname != NULL) {
if (!PyString_Check(klassname)) {
klassname = NULL;
......@@ -1916,7 +1920,7 @@ Box* instancemethodEq(BoxedInstanceMethod* self, Box* rhs) {
return boxBool(true);
} else {
if (self->obj != NULL && rhs_im->obj != NULL) {
return compareInternal(self->obj, rhs_im->obj, AST_TYPE::Eq, NULL);
return compareInternal<NOT_REWRITABLE>(self->obj, rhs_im->obj, AST_TYPE::Eq, NULL);
} else {
return boxBool(false);
}
......@@ -2325,8 +2329,8 @@ public:
if (self->isDictBacked()) {
static BoxedString* setitem_str = internStringImmortal("__setitem__");
return callattrInternal<CXX>(self->getDictBacking(), setitem_str, LookupScope::CLASS_ONLY, NULL,
ArgPassSpec(2), _key, value, NULL, NULL, NULL);
return callattrInternal<CXX, NOT_REWRITABLE>(self->getDictBacking(), setitem_str, LookupScope::CLASS_ONLY,
NULL, ArgPassSpec(2), _key, value, NULL, NULL, NULL);
}
assert(_key->cls == str_cls);
......@@ -2362,8 +2366,9 @@ public:
if (self->isDictBacked()) {
static BoxedString* setdefault_str = internStringImmortal("setdefault");
return callattrInternal<CXX>(self->getDictBacking(), setdefault_str, LookupScope::CLASS_ONLY, NULL,
ArgPassSpec(2), _key, value, NULL, NULL, NULL);
return callattrInternal<CXX, NOT_REWRITABLE>(self->getDictBacking(), setdefault_str,
LookupScope::CLASS_ONLY, NULL, ArgPassSpec(2), _key, value,
NULL, NULL, NULL);
}
assert(_key->cls == str_cls);
......@@ -2649,8 +2654,8 @@ public:
if (self->isDictBacked()) {
static BoxedString* iter_str = internStringImmortal("__iter__");
return callattrInternal<CXX>(self->getDictBacking(), iter_str, LookupScope::CLASS_ONLY, NULL,
ArgPassSpec(0), NULL, NULL, NULL, NULL, NULL);
return callattrInternal<CXX, NOT_REWRITABLE>(self->getDictBacking(), iter_str, LookupScope::CLASS_ONLY,
NULL, ArgPassSpec(0), NULL, NULL, NULL, NULL, NULL);
}
return new AttrWrapperIter(self);
......@@ -2664,8 +2669,8 @@ public:
BoxedDict* dict = (BoxedDict*)AttrWrapper::copy(_self);
assert(dict->cls == dict_cls);
static BoxedString* eq_str = internStringImmortal("__eq__");
return callattrInternal<CXX>(dict, eq_str, LookupScope::CLASS_ONLY, NULL, ArgPassSpec(1), _other, NULL, NULL,
NULL, NULL);
return callattrInternal<CXX, NOT_REWRITABLE>(dict, eq_str, LookupScope::CLASS_ONLY, NULL, ArgPassSpec(1),
_other, NULL, NULL, NULL, NULL);
}
static Box* ne(Box* _self, Box* _other) { return eq(_self, _other) == True ? False : True; }
......@@ -2840,7 +2845,7 @@ Box* objectSetattr(Box* obj, Box* attr, Box* value) {
}
BoxedString* attr_str = static_cast<BoxedString*>(attr);
setattrGeneric(obj, attr_str, value, NULL);
setattrGeneric<NOT_REWRITABLE>(obj, attr_str, value, NULL);
return None;
}
......
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