Commit 87b8302d authored by Kevin Modzelewski's avatar Kevin Modzelewski

Merge pull request #493 from tjhance/boxed-instance-method

Add im_class field to BoxedInstanceMethod, implement instancemethodRepr
parents b9f52061 4210ed9b
......@@ -153,7 +153,7 @@ public:
// CPython handles this differently: they create the equivalent of different BoxedMethodDescriptor
// objects but with different class objects, which define different __get__ and __call__ methods.
if (self->method->ml_flags & METH_CLASS)
return boxInstanceMethod(owner, self);
return boxInstanceMethod(owner, self, self->type);
if (self->method->ml_flags & METH_STATIC)
Py_FatalError("unimplemented");
......@@ -163,7 +163,7 @@ public:
if (inst == None)
return self;
else
return boxInstanceMethod(inst, self);
return boxInstanceMethod(inst, self, self->type);
}
static Box* __call__(BoxedMethodDescriptor* self, Box* obj, BoxedTuple* varargs, Box** _args);
......
......@@ -75,9 +75,10 @@ std::string ValuedCompilerType<llvm::Value*>::debugName() {
}
struct RawInstanceMethod {
CompilerVariable* obj, *func;
CompilerVariable* obj, *func, *im_class;
RawInstanceMethod(CompilerVariable* obj, CompilerVariable* func) : obj(obj), func(func) {}
RawInstanceMethod(CompilerVariable* obj, CompilerVariable* func, CompilerVariable* im_class)
: obj(obj), func(func), im_class(im_class) {}
};
class InstanceMethodType : public ValuedCompilerType<RawInstanceMethod*> {
......@@ -108,9 +109,9 @@ public:
return rtn;
}
static CompilerVariable* makeIM(CompilerVariable* obj, CompilerVariable* func) {
static CompilerVariable* makeIM(CompilerVariable* obj, CompilerVariable* func, CompilerVariable* im_class) {
CompilerVariable* rtn = new ValuedCompilerVariable<RawInstanceMethod*>(
InstanceMethodType::get(obj->getType(), func->getType()), new RawInstanceMethod(obj, func), true);
InstanceMethodType::get(obj->getType(), func->getType()), new RawInstanceMethod(obj, func, im_class), true);
obj->incvref();
func->incvref();
return rtn;
......@@ -160,9 +161,10 @@ public:
assert(im->func);
ConcreteCompilerVariable* obj = im->obj->makeConverted(emitter, UNKNOWN);
ConcreteCompilerVariable* func = im->func->makeConverted(emitter, UNKNOWN);
ConcreteCompilerVariable* im_class = im->im_class->makeConverted(emitter, UNKNOWN);
llvm::Value* boxed
= emitter.getBuilder()->CreateCall2(g.funcs.boxInstanceMethod, obj->getValue(), func->getValue());
llvm::Value* boxed = emitter.getBuilder()->CreateCall3(g.funcs.boxInstanceMethod, obj->getValue(),
func->getValue(), im_class->getValue());
obj->decvref(emitter);
func->decvref(emitter);
......@@ -175,7 +177,8 @@ public:
CompilerVariable* rtn = cache[var];
if (rtn == NULL) {
RawInstanceMethod* im = var->getValue();
RawInstanceMethod* new_im = new RawInstanceMethod(im->obj->dup(cache), im->func->dup(cache));
RawInstanceMethod* new_im
= new RawInstanceMethod(im->obj->dup(cache), im->func->dup(cache), im->im_class->dup(cache));
rtn = new VAR(this, new_im, var->isGrabbed());
while (rtn->getVrefs() < var->getVrefs())
rtn->incvref();
......@@ -1476,7 +1479,10 @@ public:
if (rtattr->cls == function_cls) {
CompilerVariable* clattr = new ConcreteCompilerVariable(
typeFromClass(function_cls), embedRelocatablePtr(rtattr, g.llvm_value_type_ptr), false);
return InstanceMethodType::makeIM(var, clattr);
return InstanceMethodType::makeIM(
var, clattr,
new ConcreteCompilerVariable(UNKNOWN, embedRelocatablePtr(cls, g.llvm_value_type_ptr), false));
}
}
......
......@@ -87,4 +87,12 @@ template <typename T1, typename T2> struct hash<pair<T1, T2>> {
};
}
namespace std {
template <typename T1, typename T2, typename T3> struct hash<tuple<T1, T2, T3>> {
size_t operator()(const tuple<T1, T2, T3> p) const {
return hash<T1>()(std::get<0>(p)) ^ (hash<T2>()(std::get<1>(p)) << 1) ^ (hash<T3>()(std::get<2>(p)) << 2);
}
};
}
#endif
......@@ -165,7 +165,7 @@ static Box* classmethodGet(Box* self, Box* obj, Box* type) {
type = obj->cls;
}
return new BoxedInstanceMethod(type, cm->cm_callable);
return new BoxedInstanceMethod(type, cm->cm_callable, type);
}
void setupDescr() {
......
......@@ -684,7 +684,7 @@ void setupDict() {
dict_cls->giveAttr("popitem", new BoxedFunction(boxRTFunction((void*)dictPopitem, BOXED_TUPLE, 1)));
auto* fromkeys_func = new BoxedFunction(boxRTFunction((void*)dictFromkeys, DICT, 3, 1, false, false), { None });
dict_cls->giveAttr("fromkeys", boxInstanceMethod(dict_cls, fromkeys_func));
dict_cls->giveAttr("fromkeys", boxInstanceMethod(dict_cls, fromkeys_func, dict_cls));
dict_cls->giveAttr("viewkeys", new BoxedFunction(boxRTFunction((void*)dictViewKeys, UNKNOWN, 1)));
dict_cls->giveAttr("viewvalues", new BoxedFunction(boxRTFunction((void*)dictViewValues, UNKNOWN, 1)));
......
......@@ -914,8 +914,13 @@ Box* nondataDescriptorInstanceSpecialCases(GetattrRewriteArgs* rewrite_args, Box
if (descr->cls == function_cls || descr->cls == instancemethod_cls || descr->cls == classmethod_cls
|| (descr->cls == method_cls
&& (static_cast<BoxedMethodDescriptor*>(descr)->method->ml_flags & (METH_CLASS | METH_STATIC)) == 0)) {
Box* im_self = NULL, * im_func = NULL;
RewriterVar* r_im_self = NULL, * r_im_func = NULL;
Box* im_self = NULL, * im_func = NULL, * im_class = obj->cls;
RewriterVar* r_im_self = NULL, * r_im_func = NULL, * r_im_class = NULL;
if (rewrite_args) {
r_im_class = rewrite_args->obj->getAttr(BOX_CLS_OFFSET);
}
if (descr->cls == function_cls) {
im_self = obj;
im_func = descr;
......@@ -942,7 +947,7 @@ Box* nondataDescriptorInstanceSpecialCases(GetattrRewriteArgs* rewrite_args, Box
im_func = cm->cm_callable;
if (rewrite_args) {
r_im_self = rewrite_args->obj->getAttr(BOX_CLS_OFFSET);
r_im_self = r_im_class;
r_im_func = r_descr->getAttr(offsetof(BoxedClassmethod, cm_callable));
r_im_func->addGuardNotEq(0);
}
......@@ -973,10 +978,10 @@ Box* nondataDescriptorInstanceSpecialCases(GetattrRewriteArgs* rewrite_args, Box
if (!for_call) {
if (rewrite_args) {
rewrite_args->out_rtn
= rewrite_args->rewriter->call(true, (void*)boxInstanceMethod, r_im_self, r_im_func);
= rewrite_args->rewriter->call(true, (void*)boxInstanceMethod, r_im_self, r_im_func, r_im_class);
rewrite_args->out_success = true;
}
return boxInstanceMethod(im_self, im_func);
return boxInstanceMethod(im_self, im_func, im_class);
} else {
*bind_obj_out = im_self;
if (rewrite_args) {
......@@ -1020,10 +1025,12 @@ Box* descriptorClsSpecialCases(GetattrRewriteArgs* rewrite_args, BoxedClass* cls
if (!for_call && descr->cls == function_cls) {
if (rewrite_args) {
// return an unbound instancemethod
rewrite_args->out_rtn = rewrite_args->rewriter->call(true, (void*)boxUnboundInstanceMethod, r_descr);
RewriterVar* r_cls = rewrite_args->obj;
rewrite_args->out_rtn
= rewrite_args->rewriter->call(true, (void*)boxUnboundInstanceMethod, r_descr, r_cls);
rewrite_args->out_success = true;
}
return boxUnboundInstanceMethod(descr);
return boxUnboundInstanceMethod(descr, cls);
}
if (rewrite_args) {
......
......@@ -716,15 +716,15 @@ extern "C" Box* createUserClass(const std::string* name, Box* _bases, Box* _attr
}
}
extern "C" Box* boxInstanceMethod(Box* obj, Box* func) {
extern "C" Box* boxInstanceMethod(Box* obj, Box* func, Box* type) {
static StatCounter num_ims("num_instancemethods");
num_ims.log();
return new BoxedInstanceMethod(obj, func);
return new BoxedInstanceMethod(obj, func, type);
}
extern "C" Box* boxUnboundInstanceMethod(Box* func) {
return new BoxedInstanceMethod(NULL, func);
extern "C" Box* boxUnboundInstanceMethod(Box* func, Box* type) {
return new BoxedInstanceMethod(NULL, func, type);
}
extern "C" BoxedString* noneRepr(Box* v) {
......@@ -774,8 +774,8 @@ static Box* functionGet(BoxedFunction* self, Box* inst, Box* owner) {
RELEASE_ASSERT(self->cls == function_cls, "");
if (inst == None)
return boxUnboundInstanceMethod(self);
return boxInstanceMethod(inst, self);
inst = NULL;
return new BoxedInstanceMethod(inst, self, owner);
}
static Box* functionCall(BoxedFunction* self, Box* args, Box* kwargs) {
......@@ -920,9 +920,11 @@ Box* instancemethodGet(BoxedInstanceMethod* self, Box* obj, Box* type) {
return self;
}
// TODO subclass test
if (!PyObject_IsSubclass(type, self->im_class)) {
return self;
}
return new BoxedInstanceMethod(obj, self->func);
return new BoxedInstanceMethod(obj, self->func, self->im_class);
}
Box* instancemethodNew(BoxedClass* cls, Box* func, Box* self, Box** args) {
......@@ -939,14 +941,49 @@ Box* instancemethodNew(BoxedClass* cls, Box* func, Box* self, Box** args) {
return NULL;
}
return new BoxedInstanceMethod(self, func);
return new BoxedInstanceMethod(self, func, classObj);
}
Box* instancemethodRepr(BoxedInstanceMethod* self) {
if (self->obj)
return boxStrConstant("<bound instancemethod object>");
else
return boxStrConstant("<unbound instancemethod object>");
// Modified from cpython, Objects/object.c, instancemethod_repr
static Box* instancemethodRepr(Box* b) {
assert(isSubclass(b->cls, instancemethod_cls));
BoxedInstanceMethod* a = static_cast<BoxedInstanceMethod*>(b);
Box* self = a->obj;
Box* func = a->func;
Box* klass = a->im_class;
Box* funcname = NULL, * klassname = NULL, * result = NULL;
const char* sfuncname = "?", * sklassname = "?";
funcname = getattrInternal(func, "__name__", NULL);
if (funcname != NULL) {
if (!PyString_Check(funcname)) {
funcname = NULL;
} else
sfuncname = PyString_AS_STRING(funcname);
}
if (klass == NULL) {
klassname = NULL;
} else {
klassname = getattrInternal(klass, "__name__", NULL);
if (klassname != NULL) {
if (!PyString_Check(klassname)) {
klassname = NULL;
} else {
sklassname = PyString_AS_STRING(klassname);
}
}
}
if (self == NULL)
result = PyString_FromFormat("<unbound method %s.%s>", sklassname, sfuncname);
else {
// This was a CPython comment: /* XXX Shouldn't use repr() here! */
Box* selfrepr = repr(self);
assert(PyString_Check(selfrepr));
result = PyString_FromFormat("<bound method %s.%s of %s>", sklassname, sfuncname, PyString_AS_STRING(selfrepr));
}
return result;
}
Box* instancemethodEq(BoxedInstanceMethod* self, Box* rhs) {
......@@ -2255,9 +2292,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(
"__subclasshook__",
boxInstanceMethod(object_cls, new BoxedFunction(boxRTFunction((void*)objectSubclasshook, UNKNOWN, 2))));
object_cls->giveAttr("__subclasshook__",
boxInstanceMethod(object_cls,
new BoxedFunction(boxRTFunction((void*)objectSubclasshook, UNKNOWN, 2)),
object_cls));
// __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!
......@@ -2369,6 +2407,9 @@ void setupRuntime() {
instancemethod_cls->giveAttr("__self__", instancemethod_cls->getattr("im_self"));
instancemethod_cls->freeze();
instancemethod_cls->giveAttr("im_class", new BoxedMemberDescriptor(BoxedMemberDescriptor::OBJECT,
offsetof(BoxedInstanceMethod, im_class), true));
slice_cls->giveAttr("__new__",
new BoxedFunction(boxRTFunction((void*)sliceNew, UNKNOWN, 4, 2, false, false), { NULL, None }));
slice_cls->giveAttr("__repr__", new BoxedFunction(boxRTFunction((void*)sliceRepr, STR, 1)));
......
......@@ -107,8 +107,8 @@ extern "C" Box* boxBool(bool);
extern "C" Box* boxInt(i64);
extern "C" i64 unboxInt(Box*);
extern "C" Box* boxFloat(double d);
extern "C" Box* boxInstanceMethod(Box* obj, Box* func);
extern "C" Box* boxUnboundInstanceMethod(Box* func);
extern "C" Box* boxInstanceMethod(Box* obj, Box* func, Box* type);
extern "C" Box* boxUnboundInstanceMethod(Box* func, Box* type);
extern "C" Box* boxStringPtr(const std::string* s);
Box* boxString(const std::string& s);
......@@ -511,10 +511,10 @@ public:
Box** in_weakreflist;
// obj is NULL for unbound instancemethod
Box* obj, *func;
Box* obj, *func, *im_class;
BoxedInstanceMethod(Box* obj, Box* func) __attribute__((visibility("default")))
: in_weakreflist(NULL), obj(obj), func(func) {}
BoxedInstanceMethod(Box* obj, Box* func, Box* im_class) __attribute__((visibility("default")))
: in_weakreflist(NULL), obj(obj), func(func), im_class(im_class) {}
DEFAULT_CLASS_SIMPLE(instancemethod_cls);
};
......
......@@ -117,3 +117,13 @@ print type(bound_instancemethod)
unbound_instancemethod = C.l
unbound_instancemethod(c2)
print type(unbound_instancemethod)
### Test instancemethod repr
print 'test instancemethod repr'
class C(object):
def f(self):
pass
def __repr__(self):
return '(alpacas are cool)'
print repr(C.f)
print repr(C().f)
......@@ -2,6 +2,38 @@ class C(object):
def foo(self):
pass
def __repr__(self):
return 'some C obj'
print type(C.foo)
print type(C.foo.im_func), type(C.foo.__func__)
print type(C.foo.im_self), type(C.foo.__self__)
print type(C.foo.im_class)
print repr(C.foo)
print type(C().foo)
print type(C().foo.im_func), type(C().foo.__func__)
print type(C().foo.im_self), type(C().foo.__self__)
print type(C().foo.im_class)
print repr(C().foo)
# old-style classes
class C:
def foo(self):
pass
def __repr__(self):
return 'some old-style C obj'
print type(C.foo)
print type(C.foo.im_func), type(C.foo.__func__)
print type(C.foo.im_self), type(C.foo.__self__)
print type(C.foo.im_class)
print repr(C.foo)
print type(C().foo)
print type(C().foo.im_func), type(C().foo.__func__)
print type(C().foo.im_self), type(C().foo.__self__)
print type(C().foo.im_class)
print repr(C().foo)
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