Commit 5e625bbd authored by Kevin Modzelewski's avatar Kevin Modzelewski

Merge branch 'delattr_by_hcls' of https://github.com/xiafan68/pyston into personal

Merges #101

Conflicts:
	src/codegen/runtime_hooks.h
parent 6f2be4d5
......@@ -475,8 +475,16 @@ private:
virtual void visit_delete(AST_Delete* node) {
for (AST_expr* target : node->targets) {
RELEASE_ASSERT(target->type == AST_TYPE::Subscript, "");
getType(ast_cast<AST_Subscript>(target)->value);
switch (target->type) {
case AST_TYPE::Subscript:
getType(ast_cast<AST_Subscript>(target)->value);
break;
case AST_TYPE::Attribute:
getType(ast_cast<AST_Attribute>(target)->value);
break;
default:
RELEASE_ASSERT(0, "");
}
}
}
......
......@@ -218,6 +218,27 @@ public:
converted->decvref(emitter);
}
void delattr(IREmitter& emitter, const OpInfo& info, ConcreteCompilerVariable* var, const std::string* attr) {
llvm::Constant* ptr = getStringConstantPtr(*attr + '\0');
// TODO
// bool do_patchpoint = ENABLE_ICDELATTRS && !info.isInterpreted();
bool do_patchpoint = false;
if (do_patchpoint) {
PatchpointSetupInfo* pp
= patchpoints::createDelattrPatchpoint(emitter.currentFunction(), info.getTypeRecorder());
std::vector<llvm::Value*> llvm_args;
llvm_args.push_back(var->getValue());
llvm_args.push_back(ptr);
emitter.createPatchpoint(pp, (void*)pyston::delattr, llvm_args, info.exc_info);
} else {
emitter.createCall2(info.exc_info, g.funcs.delattr, var->getValue(), ptr);
}
}
virtual llvm::Value* makeClassCheck(IREmitter& emitter, ConcreteCompilerVariable* var, BoxedClass* cls) {
assert(var->getValue()->getType() == g.llvm_value_type_ptr);
// TODO this is brittle: directly embeds the position of the class object:
......@@ -762,6 +783,12 @@ public:
call.setDoesNotReturn();
}
virtual void delattr(IREmitter& emitter, const OpInfo& info, VAR* var, const std::string* attr) {
llvm::CallInst* call = emitter.getBuilder()->CreateCall2(
g.funcs.raiseAttributeErrorStr, getStringConstantPtr("int\0"), getStringConstantPtr(*attr + '\0'));
call->setDoesNotReturn();
}
virtual ConcreteCompilerVariable* makeConverted(IREmitter& emitter, ConcreteCompilerVariable* var,
ConcreteCompilerType* other_type) {
if (other_type == this) {
......@@ -960,6 +987,12 @@ public:
call.setDoesNotReturn();
}
virtual void delattr(IREmitter& emitter, const OpInfo& info, VAR* var, const std::string* attr) {
llvm::CallInst* call = emitter.getBuilder()->CreateCall2(
g.funcs.raiseAttributeErrorStr, getStringConstantPtr("float\0"), getStringConstantPtr(*attr + '\0'));
call->setDoesNotReturn();
}
virtual ConcreteCompilerVariable* makeConverted(IREmitter& emitter, ConcreteCompilerVariable* var,
ConcreteCompilerType* other_type) {
if (other_type == this) {
......@@ -1217,6 +1250,10 @@ public:
return UNKNOWN->setattr(emitter, info, var, attr, v);
}
void delattr(IREmitter& emitter, const OpInfo& info, ConcreteCompilerVariable* var, const std::string* attr) {
return UNKNOWN->delattr(emitter, info, var, attr);
}
virtual void print(IREmitter& emitter, const OpInfo& info, ConcreteCompilerVariable* var) {
ConcreteCompilerVariable* converted = var->makeConverted(emitter, UNKNOWN);
converted->print(emitter, info);
......
......@@ -100,6 +100,12 @@ public:
printf("setattr not defined for %s\n", debugName().c_str());
abort();
}
virtual void delattr(IREmitter& emitter, const OpInfo& info, VAR* value, const std::string* attr) {
printf("delattr not defined for %s\n", debugName().c_str());
abort();
}
virtual CompilerVariable* callattr(IREmitter& emitter, const OpInfo& info, VAR* var, const std::string* attr,
bool clsonly, struct ArgPassSpec argspec,
const std::vector<CompilerVariable*>& args,
......@@ -232,6 +238,7 @@ public:
virtual CompilerVariable* getattr(IREmitter& emitter, const OpInfo& info, const std::string* attr, bool cls_only)
= 0;
virtual void setattr(IREmitter& emitter, const OpInfo& info, const std::string* attr, CompilerVariable* v) = 0;
virtual void delattr(IREmitter& emitter, const OpInfo& info, const std::string* attr) = 0;
virtual CompilerVariable* callattr(IREmitter& emitter, const OpInfo& info, const std::string* attr, bool clsonly,
struct ArgPassSpec argspec, const std::vector<CompilerVariable*>& args,
const std::vector<const std::string*>* keyword_names) = 0;
......@@ -296,6 +303,11 @@ public:
virtual void setattr(IREmitter& emitter, const OpInfo& info, const std::string* attr, CompilerVariable* v) {
type->setattr(emitter, info, this, attr, v);
}
virtual void delattr(IREmitter& emitter, const OpInfo& info, const std::string* attr) {
type->delattr(emitter, info, this, attr);
}
virtual CompilerVariable* callattr(IREmitter& emitter, const OpInfo& info, const std::string* attr, bool clsonly,
struct ArgPassSpec argspec, const std::vector<CompilerVariable*>& args,
const std::vector<const std::string*>* keyword_names) {
......
......@@ -1303,6 +1303,9 @@ private:
case AST_TYPE::Subscript:
_doDelitem(static_cast<AST_Subscript*>(target), exc_info);
break;
case AST_TYPE::Attribute:
_doDelAttr(static_cast<AST_Attribute*>(target), exc_info);
break;
default:
ASSERT(0, "UnSupported del target: %d", target->type);
abort();
......@@ -1340,6 +1343,11 @@ private:
converted_slice->decvref(emitter);
}
void _doDelAttr(AST_Attribute* node, ExcInfo exc_info) {
CompilerVariable* value = evalExpr(node->value, exc_info);
value->delattr(emitter, getEmptyOpInfo(exc_info), &node->attr);
}
CLFunction* _wrapFunction(AST* node, AST_arguments* args, const std::vector<AST_stmt*>& body) {
// Different compilations of the parent scope of a functiondef should lead
// to the same CLFunction* being used:
......
......@@ -139,6 +139,10 @@ PatchpointSetupInfo* createSetattrPatchpoint(CompiledFunction* parent_cf, TypeRe
return PatchpointSetupInfo::initialize(false, 2, 128, parent_cf, Setattr, type_recorder);
}
PatchpointSetupInfo* createDelattrPatchpoint(CompiledFunction* parent_cf, TypeRecorder* type_recorder) {
return PatchpointSetupInfo::initialize(false, 1, 144, parent_cf, Delattr, type_recorder);
}
PatchpointSetupInfo* createCallsitePatchpoint(CompiledFunction* parent_cf, TypeRecorder* type_recorder, int num_args) {
// TODO These are very large, but could probably be made much smaller with IC optimizations
// - using rewriter2 for better code
......
......@@ -32,6 +32,7 @@ enum PatchpointType {
GetGlobal,
Getattr,
Setattr,
Delattr,
Getitem,
Setitem,
Delitem,
......@@ -91,6 +92,7 @@ PatchpointSetupInfo* createCallsitePatchpoint(CompiledFunction* parent_cf, TypeR
PatchpointSetupInfo* createGetGlobalPatchpoint(CompiledFunction* parent_cf, TypeRecorder* type_recorder);
PatchpointSetupInfo* createGetattrPatchpoint(CompiledFunction* parent_cf, TypeRecorder* type_recorder);
PatchpointSetupInfo* createSetattrPatchpoint(CompiledFunction* parent_cf, TypeRecorder* type_recorder);
PatchpointSetupInfo* createDelattrPatchpoint(CompiledFunction* parent_cf, TypeRecorder* type_recorder);
PatchpointSetupInfo* createGetitemPatchpoint(CompiledFunction* parent_cf, TypeRecorder* type_recorder);
PatchpointSetupInfo* createSetitemPatchpoint(CompiledFunction* parent_cf, TypeRecorder* type_recorder);
PatchpointSetupInfo* createDelitemPatchpoint(CompiledFunction* parent_cf, TypeRecorder* type_recorder);
......
......@@ -169,6 +169,7 @@ void initGlobalFuncs(GlobalState& g) {
GET(getattr);
GET(setattr);
GET(delattr);
GET(getitem);
GET(setitem);
GET(delitem);
......
......@@ -33,8 +33,8 @@ struct GlobalFuncs {
llvm::Value* boxInt, *unboxInt, *boxFloat, *unboxFloat, *boxStringPtr, *boxCLFunction, *unboxCLFunction,
*boxInstanceMethod, *boxBool, *unboxBool, *createTuple, *createDict, *createList, *createSlice,
*createUserClass, *createClosure;
llvm::Value* getattr, *setattr, *print, *nonzero, *binop, *compare, *augbinop, *unboxedLen, *getitem, *getclsattr,
*getGlobal, *setitem, *delitem, *unaryop, *import, *importFrom, *importStar, *repr, *isinstance;
llvm::Value* getattr, *setattr, *delattr, *print, *nonzero, *binop, *compare, *augbinop, *unboxedLen, *getitem,
*getclsattr, *getGlobal, *setitem, *delitem, *unaryop, *import, *importFrom, *importStar, *repr, *isinstance;
llvm::Value* checkUnpackingLength, *raiseAttributeError, *raiseAttributeErrorStr, *raiseNotIterableError,
*assertNameDefined, *assertFail;
......
......@@ -1087,6 +1087,13 @@ public:
target = astsubs;
break;
}
case AST_TYPE::Attribute: {
AST_Attribute* astattr = static_cast<AST_Attribute*>(remapExpr(t, false));
astattr->ctx_type = AST_TYPE::Del;
target = astattr;
break;
}
default:
RELEASE_ASSERT(0, "UnSupported del target: %d", t->type);
}
......
......@@ -42,6 +42,7 @@ bool ENABLE_ICDELITEMS = 1 && ENABLE_ICS;
bool ENABLE_ICCALLSITES = 1 && ENABLE_ICS;
bool ENABLE_ICSETATTRS = 1 && ENABLE_ICS;
bool ENABLE_ICGETATTRS = 1 && ENABLE_ICS;
bool ENALBE_ICDELATTRS = 1 && ENABLE_ICS;
bool ENABLE_ICGETGLOBALS = 1 && ENABLE_ICS;
bool ENABLE_ICBINEXPS = 1 && ENABLE_ICS;
bool ENABLE_ICNONZEROS = 1 && ENABLE_ICS;
......
......@@ -29,7 +29,7 @@ extern int MAX_OPT_ITERATIONS;
extern bool SHOW_DISASM, FORCE_OPTIMIZE, BENCH, PROFILE, DUMPJIT, TRAP, USE_STRIPPED_STDLIB, ENABLE_INTERPRETER;
extern bool ENABLE_ICS, ENABLE_ICGENERICS, ENABLE_ICGETITEMS, ENABLE_ICSETITEMS, ENABLE_ICDELITEMS, ENABLE_ICBINEXPS,
ENABLE_ICNONZEROS, ENABLE_ICCALLSITES, ENABLE_ICSETATTRS, ENABLE_ICGETATTRS, ENABLE_ICGETGLOBALS,
ENABLE_ICNONZEROS, ENABLE_ICCALLSITES, ENABLE_ICSETATTRS, ENABLE_ICGETATTRS, ENALBE_ICDELATTRS, ENABLE_ICGETGLOBALS,
ENABLE_SPECULATION, ENABLE_OSR, ENABLE_LLVMOPTS, ENABLE_INLINING, ENABLE_REOPT, ENABLE_PYSTON_PASSES,
ENABLE_TYPE_FEEDBACK;
}
......
......@@ -341,6 +341,7 @@ public:
return -1;
return it->second;
}
HiddenClass* delAttrToMakeHC(const std::string& attr);
};
class Box;
......@@ -370,6 +371,7 @@ private:
class SetattrRewriteArgs2;
class GetattrRewriteArgs;
class GetattrRewriteArgs2;
class DelattrRewriteArgs2;
struct HCAttrs {
public:
......@@ -401,6 +403,7 @@ public:
Box* getattr(const std::string& attr, GetattrRewriteArgs* rewrite_args, GetattrRewriteArgs2* rewrite_args2);
Box* getattr(const std::string& attr) { return getattr(attr, NULL, NULL); }
void delattr(const std::string& attr, DelattrRewriteArgs2* rewrite_args);
};
......
......@@ -61,6 +61,7 @@ void force() {
FORCE(getattr);
FORCE(setattr);
FORCE(delattr);
FORCE(print);
FORCE(nonzero);
FORCE(binop);
......
......@@ -98,6 +98,17 @@ struct SetattrRewriteArgs2 {
out_success(false) {}
};
struct DelattrRewriteArgs2 {
Rewriter2* rewriter;
RewriterVarUsage2 obj;
bool more_guards_after;
bool out_success;
DelattrRewriteArgs2(Rewriter2* rewriter, RewriterVarUsage2&& obj, bool more_guards_after)
: rewriter(rewriter), obj(std::move(obj)), more_guards_after(more_guards_after), out_success(false) {}
};
struct LenRewriteArgs {
Rewriter* rewriter;
RewriterVar obj;
......@@ -331,6 +342,31 @@ HiddenClass* HiddenClass::getOrMakeChild(const std::string& attr) {
return rtn;
}
/**
* del attr from current HiddenClass, pertain the orders of remaining attrs
*/
HiddenClass* HiddenClass::delAttrToMakeHC(const std::string& attr) {
int idx = getOffset(attr);
assert(idx >= 0);
std::vector<std::string> new_attrs(attr_offsets.size() - 1);
for (auto it = attr_offsets.begin(); it != attr_offsets.end(); ++it) {
if (it->second < idx)
new_attrs[it->second] = it->first;
else if (it->second > idx) {
new_attrs[it->second - 1] = it->first;
}
}
// TODO we can first locate the parent HiddenClass of the deleted
// attribute and hence avoid creation of its ancestors.
HiddenClass* cur = getRoot();
for (const auto& attr : new_attrs) {
cur = cur->getOrMakeChild(attr);
}
return cur;
}
HiddenClass* HiddenClass::getRoot() {
static HiddenClass* root = new HiddenClass();
return root;
......@@ -2612,6 +2648,88 @@ extern "C" void delitem(Box* target, Box* slice) {
}
}
void Box::delattr(const std::string& attr, DelattrRewriteArgs2* rewrite_args) {
// as soon as the hcls changes, the guard on hidden class won't pass.
HCAttrs* attrs = getAttrsPtr();
HiddenClass* hcls = attrs->hcls;
HiddenClass* new_hcls = hcls->delAttrToMakeHC(attr);
// The order of attributes is pertained as delAttrToMakeHC constructs
// the new HiddenClass by invoking getOrMakeChild in the prevous order
// of remaining attributes
int num_attrs = hcls->attr_offsets.size();
int offset = hcls->getOffset(attr);
Box** start = attrs->attr_list->attrs;
memmove(start + offset, start + offset + 1, (num_attrs - offset - 1) * sizeof(Box*));
attrs->hcls = new_hcls;
// guarantee the size of the attr_list equals the number of attrs
int new_size = sizeof(HCAttrs::AttrList) + sizeof(Box*) * (num_attrs - 1);
attrs->attr_list = (HCAttrs::AttrList*)rt_realloc(attrs->attr_list, new_size);
}
extern "C" void delattr_internal(Box* obj, const std::string& attr, bool allow_custom,
DelattrRewriteArgs2* rewrite_args) {
static const std::string delattr_str("__delattr__");
static const std::string delete_str("__delete__");
// custom __delattr__
if (allow_custom) {
Box* delAttr = typeLookup(obj->cls, delattr_str, NULL, NULL);
if (delAttr != NULL) {
Box* boxstr = boxString(attr);
Box* rtn = runtimeCall2(delAttr, ArgPassSpec(2), obj, boxstr);
return;
}
}
// first check wether the deleting attribute is a descriptor
Box* clsAttr = getattr_internal(obj, attr, true, false, NULL, NULL);
if (clsAttr != NULL) {
Box* delAttr = getattr_internal(clsAttr, delete_str, false, true, NULL, NULL);
if (delAttr != NULL) {
Box* boxstr = boxString(attr);
Box* rtn = runtimeCall2(delAttr, ArgPassSpec(2), clsAttr, obj);
return;
}
}
// check if the attribute is in the instance's __dict__
Box* attrVal = getattr_internal(obj, attr, false, false, NULL, NULL);
if (attrVal != NULL) {
obj->delattr(attr, NULL);
} else {
// the exception cpthon throws is different when the class contains the attribute
if (clsAttr != NULL) {
raiseExcHelper(AttributeError, attr.c_str());
} else {
raiseAttributeError(obj, attr.c_str());
}
}
}
// del target.attr
extern "C" void delattr(Box* obj, const char* attr) {
static StatCounter slowpath_delattr("slowpath_delattr");
slowpath_delattr.log();
if (obj->cls == type_cls) {
BoxedClass* cobj = static_cast<BoxedClass*>(obj);
if (!isUserDefined(cobj)) {
raiseExcHelper(TypeError, "can't set attributes of built-in/extension type '%s'\n",
getNameOfClass(cobj)->c_str());
}
} else {
if (!isUserDefined(obj->cls)) {
raiseExcHelper(AttributeError, "'%s' object attribute '%s' is read-only", getTypeName(obj)->c_str(), attr);
}
}
delattr_internal(obj, attr, true, NULL);
}
// For use on __init__ return values
static void assertInitNone(Box* obj) {
if (obj != None) {
......
......@@ -43,6 +43,7 @@ extern "C" const std::string* getNameOfClass(BoxedClass* cls);
extern "C" void my_assert(bool b);
extern "C" Box* getattr(Box* obj, const char* attr);
extern "C" void setattr(Box* obj, const char* attr, Box* attr_val);
extern "C" void delattr(Box* obj, const char* attr);
extern "C" bool nonzero(Box* obj);
extern "C" Box* runtimeCall(Box*, ArgPassSpec, Box*, Box*, Box*, Box**, const std::vector<const std::string*>*);
extern "C" Box* callattr(Box*, std::string*, bool, ArgPassSpec, Box*, Box*, Box*, Box**,
......@@ -93,7 +94,8 @@ enum LookupScope {
extern "C" Box* callattrInternal(Box* obj, const std::string* attr, LookupScope, CallRewriteArgs* rewrite_args,
ArgPassSpec argspec, Box* arg1, Box* arg2, Box* arg3, Box** args,
const std::vector<const std::string*>* keyword_names);
extern "C" void delattr_internal(Box* obj, const std::string& attr, bool allow_custom,
DelattrRewriteArgs2* rewrite_args);
struct CompareRewriteArgs;
Box* compareInternal(Box* lhs, Box* rhs, int op_type, CompareRewriteArgs* rewrite_args);
Box* getattr_internal(Box* obj, const std::string& attr, bool check_cls, bool allow_custom,
......
#delete attribute of built-in types
def del_builtin_attr(o):
try:
del a.__init__
print "error"
except AttributeError, e:
#print repr(e)
print e
a=1
del_builtin_attr(a)
a=1.0
del_builtin_attr(a)
a=[1]
del_builtin_attr(a)
b={}
del_builtin_attr(a)
"""
test del procedure
> invoke __delattr__ if exists
> del instance __dict__
> if attr is not in __dict__ of instance, check if attr exists in the its class.
>if found, invoke __delete__ attribute if exists or throw AttributeError.
>if not, throw AttributeError
"""
class CustDelClass(object):
def __init__(self, val):
self.val = val
def __delattr__(self, attr):
print "del attribute %s"%(attr)
a = CustDelClass(1)
del a.val
print a.val
class AttrClass(object):
#
#classAttr = 1
def __init__(self, val):
self.val = val
def speak(self):
#print "val:%s, classAttr:%d"%(self.val, self.classAttr)
print "val%s"%(self.val)
#check the val of b should not be affected
a = AttrClass(1)
b = AttrClass(2)
a.speak()
del a.val
try:
a.speak()
print "del a.val error"
except AttributeError, e:
print e
try:
b.speak()
print "success"
except AttributeError, e:
print "error"
#could assign a new value
a.val = 1
try:
a.speak()
print "success"
except AttributeError, e:
print "error"
"""
try:
del a.classAttr
print "error"
except AttributeError, e:
print repr(e)
"""
try:
del a.speak
print "del func error"
except AttributeError, e:
print "del func:%s"%(e)
del AttrClass.speak
try:
a.speak()
print "error"
except AttributeError, e:
print e
#test custom del attr
class CustDelClass(object):
def __init__(self, val):
self.val = val
def __delattr__(self, attr):
print "__delattr__ %s"%(attr)
def speak(self):
print "val:%s"%(self.val)
a=CustDelClass(1)
del a.attr
#custom set and get attr
class CustSetClass(object):
def __setattr__(self, attr, val):
print "__setattr__ %s %s"%(attr, val)
#def __getattr__(self, attr):
def __getattribute__(self, attr):
print "__getattribute__:%s"%(attr)
return attr
a=CustSetClass()
a.attr
a.val
#del won't invoke __getattr__ or __getattribute__ to check wether attr is an attribute of a
try:
del a.attr
except AttributeError, e:
print e
"""
#descriptor
class RevealAccess(object):
def __init__(self, initval=None, name='var'):
self.val = initval
self.name = name
def __get__(self, obj, objtype):
print 'Retrieving', self.name
return self.val
def __delete__(self, obj):
print 'delete', self.name
class MyClass(object):
x = RevealAccess(10, 'var "x"')
a=MyClass()
del a.x
"""
def f(o):
print o.a
class C(object):
pass
c = C()
c.a = 1
f(c)
del c.a
try:
f(c)
print "f(c) error"
except AttributeError, e:
print e
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