Commit 47ccea66 authored by Kevin Modzelewski's avatar Kevin Modzelewski

Make use of the tp_setattro class slot

parent 580fbf25
......@@ -549,6 +549,9 @@ Box* Box::getattr(const std::string& attr, GetattrRewriteArgs* rewrite_args) {
if (rewrite_args)
rewrite_args->obj->addAttrGuard(BOX_CLS_OFFSET, (intptr_t)cls);
// if (attr == "__setattr__" && !rewrite_args)
// printf("");
#if 0
if (attr[0] == '_' && attr[1] == '_') {
std::string per_name_stat_name = "slowpath_box_getattr." + std::string(attr);
......@@ -1797,38 +1800,54 @@ extern "C" void setattr(Box* obj, const char* attr, Box* attr_val) {
std::unique_ptr<Rewriter> rewriter(
Rewriter::createRewriter(__builtin_extract_return_addr(__builtin_return_address(0)), 3, "setattr"));
setattrofunc tp_setattro = obj->cls->tp_setattro;
assert(tp_setattro);
assert(!obj->cls->tp_setattr);
if (rewriter.get()) {
auto r_cls = rewriter->getArg(0)->getAttr(offsetof(Box, cls));
// rewriter->trap();
rewriter->getArg(0)->getAttr(offsetof(Box, cls))->addAttrGuard(offsetof(BoxedClass, tp_setattr), 0);
r_cls->addAttrGuard(offsetof(BoxedClass, tp_setattr), 0);
r_cls->addAttrGuard(offsetof(BoxedClass, tp_setattro), (intptr_t)tp_setattro);
}
Box* setattr;
// Note: setattr will only be retrieved if we think it will be profitable to try calling that as opposed to
// the tp_setattr function pointer.
Box* setattr = NULL;
RewriterVar* r_setattr;
if (rewriter.get()) {
GetattrRewriteArgs rewrite_args(rewriter.get(), rewriter->getArg(0)->getAttr(offsetof(Box, cls)),
Location::any());
setattr = typeLookup(obj->cls, setattr_str, &rewrite_args);
if (rewrite_args.out_success) {
r_setattr = rewrite_args.out_rtn;
// TODO this is not good enough, since the object could get collected:
r_setattr->addGuard((intptr_t)setattr);
if (tp_setattro != PyObject_GenericSetAttr) {
if (rewriter.get()) {
GetattrRewriteArgs rewrite_args(rewriter.get(), rewriter->getArg(0)->getAttr(offsetof(Box, cls)),
Location::any());
setattr = typeLookup(obj->cls, setattr_str, &rewrite_args);
assert(setattr);
if (rewrite_args.out_success) {
r_setattr = rewrite_args.out_rtn;
// TODO this is not good enough, since the object could get collected:
r_setattr->addGuard((intptr_t)setattr);
} else {
rewriter.reset(NULL);
}
} else {
rewriter.reset(NULL);
// setattr = typeLookup(obj->cls, setattr_str, NULL);
}
} else {
setattr = typeLookup(obj->cls, setattr_str, NULL);
}
assert(setattr);
// We should probably add this as a GC root, but we can cheat a little bit since
// we know it's not going to get deallocated:
static Box* object_setattr = object_cls->getattr("__setattr__");
assert(object_setattr);
if (DEBUG >= 2) {
assert((typeLookup(obj->cls, setattr_str, NULL) == object_setattr) == (tp_setattro == PyObject_GenericSetAttr));
}
// I guess this check makes it ok for us to just rely on having guarded on the value of setattr without
// invalidating on deallocation, since we assume that object.__setattr__ will never get deallocated.
if (setattr == object_setattr) {
if (tp_setattro == PyObject_GenericSetAttr) {
if (rewriter.get()) {
// rewriter->trap();
SetattrRewriteArgs rewrite_args(rewriter.get(), rewriter->getArg(0), rewriter->getArg(2));
......@@ -1842,9 +1861,18 @@ extern "C" void setattr(Box* obj, const char* attr, Box* attr_val) {
return;
}
setattr = processDescriptor(setattr, obj, obj->cls);
Box* boxstr = boxString(attr);
runtimeCallInternal(setattr, NULL, ArgPassSpec(2), boxstr, attr_val, NULL, NULL, NULL);
if (rewriter.get()) {
assert(setattr);
// TODO actually rewrite this?
setattr = processDescriptor(setattr, obj, obj->cls);
runtimeCallInternal(setattr, NULL, ArgPassSpec(2), boxstr, attr_val, NULL, NULL, NULL);
} else {
int r = tp_setattro(obj, boxstr, attr_val);
if (r)
throwCAPIException();
}
}
bool isUserDefined(BoxedClass* cls) {
......
......@@ -1821,6 +1821,10 @@ void setupRuntime() {
// Weakrefs are used for tp_subclasses:
init_weakref();
object_cls->tp_getattro = PyObject_GenericGetAttr;
object_cls->tp_setattro = PyObject_GenericSetAttr;
add_operators(object_cls);
object_cls->finishInitialization();
type_cls->finishInitialization();
basestring_cls->finishInitialization();
......@@ -1846,9 +1850,6 @@ void setupRuntime() {
wrapperobject_cls->finishInitialization();
wrapperdescr_cls->finishInitialization();
object_cls->tp_getattro = PyObject_GenericGetAttr;
add_operators(object_cls);
str_cls->tp_flags |= Py_TPFLAGS_HAVE_NEWBUFFER;
dict_descr = new (pyston_getset_cls) BoxedGetsetDescriptor(typeDict, typeSetDict, NULL);
......@@ -1890,7 +1891,10 @@ void setupRuntime() {
object_cls->giveAttr("__init__", new BoxedFunction(boxRTFunction((void*)objectInit, UNKNOWN, 1, 0, true, false)));
object_cls->giveAttr("__repr__", new BoxedFunction(boxRTFunction((void*)objectRepr, UNKNOWN, 1, 0, false, false)));
object_cls->giveAttr("__str__", new BoxedFunction(boxRTFunction((void*)objectStr, UNKNOWN, 1, 0, false, false)));
object_cls->giveAttr("__setattr__", new BoxedFunction(boxRTFunction((void*)objectSetattr, UNKNOWN, 3)));
// __setattr__ was already set to a WrapperDescriptor; it'd be nice to set this to a faster BoxedFunction
// object_cls->setattr("__setattr__", new BoxedFunction(boxRTFunction((void*)objectSetattr, UNKNOWN, 3)), NULL);
// but unfortunately that will set tp_setattro to slot_tp_setattro on object_cls and all already-made subclasses!
// Punting on that until needed; hopefully by then we will have better Pyston slots support.
auto typeCallObj = boxRTFunction((void*)typeCall, UNKNOWN, 1, 0, true, true);
typeCallObj->internal_callable = &typeCallInternal;
......@@ -2090,6 +2094,9 @@ void setupRuntime() {
weakref_callableproxy->simple_destructor = proxy_to_tp_clear;
weakref_callableproxy->is_pyston_class = true;
assert(object_cls->tp_setattro == PyObject_GenericSetAttr);
assert(none_cls->tp_setattro == PyObject_GenericSetAttr);
setupSysEnd();
Stats::endOfInit();
......
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