Commit 1e1fa481 authored by Kevin Modzelewski's avatar Kevin Modzelewski

Merge pull request #936 from kmod/sqlalchemy_merge

Enable a bunch more sqlalchemy tests
parents 4b5e041c f6fc362a
...@@ -49,9 +49,18 @@ class WeakValueDictionary(UserDict.UserDict): ...@@ -49,9 +49,18 @@ class WeakValueDictionary(UserDict.UserDict):
self = selfref() self = selfref()
if self is not None: if self is not None:
if self._iterating: if self._iterating:
self._pending_removals.append(wr.key) self._pending_removals.append(wr)
else: else:
del self.data[wr.key] # Pyston change: adopted this pypy fix:
#
# Changed this for PyPy: made more resistent. The
# issue is that in some corner cases, self.data
# might already be changed or removed by the time
# this weakref's callback is called. If that is
# the case, we don't want to randomly kill an
# unrelated entry.
if self.data.get(wr.key) is wr:
del self.data[wr.key]
self._remove = remove self._remove = remove
# A list of keys to be removed # A list of keys to be removed
self._pending_removals = [] self._pending_removals = []
...@@ -64,7 +73,9 @@ class WeakValueDictionary(UserDict.UserDict): ...@@ -64,7 +73,9 @@ class WeakValueDictionary(UserDict.UserDict):
# We shouldn't encounter any KeyError, because this method should # We shouldn't encounter any KeyError, because this method should
# always be called *before* mutating the dict. # always be called *before* mutating the dict.
while l: while l:
del d[l.pop()] wr = l.pop()
if d.get(wr.key) is wr:
del d[wr.key]
def __getitem__(self, key): def __getitem__(self, key):
o = self.data[key]() o = self.data[key]()
...@@ -280,14 +291,32 @@ class WeakKeyDictionary(UserDict.UserDict): ...@@ -280,14 +291,32 @@ class WeakKeyDictionary(UserDict.UserDict):
""" """
def __init__(self, dict=None): def __init__(self, dict=None):
# Pyston change:
# This implementation of WeakKeyDictionary originally relied on quick destruction
# of the weakref key objects and the immediate calling of their callback. With a gc,
# there can be multiple key removals before a collection happens, at which point we
# call remove() with keys that are not the most recent version.
#
# The approach here is to check the key in the dict to make sure it is still the same.
# This is a little bit complicated since 1) if the weakref.ref's referent gets freed,
# the ref object is no longer usable as a hash key, and 2) setting a value in a dict
# when the key already exists will not update the key.
#
# So in __setitem__, remove the existing key and replace it with the new one.
# Since there's no way to query for the current key inside a dict, given a lookup key,
# we keep a separate "refs" dict to look it up.
self.data = {} self.data = {}
self.refs = {}
def remove(k, selfref=ref(self)): def remove(k, selfref=ref(self)):
self = selfref() self = selfref()
if self is not None: if self is not None:
assert len(self.data) == len(self.refs)
if self._iterating: if self._iterating:
self._pending_removals.append(k) self._pending_removals.append(k)
else: else:
del self.data[k] if self.refs.get(k) is k:
del self.data[k]
del self.refs[k]
self._remove = remove self._remove = remove
# A list of dead weakrefs (keys to be removed) # A list of dead weakrefs (keys to be removed)
self._pending_removals = [] self._pending_removals = []
...@@ -302,14 +331,20 @@ class WeakKeyDictionary(UserDict.UserDict): ...@@ -302,14 +331,20 @@ class WeakKeyDictionary(UserDict.UserDict):
# However, it means keys may already have been removed. # However, it means keys may already have been removed.
l = self._pending_removals l = self._pending_removals
d = self.data d = self.data
r = self.refs
while l: while l:
try: try:
del d[l.pop()] k = l.pop()
if self.refs.get(k) is k:
del d[k]
del r[k]
except KeyError: except KeyError:
pass pass
def __delitem__(self, key): def __delitem__(self, key):
del self.data[ref(key)] r = ref(key)
del self.data[r]
del self.refs[r]
def __getitem__(self, key): def __getitem__(self, key):
return self.data[ref(key)] return self.data[ref(key)]
...@@ -318,7 +353,11 @@ class WeakKeyDictionary(UserDict.UserDict): ...@@ -318,7 +353,11 @@ class WeakKeyDictionary(UserDict.UserDict):
return "<WeakKeyDictionary at %s>" % id(self) return "<WeakKeyDictionary at %s>" % id(self)
def __setitem__(self, key, value): def __setitem__(self, key, value):
self.data[ref(key, self._remove)] = value r = ref(key, self._remove)
self.data.pop(r, None)
self.refs.pop(r, None)
self.data[r] = value
self.refs[r] = r
def copy(self): def copy(self):
new = WeakKeyDictionary() new = WeakKeyDictionary()
...@@ -421,23 +460,28 @@ class WeakKeyDictionary(UserDict.UserDict): ...@@ -421,23 +460,28 @@ class WeakKeyDictionary(UserDict.UserDict):
def popitem(self): def popitem(self):
while 1: while 1:
key, value = self.data.popitem() _, key = self.refs.popitem()
value = self.data.pop(key)
o = key() o = key()
if o is not None: if o is not None:
return o, value return o, value
def pop(self, key, *args): def pop(self, key, *args):
return self.data.pop(ref(key), *args) r = ref(key)
self.keys.pop(r, None)
return self.data.pop(r, *args)
def setdefault(self, key, default=None): def setdefault(self, key, default=None):
return self.data.setdefault(ref(key, self._remove),default) if key not in self:
self[key] = default
return default
return self[key]
def update(self, dict=None, **kwargs): def update(self, dict=None, **kwargs):
d = self.data
if dict is not None: if dict is not None:
if not hasattr(dict, "items"): if not hasattr(dict, "items"):
dict = type({})(dict) dict = type({})(dict)
for key, value in dict.items(): for key, value in dict.items():
d[ref(key, self._remove)] = value self[key] = value
if len(kwargs): if len(kwargs):
self.update(kwargs) self.update(kwargs)
...@@ -56,13 +56,16 @@ ConcreteCompilerType* NullTypeAnalysis::getTypeAtBlockEnd(InternedString name, C ...@@ -56,13 +56,16 @@ ConcreteCompilerType* NullTypeAnalysis::getTypeAtBlockEnd(InternedString name, C
} }
// Note: the behavior of this function must match irgenerator.cpp::unboxVar()
static ConcreteCompilerType* unboxedType(ConcreteCompilerType* t) { static ConcreteCompilerType* unboxedType(ConcreteCompilerType* t) {
if (t == BOXED_BOOL)
return BOOL;
#if ENABLE_UNBOXED_VALUES
if (t == BOXED_INT) if (t == BOXED_INT)
return INT; return INT;
if (t == BOXED_FLOAT) if (t == BOXED_FLOAT)
return FLOAT; return FLOAT;
if (t == BOXED_BOOL) #endif
return BOOL;
return t; return t;
} }
......
...@@ -933,11 +933,16 @@ Box* slotTpGetattrHookInternal(Box* self, BoxedString* name, GetattrRewriteArgs* ...@@ -933,11 +933,16 @@ Box* slotTpGetattrHookInternal(Box* self, BoxedString* name, GetattrRewriteArgs*
getattribute = typeLookup(self->cls, _getattribute_str, &grewrite_args); getattribute = typeLookup(self->cls, _getattribute_str, &grewrite_args);
if (!grewrite_args.out_success) if (!grewrite_args.out_success)
rewrite_args = NULL; rewrite_args = NULL;
else if (getattribute) else if (getattribute) {
assert(grewrite_args.out_return_convention == GetattrRewriteArgs::VALID_RETURN);
r_getattribute = grewrite_args.out_rtn; r_getattribute = grewrite_args.out_rtn;
} else {
assert(grewrite_args.out_return_convention == GetattrRewriteArgs::NO_RETURN);
}
} else { } else {
getattribute = typeLookup(self->cls, _getattribute_str, NULL); getattribute = typeLookup(self->cls, _getattribute_str, NULL);
} }
// Not sure why CPython checks if getattribute is NULL since I don't think that should happen. // Not sure why CPython checks if getattribute is NULL since I don't think that should happen.
// Is there some legacy way of creating types that don't inherit from object? Anyway, I think we // Is there some legacy way of creating types that don't inherit from object? Anyway, I think we
// have the right behavior even if getattribute was somehow NULL, but add an assert because that // have the right behavior even if getattribute was somehow NULL, but add an assert because that
......
...@@ -1778,6 +1778,7 @@ public: ...@@ -1778,6 +1778,7 @@ public:
llvm::Value* unboxed = emitter.getBuilder()->CreateCall(g.funcs.unboxBool, rtn->getValue()); llvm::Value* unboxed = emitter.getBuilder()->CreateCall(g.funcs.unboxBool, rtn->getValue());
return boolFromI1(emitter, unboxed); return boolFromI1(emitter, unboxed);
} }
#if ENABLE_UNBOXED_VALUES
if (cf->spec->rtn_type == BOXED_INT) { if (cf->spec->rtn_type == BOXED_INT) {
llvm::Value* unboxed = emitter.getBuilder()->CreateCall(g.funcs.unboxInt, rtn->getValue()); llvm::Value* unboxed = emitter.getBuilder()->CreateCall(g.funcs.unboxInt, rtn->getValue());
return new ConcreteCompilerVariable(INT, unboxed, true); return new ConcreteCompilerVariable(INT, unboxed, true);
...@@ -1787,8 +1788,9 @@ public: ...@@ -1787,8 +1788,9 @@ public:
return new ConcreteCompilerVariable(FLOAT, unboxed, true); return new ConcreteCompilerVariable(FLOAT, unboxed, true);
} }
assert(cf->spec->rtn_type != BOXED_INT); assert(cf->spec->rtn_type != BOXED_INT);
ASSERT(cf->spec->rtn_type != BOXED_BOOL, "%p", cf->code);
assert(cf->spec->rtn_type != BOXED_FLOAT); assert(cf->spec->rtn_type != BOXED_FLOAT);
#endif
ASSERT(cf->spec->rtn_type != BOXED_BOOL, "%p", cf->code);
return rtn; return rtn;
} }
...@@ -2607,7 +2609,7 @@ public: ...@@ -2607,7 +2609,7 @@ public:
} }
CompilerVariable* contains(IREmitter& emitter, const OpInfo& info, VAR* var, CompilerVariable* lhs) override { CompilerVariable* contains(IREmitter& emitter, const OpInfo& info, VAR* var, CompilerVariable* lhs) override {
return undefVariable(); return boolFromI1(emitter, llvm::UndefValue::get(g.i1));
} }
CompilerVariable* getitem(IREmitter& emitter, const OpInfo& info, ConcreteCompilerVariable* var, CompilerVariable* getitem(IREmitter& emitter, const OpInfo& info, ConcreteCompilerVariable* var,
......
...@@ -874,7 +874,8 @@ private: ...@@ -874,7 +874,8 @@ private:
if (type == AST_TYPE::In || type == AST_TYPE::NotIn) { if (type == AST_TYPE::In || type == AST_TYPE::NotIn) {
CompilerVariable* r = right->contains(emitter, getOpInfoForNode(node, unw_info), left); CompilerVariable* r = right->contains(emitter, getOpInfoForNode(node, unw_info), left);
assert(r->getType() == BOOL); ASSERT(r->getType() == BOOL, "%s gave %s", right->getType()->debugName().c_str(),
r->getType()->debugName().c_str());
if (type == AST_TYPE::NotIn) { if (type == AST_TYPE::NotIn) {
ConcreteCompilerVariable* converted = r->makeConverted(emitter, BOOL); ConcreteCompilerVariable* converted = r->makeConverted(emitter, BOOL);
// TODO: would be faster to just do unboxBoolNegated // TODO: would be faster to just do unboxBoolNegated
...@@ -1510,7 +1511,9 @@ private: ...@@ -1510,7 +1511,9 @@ private:
return func; return func;
} }
// Note: the behavior of this function must match type_analysis.cpp:unboxedType()
ConcreteCompilerVariable* unboxVar(ConcreteCompilerType* t, llvm::Value* v, bool grabbed) { ConcreteCompilerVariable* unboxVar(ConcreteCompilerType* t, llvm::Value* v, bool grabbed) {
#if ENABLE_UNBOXED_VALUES
if (t == BOXED_INT) { if (t == BOXED_INT) {
llvm::Value* unboxed = emitter.getBuilder()->CreateCall(g.funcs.unboxInt, v); llvm::Value* unboxed = emitter.getBuilder()->CreateCall(g.funcs.unboxInt, v);
ConcreteCompilerVariable* rtn = new ConcreteCompilerVariable(INT, unboxed, true); ConcreteCompilerVariable* rtn = new ConcreteCompilerVariable(INT, unboxed, true);
...@@ -1521,6 +1524,7 @@ private: ...@@ -1521,6 +1524,7 @@ private:
ConcreteCompilerVariable* rtn = new ConcreteCompilerVariable(FLOAT, unboxed, true); ConcreteCompilerVariable* rtn = new ConcreteCompilerVariable(FLOAT, unboxed, true);
return rtn; return rtn;
} }
#endif
if (t == BOXED_BOOL) { if (t == BOXED_BOOL) {
llvm::Value* unboxed = emitter.getBuilder()->CreateCall(g.funcs.unboxBool, v); llvm::Value* unboxed = emitter.getBuilder()->CreateCall(g.funcs.unboxBool, v);
return boolFromI1(emitter, unboxed); return boolFromI1(emitter, unboxed);
...@@ -2198,9 +2202,11 @@ private: ...@@ -2198,9 +2202,11 @@ private:
ConcreteCompilerVariable* var = p.second->makeConverted(emitter, p.second->getConcreteType()); ConcreteCompilerVariable* var = p.second->makeConverted(emitter, p.second->getConcreteType());
converted_args.push_back(var); converted_args.push_back(var);
#if ENABLE_UNBOXED_VALUES
assert(var->getType() != BOXED_INT && "should probably unbox it, but why is it boxed in the first place?"); assert(var->getType() != BOXED_INT && "should probably unbox it, but why is it boxed in the first place?");
assert(var->getType() != BOXED_FLOAT assert(var->getType() != BOXED_FLOAT
&& "should probably unbox it, but why is it boxed in the first place?"); && "should probably unbox it, but why is it boxed in the first place?");
#endif
// This line can never get hit right now for the same reason that the variables must already be // This line can never get hit right now for the same reason that the variables must already be
// concrete, // concrete,
...@@ -2647,8 +2653,10 @@ public: ...@@ -2647,8 +2653,10 @@ public:
assert(name.s() != FRAME_INFO_PTR_NAME); assert(name.s() != FRAME_INFO_PTR_NAME);
ASSERT(irstate->getScopeInfo()->getScopeTypeOfName(name) != ScopeInfo::VarScopeType::GLOBAL, "%s", ASSERT(irstate->getScopeInfo()->getScopeTypeOfName(name) != ScopeInfo::VarScopeType::GLOBAL, "%s",
name.c_str()); name.c_str());
#if ENABLE_UNBOXED_VALUES
assert(var->getType() != BOXED_INT); assert(var->getType() != BOXED_INT);
assert(var->getType() != BOXED_FLOAT); assert(var->getType() != BOXED_FLOAT);
#endif
CompilerVariable*& cur = symbol_table[name]; CompilerVariable*& cur = symbol_table[name];
assert(cur == NULL); assert(cur == NULL);
cur = var; cur = var;
......
...@@ -67,6 +67,9 @@ public: ...@@ -67,6 +67,9 @@ public:
void push_back(AST_stmt* node) { body.push_back(node); } void push_back(AST_stmt* node) { body.push_back(node); }
void print(llvm::raw_ostream& stream = llvm::outs()); void print(llvm::raw_ostream& stream = llvm::outs());
void _print() {
print();
}
}; };
// Control Flow Graph // Control Flow Graph
......
...@@ -51,6 +51,12 @@ extern bool ENABLE_ICS, ENABLE_ICGENERICS, ENABLE_ICGETITEMS, ENABLE_ICSETITEMS, ...@@ -51,6 +51,12 @@ extern bool ENABLE_ICS, ENABLE_ICGENERICS, ENABLE_ICGETITEMS, ENABLE_ICSETITEMS,
extern bool BOOLS_AS_I64; extern bool BOOLS_AS_I64;
#define ENABLE_SAMPLING_PROFILER 0 #define ENABLE_SAMPLING_PROFILER 0
// Our current implementation of unbox values has some minor compatibility issues, where it can
// change the apparent id() / is-equality of a boxed value (by inserting extra unbox+box pairs).
// I think it can be rescued (we need the unboxed compilertype to remember the boxed value),
// but for now it's just turned off with this flag.
#define ENABLE_UNBOXED_VALUES 0
} }
} }
......
...@@ -660,7 +660,12 @@ static void graphTraversalMarking(Worklist& worklist, GCVisitor& visitor) { ...@@ -660,7 +660,12 @@ static void graphTraversalMarking(Worklist& worklist, GCVisitor& visitor) {
static void callWeakrefCallback(PyWeakReference* head) { static void callWeakrefCallback(PyWeakReference* head) {
if (head->wr_callback) { if (head->wr_callback) {
runtimeCall(head->wr_callback, ArgPassSpec(1), reinterpret_cast<Box*>(head), NULL, NULL, NULL, NULL); try {
runtimeCall(head->wr_callback, ArgPassSpec(1), reinterpret_cast<Box*>(head), NULL, NULL, NULL, NULL);
} catch (ExcInfo e) {
setCAPIException(e);
PyErr_WriteUnraisable(head->wr_callback);
}
head->wr_callback = NULL; head->wr_callback = NULL;
} }
} }
......
...@@ -564,13 +564,17 @@ Box* getattrFuncInternal(BoxedFunctionBase* func, CallRewriteArgs* rewrite_args, ...@@ -564,13 +564,17 @@ Box* getattrFuncInternal(BoxedFunctionBase* func, CallRewriteArgs* rewrite_args,
if (rewrite_args) { if (rewrite_args) {
GetattrRewriteArgs grewrite_args(rewrite_args->rewriter, rewrite_args->arg1, rewrite_args->destination); GetattrRewriteArgs grewrite_args(rewrite_args->rewriter, rewrite_args->arg1, rewrite_args->destination);
rtn = getattrInternal<CAPI>(obj, str, &grewrite_args); rtn = getattrInternal<CAPI>(obj, str, &grewrite_args);
if (!grewrite_args.out_success) // TODO could make the return valid in the NOEXC_POSSIBLE case via a helper
if (!grewrite_args.out_success || grewrite_args.out_return_convention == GetattrRewriteArgs::NOEXC_POSSIBLE)
rewrite_args = NULL; rewrite_args = NULL;
else { else {
if (!rtn && !PyErr_Occurred()) if (!rtn && !PyErr_Occurred()) {
assert(grewrite_args.out_return_convention == GetattrRewriteArgs::NO_RETURN);
r_rtn = rewrite_args->rewriter->loadConst(0); r_rtn = rewrite_args->rewriter->loadConst(0);
else } else {
assert(grewrite_args.out_return_convention == GetattrRewriteArgs::VALID_RETURN);
r_rtn = grewrite_args.out_rtn; r_rtn = grewrite_args.out_rtn;
}
} }
} else { } else {
rtn = getattrInternal<CAPI>(obj, str, NULL); rtn = getattrInternal<CAPI>(obj, str, NULL);
...@@ -673,13 +677,16 @@ Box* hasattrFuncInternal(BoxedFunctionBase* func, CallRewriteArgs* rewrite_args, ...@@ -673,13 +677,16 @@ Box* hasattrFuncInternal(BoxedFunctionBase* func, CallRewriteArgs* rewrite_args,
if (rewrite_args) { if (rewrite_args) {
GetattrRewriteArgs grewrite_args(rewrite_args->rewriter, rewrite_args->arg1, rewrite_args->destination); GetattrRewriteArgs grewrite_args(rewrite_args->rewriter, rewrite_args->arg1, rewrite_args->destination);
rtn = getattrInternal<CAPI>(obj, str, &grewrite_args); rtn = getattrInternal<CAPI>(obj, str, &grewrite_args);
if (!grewrite_args.out_success) if (!grewrite_args.out_success || grewrite_args.out_return_convention == GetattrRewriteArgs::NOEXC_POSSIBLE)
rewrite_args = NULL; rewrite_args = NULL;
else { else {
if (!rtn && !PyErr_Occurred()) if (!rtn && !PyErr_Occurred()) {
assert(grewrite_args.out_return_convention == GetattrRewriteArgs::NO_RETURN);
r_rtn = rewrite_args->rewriter->loadConst(0); r_rtn = rewrite_args->rewriter->loadConst(0);
else } else {
assert(grewrite_args.out_return_convention == GetattrRewriteArgs::VALID_RETURN);
r_rtn = grewrite_args.out_rtn; r_rtn = grewrite_args.out_rtn;
}
} }
} else { } else {
rtn = getattrInternal<CAPI>(obj, str, NULL); rtn = getattrInternal<CAPI>(obj, str, NULL);
...@@ -1322,8 +1329,8 @@ Box* getreversed(Box* o) { ...@@ -1322,8 +1329,8 @@ Box* getreversed(Box* o) {
return new (seqreviter_cls) BoxedSeqIter(o, len - 1); return new (seqreviter_cls) BoxedSeqIter(o, len - 1);
} }
Box* pydump(Box* p) { Box* pydump(Box* p, BoxedInt* level) {
dump(p); dumpEx(p, level->n);
return None; return None;
} }
...@@ -1587,8 +1594,8 @@ void setupBuiltins() { ...@@ -1587,8 +1594,8 @@ void setupBuiltins() {
builtins_module->giveAttr("ord", ord_obj); builtins_module->giveAttr("ord", ord_obj);
trap_obj = new BoxedBuiltinFunctionOrMethod(boxRTFunction((void*)trap, UNKNOWN, 0), "trap"); trap_obj = new BoxedBuiltinFunctionOrMethod(boxRTFunction((void*)trap, UNKNOWN, 0), "trap");
builtins_module->giveAttr("trap", trap_obj); builtins_module->giveAttr("trap", trap_obj);
builtins_module->giveAttr("dump", builtins_module->giveAttr(
new BoxedBuiltinFunctionOrMethod(boxRTFunction((void*)pydump, UNKNOWN, 1), "dump")); "dump", new BoxedBuiltinFunctionOrMethod(boxRTFunction((void*)pydump, UNKNOWN, 2), "dump", { boxInt(0) }));
builtins_module->giveAttr( builtins_module->giveAttr(
"dumpAddr", new BoxedBuiltinFunctionOrMethod(boxRTFunction((void*)pydumpAddr, UNKNOWN, 1), "dumpAddr")); "dumpAddr", new BoxedBuiltinFunctionOrMethod(boxRTFunction((void*)pydumpAddr, UNKNOWN, 1), "dumpAddr"));
......
...@@ -313,6 +313,8 @@ static Box* instanceGetattributeSimple(BoxedInstance* inst, BoxedString* attr_st ...@@ -313,6 +313,8 @@ static Box* instanceGetattributeSimple(BoxedInstance* inst, BoxedString* attr_st
r = classLookup(inst->inst_cls, attr_str, rewriter_args ? &grewriter_inst_args : NULL); r = classLookup(inst->inst_cls, attr_str, rewriter_args ? &grewriter_inst_args : NULL);
if (!grewriter_inst_args.out_success) if (!grewriter_inst_args.out_success)
rewriter_args = NULL; rewriter_args = NULL;
else
assert(grewriter_inst_args.out_return_convention == GetattrRewriteArgs::VALID_RETURN);
if (r) { if (r) {
Box* rtn = processDescriptor(r, inst, inst->inst_cls); Box* rtn = processDescriptor(r, inst, inst->inst_cls);
......
...@@ -1592,6 +1592,7 @@ extern "C" Box* getclsattr(Box* obj, BoxedString* attr) { ...@@ -1592,6 +1592,7 @@ extern "C" Box* getclsattr(Box* obj, BoxedString* attr) {
gotten = getclsattrInternal(obj, attr, &rewrite_args); gotten = getclsattrInternal(obj, attr, &rewrite_args);
if (rewrite_args.out_success && gotten) { if (rewrite_args.out_success && gotten) {
assert(rewrite_args.out_return_convention == GetattrRewriteArgs::VALID_RETURN);
rewriter->commitReturning(rewrite_args.out_rtn); rewriter->commitReturning(rewrite_args.out_rtn);
} }
#endif #endif
...@@ -1715,6 +1716,7 @@ Box* getattrInternalGeneric(Box* obj, BoxedString* attr, GetattrRewriteArgs* rew ...@@ -1715,6 +1716,7 @@ Box* getattrInternalGeneric(Box* obj, BoxedString* attr, GetattrRewriteArgs* rew
if (!grewrite_args.out_success) { if (!grewrite_args.out_success) {
rewrite_args = NULL; rewrite_args = NULL;
} else if (_get_) { } else if (_get_) {
assert(grewrite_args.out_return_convention == GetattrRewriteArgs::VALID_RETURN);
r_get = grewrite_args.out_rtn; r_get = grewrite_args.out_rtn;
} }
} else { } else {
...@@ -1737,6 +1739,9 @@ Box* getattrInternalGeneric(Box* obj, BoxedString* attr, GetattrRewriteArgs* rew ...@@ -1737,6 +1739,9 @@ Box* getattrInternalGeneric(Box* obj, BoxedString* attr, GetattrRewriteArgs* rew
_set_ = typeLookup(descr->cls, set_str, &grewrite_args); _set_ = typeLookup(descr->cls, set_str, &grewrite_args);
if (!grewrite_args.out_success) { if (!grewrite_args.out_success) {
rewrite_args = NULL; rewrite_args = NULL;
} else {
assert(grewrite_args.out_return_convention
== (_set_ ? GetattrRewriteArgs::VALID_RETURN : GetattrRewriteArgs::NO_RETURN));
} }
} else { } else {
_set_ = typeLookup(descr->cls, set_str, NULL); _set_ = typeLookup(descr->cls, set_str, NULL);
...@@ -1847,6 +1852,7 @@ Box* getattrInternalGeneric(Box* obj, BoxedString* attr, GetattrRewriteArgs* rew ...@@ -1847,6 +1852,7 @@ Box* getattrInternalGeneric(Box* obj, BoxedString* attr, GetattrRewriteArgs* rew
if (!grewrite_args.out_success) { if (!grewrite_args.out_success) {
rewrite_args = NULL; rewrite_args = NULL;
} else if (val) { } else if (val) {
assert(grewrite_args.out_return_convention == GetattrRewriteArgs::VALID_RETURN);
r_val = grewrite_args.out_rtn; r_val = grewrite_args.out_rtn;
} }
} else { } else {
...@@ -2190,13 +2196,14 @@ void setattrGeneric(Box* obj, BoxedString* attr, Box* val, SetattrRewriteArgs* r ...@@ -2190,13 +2196,14 @@ void setattrGeneric(Box* obj, BoxedString* attr, Box* val, SetattrRewriteArgs* r
// (otherwise no need to check descriptor logic) // (otherwise no need to check descriptor logic)
if (rewrite_args) { if (rewrite_args) {
RewriterVar* r_cls = rewrite_args->obj->getAttr(offsetof(Box, cls), Location::any()); RewriterVar* r_cls = rewrite_args->obj->getAttr(offsetof(Box, cls), Location::any());
GetattrRewriteArgs crewrite_args(rewrite_args->rewriter, r_cls, rewrite_args->rewriter->getReturnDestination()); GetattrRewriteArgs grewrite_args(rewrite_args->rewriter, r_cls, rewrite_args->rewriter->getReturnDestination());
descr = typeLookup(obj->cls, attr, &crewrite_args); descr = typeLookup(obj->cls, attr, &grewrite_args);
if (!crewrite_args.out_success) { if (!grewrite_args.out_success) {
rewrite_args = NULL; rewrite_args = NULL;
} else if (descr) { } else if (descr) {
r_descr = crewrite_args.out_rtn; assert(grewrite_args.out_return_convention == GetattrRewriteArgs::VALID_RETURN);
r_descr = grewrite_args.out_rtn;
} }
} else { } else {
descr = typeLookup(obj->cls, attr, NULL); descr = typeLookup(obj->cls, attr, NULL);
...@@ -2213,12 +2220,13 @@ void setattrGeneric(Box* obj, BoxedString* attr, Box* val, SetattrRewriteArgs* r ...@@ -2213,12 +2220,13 @@ void setattrGeneric(Box* obj, BoxedString* attr, Box* val, SetattrRewriteArgs* r
if (rewrite_args) { if (rewrite_args) {
RewriterVar* r_cls = r_descr->getAttr(offsetof(Box, cls), Location::any()); RewriterVar* r_cls = r_descr->getAttr(offsetof(Box, cls), Location::any());
GetattrRewriteArgs trewrite_args(rewrite_args->rewriter, r_cls, Location::any()); GetattrRewriteArgs grewrite_args(rewrite_args->rewriter, r_cls, Location::any());
_set_ = typeLookup(descr->cls, set_str, &trewrite_args); _set_ = typeLookup(descr->cls, set_str, &grewrite_args);
if (!trewrite_args.out_success) { if (!grewrite_args.out_success) {
rewrite_args = NULL; rewrite_args = NULL;
} else if (_set_) { } else if (_set_) {
r_set = trewrite_args.out_rtn; assert(grewrite_args.out_return_convention == GetattrRewriteArgs::VALID_RETURN);
r_set = grewrite_args.out_rtn;
} }
} else { } else {
_set_ = typeLookup(descr->cls, set_str, NULL); _set_ = typeLookup(descr->cls, set_str, NULL);
...@@ -2313,6 +2321,7 @@ extern "C" void setattr(Box* obj, BoxedString* attr, Box* attr_val) { ...@@ -2313,6 +2321,7 @@ extern "C" void setattr(Box* obj, BoxedString* attr, Box* attr_val) {
if (rewrite_args.out_success) { if (rewrite_args.out_success) {
r_setattr = rewrite_args.out_rtn; r_setattr = rewrite_args.out_rtn;
assert(rewrite_args.out_return_convention == GetattrRewriteArgs::VALID_RETURN);
// TODO this is not good enough, since the object could get collected: // TODO this is not good enough, since the object could get collected:
r_setattr->addGuard((intptr_t)setattr); r_setattr->addGuard((intptr_t)setattr);
} else { } else {
...@@ -2841,6 +2850,7 @@ Box* callattrInternal(Box* obj, BoxedString* attr, LookupScope scope, CallRewrit ...@@ -2841,6 +2850,7 @@ Box* callattrInternal(Box* obj, BoxedString* attr, LookupScope scope, CallRewrit
if (!grewrite_args.out_success || grewrite_args.out_return_convention == GetattrRewriteArgs::NOEXC_POSSIBLE) { if (!grewrite_args.out_success || grewrite_args.out_return_convention == GetattrRewriteArgs::NOEXC_POSSIBLE) {
rewrite_args = NULL; rewrite_args = NULL;
} else if (val) { } else if (val) {
assert(grewrite_args.out_return_convention == GetattrRewriteArgs::VALID_RETURN);
r_val = grewrite_args.out_rtn; r_val = grewrite_args.out_rtn;
} }
} else { } else {
...@@ -4752,6 +4762,9 @@ static Box* callItemOrSliceAttr(Box* target, BoxedString* item_str, BoxedString* ...@@ -4752,6 +4762,9 @@ static Box* callItemOrSliceAttr(Box* target, BoxedString* item_str, BoxedString*
slice_attr = typeLookup(target->cls, slice_str, &grewrite_args); slice_attr = typeLookup(target->cls, slice_str, &grewrite_args);
if (!grewrite_args.out_success) { if (!grewrite_args.out_success) {
rewrite_args = NULL; rewrite_args = NULL;
} else {
assert(grewrite_args.out_return_convention
== (slice_attr ? GetattrRewriteArgs::VALID_RETURN : GetattrRewriteArgs::NO_RETURN));
} }
} else { } else {
slice_attr = typeLookup(target->cls, slice_str, NULL); slice_attr = typeLookup(target->cls, slice_str, NULL);
...@@ -5228,12 +5241,14 @@ extern "C" Box* createBoxedIterWrapperIfNeeded(Box* o) { ...@@ -5228,12 +5241,14 @@ extern "C" Box* createBoxedIterWrapperIfNeeded(Box* o) {
if (!rewrite_args.out_success) { if (!rewrite_args.out_success) {
rewriter.reset(NULL); rewriter.reset(NULL);
} else if (r) { } else if (r) {
assert(rewrite_args.out_return_convention == GetattrRewriteArgs::VALID_RETURN);
rewrite_args.out_rtn->addGuard((uint64_t)r); rewrite_args.out_rtn->addGuard((uint64_t)r);
if (rewrite_args.out_success) { if (rewrite_args.out_success) {
rewriter->commitReturning(r_o); rewriter->commitReturning(r_o);
return o; return o;
} }
} else if (!r) { } else if (!r) {
assert(rewrite_args.out_return_convention == GetattrRewriteArgs::NO_RETURN);
RewriterVar* var = rewriter.get()->call(true, (void*)createBoxedIterWrapper, rewriter->getArg(0)); RewriterVar* var = rewriter.get()->call(true, (void*)createBoxedIterWrapper, rewriter->getArg(0));
if (rewrite_args.out_success) { if (rewrite_args.out_success) {
rewriter->commitReturning(var); rewriter->commitReturning(var);
...@@ -5534,7 +5549,7 @@ Box* _typeNew(BoxedClass* metatype, BoxedString* name, BoxedTuple* bases, BoxedD ...@@ -5534,7 +5549,7 @@ Box* _typeNew(BoxedClass* metatype, BoxedString* name, BoxedTuple* bases, BoxedD
for (const auto& p : *attr_dict) { for (const auto& p : *attr_dict) {
auto k = coerceUnicodeToStr<CXX>(p.first); auto k = coerceUnicodeToStr<CXX>(p.first);
RELEASE_ASSERT(k->cls == str_cls, ""); RELEASE_ASSERT(k->cls == str_cls, "%s", k->cls->tp_name);
BoxedString* s = static_cast<BoxedString*>(k); BoxedString* s = static_cast<BoxedString*>(k);
internStringMortalInplace(s); internStringMortalInplace(s);
made->setattr(s, p.second, NULL); made->setattr(s, p.second, NULL);
...@@ -5735,6 +5750,11 @@ extern "C" Box* getGlobal(Box* globals, BoxedString* name) { ...@@ -5735,6 +5750,11 @@ extern "C" Box* getGlobal(Box* globals, BoxedString* name) {
r = m->getattr(name, &rewrite_args); r = m->getattr(name, &rewrite_args);
if (!rewrite_args.out_success) { if (!rewrite_args.out_success) {
rewriter.reset(NULL); rewriter.reset(NULL);
} else {
if (r)
assert(rewrite_args.out_return_convention == GetattrRewriteArgs::VALID_RETURN);
else
assert(rewrite_args.out_return_convention == GetattrRewriteArgs::NO_RETURN);
} }
if (r) { if (r) {
if (rewriter.get()) { if (rewriter.get()) {
...@@ -5774,6 +5794,8 @@ extern "C" Box* getGlobal(Box* globals, BoxedString* name) { ...@@ -5774,6 +5794,8 @@ extern "C" Box* getGlobal(Box* globals, BoxedString* name) {
if (!rtn || !rewrite_args.out_success) { if (!rtn || !rewrite_args.out_success) {
rewriter.reset(NULL); rewriter.reset(NULL);
} else {
assert(rewrite_args.out_return_convention == GetattrRewriteArgs::VALID_RETURN);
} }
if (rewriter.get()) { if (rewriter.get()) {
......
...@@ -909,6 +909,7 @@ static Box* typeCallInner(CallRewriteArgs* rewrite_args, ArgPassSpec argspec, Bo ...@@ -909,6 +909,7 @@ static Box* typeCallInner(CallRewriteArgs* rewrite_args, ArgPassSpec argspec, Bo
rewrite_args = NULL; rewrite_args = NULL;
else { else {
assert(new_attr); assert(new_attr);
assert(grewrite_args.out_return_convention = GetattrRewriteArgs::VALID_RETURN);
r_new = grewrite_args.out_rtn; r_new = grewrite_args.out_rtn;
r_new->addGuard((intptr_t)new_attr); r_new->addGuard((intptr_t)new_attr);
} }
...@@ -1051,8 +1052,11 @@ static Box* typeCallInner(CallRewriteArgs* rewrite_args, ArgPassSpec argspec, Bo ...@@ -1051,8 +1052,11 @@ static Box* typeCallInner(CallRewriteArgs* rewrite_args, ArgPassSpec argspec, Bo
rewrite_args = NULL; rewrite_args = NULL;
else { else {
if (init_attr) { if (init_attr) {
assert(grewrite_args.out_return_convention = GetattrRewriteArgs::VALID_RETURN);
r_init = grewrite_args.out_rtn; r_init = grewrite_args.out_rtn;
r_init->addGuard((intptr_t)init_attr); r_init->addGuard((intptr_t)init_attr);
} else {
assert(grewrite_args.out_return_convention = GetattrRewriteArgs::NO_RETURN);
} }
} }
} else { } else {
......
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
#include "runtime/util.h" #include "runtime/util.h"
#include "codegen/codegen.h" #include "codegen/codegen.h"
#include "core/cfg.h"
#include "core/options.h" #include "core/options.h"
#include "core/types.h" #include "core/types.h"
#include "runtime/long.h" #include "runtime/long.h"
...@@ -258,6 +259,11 @@ extern "C" void dumpEx(void* p, int levels) { ...@@ -258,6 +259,11 @@ extern "C" void dumpEx(void* p, int levels) {
CLFunction* cl = f->f; CLFunction* cl = f->f;
if (cl->source) { if (cl->source) {
printf("User-defined function '%s'\n", cl->source->getName()->c_str()); printf("User-defined function '%s'\n", cl->source->getName()->c_str());
printf("Defined at %s:%d\n", cl->source->getFn()->c_str(), cl->source->body[0]->lineno);
if (cl->source->cfg && levels > 0) {
cl->source->cfg->print();
}
} else { } else {
printf("A builtin function\n"); printf("A builtin function\n");
} }
......
...@@ -62,13 +62,60 @@ sqlalchemy.testing.plugin.plugin_base.pre_begin(options) ...@@ -62,13 +62,60 @@ sqlalchemy.testing.plugin.plugin_base.pre_begin(options)
sqlalchemy.testing.plugin.plugin_base.read_config() sqlalchemy.testing.plugin.plugin_base.read_config()
sqlalchemy.testing.plugin.pytestplugin.pytest_sessionstart(None) sqlalchemy.testing.plugin.pytestplugin.pytest_sessionstart(None)
# Bug in this file: they forgot to import SkipTest
import sqlalchemy.testing.profiling
sqlalchemy.testing.profiling.SkipTest = SkipTest
# The tests are kind enough to call `lazy_gc()` to make sure things get finalized,
# but with our conservative collector that's usually not enough.
import sqlalchemy.testing.util
def no_gc():
raise SkipTest()
sqlalchemy.testing.util.lazy_gc = no_gc
import glob import glob
test_files = glob.glob(TEST_DIR + "/test*.py") + glob.glob(TEST_DIR + "/*/test*.py") test_files = glob.glob(TEST_DIR + "/test*.py") + glob.glob(TEST_DIR + "/*/test*.py")
test_files.sort()
CPYTHON_PASSING = [
'test.aaa_profiling.test_compiler', 'test.aaa_profiling.test_memusage',
'test.aaa_profiling.test_orm', 'test.aaa_profiling.test_pool', 'test.aaa_profiling.test_resultset',
'test.base.test_dependency', 'test.base.test_events', 'test.base.test_except', 'test.base.test_inspect', 'test.base.test_utils',
'test.dialect.test_mxodbc', 'test.dialect.test_pyodbc', 'test.dialect.test_sqlite', 'test.dialect.test_sybase',
'test.engine.test_bind', 'test.engine.test_ddlevents', 'test.engine.test_logging',
'test.engine.test_parseconnect', 'test.engine.test_pool', 'test.engine.test_reconnect',
'test.ext.test_compiler', 'test.ext.test_extendedattr', 'test.ext.test_hybrid', 'test.ext.test_orderinglist',
'test.orm.test_association', 'test.orm.test_assorted_eager', 'test.orm.test_attributes', 'test.orm.test_backref_mutations',
'test.orm.test_bind', 'test.orm.test_bulk', 'test.orm.test_bundle', 'test.orm.test_collection',
'test.orm.test_compile', 'test.orm.test_composites', 'test.orm.test_cycles', 'test.orm.test_defaults',
'test.orm.test_default_strategies', 'test.orm.test_deferred', 'test.orm.test_deprecations', 'test.orm.test_descriptor',
'test.orm.test_dynamic', 'test.orm.test_eager_relations', 'test.orm.test_evaluator', 'test.orm.test_events',
'test.orm.test_expire', 'test.orm.test_hasparent', 'test.orm.test_immediate_load', 'test.orm.test_inspect',
'test.orm.test_joins', 'test.orm.test_lazy_relations', 'test.orm.test_load_on_fks', 'test.orm.test_lockmode',
'test.orm.test_manytomany', 'test.orm.test_merge', 'test.orm.test_naturalpks', 'test.orm.test_of_type',
'test.orm.test_onetoone', 'test.orm.test_options', 'test.orm.test_query', 'test.orm.test_relationships',
'test.orm.test_rel_fn', 'test.orm.test_scoping', 'test.orm.test_selectable', 'test.orm.test_session',
'test.orm.test_sync', 'test.orm.test_transaction', 'test.orm.test_unitofworkv2', 'test.orm.test_update_delete',
'test.orm.test_utils', 'test.orm.test_validators', 'test.orm.test_versioning',
'test.sql.test_case_statement', 'test.sql.test_compiler', 'test.sql.test_constraints', 'test.sql.test_cte',
'test.sql.test_ddlemit', 'test.sql.test_delete', 'test.sql.test_functions', 'test.sql.test_generative',
'test.sql.test_insert', 'test.sql.test_inspect', 'test.sql.test_join_rewriting', 'test.sql.test_labels',
'test.sql.test_operators', 'test.sql.test_query', 'test.sql.test_quote', 'test.sql.test_rowcount',
'test.sql.test_selectable', 'test.sql.test_text', 'test.sql.test_unicode',
]
# These are the ones that pass on CPython (ie that we've stubbed enough of their testing # These are the ones that pass on CPython (ie that we've stubbed enough of their testing
# infrastructure to run): # infrastructure to run):
MODULES_TO_TEST = [ MODULES_TO_TEST = [
'test.aaa_profiling.test_compiler',
'test.aaa_profiling.test_orm',
'test.aaa_profiling.test_pool',
'test.base.test_dependency', 'test.base.test_dependency',
'test.base.test_events', 'test.base.test_events',
'test.base.test_except', 'test.base.test_except',
...@@ -77,26 +124,107 @@ MODULES_TO_TEST = [ ...@@ -77,26 +124,107 @@ MODULES_TO_TEST = [
'test.dialect.test_mxodbc', 'test.dialect.test_mxodbc',
'test.dialect.test_pyodbc', 'test.dialect.test_pyodbc',
'test.dialect.test_sybase', 'test.dialect.test_sybase',
'test.engine.test_bind',
'test.engine.test_ddlevents',
'test.engine.test_parseconnect', 'test.engine.test_parseconnect',
'test.engine.test_pool',
'test.engine.test_reconnect',
'test.ext.test_compiler', 'test.ext.test_compiler',
'test.orm.test_association',
'test.orm.test_assorted_eager',
'test.orm.test_backref_mutations',
'test.orm.test_bind',
'test.orm.test_bulk',
'test.orm.test_bundle',
'test.orm.test_compile',
'test.orm.test_cycles',
'test.orm.test_defaults',
'test.orm.test_default_strategies',
'test.orm.test_deferred',
'test.orm.test_deprecations',
'test.orm.test_descriptor', 'test.orm.test_descriptor',
'test.orm.test_eager_relations',
'test.orm.test_evaluator',
'test.orm.test_expire',
'test.orm.test_inspect', 'test.orm.test_inspect',
'test.orm.test_load_on_fks',
'test.orm.test_lockmode',
'test.orm.test_onetoone',
'test.orm.test_options',
'test.orm.test_query', 'test.orm.test_query',
'test.orm.test_rel_fn',
'test.orm.test_scoping',
'test.orm.test_selectable',
'test.orm.test_sync',
'test.orm.test_validators',
'test.sql.test_case_statement',
'test.sql.test_constraints',
'test.sql.test_cte', 'test.sql.test_cte',
'test.sql.test_ddlemit', 'test.sql.test_ddlemit',
'test.sql.test_delete',
'test.sql.test_functions',
'test.sql.test_insert',
'test.sql.test_inspect', 'test.sql.test_inspect',
'test.sql.test_join_rewriting',
'test.sql.test_labels',
'test.sql.test_operators', 'test.sql.test_operators',
'test.sql.test_query',
'test.sql.test_rowcount',
] ]
FAILING = [
# 'test.aaa_profiling.test_memusage', # Wants gc.get_objects
# 'test.aaa_profiling.test_resultset', # Wants sys.getrefcount
# 'test.dialect.test_sqlite', # ascii codec can't encode
# 'test.engine.test_logging', # Unclear
# 'test.ext.test_extendedattr', # does `locals()[42] = 99` in a classdef to prove it can. maybe we could say is_pypy to avoid it.
'test.ext.test_hybrid',
'test.ext.test_orderinglist',
'test.orm.test_attributes',
'test.orm.test_collection',
'test.orm.test_composites',
'test.orm.test_dynamic',
'test.orm.test_events',
'test.orm.test_hasparent',
'test.orm.test_immediate_load',
'test.orm.test_joins',
'test.orm.test_lazy_relations',
'test.orm.test_manytomany',
'test.orm.test_merge',
'test.orm.test_naturalpks',
'test.orm.test_of_type',
'test.orm.test_relationships',
'test.orm.test_session',
'test.orm.test_transaction',
'test.orm.test_unitofworkv2',
'test.orm.test_update_delete',
'test.orm.test_utils',
'test.orm.test_versioning',
'test.sql.test_compiler',
'test.sql.test_generative',
'test.sql.test_quote',
'test.sql.test_selectable',
'test.sql.test_text',
'test.sql.test_unicode'
]
# MODULES_TO_TEST = ['test.orm.test_bulk']
# MODULES_TO_TEST = FAILING[:1]
passed = [] passed = []
failed = [] failed = []
for fn in test_files: for run_idx in xrange(1):
for fn in test_files:
assert fn.startswith(TEST_DIR + '/') assert fn.startswith(TEST_DIR + '/')
assert fn.endswith(".py") assert fn.endswith(".py")
mname = fn[len(SQLALCHEMY_DIR) + 1:-3].replace('/', '.') mname = fn[len(SQLALCHEMY_DIR) + 1:-3].replace('/', '.')
if mname not in MODULES_TO_TEST: if mname not in MODULES_TO_TEST:
continue continue
if mname == 'test.sql.test_functions' and run_idx > 0:
continue
print '=' * 50 print '=' * 50
print mname print mname
...@@ -114,9 +242,11 @@ for fn in test_files: ...@@ -114,9 +242,11 @@ for fn in test_files:
for t in dir(n): for t in dir(n):
if not t.startswith("test_"): if not t.startswith("test_"):
continue continue
if clsname == "SubclassGrowthTest" and t == "test_subclass":
# This test should be marked as requiring predictable_pc # These test should be marked as requiring predictable_pc
if (clsname == "SubclassGrowthTest" and t == "test_subclass"):
continue continue
print "Running", t print "Running", t
n.setup() n.setup()
try: try:
......
# Exceptions from finalizers should get caught:
import sys import sys
from testing_helpers import test_gc from testing_helpers import test_gc
...@@ -24,4 +25,27 @@ test_gc(test, 10) ...@@ -24,4 +25,27 @@ test_gc(test, 10)
print sorted(strs) print sorted(strs)
print "done"
# Similarly for exceptions from weakref callbacks:
import weakref
called_callback = False
def callback(ref):
global called_callback
if not called_callback:
print "callback"
called_callback = True
raise ValueError()
class C(object):
pass
import gc
l = []
# Make a bunch of them just to make sure at least one gets collected:
for i in xrange(100):
l.append(weakref.ref(C(), callback))
gc.collect()
# Test some weird hasattr guarding scenarios # Test some weird getattr/hasattr guarding scenarios
# I think this applies equally well to getattr
# Make sure that we guard correctly when a __getattr__ is involved:
def f(o): def f(o):
print hasattr(o, "a") print hasattr(o, "a")
print getattr(o, "a", None) print getattr(o, "a", None)
...@@ -21,3 +22,14 @@ for i in xrange(300): ...@@ -21,3 +22,14 @@ for i in xrange(300):
setattr(c, str(i), i) setattr(c, str(i), i)
f(c) f(c)
# Make sure that we guard correctly when we are megamorphic
class C(object):
pass
l = []
for i in xrange(200):
c = C()
setattr(c, "a%d" % i, i)
# We should do the right guarding so that when i==150 comes around, this will return True/None:
print i, hasattr(c, "a150"), getattr(c, "a150", None)
# Regression test:
# speculation should not result in ints changing their ids.
# I guess this means that if we unbox, we have to know what we would box to.
class C(object):
pass
c = C()
c.a = 100000
# Test it via osr:
def f():
for i in xrange(11000):
a1 = c.a
a2 = c.a
if 0:
pass
assert id(a1) == id(a2), i
f()
# Test it via reopt:
def f2():
a1 = c.a
a2 = c.a
if 0:
pass
assert id(a1) == id(a2)
for i in xrange(11000):
f2()
# Test function returns:
def g():
return 1000
def f3():
assert id(g()) == id(g())
for i in xrange(11000):
f3()
# Test function args:
def f4(a, b):
assert id(a) == id(b)
for i in xrange(11000):
f4(1000, 1000)
...@@ -32,3 +32,13 @@ try: ...@@ -32,3 +32,13 @@ try:
print 1.0[0] print 1.0[0]
except TypeError, e: except TypeError, e:
print e print e
def f2():
if 0:
1 in l
l = []
for i in xrange(100):
f2()
from weakref import WeakKeyDictionary, WeakValueDictionary
class S(object):
def __init__(self, n):
self.n = n
def __hash__(self):
return hash(self.n)
def __eq__(self, rhs):
return self.n == rhs.n
def test(d):
print "Testing on", d.__class__
k, v = None, None
for i in xrange(10):
print i
for j in xrange(100):
k, v = S(0), S(0)
d[k] = v
import gc
gc.collect()
print len(d.keys()), k in d
test(WeakKeyDictionary())
test(WeakValueDictionary())
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