Commit ffa4566e authored by Travis Hance's avatar Travis Hance

Merge pull request #206 from tjhance/static_class_method

staticmethods and classmethods
parents d79da132 6d010d06
...@@ -827,5 +827,7 @@ void setupBuiltins() { ...@@ -827,5 +827,7 @@ void setupBuiltins() {
builtins_module->giveAttr("complex", complex_cls); builtins_module->giveAttr("complex", complex_cls);
builtins_module->giveAttr("super", super_cls); builtins_module->giveAttr("super", super_cls);
builtins_module->giveAttr("property", property_cls); builtins_module->giveAttr("property", property_cls);
builtins_module->giveAttr("staticmethod", staticmethod_cls);
builtins_module->giveAttr("classmethod", classmethod_cls);
} }
} }
...@@ -70,6 +70,44 @@ static Box* propertySet(Box* self, Box* obj, Box* val) { ...@@ -70,6 +70,44 @@ static Box* propertySet(Box* self, Box* obj, Box* val) {
return None; return None;
} }
static Box* staticmethodNew(Box* cls, Box* f) {
RELEASE_ASSERT(cls == staticmethod_cls, "");
return new BoxedStaticmethod(f);
}
static Box* staticmethodGet(Box* self, Box* obj, Box* type) {
RELEASE_ASSERT(self->cls == staticmethod_cls, "");
BoxedStaticmethod* sm = static_cast<BoxedStaticmethod*>(self);
if (sm->sm_callable == NULL) {
raiseExcHelper(RuntimeError, "uninitialized staticmethod object");
}
return sm->sm_callable;
}
static Box* classmethodNew(Box* cls, Box* f) {
RELEASE_ASSERT(cls == classmethod_cls, "");
return new BoxedClassmethod(f);
}
static Box* classmethodGet(Box* self, Box* obj, Box* type) {
RELEASE_ASSERT(self->cls == classmethod_cls, "");
BoxedClassmethod* cm = static_cast<BoxedClassmethod*>(self);
if (cm->cm_callable == NULL) {
raiseExcHelper(RuntimeError, "uninitialized classmethod object");
}
if (type == NULL) {
type = obj->cls;
}
return new BoxedInstanceMethod(type, cm->cm_callable);
}
void setupDescr() { void setupDescr() {
member_cls->giveAttr("__name__", boxStrConstant("member")); member_cls->giveAttr("__name__", boxStrConstant("member"));
member_cls->giveAttr("__get__", new BoxedFunction(boxRTFunction((void*)memberGet, UNKNOWN, 3))); member_cls->giveAttr("__get__", new BoxedFunction(boxRTFunction((void*)memberGet, UNKNOWN, 3)));
...@@ -83,6 +121,23 @@ void setupDescr() { ...@@ -83,6 +121,23 @@ void setupDescr() {
property_cls->giveAttr("__set__", property_cls->giveAttr("__set__",
new BoxedFunction(boxRTFunction((void*)propertySet, UNKNOWN, 3, 0, false, false))); new BoxedFunction(boxRTFunction((void*)propertySet, UNKNOWN, 3, 0, false, false)));
property_cls->freeze(); property_cls->freeze();
staticmethod_cls->giveAttr("__name__", boxStrConstant("staticmethod"));
staticmethod_cls->giveAttr("__new__",
new BoxedFunction(boxRTFunction((void*)staticmethodNew, UNKNOWN, 5, 4, false, false),
{ None, None, None, None }));
staticmethod_cls->giveAttr("__get__",
new BoxedFunction(boxRTFunction((void*)staticmethodGet, UNKNOWN, 3, 0, false, false)));
staticmethod_cls->freeze();
classmethod_cls->giveAttr("__name__", boxStrConstant("classmethod"));
classmethod_cls->giveAttr("__new__",
new BoxedFunction(boxRTFunction((void*)classmethodNew, UNKNOWN, 5, 4, false, false),
{ None, None, None, None }));
classmethod_cls->giveAttr("__get__",
new BoxedFunction(boxRTFunction((void*)classmethodGet, UNKNOWN, 3, 0, false, false)));
classmethod_cls->freeze();
} }
void teardownDescr() { void teardownDescr() {
......
...@@ -666,40 +666,108 @@ Box* typeLookup(BoxedClass* cls, const std::string& attr, GetattrRewriteArgs* re ...@@ -666,40 +666,108 @@ Box* typeLookup(BoxedClass* cls, const std::string& attr, GetattrRewriteArgs* re
} }
bool isNondataDescriptorInstanceSpecialCase(Box* descr) { bool isNondataDescriptorInstanceSpecialCase(Box* descr) {
return descr->cls == function_cls || descr->cls == method_cls; return descr->cls == function_cls || descr->cls == instancemethod_cls || descr->cls == staticmethod_cls
|| descr->cls == classmethod_cls;
} }
Box* nondataDescriptorInstanceSpecialCases(GetattrRewriteArgs* rewrite_args, Box* obj, Box* descr, RewriterVar* r_descr, Box* nondataDescriptorInstanceSpecialCases(GetattrRewriteArgs* rewrite_args, Box* obj, Box* descr, RewriterVar* r_descr,
bool for_call, bool* should_bind_out) { bool for_call, Box** bind_obj_out, RewriterVar** r_bind_obj_out) {
// Special case: non-data descriptor: function // Special case: non-data descriptor: function, instancemethod or classmethod
if (descr->cls == function_cls || descr->cls == method_cls) { // Returns a bound instancemethod
if (descr->cls == function_cls || descr->cls == instancemethod_cls || descr->cls == classmethod_cls) {
Box* im_self = NULL, * im_func = NULL;
RewriterVar* r_im_self = NULL, * r_im_func = NULL;
if (descr->cls == function_cls) {
im_self = obj;
im_func = descr;
if (rewrite_args) {
r_im_self = rewrite_args->obj;
r_im_func = r_descr;
}
} else if (descr->cls == classmethod_cls) {
static StatCounter slowpath("slowpath_classmethod_get");
slowpath.log();
BoxedClassmethod* cm = static_cast<BoxedClassmethod*>(descr);
im_self = obj->cls;
if (cm->cm_callable == NULL) {
raiseExcHelper(RuntimeError, "uninitialized classmethod object");
}
im_func = cm->cm_callable;
if (rewrite_args) {
r_im_self = rewrite_args->obj->getAttr(BOX_CLS_OFFSET);
r_im_func = r_descr->getAttr(offsetof(BoxedClassmethod, cm_callable));
r_im_func->addGuardNotEq(0);
}
} else if (descr->cls == instancemethod_cls) {
static StatCounter slowpath("slowpath_instancemethod_get");
slowpath.log();
BoxedInstanceMethod* im = static_cast<BoxedInstanceMethod*>(descr);
if (im->obj != NULL) {
if (rewrite_args) {
r_descr->addAttrGuard(offsetof(BoxedInstanceMethod, obj), 0, /* negate */ true);
}
return descr;
} else {
// TODO subclass check
im_self = obj;
im_func = im->func;
if (rewrite_args) {
r_descr->addAttrGuard(offsetof(BoxedInstanceMethod, obj), 0, /* negate */ false);
r_im_self = rewrite_args->obj;
r_im_func = r_descr->getAttr(offsetof(BoxedInstanceMethod, func));
}
}
} else {
assert(false);
}
if (!for_call) { if (!for_call) {
if (rewrite_args) { if (rewrite_args) {
// can't guard after because we make this call... the call is trivial enough
// that we can probably work around it if it's important, but otherwise, if
// this triggers, just abort rewriting, I guess
rewrite_args->out_rtn rewrite_args->out_rtn
= rewrite_args->rewriter->call(false, (void*)boxInstanceMethod, rewrite_args->obj, r_descr); = rewrite_args->rewriter->call(false, (void*)boxInstanceMethod, r_im_self, r_im_func);
rewrite_args->out_success = true; rewrite_args->out_success = true;
} }
return boxInstanceMethod(obj, descr); return boxInstanceMethod(im_self, im_func);
} else { } else {
*bind_obj_out = im_self;
if (rewrite_args) { if (rewrite_args) {
rewrite_args->out_rtn = r_descr; rewrite_args->out_rtn = r_im_func;
rewrite_args->out_success = true; rewrite_args->out_success = true;
*r_bind_obj_out = r_im_self;
} }
*should_bind_out = true; return im_func;
return descr;
} }
} }
else if (descr->cls == staticmethod_cls) {
static StatCounter slowpath("slowpath_staticmethod_get");
slowpath.log();
BoxedStaticmethod* sm = static_cast<BoxedStaticmethod*>(descr);
if (sm->sm_callable == NULL) {
raiseExcHelper(RuntimeError, "uninitialized staticmethod object");
}
if (rewrite_args) {
RewriterVar* r_sm_callable = r_descr->getAttr(offsetof(BoxedStaticmethod, sm_callable));
r_sm_callable->addGuardNotEq(0);
rewrite_args->out_success = true;
rewrite_args->out_rtn = r_sm_callable;
}
return sm->sm_callable;
}
return NULL; return NULL;
} }
Box* descriptorClsSpecialCases(GetattrRewriteArgs* rewrite_args, BoxedClass* cls, Box* descr, RewriterVar* r_descr, Box* descriptorClsSpecialCases(GetattrRewriteArgs* rewrite_args, BoxedClass* cls, Box* descr, RewriterVar* r_descr,
bool for_call, bool* should_bind_out) { bool for_call, Box** bind_obj_out, RewriterVar** r_bind_obj_out) {
// Special case: functions // Special case: functions
if (descr->cls == function_cls || descr->cls == method_cls) { if (descr->cls == function_cls || descr->cls == instancemethod_cls) {
if (rewrite_args) if (rewrite_args)
r_descr->addAttrGuard(BOX_CLS_OFFSET, (uint64_t)descr->cls); r_descr->addAttrGuard(BOX_CLS_OFFSET, (uint64_t)descr->cls);
...@@ -716,7 +784,6 @@ Box* descriptorClsSpecialCases(GetattrRewriteArgs* rewrite_args, BoxedClass* cls ...@@ -716,7 +784,6 @@ Box* descriptorClsSpecialCases(GetattrRewriteArgs* rewrite_args, BoxedClass* cls
rewrite_args->out_success = true; rewrite_args->out_success = true;
rewrite_args->out_rtn = r_descr; rewrite_args->out_rtn = r_descr;
} }
// leave should_bind_out set to false
return descr; return descr;
} }
...@@ -764,7 +831,8 @@ static Box* boxStringFromCharPtr(const char* s) { ...@@ -764,7 +831,8 @@ static Box* boxStringFromCharPtr(const char* s) {
} }
Box* dataDescriptorInstanceSpecialCases(GetattrRewriteArgs* rewrite_args, const std::string& attr_name, Box* obj, Box* dataDescriptorInstanceSpecialCases(GetattrRewriteArgs* rewrite_args, const std::string& attr_name, Box* obj,
Box* descr, RewriterVar* r_descr, bool for_call, bool* should_bind_out) { Box* descr, RewriterVar* r_descr, bool for_call, Box** bind_obj_out,
RewriterVar** r_bind_obj_out) {
// Special case: data descriptor: member descriptor // Special case: data descriptor: member descriptor
if (descr->cls == member_cls) { if (descr->cls == member_cls) {
static StatCounter slowpath("slowpath_member_descriptor_get"); static StatCounter slowpath("slowpath_member_descriptor_get");
...@@ -908,7 +976,7 @@ Box* dataDescriptorInstanceSpecialCases(GetattrRewriteArgs* rewrite_args, const ...@@ -908,7 +976,7 @@ Box* dataDescriptorInstanceSpecialCases(GetattrRewriteArgs* rewrite_args, const
inline Box* getclsattr_internal(Box* obj, const std::string& attr, GetattrRewriteArgs* rewrite_args) { inline Box* getclsattr_internal(Box* obj, const std::string& attr, GetattrRewriteArgs* rewrite_args) {
return getattrInternalGeneral(obj, attr, rewrite_args, return getattrInternalGeneral(obj, attr, rewrite_args,
/* cls_only */ true, /* cls_only */ true,
/* for_call */ false, NULL); /* for_call */ false, NULL, NULL);
} }
extern "C" Box* getclsattr(Box* obj, const char* attr) { extern "C" Box* getclsattr(Box* obj, const char* attr) {
...@@ -976,9 +1044,9 @@ static Box* (*runtimeCall3)(Box*, ArgPassSpec, Box*, Box*, Box*) ...@@ -976,9 +1044,9 @@ static Box* (*runtimeCall3)(Box*, ArgPassSpec, Box*, Box*, Box*)
= (Box * (*)(Box*, ArgPassSpec, Box*, Box*, Box*))runtimeCall; = (Box * (*)(Box*, ArgPassSpec, Box*, Box*, Box*))runtimeCall;
Box* getattrInternalGeneral(Box* obj, const std::string& attr, GetattrRewriteArgs* rewrite_args, bool cls_only, Box* getattrInternalGeneral(Box* obj, const std::string& attr, GetattrRewriteArgs* rewrite_args, bool cls_only,
bool for_call, bool* should_bind_out) { bool for_call, Box** bind_obj_out, RewriterVar** r_bind_obj_out) {
if (for_call) { if (for_call) {
*should_bind_out = false; *bind_obj_out = NULL;
} }
if (obj->cls == closure_cls) { if (obj->cls == closure_cls) {
...@@ -1072,8 +1140,8 @@ Box* getattrInternalGeneral(Box* obj, const std::string& attr, GetattrRewriteArg ...@@ -1072,8 +1140,8 @@ Box* getattrInternalGeneral(Box* obj, const std::string& attr, GetattrRewriteArg
r_descr->addAttrGuard(BOX_CLS_OFFSET, (uint64_t)descr->cls); r_descr->addAttrGuard(BOX_CLS_OFFSET, (uint64_t)descr->cls);
// Special-case data descriptors (e.g., member descriptors) // Special-case data descriptors (e.g., member descriptors)
Box* res Box* res = dataDescriptorInstanceSpecialCases(rewrite_args, attr, obj, descr, r_descr, for_call, bind_obj_out,
= dataDescriptorInstanceSpecialCases(rewrite_args, attr, obj, descr, r_descr, for_call, should_bind_out); r_bind_obj_out);
if (res) { if (res) {
return res; return res;
} }
...@@ -1192,7 +1260,7 @@ Box* getattrInternalGeneral(Box* obj, const std::string& attr, GetattrRewriteArg ...@@ -1192,7 +1260,7 @@ Box* getattrInternalGeneral(Box* obj, const std::string& attr, GetattrRewriteArg
if (val) { if (val) {
Box* res = descriptorClsSpecialCases(rewrite_args, static_cast<BoxedClass*>(obj), val, r_val, for_call, Box* res = descriptorClsSpecialCases(rewrite_args, static_cast<BoxedClass*>(obj), val, r_val, for_call,
should_bind_out); bind_obj_out, r_bind_obj_out);
if (res) { if (res) {
return res; return res;
} }
...@@ -1252,7 +1320,8 @@ Box* getattrInternalGeneral(Box* obj, const std::string& attr, GetattrRewriteArg ...@@ -1252,7 +1320,8 @@ Box* getattrInternalGeneral(Box* obj, const std::string& attr, GetattrRewriteArg
// If descr and __get__ exist, then call __get__ // If descr and __get__ exist, then call __get__
if (descr) { if (descr) {
// Special cases first // Special cases first
Box* res = nondataDescriptorInstanceSpecialCases(rewrite_args, obj, descr, r_descr, for_call, should_bind_out); Box* res = nondataDescriptorInstanceSpecialCases(rewrite_args, obj, descr, r_descr, for_call, bind_obj_out,
r_bind_obj_out);
if (res) { if (res) {
return res; return res;
} }
...@@ -1318,7 +1387,7 @@ Box* getattrInternalGeneral(Box* obj, const std::string& attr, GetattrRewriteArg ...@@ -1318,7 +1387,7 @@ Box* getattrInternalGeneral(Box* obj, const std::string& attr, GetattrRewriteArg
Box* getattrInternal(Box* obj, const std::string& attr, GetattrRewriteArgs* rewrite_args) { Box* getattrInternal(Box* obj, const std::string& attr, GetattrRewriteArgs* rewrite_args) {
return getattrInternalGeneral(obj, attr, rewrite_args, return getattrInternalGeneral(obj, attr, rewrite_args,
/* cls_only */ false, /* cls_only */ false,
/* for_call */ false, NULL); /* for_call */ false, NULL, NULL);
} }
extern "C" Box* getattr(Box* obj, const char* attr) { extern "C" Box* getattr(Box* obj, const char* attr) {
...@@ -1826,26 +1895,27 @@ extern "C" Box* callattrInternal(Box* obj, const std::string* attr, LookupScope ...@@ -1826,26 +1895,27 @@ extern "C" Box* callattrInternal(Box* obj, const std::string* attr, LookupScope
// Look up the argument. Pass in the arguments to getattrInternalGeneral or getclsattr_general // Look up the argument. Pass in the arguments to getattrInternalGeneral or getclsattr_general
// that will shortcut functions by not putting them into instancemethods // that will shortcut functions by not putting them into instancemethods
bool should_bind; Box* bind_obj;
RewriterVar* r_bind_obj;
Box* val; Box* val;
RewriterVar* r_val = NULL; RewriterVar* r_val = NULL;
if (rewrite_args) { if (rewrite_args) {
GetattrRewriteArgs grewrite_args(rewrite_args->rewriter, rewrite_args->obj, Location::any()); GetattrRewriteArgs grewrite_args(rewrite_args->rewriter, rewrite_args->obj, Location::any());
val = getattrInternalGeneral(obj, *attr, &grewrite_args, scope == CLASS_ONLY, true, &should_bind); val = getattrInternalGeneral(obj, *attr, &grewrite_args, scope == CLASS_ONLY, true, &bind_obj, &r_bind_obj);
if (!grewrite_args.out_success) { if (!grewrite_args.out_success) {
rewrite_args = NULL; rewrite_args = NULL;
} else if (val) { } else if (val) {
r_val = grewrite_args.out_rtn; r_val = grewrite_args.out_rtn;
} }
} else { } else {
val = getattrInternalGeneral(obj, *attr, NULL, scope == CLASS_ONLY, true, &should_bind); val = getattrInternalGeneral(obj, *attr, NULL, scope == CLASS_ONLY, true, &bind_obj, &r_bind_obj);
} }
if (val == NULL) { if (val == NULL) {
return val; return val;
} }
if (should_bind) { if (bind_obj != NULL) {
if (rewrite_args) { if (rewrite_args) {
r_val->addGuard((int64_t)val); r_val->addGuard((int64_t)val);
} }
...@@ -1857,7 +1927,7 @@ extern "C" Box* callattrInternal(Box* obj, const std::string* attr, LookupScope ...@@ -1857,7 +1927,7 @@ extern "C" Box* callattrInternal(Box* obj, const std::string* attr, LookupScope
Box* rtn; Box* rtn;
if (rewrite_args) { if (rewrite_args) {
CallRewriteArgs srewrite_args(rewrite_args->rewriter, r_val, rewrite_args->destination); CallRewriteArgs srewrite_args(rewrite_args->rewriter, r_val, rewrite_args->destination);
srewrite_args.arg1 = rewrite_args->obj; srewrite_args.arg1 = r_bind_obj;
// should be no-ops: // should be no-ops:
if (npassed_args >= 1) if (npassed_args >= 1)
...@@ -1870,7 +1940,7 @@ extern "C" Box* callattrInternal(Box* obj, const std::string* attr, LookupScope ...@@ -1870,7 +1940,7 @@ extern "C" Box* callattrInternal(Box* obj, const std::string* attr, LookupScope
rtn = runtimeCallInternal(val, &srewrite_args, ArgPassSpec(argspec.num_args + 1, argspec.num_keywords, rtn = runtimeCallInternal(val, &srewrite_args, ArgPassSpec(argspec.num_args + 1, argspec.num_keywords,
argspec.has_starargs, argspec.has_kwargs), argspec.has_starargs, argspec.has_kwargs),
obj, arg1, arg2, NULL, keyword_names); bind_obj, arg1, arg2, NULL, keyword_names);
if (!srewrite_args.out_success) { if (!srewrite_args.out_success) {
rewrite_args = NULL; rewrite_args = NULL;
...@@ -1880,7 +1950,7 @@ extern "C" Box* callattrInternal(Box* obj, const std::string* attr, LookupScope ...@@ -1880,7 +1950,7 @@ extern "C" Box* callattrInternal(Box* obj, const std::string* attr, LookupScope
} else { } else {
rtn = runtimeCallInternal(val, NULL, ArgPassSpec(argspec.num_args + 1, argspec.num_keywords, rtn = runtimeCallInternal(val, NULL, ArgPassSpec(argspec.num_args + 1, argspec.num_keywords,
argspec.has_starargs, argspec.has_kwargs), argspec.has_starargs, argspec.has_kwargs),
obj, arg1, arg2, NULL, keyword_names); bind_obj, arg1, arg2, NULL, keyword_names);
} }
if (rewrite_args) if (rewrite_args)
...@@ -1896,7 +1966,7 @@ extern "C" Box* callattrInternal(Box* obj, const std::string* attr, LookupScope ...@@ -1896,7 +1966,7 @@ extern "C" Box* callattrInternal(Box* obj, const std::string* attr, LookupScope
Box* rtn; Box* rtn;
if (rewrite_args) { if (rewrite_args) {
CallRewriteArgs srewrite_args(rewrite_args->rewriter, r_val, rewrite_args->destination); CallRewriteArgs srewrite_args(rewrite_args->rewriter, r_val, rewrite_args->destination);
srewrite_args.arg1 = rewrite_args->obj; srewrite_args.arg1 = r_bind_obj;
srewrite_args.arg2 = rewrite_args->arg1; srewrite_args.arg2 = rewrite_args->arg1;
srewrite_args.arg3 = rewrite_args->arg2; srewrite_args.arg3 = rewrite_args->arg2;
srewrite_args.args = rewrite_args->rewriter->allocateAndCopyPlus1( srewrite_args.args = rewrite_args->rewriter->allocateAndCopyPlus1(
...@@ -1907,7 +1977,7 @@ extern "C" Box* callattrInternal(Box* obj, const std::string* attr, LookupScope ...@@ -1907,7 +1977,7 @@ extern "C" Box* callattrInternal(Box* obj, const std::string* attr, LookupScope
rtn = runtimeCallInternal(val, &srewrite_args, ArgPassSpec(argspec.num_args + 1, argspec.num_keywords, rtn = runtimeCallInternal(val, &srewrite_args, ArgPassSpec(argspec.num_args + 1, argspec.num_keywords,
argspec.has_starargs, argspec.has_kwargs), argspec.has_starargs, argspec.has_kwargs),
obj, arg1, arg2, new_args, keyword_names); bind_obj, arg1, arg2, new_args, keyword_names);
if (!srewrite_args.out_success) { if (!srewrite_args.out_success) {
rewrite_args = NULL; rewrite_args = NULL;
...@@ -1919,7 +1989,7 @@ extern "C" Box* callattrInternal(Box* obj, const std::string* attr, LookupScope ...@@ -1919,7 +1989,7 @@ extern "C" Box* callattrInternal(Box* obj, const std::string* attr, LookupScope
} else { } else {
rtn = runtimeCallInternal(val, NULL, ArgPassSpec(argspec.num_args + 1, argspec.num_keywords, rtn = runtimeCallInternal(val, NULL, ArgPassSpec(argspec.num_args + 1, argspec.num_keywords,
argspec.has_starargs, argspec.has_kwargs), argspec.has_starargs, argspec.has_kwargs),
obj, arg1, arg2, new_args, keyword_names); bind_obj, arg1, arg2, new_args, keyword_names);
} }
return rtn; return rtn;
} }
......
...@@ -105,7 +105,7 @@ struct CompareRewriteArgs; ...@@ -105,7 +105,7 @@ struct CompareRewriteArgs;
Box* compareInternal(Box* lhs, Box* rhs, int op_type, CompareRewriteArgs* rewrite_args); Box* compareInternal(Box* lhs, Box* rhs, int op_type, CompareRewriteArgs* rewrite_args);
Box* getattrInternal(Box* obj, const std::string& attr, GetattrRewriteArgs* rewrite_args); Box* getattrInternal(Box* obj, const std::string& attr, GetattrRewriteArgs* rewrite_args);
Box* getattrInternalGeneral(Box* obj, const std::string& attr, GetattrRewriteArgs* rewrite_args, bool cls_only, Box* getattrInternalGeneral(Box* obj, const std::string& attr, GetattrRewriteArgs* rewrite_args, bool cls_only,
bool for_call, bool* should_bind_out); bool for_call, Box** bind_obj_out, RewriterVar** r_bind_obj_out);
Box* typeLookup(BoxedClass* cls, const std::string& attr, GetattrRewriteArgs* rewrite_args); Box* typeLookup(BoxedClass* cls, const std::string& attr, GetattrRewriteArgs* rewrite_args);
......
...@@ -213,6 +213,33 @@ extern "C" void instancemethodGCHandler(GCVisitor* v, Box* b) { ...@@ -213,6 +213,33 @@ extern "C" void instancemethodGCHandler(GCVisitor* v, Box* b) {
v->visit(im->func); v->visit(im->func);
} }
extern "C" void propertyGCHandler(GCVisitor* v, Box* b) {
BoxedProperty* prop = (BoxedProperty*)b;
if (prop->prop_get)
v->visit(prop->prop_get);
if (prop->prop_set)
v->visit(prop->prop_set);
if (prop->prop_del)
v->visit(prop->prop_del);
if (prop->prop_doc)
v->visit(prop->prop_doc);
}
extern "C" void staticmethodGCHandler(GCVisitor* v, Box* b) {
BoxedStaticmethod* sm = (BoxedStaticmethod*)b;
if (sm->sm_callable)
v->visit(sm->sm_callable);
}
extern "C" void classmethodGCHandler(GCVisitor* v, Box* b) {
BoxedClassmethod* cm = (BoxedClassmethod*)b;
if (cm->cm_callable)
v->visit(cm->cm_callable);
}
// This probably belongs in list.cpp? // This probably belongs in list.cpp?
extern "C" void listGCHandler(GCVisitor* v, Box* b) { extern "C" void listGCHandler(GCVisitor* v, Box* b) {
boxGCHandler(v, b); boxGCHandler(v, b);
...@@ -291,7 +318,8 @@ extern "C" void closureGCHandler(GCVisitor* v, Box* b) { ...@@ -291,7 +318,8 @@ extern "C" void closureGCHandler(GCVisitor* v, Box* b) {
extern "C" { extern "C" {
BoxedClass* object_cls, *type_cls, *none_cls, *bool_cls, *int_cls, *float_cls, *str_cls, *function_cls, BoxedClass* object_cls, *type_cls, *none_cls, *bool_cls, *int_cls, *float_cls, *str_cls, *function_cls,
*instancemethod_cls, *list_cls, *slice_cls, *module_cls, *dict_cls, *tuple_cls, *file_cls, *member_cls, *instancemethod_cls, *list_cls, *slice_cls, *module_cls, *dict_cls, *tuple_cls, *file_cls, *member_cls,
*closure_cls, *generator_cls, *complex_cls, *basestring_cls, *unicode_cls, *property_cls; *closure_cls, *generator_cls, *complex_cls, *basestring_cls, *unicode_cls, *property_cls, *staticmethod_cls,
*classmethod_cls;
BoxedTuple* EmptyTuple; BoxedTuple* EmptyTuple;
...@@ -437,6 +465,18 @@ extern "C" Box* sliceNew(Box* cls, Box* start, Box* stop, Box** args) { ...@@ -437,6 +465,18 @@ extern "C" Box* sliceNew(Box* cls, Box* start, Box* stop, Box** args) {
return createSlice(start, stop, step); return createSlice(start, stop, step);
} }
Box* instancemethodGet(BoxedInstanceMethod* self, Box* obj, Box* type) {
RELEASE_ASSERT(self->cls == instancemethod_cls, "");
if (self->obj != NULL) {
return self;
}
// TODO subclass test
return new BoxedInstanceMethod(obj, self->func);
}
Box* instancemethodRepr(BoxedInstanceMethod* self) { Box* instancemethodRepr(BoxedInstanceMethod* self) {
if (self->obj) if (self->obj)
return boxStrConstant("<bound instancemethod object>"); return boxStrConstant("<bound instancemethod object>");
...@@ -700,7 +740,10 @@ void setupRuntime() { ...@@ -700,7 +740,10 @@ void setupRuntime() {
member_cls = new BoxedClass(type_cls, object_cls, NULL, 0, sizeof(BoxedMemberDescriptor), false); member_cls = new BoxedClass(type_cls, object_cls, NULL, 0, sizeof(BoxedMemberDescriptor), false);
closure_cls = new BoxedClass(type_cls, object_cls, &closureGCHandler, offsetof(BoxedClosure, attrs), closure_cls = new BoxedClass(type_cls, object_cls, &closureGCHandler, offsetof(BoxedClosure, attrs),
sizeof(BoxedClosure), false); sizeof(BoxedClosure), false);
property_cls = new BoxedClass(type_cls, object_cls, NULL, 0, sizeof(BoxedProperty), false); property_cls = new BoxedClass(type_cls, object_cls, &propertyGCHandler, 0, sizeof(BoxedProperty), false);
staticmethod_cls
= new BoxedClass(type_cls, object_cls, &staticmethodGCHandler, 0, sizeof(BoxedStaticmethod), false);
classmethod_cls = new BoxedClass(type_cls, object_cls, &classmethodGCHandler, 0, sizeof(BoxedClassmethod), false);
attrwrapper_cls = new BoxedClass(type_cls, object_cls, &AttrWrapper::gcHandler, 0, sizeof(AttrWrapper), false); attrwrapper_cls = new BoxedClass(type_cls, object_cls, &AttrWrapper::gcHandler, 0, sizeof(AttrWrapper), false);
STR = typeFromClass(str_cls); STR = typeFromClass(str_cls);
...@@ -783,6 +826,8 @@ void setupRuntime() { ...@@ -783,6 +826,8 @@ void setupRuntime() {
instancemethod_cls->giveAttr("__name__", boxStrConstant("instancemethod")); instancemethod_cls->giveAttr("__name__", boxStrConstant("instancemethod"));
instancemethod_cls->giveAttr("__repr__", new BoxedFunction(boxRTFunction((void*)instancemethodRepr, STR, 1))); instancemethod_cls->giveAttr("__repr__", new BoxedFunction(boxRTFunction((void*)instancemethodRepr, STR, 1)));
instancemethod_cls->giveAttr("__eq__", new BoxedFunction(boxRTFunction((void*)instancemethodEq, UNKNOWN, 2))); instancemethod_cls->giveAttr("__eq__", new BoxedFunction(boxRTFunction((void*)instancemethodEq, UNKNOWN, 2)));
instancemethod_cls->giveAttr(
"__get__", new BoxedFunction(boxRTFunction((void*)instancemethodGet, UNKNOWN, 3, 0, false, false)));
instancemethod_cls->freeze(); instancemethod_cls->freeze();
slice_cls->giveAttr("__name__", boxStrConstant("slice")); slice_cls->giveAttr("__name__", boxStrConstant("slice"));
......
...@@ -80,7 +80,8 @@ Box* getSysStdout(); ...@@ -80,7 +80,8 @@ Box* getSysStdout();
extern "C" { extern "C" {
extern BoxedClass* object_cls, *type_cls, *bool_cls, *int_cls, *long_cls, *float_cls, *str_cls, *function_cls, extern BoxedClass* object_cls, *type_cls, *bool_cls, *int_cls, *long_cls, *float_cls, *str_cls, *function_cls,
*none_cls, *instancemethod_cls, *list_cls, *slice_cls, *module_cls, *dict_cls, *tuple_cls, *file_cls, *xrange_cls, *none_cls, *instancemethod_cls, *list_cls, *slice_cls, *module_cls, *dict_cls, *tuple_cls, *file_cls, *xrange_cls,
*member_cls, *method_cls, *closure_cls, *generator_cls, *complex_cls, *basestring_cls, *unicode_cls, *property_cls; *member_cls, *method_cls, *closure_cls, *generator_cls, *complex_cls, *basestring_cls, *unicode_cls, *property_cls,
*staticmethod_cls, *classmethod_cls;
} }
extern "C" { extern Box* None, *NotImplemented, *True, *False; } extern "C" { extern Box* None, *NotImplemented, *True, *False; }
extern "C" { extern "C" {
...@@ -404,6 +405,20 @@ public: ...@@ -404,6 +405,20 @@ public:
: Box(property_cls), prop_get(get), prop_set(set), prop_del(del), prop_doc(doc) {} : Box(property_cls), prop_get(get), prop_set(set), prop_del(del), prop_doc(doc) {}
}; };
class BoxedStaticmethod : public Box {
public:
Box* sm_callable;
BoxedStaticmethod(Box* callable) : Box(staticmethod_cls), sm_callable(callable){};
};
class BoxedClassmethod : public Box {
public:
Box* cm_callable;
BoxedClassmethod(Box* callable) : Box(classmethod_cls), cm_callable(callable){};
};
// TODO is there any particular reason to make this a Box, ie a python-level object? // TODO is there any particular reason to make this a Box, ie a python-level object?
class BoxedClosure : public Box { class BoxedClosure : public Box {
public: public:
......
# run_args: -n
# statcheck: noninit_count('slowpath_classmethod_get') <= 10
# statcheck: noninit_count('slowpath_staticmethod_get') <= 10
# statcheck: noninit_count('slowpath_instancemethod_get') <= 10
def _f_plain(self, a, b, c, d):
print 'in f', type(self), a, b, c, d
@staticmethod
def _g(a, b, c, d):
print 'in g', a, b, c, d
@classmethod
def _h(cls, a, b, c, d):
print 'in h', cls, a, b, c, d
class C(object):
f_plain = _f_plain
g = _g
h = _h
_f = C.f_plain
C.f = _f
def run():
c = C()
c.f(1, 2, 3, 4)
c.g(1, 2, 3, 4)
c.h(1, 2, 3, 4)
f1 = c.f
f1(1,2,3,4)
g1 = c.g
g1(1,2,3,4)
h1 = c.h
h1(1,2,3,4)
_f.__get__(c, C)(1,2,3,4)
_g.__get__(c, C)(1,2,3,4)
_h.__get__(c, C)(1,2,3,4)
for i in xrange(1000):
run()
class C(object):
@staticmethod
def f(a, b, c, d):
print a, b, c, d
@classmethod
def g(cls, a, b, c, d):
print cls, a, b, c, d
c = C()
c.f(1, 2, 3, 4)
c.g(5, 6, 7, 8)
C.f(9, 10, 11, 12)
C.f(13, 14, 15, 16)
@staticmethod
def f(a, b, c, d):
print a, b, c, d
@classmethod
def g(cls, a, b, c, d):
print cls, a, b, c, d
f.__get__(c, C)(17, 18, 19, 20)
g.__get__(c, C)(21, 22, 23, 24)
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