Commit 17cbc7ab authored by Kevin Modzelewski's avatar Kevin Modzelewski

Basic metaclass support

We actually had most of the base support in place; this commit just adds
the ability to specify a metaclass other than type_cls, and the ability
to determine which metaclass to use when defining a new class.

But just like how we have the base functionality to inherit from all the
builtin types but haven't updated all the functions yet, I bet there
are more places that assume the type of a class is always type_cls.
parent c13c53b7
......@@ -107,7 +107,7 @@ int LivenessAnalysis::getStringIndex(const std::string& s) {
}
LivenessAnalysis::LivenessAnalysis(CFG* cfg) : cfg(cfg) {
Timer _t("LivenessAnalysis()");
Timer _t("LivenessAnalysis()", 10);
for (CFGBlock* b : cfg->blocks) {
auto visitor = new LivenessBBVisitor(this); // livenessCache unique_ptr will delete it.
......@@ -122,7 +122,7 @@ LivenessAnalysis::LivenessAnalysis(CFG* cfg) : cfg(cfg) {
}
bool LivenessAnalysis::isLiveAtEnd(const std::string& name, CFGBlock* block) {
Timer _t("LivenessAnalysis()");
Timer _t("LivenessAnalysis()", 10);
if (name[0] != '#')
return true;
......@@ -310,7 +310,7 @@ void DefinednessBBAnalyzer::processBB(Map& starting, CFGBlock* block) const {
DefinednessAnalysis::DefinednessAnalysis(const SourceInfo::ArgNames& arg_names, CFG* cfg, ScopeInfo* scope_info)
: scope_info(scope_info) {
Timer _t("DefinednessAnalysis()");
Timer _t("DefinednessAnalysis()", 10);
results = computeFixedPoint(cfg, DefinednessBBAnalyzer(cfg, arg_names), false);
......@@ -344,7 +344,7 @@ const DefinednessAnalysis::RequiredSet& DefinednessAnalysis::getDefinedNamesAtEn
PhiAnalysis::PhiAnalysis(const SourceInfo::ArgNames& arg_names, CFG* cfg, LivenessAnalysis* liveness,
ScopeInfo* scope_info)
: definedness(arg_names, cfg, scope_info), liveness(liveness) {
Timer _t("PhiAnalysis()");
Timer _t("PhiAnalysis()", 10);
for (CFGBlock* block : cfg->blocks) {
RequiredSet required;
......
......@@ -146,7 +146,6 @@ public:
~RewriterVarUsage() {
if (!done_using) {
assert(std::uncaught_exception());
setDoneUsing();
}
}
......
......@@ -1334,27 +1334,25 @@ private:
ScopeInfo* scope_info = irstate->getSourceInfo()->scoping->getScopeInfoForNode(node);
assert(scope_info);
if (node->bases.size() == 0) {
printf("Warning: old-style class '%s' in file '%s' detected! Converting to a new-style class!\n",
node->name.c_str(), irstate->getSourceInfo()->parent_module->fn.c_str());
std::vector<CompilerVariable*> bases;
for (auto b : node->bases) {
CompilerVariable* base = evalExpr(b, exc_info);
bases.push_back(base);
}
AST_Name* base = new AST_Name();
base->id = "object";
base->ctx_type = AST_TYPE::Load;
node->bases.push_back(base);
CompilerVariable* _bases_tuple = makeTuple(bases);
for (auto b : bases) {
b->decvref(emitter);
}
RELEASE_ASSERT(node->bases.size() == 1, "");
ConcreteCompilerVariable* bases_tuple = _bases_tuple->makeConverted(emitter, _bases_tuple->getBoxType());
_bases_tuple->decvref(emitter);
std::vector<CompilerVariable*> decorators;
for (auto d : node->decorator_list) {
decorators.push_back(evalExpr(d, exc_info));
}
CompilerVariable* base = evalExpr(node->bases[0], exc_info);
ConcreteCompilerVariable* converted_base = base->makeConverted(emitter, base->getBoxType());
base->decvref(emitter);
CLFunction* cl = _wrapFunction(node, nullptr, node->body);
// TODO duplication with _createFunction:
......@@ -1380,7 +1378,7 @@ private:
llvm::Value* classobj
= emitter.createCall3(exc_info, g.funcs.createUserClass, embedConstantPtr(&node->name, g.llvm_str_type_ptr),
converted_base->getValue(), converted_attr_dict->getValue()).getInstruction();
bases_tuple->getValue(), converted_attr_dict->getValue()).getInstruction();
// Note: createuserClass is free to manufacture non-class objects
CompilerVariable* cls = new ConcreteCompilerVariable(UNKNOWN, classobj, true);
......
......@@ -54,6 +54,11 @@ struct ArgPassSpec {
assert(num_keywords <= MAX_KEYWORDS);
}
bool operator==(ArgPassSpec rhs) {
return has_starargs == rhs.has_starargs && has_kwargs == rhs.has_kwargs && num_keywords == rhs.num_keywords
&& num_args == rhs.num_args;
}
int totalPassed() { return num_args + num_keywords + (has_starargs ? 1 : 0) + (has_kwargs ? 1 : 0); }
uintptr_t asInt() const { return *reinterpret_cast<const uintptr_t*>(this); }
......@@ -431,7 +436,8 @@ public:
// will need to update this once we support tp_getattr-style overriding:
bool hasGenericGetattr() { return true; }
BoxedClass(BoxedClass* base, gcvisit_func gc_visit, int attrs_offset, int instance_size, bool is_user_defined);
BoxedClass(BoxedClass* metaclass, BoxedClass* base, gcvisit_func gc_visit, int attrs_offset, int instance_size,
bool is_user_defined);
void freeze() {
assert(!is_constant);
is_constant = true;
......
......@@ -32,14 +32,14 @@ private:
bool ended;
public:
Timer(const char* desc=NULL, long min_usec=-1);
Timer(const char* desc = NULL, long min_usec = -1);
~Timer();
void restart(const char* newdesc, long new_min_usec);
void restart(const char* newdesc=NULL);
void restart(const char* newdesc = NULL);
long end();
long split(const char* newdesc=NULL) {
long split(const char* newdesc = NULL) {
long rtn = end();
restart(newdesc);
return rtn;
......
......@@ -457,7 +457,8 @@ Box* exceptionRepr(Box* b) {
}
static BoxedClass* makeBuiltinException(BoxedClass* base, const char* name) {
BoxedClass* cls = new BoxedClass(base, NULL, offsetof(BoxedException, attrs), sizeof(BoxedException), false);
BoxedClass* cls
= new BoxedClass(type_cls, base, NULL, offsetof(BoxedException, attrs), sizeof(BoxedException), false);
cls->giveAttr("__name__", boxStrConstant(name));
// TODO these should be on the base Exception class:
......@@ -554,7 +555,7 @@ void setupBuiltins() {
builtins_module->giveAttr("None", None);
notimplemented_cls = new BoxedClass(object_cls, NULL, 0, sizeof(Box), false);
notimplemented_cls = new BoxedClass(type_cls, object_cls, NULL, 0, sizeof(Box), false);
notimplemented_cls->giveAttr("__name__", boxStrConstant("NotImplementedType"));
notimplemented_cls->giveAttr("__repr__", new BoxedFunction(boxRTFunction((void*)notimplementedRepr, STR, 1)));
notimplemented_cls->freeze();
......@@ -636,7 +637,7 @@ void setupBuiltins() {
builtins_module->giveAttr("issubclass", issubclass_obj);
enumerate_cls = new BoxedClass(object_cls, &BoxedEnumerate::gcHandler, 0, sizeof(BoxedEnumerate), false);
enumerate_cls = new BoxedClass(type_cls, object_cls, &BoxedEnumerate::gcHandler, 0, sizeof(BoxedEnumerate), false);
enumerate_cls->giveAttr("__name__", boxStrConstant("enumerate"));
enumerate_cls->giveAttr(
"__new__",
......
......@@ -126,7 +126,7 @@ void setupSys() {
sys_module->giveAttr("maxint", boxInt(PYSTON_INT_MAX));
sys_flags_cls = new BoxedClass(object_cls, BoxedSysFlags::gcHandler, 0, sizeof(BoxedSysFlags), false);
sys_flags_cls = new BoxedClass(type_cls, object_cls, BoxedSysFlags::gcHandler, 0, sizeof(BoxedSysFlags), false);
sys_flags_cls->giveAttr("__name__", boxStrConstant("flags"));
sys_flags_cls->giveAttr("__new__",
new BoxedFunction(boxRTFunction((void*)BoxedSysFlags::__new__, UNKNOWN, 1, 0, true, true)));
......
......@@ -521,7 +521,7 @@ BoxedModule* importTestExtension() {
}
void setupCAPI() {
capifunc_cls = new BoxedClass(object_cls, NULL, 0, sizeof(BoxedCApiFunction), false);
capifunc_cls = new BoxedClass(type_cls, object_cls, NULL, 0, sizeof(BoxedCApiFunction), false);
capifunc_cls->giveAttr("__name__", boxStrConstant("capifunc"));
capifunc_cls->giveAttr("__repr__",
......@@ -533,7 +533,7 @@ void setupCAPI() {
capifunc_cls->freeze();
method_cls = new BoxedClass(object_cls, NULL, 0, sizeof(BoxedMethodDescriptor), false);
method_cls = new BoxedClass(type_cls, object_cls, NULL, 0, sizeof(BoxedMethodDescriptor), false);
method_cls->giveAttr("__name__", boxStrConstant("method"));
method_cls->giveAttr("__call__", new BoxedFunction(boxRTFunction((void*)BoxedMethodDescriptor::__call__, UNKNOWN, 2,
0, true, true)));
......
......@@ -265,7 +265,7 @@ extern "C" void dictIteratorGCHandler(GCVisitor* v, Box* b) {
}
void setupDict() {
dict_iterator_cls = new BoxedClass(object_cls, &dictIteratorGCHandler, 0, sizeof(BoxedDict), false);
dict_iterator_cls = new BoxedClass(type_cls, object_cls, &dictIteratorGCHandler, 0, sizeof(BoxedDict), false);
dict_cls->giveAttr("__name__", boxStrConstant("dict"));
dict_cls->giveAttr("__len__", new BoxedFunction(boxRTFunction((void*)dictLen, BOXED_INT, 1)));
......
......@@ -179,7 +179,7 @@ extern "C" void generatorGCHandler(GCVisitor* v, Box* b) {
void setupGenerator() {
generator_cls = new BoxedClass(object_cls, &generatorGCHandler, offsetof(BoxedGenerator, attrs),
generator_cls = new BoxedClass(type_cls, object_cls, &generatorGCHandler, offsetof(BoxedGenerator, attrs),
sizeof(BoxedGenerator), false);
generator_cls->giveAttr("__name__", boxStrConstant("generator"));
generator_cls->giveAttr("__iter__",
......
......@@ -110,9 +110,9 @@ Box* xrangeIter(Box* self) {
}
void setupXrange() {
xrange_cls = new BoxedClass(object_cls, NULL, 0, sizeof(BoxedXrange), false);
xrange_cls = new BoxedClass(type_cls, object_cls, NULL, 0, sizeof(BoxedXrange), false);
xrange_cls->giveAttr("__name__", boxStrConstant("xrange"));
xrange_iterator_cls = new BoxedClass(object_cls, &BoxedXrangeIterator::xrangeIteratorGCHandler, 0,
xrange_iterator_cls = new BoxedClass(type_cls, object_cls, &BoxedXrangeIterator::xrangeIteratorGCHandler, 0,
sizeof(BoxedXrangeIterator), false);
xrange_iterator_cls->giveAttr("__name__", boxStrConstant("rangeiterator"));
......
......@@ -58,7 +58,7 @@ Box* seqiterNext(Box* s) {
}
void setupIter() {
seqiter_cls = new BoxedClass(object_cls, NULL, 0, sizeof(BoxedSeqIter), false);
seqiter_cls = new BoxedClass(type_cls, object_cls, NULL, 0, sizeof(BoxedSeqIter), false);
seqiter_cls->giveAttr("__name__", boxStrConstant("iterator"));
seqiter_cls->giveAttr("next", new BoxedFunction(boxRTFunction((void*)seqiterNext, UNKNOWN, 1)));
......
......@@ -558,7 +558,7 @@ Box* listEq(BoxedList* self, Box* rhs) {
}
void setupList() {
list_iterator_cls = new BoxedClass(object_cls, &listIteratorGCHandler, 0, sizeof(BoxedList), false);
list_iterator_cls = new BoxedClass(type_cls, object_cls, &listIteratorGCHandler, 0, sizeof(BoxedList), false);
list_cls->giveAttr("__name__", boxStrConstant("list"));
......
......@@ -381,10 +381,16 @@ extern "C" void checkUnpackingLength(i64 expected, i64 given) {
}
}
BoxedClass::BoxedClass(BoxedClass* base, gcvisit_func gc_visit, int attrs_offset, int instance_size,
bool is_user_defined)
: BoxVar(type_cls, 0), tp_basicsize(instance_size), tp_dealloc(NULL), base(base), gc_visit(gc_visit),
BoxedClass::BoxedClass(BoxedClass* metaclass, BoxedClass* base, gcvisit_func gc_visit, int attrs_offset,
int instance_size, bool is_user_defined)
: BoxVar(metaclass, 0), tp_basicsize(instance_size), tp_dealloc(NULL), base(base), gc_visit(gc_visit),
attrs_offset(attrs_offset), is_constant(false), is_user_defined(is_user_defined) {
if (metaclass == NULL) {
assert(type_cls == NULL);
} else {
assert(isSubclass(metaclass, type_cls));
}
assert(tp_dealloc == NULL);
if (gc_visit == NULL) {
......@@ -3196,6 +3202,66 @@ static void assertInitNone(Box* obj) {
}
}
Box* typeNew(Box* _cls, Box* arg1, Box* arg2, Box** _args) {
Box* arg3 = _args[0];
if (!isSubclass(_cls->cls, type_cls))
raiseExcHelper(TypeError, "type.__new__(X): X is not a type object (%s)", getTypeName(_cls)->c_str());
BoxedClass* cls = static_cast<BoxedClass*>(_cls);
RELEASE_ASSERT(isSubclass(cls, type_cls), "");
if (arg2 == NULL) {
assert(arg3 == NULL);
BoxedClass* rtn = arg1->cls;
return rtn;
}
RELEASE_ASSERT(arg3->cls == dict_cls, "%s", getTypeName(arg3)->c_str());
BoxedDict* attr_dict = static_cast<BoxedDict*>(arg3);
RELEASE_ASSERT(arg2->cls == tuple_cls, "");
BoxedTuple* bases = static_cast<BoxedTuple*>(arg2);
RELEASE_ASSERT(arg1->cls == str_cls, "");
BoxedString* name = static_cast<BoxedString*>(arg1);
BoxedClass* base;
if (bases->elts.size() == 0) {
printf("Warning: old style class detected\n");
base = object_cls;
} else {
RELEASE_ASSERT(bases->elts.size() == 1, "");
Box* _base = bases->elts[0];
RELEASE_ASSERT(_base->cls == type_cls, "");
base = static_cast<BoxedClass*>(_base);
}
BoxedClass* made;
if (base->instancesHaveAttrs()) {
made = new BoxedClass(cls, base, NULL, base->attrs_offset, base->tp_basicsize, true);
} else {
assert(base->tp_basicsize % sizeof(void*) == 0);
made = new BoxedClass(cls, base, NULL, base->tp_basicsize, base->tp_basicsize + sizeof(HCAttrs), true);
}
for (const auto& p : attr_dict->d) {
assert(p.first->cls == str_cls);
made->giveAttr(static_cast<BoxedString*>(p.first)->s, p.second);
}
if (made->getattr("__doc__") == NULL) {
made->giveAttr("__doc__", None);
}
// Note: make sure to do this after assigning the attrs, since it will overwrite any defined __name__
made->setattr("__name__", name, NULL);
return made;
}
Box* typeCallInternal(BoxedFunction* f, CallRewriteArgs* rewrite_args, ArgPassSpec argspec, Box* arg1, Box* arg2,
Box* arg3, Box** args, const std::vector<const std::string*>* keyword_names) {
int npassed_args = argspec.totalPassed();
......@@ -3203,21 +3269,38 @@ Box* typeCallInternal(BoxedFunction* f, CallRewriteArgs* rewrite_args, ArgPassSp
static StatCounter slowpath_typecall("slowpath_typecall");
slowpath_typecall.log();
// if (rewrite_args && VERBOSITY()) {
// printf("typeCallInternal: %d", rewrite_args->obj.getArgnum());
// if (npassed_args >= 1) printf(" %d", rewrite_args->arg1.getArgnum());
// if (npassed_args >= 2) printf(" %d", rewrite_args->arg2.getArgnum());
// if (npassed_args >= 3) printf(" %d", rewrite_args->arg3.getArgnum());
// if (npassed_args >= 4) printf(" %d", rewrite_args->args.getArgnum());
// printf("\n");
//}
// TODO shouldn't have to redo this argument handling here...
if (argspec.has_starargs) {
rewrite_args = NULL;
assert(argspec.num_args == 0); // doesn't need to be true, but assumed here
Box* starargs = arg1;
assert(starargs->cls == tuple_cls);
BoxedTuple* targs = static_cast<BoxedTuple*>(starargs);
int n = targs->elts.size();
if (n >= 1)
arg1 = targs->elts[0];
if (n >= 2)
arg2 = targs->elts[1];
if (n >= 3)
arg3 = targs->elts[2];
if (n >= 4)
args = &targs->elts[3];
argspec = ArgPassSpec(n);
}
Box* _cls = arg1;
RewriterVarUsage r_ccls(RewriterVarUsage::empty());
RewriterVarUsage r_new(RewriterVarUsage::empty());
RewriterVarUsage r_init(RewriterVarUsage::empty());
Box* new_attr, *init_attr;
if (rewrite_args) {
assert(!argspec.has_starargs);
assert(argspec.num_args > 0);
rewrite_args->obj.setDoneUsing();
// rewrite_args->rewriter->annotate(0);
// rewrite_args->rewriter->trap();
......@@ -3227,17 +3310,16 @@ Box* typeCallInternal(BoxedFunction* f, CallRewriteArgs* rewrite_args, ArgPassSp
r_ccls.addGuard((intptr_t)arg1);
}
Box* cls = arg1;
if (cls->cls != type_cls) {
if (!isSubclass(_cls->cls, type_cls)) {
raiseExcHelper(TypeError, "descriptor '__call__' requires a 'type' object but received an '%s'",
getTypeName(cls)->c_str());
getTypeName(_cls)->c_str());
}
BoxedClass* ccls = static_cast<BoxedClass*>(cls);
BoxedClass* cls = static_cast<BoxedClass*>(_cls);
if (rewrite_args) {
GetattrRewriteArgs grewrite_args(rewrite_args->rewriter, r_ccls.addUse(), rewrite_args->destination, true);
new_attr = typeLookup(ccls, _new_str, &grewrite_args);
new_attr = typeLookup(cls, _new_str, &grewrite_args);
if (!grewrite_args.out_success)
rewrite_args = NULL;
......@@ -3248,13 +3330,13 @@ Box* typeCallInternal(BoxedFunction* f, CallRewriteArgs* rewrite_args, ArgPassSp
}
}
} else {
new_attr = typeLookup(ccls, _new_str, NULL);
new_attr = typeLookup(cls, _new_str, NULL);
}
assert(new_attr && "This should always resolve");
if (rewrite_args) {
GetattrRewriteArgs grewrite_args(rewrite_args->rewriter, r_ccls.addUse(), rewrite_args->destination, true);
init_attr = typeLookup(ccls, _init_str, &grewrite_args);
init_attr = typeLookup(cls, _init_str, &grewrite_args);
if (!grewrite_args.out_success)
rewrite_args = NULL;
......@@ -3266,7 +3348,7 @@ Box* typeCallInternal(BoxedFunction* f, CallRewriteArgs* rewrite_args, ArgPassSp
rewrite_args->rewriter->setDoneGuarding();
}
} else {
init_attr = typeLookup(ccls, _init_str, NULL);
init_attr = typeLookup(cls, _init_str, NULL);
}
// The init_attr should always resolve as well, but doesn't yet
......@@ -3310,8 +3392,14 @@ Box* typeCallInternal(BoxedFunction* f, CallRewriteArgs* rewrite_args, ArgPassSp
}
assert(made);
// Special-case (also a special case in CPython): if we just called type.__new__(arg), don't call __init__
if (cls == type_cls && argspec == ArgPassSpec(2))
return made;
// If this is true, not supposed to call __init__:
RELEASE_ASSERT(made->cls == ccls, "allowed but unsupported");
RELEASE_ASSERT(made->cls == cls, "allowed but unsupported (%s vs %s)", getNameOfClass(made->cls)->c_str(),
getNameOfClass(cls)->c_str());
if (init_attr && init_attr != typeLookup(object_cls, _init_str, NULL)) {
Box* initrtn;
......@@ -3329,7 +3417,7 @@ Box* typeCallInternal(BoxedFunction* f, CallRewriteArgs* rewrite_args, ArgPassSp
srewrite_args.args_guarded = true;
srewrite_args.func_guarded = true;
// initrtn = callattrInternal(ccls, &_init_str, INST_ONLY, &srewrite_args, argspec, made, arg2, arg3, args,
// initrtn = callattrInternal(cls, &_init_str, INST_ONLY, &srewrite_args, argspec, made, arg2, arg3, args,
// keyword_names);
initrtn = runtimeCallInternal(init_attr, &srewrite_args, argspec, made, arg2, arg3, args, keyword_names);
......@@ -3340,14 +3428,12 @@ Box* typeCallInternal(BoxedFunction* f, CallRewriteArgs* rewrite_args, ArgPassSp
.setDoneUsing();
}
} else {
// initrtn = callattrInternal(ccls, &_init_str, INST_ONLY, NULL, argspec, made, arg2, arg3, args,
// initrtn = callattrInternal(cls, &_init_str, INST_ONLY, NULL, argspec, made, arg2, arg3, args,
// keyword_names);
initrtn = runtimeCallInternal(init_attr, NULL, argspec, made, arg2, arg3, args, keyword_names);
}
assertInitNone(initrtn);
} else {
// TODO this shouldn't be reached
// assert(0 && "I don't think this should be reached");
if (new_attr == NULL && npassed_args != 1) {
// TODO not npassed args, since the starargs or kwargs could be null
raiseExcHelper(TypeError, objectNewParameterTypeErrorMsg());
......@@ -3382,15 +3468,7 @@ Box* typeCall(Box* obj, BoxedList* vararg) {
else if (vararg->size == 2)
return typeCallInternal3(NULL, NULL, ArgPassSpec(3), obj, vararg->elts->elts[0], vararg->elts->elts[1]);
else
return typeCallInternal(NULL, NULL, ArgPassSpec(1 + vararg->size), obj, vararg->elts->elts[0],
vararg->elts->elts[1], &vararg->elts->elts[2], NULL);
}
Box* typeNew(Box* cls, Box* obj) {
assert(cls == type_cls);
BoxedClass* rtn = obj->cls;
return rtn;
abort();
}
extern "C" void delGlobal(BoxedModule* m, std::string* name) {
......
......@@ -118,7 +118,7 @@ extern "C" void raiseAttributeError(Box* obj, const char* attr) __attribute__((_
extern "C" void raiseNotIterableError(const char* typeName) __attribute__((__noreturn__));
Box* typeCall(Box*, BoxedList*);
Box* typeNew(Box*, Box*);
Box* typeNew(Box* cls, Box* arg1, Box* arg2, Box** _args);
bool isUserDefined(BoxedClass* cls);
Box* callCLFunc(CLFunction* f, CallRewriteArgs* rewrite_args, int num_output_args, BoxedClosure* closure,
......
......@@ -211,7 +211,7 @@ void setupSet() {
set_cls->giveAttr("__name__", boxStrConstant("set"));
frozenset_cls->giveAttr("__name__", boxStrConstant("frozenset"));
set_iterator_cls = new BoxedClass(object_cls, &setIteratorGCHandler, 0, sizeof(BoxedSet), false);
set_iterator_cls = new BoxedClass(type_cls, object_cls, &setIteratorGCHandler, 0, sizeof(BoxedSet), false);
set_iterator_cls->giveAttr("__name__", boxStrConstant("setiterator"));
set_iterator_cls->giveAttr("__hasnext__",
new BoxedFunction(boxRTFunction((void*)setiteratorHasnext, BOXED_BOOL, 1)));
......
......@@ -880,7 +880,7 @@ static PyBufferProcs string_as_buffer = {
};
void setupStr() {
str_iterator_cls = new BoxedClass(object_cls, &strIteratorGCHandler, 0, sizeof(BoxedString), false);
str_iterator_cls = new BoxedClass(type_cls, object_cls, &strIteratorGCHandler, 0, sizeof(BoxedString), false);
str_iterator_cls->giveAttr("__name__", boxStrConstant("striterator"));
str_iterator_cls->giveAttr("__hasnext__",
new BoxedFunction(boxRTFunction((void*)BoxedStringIterator::hasnext, BOXED_BOOL, 1)));
......
......@@ -353,7 +353,7 @@ extern "C" void tupleIteratorGCHandler(GCVisitor* v, Box* b) {
void setupTuple() {
tuple_iterator_cls = new BoxedClass(object_cls, &tupleIteratorGCHandler, 0, sizeof(BoxedTuple), false);
tuple_iterator_cls = new BoxedClass(type_cls, object_cls, &tupleIteratorGCHandler, 0, sizeof(BoxedTuple), false);
tuple_cls->giveAttr("__name__", boxStrConstant("tuple"));
......
......@@ -305,39 +305,38 @@ BoxedClass* object_cls, *type_cls, *none_cls, *bool_cls, *int_cls, *float_cls, *
BoxedTuple* EmptyTuple;
}
extern "C" Box* createUserClass(std::string* name, Box* _base, Box* _attr_dict) {
assert(_base);
assert(isSubclass(_base->cls, type_cls));
BoxedClass* base = static_cast<BoxedClass*>(_base);
extern "C" Box* createUserClass(std::string* name, Box* _bases, Box* _attr_dict) {
ASSERT(_attr_dict->cls == dict_cls, "%s", getTypeName(_attr_dict)->c_str());
BoxedDict* attr_dict = static_cast<BoxedDict*>(_attr_dict);
RELEASE_ASSERT(attr_dict->d.count(boxStrConstant("__metaclass__")) == 0, "metaclasses not supported yet");
assert(_bases->cls == tuple_cls);
BoxedTuple* bases = static_cast<BoxedTuple*>(_bases);
BoxedClass* made;
Box* metaclass = NULL;
metaclass = attr_dict->getOrNull(boxStrConstant("__metaclass__"));
if (base->instancesHaveAttrs()) {
made = new BoxedClass(base, NULL, base->attrs_offset, base->tp_basicsize, true);
if (metaclass != NULL) {
} else if (bases->elts.size() > 0) {
// TODO Apparently this is supposed to look up __class__, and if that throws
// an error, then look up ob_type (aka cls)
metaclass = bases->elts[0]->cls;
} else {
assert(base->tp_basicsize % sizeof(void*) == 0);
made = new BoxedClass(base, NULL, base->tp_basicsize, base->tp_basicsize + sizeof(HCAttrs), true);
}
for (const auto& p : attr_dict->d) {
assert(p.first->cls == str_cls);
made->giveAttr(static_cast<BoxedString*>(p.first)->s, p.second);
}
BoxedModule* m = getCurrentModule();
metaclass = m->getattr("__metaclass__");
if (made->getattr("__doc__") == NULL) {
made->giveAttr("__doc__", None);
if (!metaclass) {
printf("Warning: old style class detected\n");
metaclass = type_cls;
// Py_FatalError("Should default to an old-style class here");
}
}
assert(metaclass);
// Note: make sure to do this after assigning the attrs, since it will overwrite any defined __name__
made->setattr("__name__", boxString(*name), NULL);
BoxedClass* made;
return made;
Box* r = runtimeCall(metaclass, ArgPassSpec(3), boxStringPtr(name), _bases, _attr_dict, NULL, NULL);
RELEASE_ASSERT(r, "");
return r;
}
extern "C" Box* boxInstanceMethod(Box* obj, Box* func) {
......@@ -639,17 +638,17 @@ void setupRuntime() {
root_hcls = HiddenClass::makeRoot();
gc::registerPermanentRoot(root_hcls);
object_cls = new BoxedClass(NULL, &boxGCHandler, 0, sizeof(Box), false);
type_cls = new BoxedClass(object_cls, &typeGCHandler, offsetof(BoxedClass, attrs), sizeof(BoxedClass), false);
object_cls = new BoxedClass(NULL, NULL, &boxGCHandler, 0, sizeof(Box), false);
type_cls = new BoxedClass(NULL, object_cls, &typeGCHandler, offsetof(BoxedClass, attrs), sizeof(BoxedClass), false);
type_cls->cls = type_cls;
object_cls->cls = type_cls;
none_cls = new BoxedClass(object_cls, NULL, 0, sizeof(Box), false);
none_cls = new BoxedClass(type_cls, object_cls, NULL, 0, sizeof(Box), false);
None = new Box(none_cls);
gc::registerPermanentRoot(None);
// TODO we leak all the string data!
str_cls = new BoxedClass(object_cls, NULL, 0, sizeof(BoxedString), false);
str_cls = new BoxedClass(type_cls, object_cls, NULL, 0, sizeof(BoxedString), false);
// It wasn't safe to add __base__ attributes until object+type+str are set up, so do that now:
type_cls->giveAttr("__base__", object_cls);
......@@ -658,35 +657,36 @@ void setupRuntime() {
object_cls->giveAttr("__base__", None);
tuple_cls = new BoxedClass(object_cls, &tupleGCHandler, 0, sizeof(BoxedTuple), false);
tuple_cls = new BoxedClass(type_cls, object_cls, &tupleGCHandler, 0, sizeof(BoxedTuple), false);
EmptyTuple = new BoxedTuple({});
gc::registerPermanentRoot(EmptyTuple);
module_cls = new BoxedClass(object_cls, NULL, offsetof(BoxedModule, attrs), sizeof(BoxedModule), false);
module_cls = new BoxedClass(type_cls, object_cls, NULL, offsetof(BoxedModule, attrs), sizeof(BoxedModule), false);
// TODO it'd be nice to be able to do these in the respective setupType methods,
// but those setup methods probably want access to these objects.
// We could have a multi-stage setup process, but that seems overkill for now.
bool_cls = new BoxedClass(object_cls, NULL, 0, sizeof(BoxedBool), false);
int_cls = new BoxedClass(object_cls, NULL, 0, sizeof(BoxedInt), false);
complex_cls = new BoxedClass(object_cls, NULL, 0, sizeof(BoxedComplex), false);
bool_cls = new BoxedClass(type_cls, object_cls, NULL, 0, sizeof(BoxedBool), false);
int_cls = new BoxedClass(type_cls, object_cls, NULL, 0, sizeof(BoxedInt), false);
complex_cls = new BoxedClass(type_cls, object_cls, NULL, 0, sizeof(BoxedComplex), false);
// TODO we're leaking long memory!
long_cls = new BoxedClass(object_cls, NULL, 0, sizeof(BoxedLong), false);
float_cls = new BoxedClass(object_cls, NULL, 0, sizeof(BoxedFloat), false);
function_cls
= new BoxedClass(object_cls, &functionGCHandler, offsetof(BoxedFunction, attrs), sizeof(BoxedFunction), false);
instancemethod_cls = new BoxedClass(object_cls, &instancemethodGCHandler, 0, sizeof(BoxedInstanceMethod), false);
list_cls = new BoxedClass(object_cls, &listGCHandler, 0, sizeof(BoxedList), false);
slice_cls = new BoxedClass(object_cls, &sliceGCHandler, 0, sizeof(BoxedSlice), false);
dict_cls = new BoxedClass(object_cls, &dictGCHandler, 0, sizeof(BoxedDict), false);
file_cls = new BoxedClass(object_cls, NULL, 0, sizeof(BoxedFile), false);
set_cls = new BoxedClass(object_cls, &setGCHandler, 0, sizeof(BoxedSet), false);
frozenset_cls = new BoxedClass(object_cls, &setGCHandler, 0, sizeof(BoxedSet), false);
member_cls = new BoxedClass(object_cls, NULL, 0, sizeof(BoxedMemberDescriptor), false);
closure_cls
= new BoxedClass(object_cls, &closureGCHandler, offsetof(BoxedClosure, attrs), sizeof(BoxedClosure), false);
attrwrapper_cls = new BoxedClass(object_cls, &AttrWrapper::gcHandler, 0, sizeof(AttrWrapper), false);
long_cls = new BoxedClass(type_cls, object_cls, NULL, 0, sizeof(BoxedLong), false);
float_cls = new BoxedClass(type_cls, object_cls, NULL, 0, sizeof(BoxedFloat), false);
function_cls = new BoxedClass(type_cls, object_cls, &functionGCHandler, offsetof(BoxedFunction, attrs),
sizeof(BoxedFunction), false);
instancemethod_cls
= new BoxedClass(type_cls, object_cls, &instancemethodGCHandler, 0, sizeof(BoxedInstanceMethod), false);
list_cls = new BoxedClass(type_cls, object_cls, &listGCHandler, 0, sizeof(BoxedList), false);
slice_cls = new BoxedClass(type_cls, object_cls, &sliceGCHandler, 0, sizeof(BoxedSlice), false);
dict_cls = new BoxedClass(type_cls, object_cls, &dictGCHandler, 0, sizeof(BoxedDict), false);
file_cls = new BoxedClass(type_cls, object_cls, NULL, 0, sizeof(BoxedFile), false);
set_cls = new BoxedClass(type_cls, object_cls, &setGCHandler, 0, sizeof(BoxedSet), false);
frozenset_cls = new BoxedClass(type_cls, object_cls, &setGCHandler, 0, sizeof(BoxedSet), 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),
sizeof(BoxedClosure), false);
attrwrapper_cls = new BoxedClass(type_cls, object_cls, &AttrWrapper::gcHandler, 0, sizeof(AttrWrapper), false);
STR = typeFromClass(str_cls);
BOXED_INT = typeFromClass(int_cls);
......@@ -715,7 +715,8 @@ void setupRuntime() {
type_cls->giveAttr("__call__", new BoxedFunction(typeCallObj));
type_cls->giveAttr("__name__", boxStrConstant("type"));
type_cls->giveAttr("__new__", new BoxedFunction(boxRTFunction((void*)typeNew, UNKNOWN, 2)));
type_cls->giveAttr("__new__",
new BoxedFunction(boxRTFunction((void*)typeNew, UNKNOWN, 4, 2, false, false), { NULL, NULL }));
type_cls->giveAttr("__repr__", new BoxedFunction(boxRTFunction((void*)typeRepr, STR, 1)));
type_cls->giveAttr("__str__", type_cls->getattr("__repr__"));
type_cls->giveAttr("__hash__", new BoxedFunction(boxRTFunction((void*)typeHash, BOXED_INT, 1)));
......
......@@ -296,6 +296,13 @@ public:
DictMap d;
BoxedDict() __attribute__((visibility("default"))) : Box(dict_cls) {}
Box* getOrNull(Box* k) {
const auto& p = d.find(k);
if (p != d.end())
return p->second;
return NULL;
}
};
class BoxedFunction : public Box {
......
# expected: fail
# - metaclasses
# Metaclass test:
class M(type):
......
# expected: fail
# - metaclasses, inheritance
# This would make a good Python quiz:
sl = slice(1,2)
......
class MM(type):
def __new__(*args):
print "MM.__new__", args[:3]
return type.__new__(*args)
def __call__(*args):
print "MM.__call__", args[:3]
return type.__call__(*args)
print "Made MM", type(MM)
class M(type):
__metaclass__ = MM
def __new__(*args):
print "M.__new__", args[:3]
return type.__new__(*args)
def __call__(*args):
print "M.__call__", args[:3]
return type.__call__(*args)
print "Made M", type(M)
class C(object):
__metaclass__ = M
print "Made C", type(C)
def f(*args):
print "f()", args[:2]
class C(object):
# Metaclasses don't need to be type objects:
__metaclass__ = f
print C
print type.__call__(int, 1)
try:
type.__new__(1, 2, 3)
except TypeError, e:
print e
......@@ -35,7 +35,7 @@ IMAGE = "pyston_dbg"
KEEP_GOING = False
FN_JUST_SIZE = 20
EXTRA_JIT_ARGS = []
TIME_LIMIT = 2
TIME_LIMIT = 3
# For fun, can test pypy.
# Tough because the tester will check to see if the error messages are exactly the
......
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