Commit 53c2fadd authored by Kevin Modzelewski's avatar Kevin Modzelewski

Basic inheritance functionality

Python inheritance is remarkably complicated... this commit implements the basics.
There are still a fair number of things that are unimplemented, and some things
like inheriting from all the basic types haven't been added yet.
parent 02ff68f2
......@@ -201,6 +201,7 @@ public:
virtual bool visit_print(AST_Print* node) { return true; }
virtual bool visit_raise(AST_Raise* node) { return true; }
virtual bool visit_return(AST_Return* node) { return true; }
virtual bool visit_unreachable(AST_Unreachable* node) { return true; }
virtual bool visit_classdef(AST_ClassDef* node) {
_doSet(node->name);
......
......@@ -510,6 +510,8 @@ private:
}
}
virtual void visit_unreachable(AST_Unreachable* node) {}
public:
static void propagate(CFGBlock* block, const TypeMap& starting, TypeMap& ending, ExprTypeMap& expr_types,
TypeSpeculations& type_speculations, TypeAnalysis::SpeculationLevel speculation,
......
......@@ -138,7 +138,7 @@ RewriterVarUsage2 RewriterVarUsage2::getAttr(int offset, KillFlag kill, Location
assembler::Register this_reg = var->getInReg();
Rewriter2* rewriter = var->rewriter;
if (kill) {
if (kill == Kill) {
setDoneUsing();
}
......@@ -176,6 +176,7 @@ void RewriterVarUsage2::setDoneUsing() {
assertValid();
done_using = true;
var->decUse();
var = NULL;
}
RewriterVarUsage2::RewriterVarUsage2(RewriterVarUsage2&& usage) {
......
......@@ -141,10 +141,6 @@ public:
// semantically we have to pass the ownership of the use.
RewriterVarUsage2(RewriterVarUsage2&& usage);
RewriterVarUsage2& operator=(RewriterVarUsage2&& usage);
// assert(this->var == NULL)
// assert(this->done_using)
// assert(usage->var != NULL)
// assert(!usage->done_using)
static RewriterVarUsage2 empty();
......@@ -156,12 +152,6 @@ public:
#endif
void setDoneUsing();
// void setDoneUsing() {
// assert(!done_using);
// done_using = true;
//
// var->delUse();
//}
// RewriterVarUsage2 addUse() { return var->addUse(); }
RewriterVarUsage2 addUse();
......
......@@ -1306,6 +1306,11 @@ public:
virtual CompilerType* getattrType(const std::string* attr, bool cls_only) {
return BOXED_TUPLE->getattrType(attr, cls_only);
}
virtual CompilerVariable* callattr(IREmitter& emitter, const OpInfo& info, VAR* var, const std::string* attr,
bool clsonly, const std::vector<CompilerVariable*>& args) {
return makeConverted(emitter, var, getConcreteType())->callattr(emitter, info, attr, clsonly, args);
}
};
CompilerType* makeTupleType(const std::vector<CompilerType*>& elt_types) {
......
......@@ -1307,16 +1307,19 @@ private:
ScopeInfo* scope_info = irstate->getSourceInfo()->scoping->getScopeInfoForNode(node);
RELEASE_ASSERT(node->bases.size() == 1, "");
CompilerVariable* base = evalExpr(node->bases[0], exc_info);
ConcreteCompilerVariable* converted_base = base->makeConverted(emitter, base->getBoxType());
base->decvref(emitter);
llvm::Value* classobj
= emitter.createCall2(exc_info, g.funcs.createUserClass, embedConstantPtr(&node->name, g.llvm_str_type_ptr),
= emitter.createCall3(exc_info, g.funcs.createUserClass, embedConstantPtr(&node->name, g.llvm_str_type_ptr),
converted_base->getValue(),
embedConstantPtr(irstate->getSourceInfo()->parent_module, g.llvm_module_type_ptr))
.getInstruction();
ConcreteCompilerVariable* cls = new ConcreteCompilerVariable(typeFromClass(type_cls), classobj, true);
RELEASE_ASSERT(node->bases.size() == 1, "");
RELEASE_ASSERT(node->bases[0]->type == AST_TYPE::Name, "");
RELEASE_ASSERT(ast_cast<AST_Name>(node->bases[0])->id == "object", "");
// CompilerVariable* name = makeStr(&node->name);
// cls->setattr(emitter, "__name__", name);
// name->decvref(emitter);
......@@ -1820,6 +1823,10 @@ private:
case AST_TYPE::Raise:
doRaise(ast_cast<AST_Raise>(node), exc_info);
break;
case AST_TYPE::Unreachable:
emitter.getBuilder()->CreateUnreachable();
endBlock(FINISHED);
break;
default:
printf("Unhandled stmt type at " __FILE__ ":" STRINGIFY(__LINE__) ": %d\n", node->type);
exit(1);
......
......@@ -140,7 +140,10 @@ PatchpointSetupInfo* createSetattrPatchpoint(CompiledFunction* parent_cf, TypeRe
}
PatchpointSetupInfo* createCallsitePatchpoint(CompiledFunction* parent_cf, TypeRecorder* type_recorder, int num_args) {
return PatchpointSetupInfo::initialize(true, 3, 320 + 36 * num_args, parent_cf, Callsite, type_recorder);
// TODO These are very large, but could probably be made much smaller with IC optimizations
// - using rewriter2 for better code
// - not emitting duplicate guards
return PatchpointSetupInfo::initialize(true, 3, 480 + 48 * num_args, parent_cf, Callsite, type_recorder);
}
PatchpointSetupInfo* createGetGlobalPatchpoint(CompiledFunction* parent_cf, TypeRecorder* type_recorder) {
......@@ -148,7 +151,7 @@ PatchpointSetupInfo* createGetGlobalPatchpoint(CompiledFunction* parent_cf, Type
}
PatchpointSetupInfo* createBinexpPatchpoint(CompiledFunction* parent_cf, TypeRecorder* type_recorder) {
return PatchpointSetupInfo::initialize(true, 4, 256, parent_cf, Binexp, type_recorder);
return PatchpointSetupInfo::initialize(true, 4, 320, parent_cf, Binexp, type_recorder);
}
PatchpointSetupInfo* createNonzeroPatchpoint(CompiledFunction* parent_cf, TypeRecorder* type_recorder) {
......
......@@ -184,8 +184,6 @@ void initGlobalFuncs(GlobalState& g) {
GET(printFloat);
GET(listAppendInternal);
GET(dump);
g.funcs.runtimeCall = getFunc((void*)runtimeCall, "runtimeCall");
g.funcs.runtimeCall0 = addFunc((void*)runtimeCall, g.llvm_value_type_ptr, g.llvm_value_type_ptr, g.i64);
g.funcs.runtimeCall1
......
......@@ -33,7 +33,6 @@ struct GlobalFuncs {
llvm::Value* checkUnpackingLength, *raiseAttributeError, *raiseAttributeErrorStr, *raiseNotIterableError,
*assertNameDefined, *assertFail;
llvm::Value* printFloat, *listAppendInternal;
llvm::Value* dump;
llvm::Value* runtimeCall0, *runtimeCall1, *runtimeCall2, *runtimeCall3, *runtimeCall;
llvm::Value* callattr0, *callattr1, *callattr2, *callattr3, *callattr;
llvm::Value* reoptCompiledFunc, *compilePartialFunc;
......
......@@ -786,6 +786,16 @@ void* AST_UnaryOp::accept_expr(ExprVisitor* v) {
return v->visit_unaryop(this);
}
void AST_Unreachable::accept(ASTVisitor* v) {
bool skip = v->visit_unreachable(this);
if (skip)
return;
}
void AST_Unreachable::accept_stmt(StmtVisitor* v) {
v->visit_unreachable(this);
}
void AST_While::accept(ASTVisitor* v) {
bool skip = v->visit_while(this);
if (skip)
......@@ -1518,6 +1528,11 @@ bool PrintVisitor::visit_unaryop(AST_UnaryOp* node) {
return true;
}
bool PrintVisitor::visit_unreachable(AST_Unreachable* node) {
printf("<unreachable>");
return true;
}
bool PrintVisitor::visit_while(AST_While* node) {
printf("while ");
node->test->accept(this);
......@@ -1783,6 +1798,10 @@ public:
output->push_back(node);
return false;
}
virtual bool visit_unreachable(AST_Unreachable* node) {
output->push_back(node);
return false;
}
virtual bool visit_while(AST_While* node) {
output->push_back(node);
return false;
......
......@@ -124,6 +124,7 @@ enum AST_TYPE {
AugBinOp = 203,
Invoke = 204,
LangPrimitive = 205,
Unreachable = 206,
};
};
......@@ -857,6 +858,15 @@ public:
static const AST_TYPE::AST_TYPE TYPE = AST_TYPE::LangPrimitive;
};
class AST_Unreachable : public AST_stmt {
public:
virtual void accept(ASTVisitor* v);
virtual void accept_stmt(StmtVisitor* v);
AST_Unreachable() : AST_stmt(AST_TYPE::Unreachable) {}
static const AST_TYPE::AST_TYPE TYPE = AST_TYPE::Unreachable;
};
template <typename T> T* ast_cast(AST* node) {
assert(node->type == T::TYPE);
......@@ -919,6 +929,7 @@ public:
virtual bool visit_tryfinally(AST_TryFinally* node) { RELEASE_ASSERT(0, ""); }
virtual bool visit_tuple(AST_Tuple* node) { RELEASE_ASSERT(0, ""); }
virtual bool visit_unaryop(AST_UnaryOp* node) { RELEASE_ASSERT(0, ""); }
virtual bool visit_unreachable(AST_Unreachable* node) { RELEASE_ASSERT(0, ""); }
virtual bool visit_while(AST_While* node) { RELEASE_ASSERT(0, ""); }
virtual bool visit_with(AST_With* node) { RELEASE_ASSERT(0, ""); }
......@@ -980,6 +991,7 @@ public:
virtual bool visit_tryfinally(AST_TryFinally* node) { return false; }
virtual bool visit_tuple(AST_Tuple* node) { return false; }
virtual bool visit_unaryop(AST_UnaryOp* node) { return false; }
virtual bool visit_unreachable(AST_Unreachable* node) { return false; }
virtual bool visit_while(AST_While* node) { return false; }
virtual bool visit_with(AST_With* node) { return false; }
......@@ -1042,6 +1054,7 @@ public:
virtual void visit_return(AST_Return* node) { RELEASE_ASSERT(0, ""); }
virtual void visit_tryexcept(AST_TryExcept* node) { RELEASE_ASSERT(0, ""); }
virtual void visit_tryfinally(AST_TryFinally* node) { RELEASE_ASSERT(0, ""); }
virtual void visit_unreachable(AST_Unreachable* node) { RELEASE_ASSERT(0, ""); }
virtual void visit_while(AST_While* node) { RELEASE_ASSERT(0, ""); }
virtual void visit_with(AST_With* node) { RELEASE_ASSERT(0, ""); }
......@@ -1108,6 +1121,7 @@ public:
virtual bool visit_tryexcept(AST_TryExcept* node);
virtual bool visit_tryfinally(AST_TryFinally* node);
virtual bool visit_unaryop(AST_UnaryOp* node);
virtual bool visit_unreachable(AST_Unreachable* node);
virtual bool visit_while(AST_While* node);
virtual bool visit_with(AST_With* node);
......
......@@ -1310,6 +1310,10 @@ public:
if (node->arg2)
remapped->arg2 = remapExpr(node->arg2);
push_back(remapped);
curblock->push_back(new AST_Unreachable());
curblock = NULL;
return true;
}
......@@ -1331,10 +1335,12 @@ public:
}
CFGBlock* join_block = cfg->addDeferredBlock();
AST_Jump* j = new AST_Jump();
j->target = join_block;
push_back(j);
curblock->connectTo(join_block);
if (curblock) {
AST_Jump* j = new AST_Jump();
j->target = join_block;
push_back(j);
curblock->connectTo(join_block);
}
if (exc_handler_block->predecessors.size() == 0) {
delete exc_handler_block;
......@@ -1357,11 +1363,12 @@ public:
is_caught_here->args.push_back(handled_type);
is_caught_here->args.push_back(makeNum(1)); // flag: false_on_noncls
AST_Branch* br = new AST_Branch();
br->test = remapExpr(is_caught_here);
CFGBlock* exc_handle = cfg->addBlock();
exc_next = cfg->addDeferredBlock();
AST_Branch* br = new AST_Branch();
br->test = remapExpr(is_caught_here);
br->iftrue = exc_handle;
br->iffalse = exc_next;
curblock->connectTo(exc_handle);
......@@ -1380,10 +1387,12 @@ public:
subnode->accept(this);
}
AST_Jump* j = new AST_Jump();
j->target = join_block;
push_back(j);
curblock->connectTo(join_block);
if (curblock) {
AST_Jump* j = new AST_Jump();
j->target = join_block;
push_back(j);
curblock->connectTo(join_block);
}
if (exc_next) {
cfg->placeBlock(exc_next);
......@@ -1397,12 +1406,19 @@ public:
AST_Raise* raise = new AST_Raise();
raise->arg0 = exc_obj;
push_back(raise);
curblock->push_back(new AST_Unreachable());
curblock = NULL;
}
}
cfg->placeBlock(join_block);
curblock = join_block;
if (join_block->predecessors.size() == 0) {
delete join_block;
curblock = NULL;
} else {
cfg->placeBlock(join_block);
curblock = join_block;
}
return true;
}
......@@ -1579,9 +1595,13 @@ CFG* computeCFG(AST_TYPE::AST_TYPE root_type, std::vector<AST_stmt*> body) {
ASSERT(b2->idx != -1, "Forgot to place a block!");
}
ASSERT(b->body.size(), "%d", b->idx);
ASSERT(b->successors.size() <= 2, "%d has too many successors!", b->idx);
if (b->successors.size() == 0)
assert(b->body.back()->type == AST_TYPE::Return || b->body.back()->type == AST_TYPE::Raise);
if (b->successors.size() == 0) {
AST_stmt* terminator = b->body.back();
assert(terminator->type == AST_TYPE::Return || terminator->type == AST_TYPE::Raise
|| terminator->type == AST_TYPE::Unreachable);
}
if (b->predecessors.size() == 0)
assert(b == rtn->getStartingBlock());
......
......@@ -66,11 +66,8 @@ public:
extern "C" const AllocationKind untracked_kind, conservative_kind;
class ObjectFlavor;
extern "C" const ObjectFlavor user_flavor;
class ObjectFlavor : public AllocationKind {
public:
bool isUserDefined() const { return this == &user_flavor; }
ObjectFlavor(GCHandler gc_handler, FinalizationFunc finalizer) __attribute__((visibility("default")))
: AllocationKind(gc_handler, finalizer) {}
};
......@@ -350,6 +347,10 @@ public:
// to guard on anything about the class.
ICInvalidator dependent_icgetattrs;
// Only a single base supported for now.
// Is NULL iff this is object_cls
BoxedClass* const base;
// Offset of the HCAttrs object or 0 if there are no hcattrs.
// Analogous to tp_dictoffset
const int attrs_offset;
......@@ -371,7 +372,7 @@ public:
// will need to update this once we support tp_getattr-style overriding:
bool hasGenericGetattr() { return true; }
BoxedClass(int attrs_offset, int instance_size, bool is_user_defined);
BoxedClass(BoxedClass* base, int attrs_offset, int instance_size, bool is_user_defined);
void freeze() {
assert(!is_constant);
is_constant = true;
......
......@@ -369,8 +369,8 @@ Box* exceptionRepr(Box* b) {
return boxString(*getTypeName(b) + "(" + message_s->s + ",)");
}
static BoxedClass* makeBuiltinException(const char* name) {
BoxedClass* cls = new BoxedClass(offsetof(BoxedException, attrs), sizeof(BoxedException), false);
static BoxedClass* makeBuiltinException(BoxedClass* base, const char* name) {
BoxedClass* cls = new BoxedClass(base, offsetof(BoxedException, attrs), sizeof(BoxedException), false);
cls->giveAttr("__name__", boxStrConstant(name));
// TODO these should be on the base Exception class:
......@@ -388,7 +388,7 @@ void setupBuiltins() {
builtins_module->giveAttr("None", None);
notimplemented_cls = new BoxedClass(0, sizeof(Box), false);
notimplemented_cls = new BoxedClass(object_cls, 0, sizeof(Box), false);
notimplemented_cls->giveAttr("__name__", boxStrConstant("NotImplementedType"));
notimplemented_cls->giveAttr("__repr__",
new BoxedFunction(boxRTFunction((void*)notimplementedRepr, NULL, 1, false)));
......@@ -402,20 +402,20 @@ void setupBuiltins() {
builtins_module->giveAttr("all", new BoxedFunction(boxRTFunction((void*)all, BOXED_BOOL, 1, false)));
builtins_module->giveAttr("any", new BoxedFunction(boxRTFunction((void*)any, BOXED_BOOL, 1, false)));
Exception = makeBuiltinException("Exception");
AssertionError = makeBuiltinException("AssertionError");
AttributeError = makeBuiltinException("AttributeError");
TypeError = makeBuiltinException("TypeError");
NameError = makeBuiltinException("NameError");
KeyError = makeBuiltinException("KeyError");
IndexError = makeBuiltinException("IndexError");
IOError = makeBuiltinException("IOError");
OSError = makeBuiltinException("OSError");
ZeroDivisionError = makeBuiltinException("ZeroDivisionError");
ValueError = makeBuiltinException("ValueError");
UnboundLocalError = makeBuiltinException("UnboundLocalError");
RuntimeError = makeBuiltinException("RuntimeError");
ImportError = makeBuiltinException("ImportError");
Exception = makeBuiltinException(object_cls, "Exception");
AssertionError = makeBuiltinException(Exception, "AssertionError");
AttributeError = makeBuiltinException(Exception, "AttributeError");
TypeError = makeBuiltinException(Exception, "TypeError");
NameError = makeBuiltinException(Exception, "NameError");
KeyError = makeBuiltinException(Exception, "KeyError");
IndexError = makeBuiltinException(Exception, "IndexError");
IOError = makeBuiltinException(Exception, "IOError");
OSError = makeBuiltinException(Exception, "OSError");
ZeroDivisionError = makeBuiltinException(Exception, "ZeroDivisionError");
ValueError = makeBuiltinException(Exception, "ValueError");
UnboundLocalError = makeBuiltinException(Exception, "UnboundLocalError");
RuntimeError = makeBuiltinException(Exception, "RuntimeError");
ImportError = makeBuiltinException(Exception, "ImportError");
repr_obj = new BoxedFunction(boxRTFunction((void*)repr, NULL, 1, false));
builtins_module->giveAttr("repr", repr_obj);
......@@ -476,6 +476,7 @@ void setupBuiltins() {
builtins_module->giveAttr("map", new BoxedFunction(boxRTFunction((void*)map2, LIST, 2, false)));
builtins_module->giveAttr("zip", new BoxedFunction(boxRTFunction((void*)zip2, LIST, 2, false)));
builtins_module->giveAttr("object", object_cls);
builtins_module->giveAttr("str", str_cls);
builtins_module->giveAttr("int", int_cls);
builtins_module->giveAttr("float", float_cls);
......
......@@ -120,7 +120,7 @@ BoxedModule* getTestModule() {
}
void setupCAPI() {
capifunc_cls = new BoxedClass(0, sizeof(BoxedCApiFunction), false);
capifunc_cls = new BoxedClass(object_cls, 0, sizeof(BoxedCApiFunction), false);
capifunc_cls->giveAttr("__name__", boxStrConstant("capifunc"));
capifunc_cls->giveAttr("__repr__",
......
......@@ -86,8 +86,6 @@ void force() {
FORCE(printFloat);
FORCE(listAppendInternal);
FORCE(dump);
FORCE(runtimeCall);
FORCE(callattr);
......
......@@ -120,9 +120,9 @@ Box* xrangeIter(Box* self) {
}
void setupXrange() {
xrange_cls = new BoxedClass(0, sizeof(BoxedXrange), false);
xrange_cls = new BoxedClass(object_cls, 0, sizeof(BoxedXrange), false);
xrange_cls->giveAttr("__name__", boxStrConstant("xrange"));
xrange_iterator_cls = new BoxedClass(0, sizeof(BoxedXrangeIterator), false);
xrange_iterator_cls = new BoxedClass(object_cls, 0, sizeof(BoxedXrangeIterator), false);
xrange_iterator_cls->giveAttr("__name__", boxStrConstant("rangeiterator"));
CLFunction* xrange_clf = boxRTFunction((void*)xrange1, NULL, 2, false);
......
......@@ -433,7 +433,7 @@ extern "C" Box* listNew2(Box* cls, Box* container) {
}
void setupList() {
list_iterator_cls = new BoxedClass(0, sizeof(BoxedList), false);
list_iterator_cls = new BoxedClass(object_cls, 0, sizeof(BoxedList), false);
list_cls->giveAttr("__name__", boxStrConstant("list"));
......
This diff is collapsed.
......@@ -54,7 +54,6 @@ extern "C" Box* open2(Box* arg1, Box* arg2);
extern "C" Box* compare(Box*, Box*, int);
extern "C" BoxedInt* len(Box* obj);
extern "C" void print(Box* obj);
extern "C" void dump(Box* obj);
// extern "C" Box* trap();
extern "C" i64 unboxedLen(Box* obj);
extern "C" Box* binop(Box* lhs, Box* rhs, int op_type);
......@@ -69,6 +68,7 @@ extern "C" Box* import(const std::string* name);
extern "C" void checkUnpackingLength(i64 expected, i64 given);
extern "C" void assertNameDefined(bool b, const char* name);
extern "C" void assertFail(BoxedModule* inModule, Box* msg);
extern "C" bool isSubclass(BoxedClass* child, BoxedClass* parent);
class BinopRewriteArgs;
extern "C" Box* binopInternal(Box* lhs, Box* rhs, int op_type, bool inplace, BinopRewriteArgs* rewrite_args);
......@@ -87,6 +87,9 @@ Box* compareInternal(Box* lhs, Box* rhs, int op_type, CompareRewriteArgs* rewrit
Box* getattr_internal(Box* obj, const std::string& attr, bool check_cls, bool allow_custom,
GetattrRewriteArgs* rewrite_args, GetattrRewriteArgs2* rewrite_args2);
Box* typeLookup(BoxedClass* cls, const std::string& attr, GetattrRewriteArgs* rewrite_args,
GetattrRewriteArgs2* rewrite_args2);
extern "C" void raiseAttributeErrorStr(const char* typeName, const char* attr) __attribute__((__noreturn__));
extern "C" void raiseAttributeError(Box* obj, const char* attr) __attribute__((__noreturn__));
extern "C" void raiseNotIterableError(const char* typeName) __attribute__((__noreturn__));
......
......@@ -176,7 +176,7 @@ using namespace pyston::set;
void setupSet() {
set_cls->giveAttr("__name__", boxStrConstant("set"));
set_iterator_cls = new BoxedClass(0, sizeof(BoxedSet), false);
set_iterator_cls = new BoxedClass(object_cls, 0, sizeof(BoxedSet), false);
set_iterator_cls->giveAttr("__name__", boxStrConstant("setiterator"));
set_iterator_cls->giveAttr("__hasnext__",
new BoxedFunction(boxRTFunction((void*)setiteratorHasnext, BOXED_BOOL, 1, false)));
......
......@@ -524,7 +524,7 @@ Box* strCount2(BoxedString* self, Box* elt) {
}
void setupStr() {
str_iterator_cls = new BoxedClass(0, sizeof(BoxedString), false);
str_iterator_cls = new BoxedClass(object_cls, 0, sizeof(BoxedString), false);
str_iterator_cls->giveAttr("__name__", boxStrConstant("striterator"));
str_iterator_cls->giveAttr("__hasnext__",
new BoxedFunction(boxRTFunction((void*)BoxedStringIterator::hasnext, NULL, 1, false)));
......
......@@ -204,9 +204,10 @@ extern "C" void conservativeGCHandler(GCVisitor* v, void* p) {
}
extern "C" {
BoxedClass* 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;
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;
const ObjectFlavor object_flavor(&boxGCHandler, NULL);
const ObjectFlavor type_flavor(&typeGCHandler, NULL);
const ObjectFlavor none_flavor(&boxGCHandler, NULL);
const ObjectFlavor bool_flavor(&boxGCHandler, NULL);
......@@ -221,7 +222,6 @@ const ObjectFlavor module_flavor(&boxGCHandler, NULL);
const ObjectFlavor dict_flavor(&dictGCHandler, NULL);
const ObjectFlavor tuple_flavor(&tupleGCHandler, NULL);
const ObjectFlavor file_flavor(&boxGCHandler, NULL);
const ObjectFlavor user_flavor(&boxGCHandler, NULL);
const ObjectFlavor member_flavor(&boxGCHandler, NULL);
const AllocationKind untracked_kind(NULL, NULL);
......@@ -229,14 +229,26 @@ const AllocationKind hc_kind(&hcGCHandler, NULL);
const AllocationKind conservative_kind(&conservativeGCHandler, NULL);
}
extern "C" Box* createUserClass(std::string* name, BoxedModule* parent_module) {
BoxedClass* rtn = new BoxedClass(offsetof(BoxedUserObject, attrs), sizeof(BoxedUserObject), true);
rtn->giveAttr("__name__", boxString(*name));
extern "C" Box* createUserClass(std::string* name, Box* _base, BoxedModule* parent_module) {
assert(_base);
assert(isSubclass(_base->cls, type_cls));
BoxedClass* base = static_cast<BoxedClass*>(_base);
BoxedClass* made;
if (base->instancesHaveAttrs()) {
made = new BoxedClass(base, base->attrs_offset, base->instance_size, true);
} else {
assert(base->instance_size % sizeof(void*) == 0);
made = new BoxedClass(base, base->instance_size, base->instance_size + sizeof(HCAttrs), true);
}
made->giveAttr("__name__", boxString(*name));
Box* modname = parent_module->getattr("__name__", NULL, NULL);
rtn->giveAttr("__module__", modname);
made->giveAttr("__module__", modname);
return rtn;
return made;
}
extern "C" Box* boxInstanceMethod(Box* obj, Box* func) {
......@@ -371,35 +383,67 @@ CLFunction* unboxRTFunction(Box* b) {
return static_cast<BoxedFunction*>(b)->f;
}
Box* objectNew1(BoxedClass* cls) {
assert(cls->instance_size >= sizeof(Box));
void* mem = rt_alloc(cls->instance_size);
Box* rtn = ::new (mem) Box(&object_flavor, cls);
if (cls->attrs_offset) {
HCAttrs* attrs = rtn->getAttrs();
attrs = new ((void*)attrs) HCAttrs();
}
return rtn;
}
Box* objectNew(BoxedClass* cls, BoxedList* args) {
assert(isSubclass(cls->cls, type_cls));
if (args->size != 0) {
if (typeLookup(cls, "__init__", NULL, NULL) == NULL)
raiseExcHelper(TypeError, "object.__new__() takes no parameters");
}
return objectNew1(cls);
}
bool TRACK_ALLOCATIONS = false;
void setupRuntime() {
HiddenClass::getRoot();
type_cls = new BoxedClass(offsetof(BoxedClass, attrs), sizeof(BoxedClass), false);
object_cls = new BoxedClass(NULL, 0, sizeof(Box), false);
type_cls = new BoxedClass(object_cls, offsetof(BoxedClass, attrs), sizeof(BoxedClass), false);
type_cls->cls = type_cls;
object_cls->cls = type_cls;
none_cls = new BoxedClass(0, sizeof(Box), false);
none_cls = new BoxedClass(object_cls, 0, sizeof(Box), false);
None = new Box(&none_flavor, none_cls);
gc::registerStaticRootObj(None);
module_cls = new BoxedClass(offsetof(BoxedModule, attrs), sizeof(BoxedModule), false);
str_cls = new BoxedClass(object_cls, 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);
str_cls->giveAttr("__base__", object_cls);
none_cls->giveAttr("__base__", object_cls);
object_cls->giveAttr("__base__", None);
module_cls = new BoxedClass(object_cls, 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(0, sizeof(BoxedBool), false);
int_cls = new BoxedClass(0, sizeof(BoxedInt), false);
float_cls = new BoxedClass(0, sizeof(BoxedFloat), false);
str_cls = new BoxedClass(0, sizeof(BoxedString), false);
function_cls = new BoxedClass(offsetof(BoxedFunction, attrs), sizeof(BoxedFunction), false);
instancemethod_cls = new BoxedClass(0, sizeof(BoxedInstanceMethod), false);
list_cls = new BoxedClass(0, sizeof(BoxedList), false);
slice_cls = new BoxedClass(0, sizeof(BoxedSlice), false);
dict_cls = new BoxedClass(0, sizeof(BoxedDict), false);
tuple_cls = new BoxedClass(0, sizeof(BoxedTuple), false);
file_cls = new BoxedClass(0, sizeof(BoxedFile), false);
set_cls = new BoxedClass(0, sizeof(BoxedSet), false);
member_cls = new BoxedClass(0, sizeof(BoxedMemberDescriptor), false);
bool_cls = new BoxedClass(object_cls, 0, sizeof(BoxedBool), false);
int_cls = new BoxedClass(object_cls, 0, sizeof(BoxedInt), false);
float_cls = new BoxedClass(object_cls, 0, sizeof(BoxedFloat), false);
function_cls = new BoxedClass(object_cls, offsetof(BoxedFunction, attrs), sizeof(BoxedFunction), false);
instancemethod_cls = new BoxedClass(object_cls, 0, sizeof(BoxedInstanceMethod), false);
list_cls = new BoxedClass(object_cls, 0, sizeof(BoxedList), false);
slice_cls = new BoxedClass(object_cls, 0, sizeof(BoxedSlice), false);
dict_cls = new BoxedClass(object_cls, 0, sizeof(BoxedDict), false);
tuple_cls = new BoxedClass(object_cls, 0, sizeof(BoxedTuple), false);
file_cls = new BoxedClass(object_cls, 0, sizeof(BoxedFile), false);
set_cls = new BoxedClass(object_cls, 0, sizeof(BoxedSet), false);
member_cls = new BoxedClass(object_cls, 0, sizeof(BoxedMemberDescriptor), false);
STR = typeFromClass(str_cls);
BOXED_INT = typeFromClass(int_cls);
......@@ -413,6 +457,12 @@ void setupRuntime() {
SET = typeFromClass(set_cls);
BOXED_TUPLE = typeFromClass(tuple_cls);
object_cls->giveAttr("__name__", boxStrConstant("object"));
auto object_new = boxRTFunction((void*)objectNew1, NULL, 1, false);
addRTFunction(object_new, (void*)objectNew, NULL, 1, true);
object_cls->giveAttr("__new__", new BoxedFunction(object_new));
object_cls->freeze();
type_cls->giveAttr("__name__", boxStrConstant("type"));
type_cls->giveAttr("__call__", new BoxedFunction(boxRTFunction((void*)typeCall, NULL, 1, true)));
type_cls->giveAttr("__new__", new BoxedFunction(boxRTFunction((void*)typeNew, NULL, 2, true)));
......
......@@ -59,16 +59,14 @@ BoxedDict* getSysModulesDict();
BoxedList* getSysPath();
extern "C" {
extern BoxedClass* type_cls, *bool_cls, *int_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, *member_cls;
extern BoxedClass* object_cls, *type_cls, *bool_cls, *int_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, *member_cls;
}
extern "C" {
extern const ObjectFlavor type_flavor, bool_flavor, int_flavor, float_flavor, str_flavor, function_flavor, none_flavor,
instancemethod_flavor, list_flavor, slice_flavor, module_flavor, dict_flavor, tuple_flavor, file_flavor,
xrange_flavor, member_flavor;
extern const ObjectFlavor object_flavor, type_flavor, bool_flavor, int_flavor, float_flavor, str_flavor,
function_flavor, none_flavor, instancemethod_flavor, list_flavor, slice_flavor, module_flavor, dict_flavor,
tuple_flavor, file_flavor, xrange_flavor, member_flavor;
}
extern "C" { extern const ObjectFlavor user_flavor; }
extern "C" { extern Box* None, *NotImplemented, *True, *False; }
extern "C" {
extern Box* repr_obj, *len_obj, *hash_obj, *range_obj, *abs_obj, *min_obj, *max_obj, *open_obj, *chr_obj, *ord_obj,
......@@ -88,7 +86,7 @@ extern "C" void listAppendInternal(Box* self, Box* v);
extern "C" void listAppendArrayInternal(Box* self, Box** v, int nelts);
extern "C" Box* boxCLFunction(CLFunction* f);
extern "C" CLFunction* unboxCLFunction(Box* b);
extern "C" Box* createUserClass(std::string* name, BoxedModule* parent_module);
extern "C" Box* createUserClass(std::string* name, Box* base, BoxedModule* parent_module);
extern "C" double unboxFloat(Box* b);
extern "C" Box* createDict();
extern "C" Box* createList();
......@@ -268,14 +266,6 @@ public:
BoxedFunction(CLFunction* f);
};
// TODO hack
class BoxedUserObject : public Box {
public:
HCAttrs attrs;
BoxedUserObject(BoxedClass* cls) : Box(&user_flavor, cls) {}
};
class BoxedModule : public Box {
public:
HCAttrs attrs;
......
# expected: fail
# - don't support object.__new__ yet
# Regression test:
# If the init function doesn't exist, shouldn't just silently ignore any args
# that got passed
......
......@@ -28,3 +28,26 @@ except ZeroDivisionError, e:
print e.message
print str(e), repr(e)
print e
class MyException(Exception):
pass
def catches(e):
try:
try:
raise e
except MyException:
return True
except:
return False
print catches(Exception())
print catches(AttributeError())
print catches(MyException())
def f():
try:
raise Exception()
except:
print True
f()
def f1():
class C(object):
pass
class D(C):
pass
C.a = 1
print D.a
for inst in [C(), D(), object()]:
for cls in [C, D, object]:
print isinstance(inst, cls)
print object.__base__
print C.__base__
print D.__base__
print type.__base__
print type(None).__base__
# Just make sure these exist:
repr(Exception.__base__)
repr(str.__base__)
f1()
def f2():
class B(object):
def wrapper(self, n):
self.foo(n)
self.foo(n)
class C(B):
def foo(self, n):
print n
c = C()
print c.wrapper(2)
f2()
# object.__new__ doesn't complain if __init__ is overridden:
class C1(object):
def __init__(self, a):
pass
class C2(object):
pass
print "Trying C1"
object.__new__(C1, 1)
print "Trying C2"
object.__new__(C2, 1)
......@@ -33,3 +33,28 @@ class C2(object):
c = C2()
call_f(c, 2)
call_f(c, 2)
n = 0
def f():
C()
def init(self):
pass
class C(object):
def __new__(cls):
global n
n += 1
if n == 10:
C.__init__ = init
f()
return object.__new__(cls)
for i in xrange(20):
f()
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