Commit 4f3885c4 authored by Kevin Modzelewski's avatar Kevin Modzelewski

Merge pull request #1120 from undingen/threading_fixes

Threading and multiprocessing related fixes
parents 75bd1059 ca7c5b86
...@@ -1359,7 +1359,7 @@ xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx*/ ...@@ -1359,7 +1359,7 @@ xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx*/
*/ */
#define PyMapping_Items(O) PyObject_CallMethod(O,"items",NULL) #define PyMapping_Items(O) PyObject_CallMethod(O,"items",NULL)
PyAPI_FUNC(PyObject *) PyMapping_GetItemString(PyObject *o, char *key) PYSTON_NOEXCEPT; PyAPI_FUNC(PyObject *) PyMapping_GetItemString(PyObject *o, const char *key) PYSTON_NOEXCEPT;
/* /*
Return element of o corresponding to the object, key, or NULL Return element of o corresponding to the object, key, or NULL
...@@ -1367,7 +1367,7 @@ xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx*/ ...@@ -1367,7 +1367,7 @@ xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx*/
o[key]. o[key].
*/ */
PyAPI_FUNC(int) PyMapping_SetItemString(PyObject *o, char *key, PyAPI_FUNC(int) PyMapping_SetItemString(PyObject *o, const char *key,
PyObject *value) PYSTON_NOEXCEPT; PyObject *value) PYSTON_NOEXCEPT;
/* /*
......
...@@ -249,7 +249,7 @@ PyAPI_FUNC(void) _PyErr_BadInternalCall(const char *filename, int lineno) PYSTON ...@@ -249,7 +249,7 @@ PyAPI_FUNC(void) _PyErr_BadInternalCall(const char *filename, int lineno) PYSTON
/* Function to create a new exception */ /* Function to create a new exception */
PyAPI_FUNC(PyObject *) PyErr_NewException( PyAPI_FUNC(PyObject *) PyErr_NewException(
char *name, PyObject *base, PyObject *dict) PYSTON_NOEXCEPT; const char *name, PyObject *base, PyObject *dict) PYSTON_NOEXCEPT;
PyAPI_FUNC(PyObject *) PyErr_NewExceptionWithDoc( PyAPI_FUNC(PyObject *) PyErr_NewExceptionWithDoc(
char *name, char *doc, PyObject *base, PyObject *dict) PYSTON_NOEXCEPT; char *name, char *doc, PyObject *base, PyObject *dict) PYSTON_NOEXCEPT;
PyAPI_FUNC(void) PyErr_WriteUnraisable(PyObject *) PYSTON_NOEXCEPT; PyAPI_FUNC(void) PyErr_WriteUnraisable(PyObject *) PYSTON_NOEXCEPT;
......
...@@ -551,7 +551,7 @@ PyErr_Format(PyObject *exception, const char *format, ...) ...@@ -551,7 +551,7 @@ PyErr_Format(PyObject *exception, const char *format, ...)
PyObject * PyObject *
PyErr_NewException(char *name, PyObject *base, PyObject *dict) PyErr_NewException(const char *name, PyObject *base, PyObject *dict)
{ {
char *dot; char *dot;
PyObject *modulename = NULL; PyObject *modulename = NULL;
......
...@@ -1804,7 +1804,7 @@ extern "C" int PyMapping_HasKey(PyObject* o, PyObject* key) noexcept { ...@@ -1804,7 +1804,7 @@ extern "C" int PyMapping_HasKey(PyObject* o, PyObject* key) noexcept {
return 0; return 0;
} }
extern "C" PyObject* PyMapping_GetItemString(PyObject* o, char* key) noexcept { extern "C" PyObject* PyMapping_GetItemString(PyObject* o, const char* key) noexcept {
PyObject* okey, *r; PyObject* okey, *r;
if (key == NULL) if (key == NULL)
...@@ -1818,7 +1818,7 @@ extern "C" PyObject* PyMapping_GetItemString(PyObject* o, char* key) noexcept { ...@@ -1818,7 +1818,7 @@ extern "C" PyObject* PyMapping_GetItemString(PyObject* o, char* key) noexcept {
return r; return r;
} }
extern "C" int PyMapping_SetItemString(PyObject* o, char* key, PyObject* value) noexcept { extern "C" int PyMapping_SetItemString(PyObject* o, const char* key, PyObject* value) noexcept {
PyObject* okey; PyObject* okey;
int r; int r;
......
...@@ -41,7 +41,10 @@ public: ...@@ -41,7 +41,10 @@ public:
static BoxedString* __repr__(BoxedCApiFunction* self) { static BoxedString* __repr__(BoxedCApiFunction* self) {
assert(self->cls == capifunc_cls); assert(self->cls == capifunc_cls);
return boxString(self->method_def->ml_name); if (self->passthrough == NULL)
return (BoxedString*)PyString_FromFormat("<built-in function %s>", self->method_def->ml_name);
return (BoxedString*)PyString_FromFormat("<built-in method %s of %s object at %p>", self->method_def->ml_name,
self->passthrough->cls->tp_name, self->passthrough);
} }
static Box* __call__(BoxedCApiFunction* self, BoxedTuple* varargs, BoxedDict* kwargs); static Box* __call__(BoxedCApiFunction* self, BoxedTuple* varargs, BoxedDict* kwargs);
......
...@@ -522,11 +522,34 @@ void registerMainThread() { ...@@ -522,11 +522,34 @@ void registerMainThread() {
assert(!PyErr_Occurred()); assert(!PyErr_Occurred());
} }
/* Wait until threading._shutdown completes, provided
the threading module was imported in the first place.
The shutdown routine will wait until all non-daemon
"threading" threads have completed. */
static void wait_for_thread_shutdown(void) noexcept {
#ifdef WITH_THREAD
PyObject* result;
PyThreadState* tstate = PyThreadState_GET();
PyObject* threading = PyMapping_GetItemString(getSysModulesDict(), "threading");
if (threading == NULL) {
/* threading not imported */
PyErr_Clear();
return;
}
result = PyObject_CallMethod(threading, "_shutdown", "");
if (result == NULL)
PyErr_WriteUnraisable(threading);
else
Py_DECREF(result);
Py_DECREF(threading);
#endif
}
void finishMainThread() { void finishMainThread() {
assert(current_internal_thread_state); assert(current_internal_thread_state);
current_internal_thread_state->assertNoGenerators(); current_internal_thread_state->assertNoGenerators();
// TODO maybe this is the place to wait for non-daemon threads? wait_for_thread_shutdown();
} }
bool isMainThread() { bool isMainThread() {
...@@ -601,6 +624,22 @@ extern "C" void PyEval_ReInitThreads() noexcept { ...@@ -601,6 +624,22 @@ extern "C" void PyEval_ReInitThreads() noexcept {
threads_waiting_on_gil = 0; threads_waiting_on_gil = 0;
PerThreadSetBase::runAllForkHandlers(); PerThreadSetBase::runAllForkHandlers();
/* Update the threading module with the new state.
*/
Box* threading = PyMapping_GetItemString(getSysModulesDict(), "threading");
if (threading == NULL) {
/* threading not imported */
PyErr_Clear();
return;
}
Box* result = PyObject_CallMethod(threading, "_after_fork", NULL);
if (result == NULL)
PyErr_WriteUnraisable(threading);
else
Py_DECREF(result);
Py_DECREF(threading);
} }
void acquireGLWrite() { void acquireGLWrite() {
......
...@@ -2540,7 +2540,7 @@ void setupBuiltins() { ...@@ -2540,7 +2540,7 @@ void setupBuiltins() {
{ "reload", builtin_reload, METH_O, reload_doc }, { "reload", builtin_reload, METH_O, reload_doc },
}; };
for (auto& md : builtin_methods) { for (auto& md : builtin_methods) {
builtins_module->giveAttr(md.ml_name, new BoxedCApiFunction(&md, builtins_module, boxString("__builtin__"))); builtins_module->giveAttr(md.ml_name, new BoxedCApiFunction(&md, NULL, boxString("__builtin__")));
} }
} }
} }
...@@ -67,9 +67,6 @@ Box* sysExcClear() { ...@@ -67,9 +67,6 @@ Box* sysExcClear() {
static Box* sysExit(Box* arg) { static Box* sysExit(Box* arg) {
assert(arg); assert(arg);
Box* exc = runtimeCall(SystemExit, ArgPassSpec(1), arg, NULL, NULL, NULL, NULL); Box* exc = runtimeCall(SystemExit, ArgPassSpec(1), arg, NULL, NULL, NULL, NULL);
// TODO this should be handled by the SystemExit constructor
exc->giveAttr("code", arg);
raiseExc(exc); raiseExc(exc);
} }
...@@ -728,7 +725,7 @@ void setupSys() { ...@@ -728,7 +725,7 @@ void setupSys() {
sys_flags_cls->freeze(); sys_flags_cls->freeze();
for (auto& md : sys_methods) { for (auto& md : sys_methods) {
sys_module->giveAttr(md.ml_name, new BoxedCApiFunction(&md, sys_module, boxString("sys"))); sys_module->giveAttr(md.ml_name, new BoxedCApiFunction(&md, NULL, boxString("sys")));
} }
sys_module->giveAttr("__displayhook__", sys_module->getattr(internStringMortal("displayhook"))); sys_module->giveAttr("__displayhook__", sys_module->getattr(internStringMortal("displayhook")));
......
...@@ -90,7 +90,7 @@ static void* thread_start(Box* target, Box* varargs, Box* kwargs) { ...@@ -90,7 +90,7 @@ static void* thread_start(Box* target, Box* varargs, Box* kwargs) {
// TODO this should take kwargs, which defaults to empty // TODO this should take kwargs, which defaults to empty
Box* startNewThread(Box* target, Box* args, Box* kw) { Box* startNewThread(Box* target, Box* args, Box* kw) {
intptr_t thread_id = start_thread(&thread_start, target, args, kw); intptr_t thread_id = start_thread(&thread_start, target, args, kw);
return boxInt(thread_id ^ 0x12345678901L); return boxInt(thread_id);
} }
#define CHECK_STATUS(name) \ #define CHECK_STATUS(name) \
...@@ -244,11 +244,7 @@ void setupThread() { ...@@ -244,11 +244,7 @@ void setupThread() {
thread_lock_cls->giveAttr("locked_lock", thread_lock_cls->getattr(internStringMortal("locked"))); thread_lock_cls->giveAttr("locked_lock", thread_lock_cls->getattr(internStringMortal("locked")));
thread_lock_cls->freeze(); thread_lock_cls->freeze();
ThreadError = BoxedClass::create(type_cls, Exception, NULL, Exception->attrs_offset, Exception->tp_weaklistoffset, ThreadError = (BoxedClass*)PyErr_NewException("thread.error", NULL, NULL);
Exception->tp_basicsize, false, "error");
ThreadError->giveAttr("__module__", boxString("thread"));
ThreadError->freeze();
thread_module->giveAttr("error", ThreadError); thread_module->giveAttr("error", ThreadError);
} }
} }
...@@ -1427,20 +1427,6 @@ static Box* typeSubDict(Box* obj, void* context) { ...@@ -1427,20 +1427,6 @@ static Box* typeSubDict(Box* obj, void* context) {
abort(); abort();
} }
void Box::setDictBacked(Box* val) {
assert(this->cls->instancesHaveHCAttrs());
RELEASE_ASSERT(val->cls == dict_cls || val->cls == attrwrapper_cls, "");
auto new_attr_list = (HCAttrs::AttrList*)gc_alloc(sizeof(HCAttrs::AttrList) + sizeof(Box*), gc::GCKind::PRECISE);
new_attr_list->attrs[0] = val;
HCAttrs* hcattrs = this->getHCAttrsPtr();
hcattrs->hcls = HiddenClass::dict_backed;
hcattrs->attr_list = new_attr_list;
}
static void typeSubSetDict(Box* obj, Box* val, void* context) { static void typeSubSetDict(Box* obj, Box* val, void* context) {
if (obj->cls->instancesHaveDictAttrs()) { if (obj->cls->instancesHaveDictAttrs()) {
RELEASE_ASSERT(val->cls == dict_cls, ""); RELEASE_ASSERT(val->cls == dict_cls, "");
...@@ -1449,16 +1435,7 @@ static void typeSubSetDict(Box* obj, Box* val, void* context) { ...@@ -1449,16 +1435,7 @@ static void typeSubSetDict(Box* obj, Box* val, void* context) {
} }
if (obj->cls->instancesHaveHCAttrs()) { if (obj->cls->instancesHaveHCAttrs()) {
RELEASE_ASSERT(PyDict_Check(val) || val->cls == attrwrapper_cls, "%s", val->cls->tp_name); obj->setDictBacked(val);
auto new_attr_list
= (HCAttrs::AttrList*)gc_alloc(sizeof(HCAttrs::AttrList) + sizeof(Box*), gc::GCKind::PRECISE);
new_attr_list->attrs[0] = val;
HCAttrs* hcattrs = obj->getHCAttrsPtr();
hcattrs->hcls = HiddenClass::dict_backed;
hcattrs->attr_list = new_attr_list;
return; return;
} }
...@@ -2294,32 +2271,45 @@ public: ...@@ -2294,32 +2271,45 @@ public:
// or PyModule_GetDict to return real dicts. // or PyModule_GetDict to return real dicts.
class AttrWrapper : public Box { class AttrWrapper : public Box {
private: private:
Box* b; // The fields are not not allowed to be set at the same time
Box* b; // set when this attribute wrapper wraps a Box (default mode)
BoxedDict* private_dict; // set when the attribute wrapper does not wrap a Box anymore because the Box.__dict__
// changed to another dict.
// This is useful when we assign non str_cls keys, because the attribute array only supports strs.
void convertToDictBacked() { void convertToDictBacked() {
HCAttrs* attrs = this->b->getHCAttrsPtr(); if (isDictBacked())
if (attrs->hcls->type == HiddenClass::DICT_BACKED)
return; return;
BoxedDict* d = new BoxedDict(); HCAttrs* attrs = this->b->getHCAttrsPtr();
assert(attrs->hcls->type != HiddenClass::DICT_BACKED);
BoxedDict* d = (BoxedDict*)AttrWrapper::copy(this);
RELEASE_ASSERT(attrs->hcls->type == HiddenClass::NORMAL || attrs->hcls->type == HiddenClass::SINGLETON, ""); HCAttrs* hcattrs = b->getHCAttrsPtr();
for (const auto& p : attrs->hcls->getStrAttrOffsets()) { auto new_attr_list
d->d[p.first] = attrs->attr_list->attrs[p.second]; = (HCAttrs::AttrList*)gc_alloc(sizeof(HCAttrs::AttrList) + sizeof(Box*), gc::GCKind::PRECISE);
} new_attr_list->attrs[0] = d;
b->setDictBacked(d); hcattrs->hcls = HiddenClass::dict_backed;
hcattrs->attr_list = new_attr_list;
} }
bool isDictBacked() { return b->getHCAttrsPtr()->hcls->type == HiddenClass::DICT_BACKED; } bool isDictBacked() {
if (private_dict)
return private_dict;
return b->getHCAttrsPtr()->hcls->type == HiddenClass::DICT_BACKED;
}
Box* getDictBacking() { Box* getDictBacking() {
assert(isDictBacked()); assert(isDictBacked());
if (private_dict)
return private_dict;
return b->getHCAttrsPtr()->attr_list->attrs[0]; return b->getHCAttrsPtr()->attr_list->attrs[0];
} }
public: public:
AttrWrapper(Box* b) : b(b) { AttrWrapper(Box* b) : b(b), private_dict(NULL) {
assert(b->cls->instancesHaveHCAttrs()); assert(b->cls->instancesHaveHCAttrs());
// We currently don't support creating an attrwrapper around a dict-backed object, // We currently don't support creating an attrwrapper around a dict-backed object,
...@@ -2331,15 +2321,28 @@ public: ...@@ -2331,15 +2321,28 @@ public:
|| b->getHCAttrsPtr()->hcls->type == HiddenClass::SINGLETON); || b->getHCAttrsPtr()->hcls->type == HiddenClass::SINGLETON);
} }
void convertToPivateDict() {
RELEASE_ASSERT(!private_dict, "");
RELEASE_ASSERT(b, "");
private_dict = (BoxedDict*)AttrWrapper::copy(this);
assert(PyDict_CheckExact(private_dict));
b = NULL;
}
DEFAULT_CLASS(attrwrapper_cls); DEFAULT_CLASS(attrwrapper_cls);
Box* getUnderlying() { return b; } Box* getUnderlying() {
if (private_dict)
return private_dict;
return b;
}
static void gcHandler(GCVisitor* v, Box* b) { static void gcHandler(GCVisitor* v, Box* b) {
Box::gcHandler(v, b); Box::gcHandler(v, b);
AttrWrapper* aw = (AttrWrapper*)b; AttrWrapper* aw = (AttrWrapper*)b;
v->visit(&aw->b); v->visit(&aw->b);
v->visit(&aw->private_dict);
} }
static Box* setitem(Box* _self, Box* _key, Box* value) { static Box* setitem(Box* _self, Box* _key, Box* value) {
...@@ -2408,7 +2411,14 @@ public: ...@@ -2408,7 +2411,14 @@ public:
RELEASE_ASSERT(_self->cls == attrwrapper_cls, ""); RELEASE_ASSERT(_self->cls == attrwrapper_cls, "");
AttrWrapper* self = static_cast<AttrWrapper*>(_self); AttrWrapper* self = static_cast<AttrWrapper*>(_self);
_key = coerceUnicodeToStr<CXX>(_key); if (_key->cls != str_cls)
self->convertToDictBacked();
if (self->isDictBacked()) {
static BoxedString* get_str = internStringImmortal("get");
return callattrInternal<CXX, NOT_REWRITABLE>(self->getDictBacking(), get_str, LookupScope::CLASS_ONLY, NULL,
ArgPassSpec(2), _key, def, NULL, NULL, NULL);
}
RELEASE_ASSERT(_key->cls == str_cls, ""); RELEASE_ASSERT(_key->cls == str_cls, "");
BoxedString* key = static_cast<BoxedString*>(_key); BoxedString* key = static_cast<BoxedString*>(_key);
...@@ -2424,9 +2434,14 @@ public: ...@@ -2424,9 +2434,14 @@ public:
RELEASE_ASSERT(_self->cls == attrwrapper_cls, ""); RELEASE_ASSERT(_self->cls == attrwrapper_cls, "");
AttrWrapper* self = static_cast<AttrWrapper*>(_self); AttrWrapper* self = static_cast<AttrWrapper*>(_self);
_key = coerceUnicodeToStr<S>(_key); if (_key->cls != str_cls)
if (S == CAPI && !_key) self->convertToDictBacked();
return NULL;
if (self->isDictBacked()) {
static BoxedString* getitem_str = internStringImmortal("__getitem__");
return callattrInternal<S, NOT_REWRITABLE>(self->getDictBacking(), getitem_str, LookupScope::CLASS_ONLY,
NULL, ArgPassSpec(1), _key, NULL, NULL, NULL, NULL);
}
RELEASE_ASSERT(_key->cls == str_cls, ""); RELEASE_ASSERT(_key->cls == str_cls, "");
BoxedString* key = static_cast<BoxedString*>(_key); BoxedString* key = static_cast<BoxedString*>(_key);
...@@ -2446,7 +2461,14 @@ public: ...@@ -2446,7 +2461,14 @@ public:
RELEASE_ASSERT(_self->cls == attrwrapper_cls, ""); RELEASE_ASSERT(_self->cls == attrwrapper_cls, "");
AttrWrapper* self = static_cast<AttrWrapper*>(_self); AttrWrapper* self = static_cast<AttrWrapper*>(_self);
_key = coerceUnicodeToStr<CXX>(_key); if (_key->cls != str_cls)
self->convertToDictBacked();
if (self->isDictBacked()) {
static BoxedString* pop_str = internStringImmortal("pop");
return callattrInternal<CXX, NOT_REWRITABLE>(self->getDictBacking(), pop_str, LookupScope::CLASS_ONLY, NULL,
ArgPassSpec(2), _key, default_, NULL, NULL, NULL);
}
RELEASE_ASSERT(_key->cls == str_cls, ""); RELEASE_ASSERT(_key->cls == str_cls, "");
BoxedString* key = static_cast<BoxedString*>(_key); BoxedString* key = static_cast<BoxedString*>(_key);
...@@ -2467,7 +2489,14 @@ public: ...@@ -2467,7 +2489,14 @@ public:
RELEASE_ASSERT(_self->cls == attrwrapper_cls, ""); RELEASE_ASSERT(_self->cls == attrwrapper_cls, "");
AttrWrapper* self = static_cast<AttrWrapper*>(_self); AttrWrapper* self = static_cast<AttrWrapper*>(_self);
_key = coerceUnicodeToStr<CXX>(_key); if (_key->cls != str_cls)
self->convertToDictBacked();
if (self->isDictBacked()) {
static BoxedString* delitem_str = internStringImmortal("__delitem__");
return callattrInternal<CXX, NOT_REWRITABLE>(self->getDictBacking(), delitem_str, LookupScope::CLASS_ONLY,
NULL, ArgPassSpec(1), _key, NULL, NULL, NULL, NULL);
}
RELEASE_ASSERT(_key->cls == str_cls, ""); RELEASE_ASSERT(_key->cls == str_cls, "");
BoxedString* key = static_cast<BoxedString*>(_key); BoxedString* key = static_cast<BoxedString*>(_key);
...@@ -2487,20 +2516,31 @@ public: ...@@ -2487,20 +2516,31 @@ public:
std::string O(""); std::string O("");
llvm::raw_string_ostream os(O); llvm::raw_string_ostream os(O);
os << "attrwrapper({"; os << "attrwrapper(";
if (self->isDictBacked()) {
HCAttrs* attrs = self->b->getHCAttrsPtr(); static BoxedString* repr_str = internStringImmortal("__repr__");
RELEASE_ASSERT(attrs->hcls->type == HiddenClass::NORMAL || attrs->hcls->type == HiddenClass::SINGLETON, ""); Box* dict_repr
bool first = true; = callattrInternal<CXX, NOT_REWRITABLE>(self->getDictBacking(), repr_str, LookupScope::CLASS_ONLY, NULL,
for (const auto& p : attrs->hcls->getStrAttrOffsets()) { ArgPassSpec(0), NULL, NULL, NULL, NULL, NULL);
if (!first) RELEASE_ASSERT(PyString_CheckExact(dict_repr), "");
os << ", "; os << ((BoxedString*)dict_repr)->s();
first = false; } else {
HCAttrs* attrs = self->b->getHCAttrsPtr();
BoxedString* v = attrs->attr_list->attrs[p.second]->reprICAsString(); os << "{";
os << p.first->s() << ": " << v->s(); RELEASE_ASSERT(attrs->hcls->type == HiddenClass::NORMAL || attrs->hcls->type == HiddenClass::SINGLETON, "");
bool first = true;
for (const auto& p : attrs->hcls->getStrAttrOffsets()) {
if (!first)
os << ", ";
first = false;
BoxedString* v = attrs->attr_list->attrs[p.second]->reprICAsString();
os << p.first->s() << ": " << v->s();
}
os << "}";
} }
os << "})"; os << ")";
return boxString(os.str()); return boxString(os.str());
} }
...@@ -2508,9 +2548,14 @@ public: ...@@ -2508,9 +2548,14 @@ public:
RELEASE_ASSERT(_self->cls == attrwrapper_cls, ""); RELEASE_ASSERT(_self->cls == attrwrapper_cls, "");
AttrWrapper* self = static_cast<AttrWrapper*>(_self); AttrWrapper* self = static_cast<AttrWrapper*>(_self);
_key = coerceUnicodeToStr<S>(_key); if (_key->cls != str_cls)
if (S == CAPI && !_key) self->convertToDictBacked();
return NULL;
if (self->isDictBacked()) {
static BoxedString* contains_str = internStringImmortal("__contains__");
return callattrInternal<S, NOT_REWRITABLE>(self->getDictBacking(), contains_str, LookupScope::CLASS_ONLY,
NULL, ArgPassSpec(1), _key, NULL, NULL, NULL, NULL);
}
RELEASE_ASSERT(_key->cls == str_cls, ""); RELEASE_ASSERT(_key->cls == str_cls, "");
BoxedString* key = static_cast<BoxedString*>(_key); BoxedString* key = static_cast<BoxedString*>(_key);
...@@ -2537,6 +2582,13 @@ public: ...@@ -2537,6 +2582,13 @@ public:
RELEASE_ASSERT(_self->cls == attrwrapper_cls, ""); RELEASE_ASSERT(_self->cls == attrwrapper_cls, "");
AttrWrapper* self = static_cast<AttrWrapper*>(_self); AttrWrapper* self = static_cast<AttrWrapper*>(_self);
if (self->isDictBacked()) {
static BoxedString* keys_str = internStringImmortal("keys");
return callattrInternal<CXX, NOT_REWRITABLE>(self->getDictBacking(), keys_str, LookupScope::CLASS_ONLY,
NULL, ArgPassSpec(0), NULL, NULL, NULL, NULL, NULL);
}
BoxedList* rtn = new BoxedList(); BoxedList* rtn = new BoxedList();
HCAttrs* attrs = self->b->getHCAttrsPtr(); HCAttrs* attrs = self->b->getHCAttrsPtr();
...@@ -2551,6 +2603,12 @@ public: ...@@ -2551,6 +2603,12 @@ public:
RELEASE_ASSERT(_self->cls == attrwrapper_cls, ""); RELEASE_ASSERT(_self->cls == attrwrapper_cls, "");
AttrWrapper* self = static_cast<AttrWrapper*>(_self); AttrWrapper* self = static_cast<AttrWrapper*>(_self);
if (self->isDictBacked()) {
static BoxedString* values_str = internStringImmortal("values");
return callattrInternal<CXX, NOT_REWRITABLE>(self->getDictBacking(), values_str, LookupScope::CLASS_ONLY,
NULL, ArgPassSpec(0), NULL, NULL, NULL, NULL, NULL);
}
BoxedList* rtn = new BoxedList(); BoxedList* rtn = new BoxedList();
HCAttrs* attrs = self->b->getHCAttrsPtr(); HCAttrs* attrs = self->b->getHCAttrsPtr();
...@@ -2565,6 +2623,12 @@ public: ...@@ -2565,6 +2623,12 @@ public:
RELEASE_ASSERT(_self->cls == attrwrapper_cls, ""); RELEASE_ASSERT(_self->cls == attrwrapper_cls, "");
AttrWrapper* self = static_cast<AttrWrapper*>(_self); AttrWrapper* self = static_cast<AttrWrapper*>(_self);
if (self->isDictBacked()) {
static BoxedString* items_str = internStringImmortal("items");
return callattrInternal<CXX, NOT_REWRITABLE>(self->getDictBacking(), items_str, LookupScope::CLASS_ONLY,
NULL, ArgPassSpec(0), NULL, NULL, NULL, NULL, NULL);
}
BoxedList* rtn = new BoxedList(); BoxedList* rtn = new BoxedList();
HCAttrs* attrs = self->b->getHCAttrsPtr(); HCAttrs* attrs = self->b->getHCAttrsPtr();
...@@ -2595,6 +2659,12 @@ public: ...@@ -2595,6 +2659,12 @@ public:
RELEASE_ASSERT(_self->cls == attrwrapper_cls, ""); RELEASE_ASSERT(_self->cls == attrwrapper_cls, "");
AttrWrapper* self = static_cast<AttrWrapper*>(_self); AttrWrapper* self = static_cast<AttrWrapper*>(_self);
if (self->isDictBacked()) {
static BoxedString* copy_str = internStringImmortal("copy");
return callattrInternal<CXX, NOT_REWRITABLE>(self->getDictBacking(), copy_str, LookupScope::CLASS_ONLY,
NULL, ArgPassSpec(0), NULL, NULL, NULL, NULL, NULL);
}
BoxedDict* rtn = new BoxedDict(); BoxedDict* rtn = new BoxedDict();
HCAttrs* attrs = self->b->getHCAttrsPtr(); HCAttrs* attrs = self->b->getHCAttrsPtr();
...@@ -2609,6 +2679,12 @@ public: ...@@ -2609,6 +2679,12 @@ public:
RELEASE_ASSERT(_self->cls == attrwrapper_cls, ""); RELEASE_ASSERT(_self->cls == attrwrapper_cls, "");
AttrWrapper* self = static_cast<AttrWrapper*>(_self); AttrWrapper* self = static_cast<AttrWrapper*>(_self);
if (self->isDictBacked()) {
static BoxedString* clear_str = internStringImmortal("clear");
return callattrInternal<CXX, NOT_REWRITABLE>(self->getDictBacking(), clear_str, LookupScope::CLASS_ONLY,
NULL, ArgPassSpec(0), NULL, NULL, NULL, NULL, NULL);
}
HCAttrs* attrs = self->b->getHCAttrsPtr(); HCAttrs* attrs = self->b->getHCAttrsPtr();
RELEASE_ASSERT(attrs->hcls->type == HiddenClass::NORMAL || attrs->hcls->type == HiddenClass::SINGLETON, ""); RELEASE_ASSERT(attrs->hcls->type == HiddenClass::NORMAL || attrs->hcls->type == HiddenClass::SINGLETON, "");
...@@ -2625,6 +2701,12 @@ public: ...@@ -2625,6 +2701,12 @@ public:
RELEASE_ASSERT(_self->cls == attrwrapper_cls, ""); RELEASE_ASSERT(_self->cls == attrwrapper_cls, "");
AttrWrapper* self = static_cast<AttrWrapper*>(_self); AttrWrapper* self = static_cast<AttrWrapper*>(_self);
if (self->isDictBacked()) {
static BoxedString* len_str = internStringImmortal("__len__");
return callattrInternal<CXX, NOT_REWRITABLE>(self->getDictBacking(), len_str, LookupScope::CLASS_ONLY, NULL,
ArgPassSpec(0), NULL, NULL, NULL, NULL, NULL);
}
HCAttrs* attrs = self->b->getHCAttrsPtr(); HCAttrs* attrs = self->b->getHCAttrsPtr();
RELEASE_ASSERT(attrs->hcls->type == HiddenClass::NORMAL || attrs->hcls->type == HiddenClass::SINGLETON, ""); RELEASE_ASSERT(attrs->hcls->type == HiddenClass::NORMAL || attrs->hcls->type == HiddenClass::SINGLETON, "");
return boxInt(attrs->hcls->getStrAttrOffsets().size()); return boxInt(attrs->hcls->getStrAttrOffsets().size());
...@@ -2639,9 +2721,17 @@ public: ...@@ -2639,9 +2721,17 @@ public:
RELEASE_ASSERT(args->size() <= 1, ""); // should throw a TypeError RELEASE_ASSERT(args->size() <= 1, ""); // should throw a TypeError
if (self->isDictBacked()) {
static BoxedString* update_str = internStringImmortal("update");
return callattrInternal<CXX, NOT_REWRITABLE>(self->getDictBacking(), update_str, LookupScope::CLASS_ONLY,
NULL, ArgPassSpec(0, 0, true, true), args, kwargs, NULL, NULL,
NULL);
}
auto handle = [&](Box* _container) { auto handle = [&](Box* _container) {
if (_container->cls == attrwrapper_cls) { if (_container->cls == attrwrapper_cls) {
AttrWrapper* container = static_cast<AttrWrapper*>(_container); AttrWrapper* container = static_cast<AttrWrapper*>(_container);
RELEASE_ASSERT(!container->isDictBacked(), "not implemented");
HCAttrs* attrs = container->b->getHCAttrsPtr(); HCAttrs* attrs = container->b->getHCAttrsPtr();
RELEASE_ASSERT(attrs->hcls->type == HiddenClass::NORMAL || attrs->hcls->type == HiddenClass::SINGLETON, RELEASE_ASSERT(attrs->hcls->type == HiddenClass::NORMAL || attrs->hcls->type == HiddenClass::SINGLETON,
...@@ -2785,6 +2875,36 @@ Box* unwrapAttrWrapper(Box* b) { ...@@ -2785,6 +2875,36 @@ Box* unwrapAttrWrapper(Box* b) {
return static_cast<AttrWrapper*>(b)->getUnderlying(); return static_cast<AttrWrapper*>(b)->getUnderlying();
} }
void Box::setDictBacked(Box* val) {
// this checks for: v.__dict__ = v.__dict__
if (val->cls == attrwrapper_cls && unwrapAttrWrapper(val) == this)
return;
assert(this->cls->instancesHaveHCAttrs());
HCAttrs* hcattrs = this->getHCAttrsPtr();
RELEASE_ASSERT(PyDict_Check(val) || val->cls == attrwrapper_cls, "");
// If there is an old attrwrapper it is not allowed to wrap the instance anymore instead it has to switch to a
// private dictonary.
// e.g.:
// a = v.__dict__
// v.__dict__ = {} # 'a' must switch now from wrapping 'v' to a the private dict.
int offset = hcattrs->hcls->type != HiddenClass::DICT_BACKED ? hcattrs->hcls->getAttrwrapperOffset() : -1;
if (offset != -1) {
AttrWrapper* wrapper = (AttrWrapper*)hcattrs->attr_list->attrs[offset];
RELEASE_ASSERT(wrapper->cls == attrwrapper_cls, "");
wrapper->convertToPivateDict();
}
// assign the dict to the attribute list and switch to the dict backed strategy
auto new_attr_list = (HCAttrs::AttrList*)gc_alloc(sizeof(HCAttrs::AttrList) + sizeof(Box*), gc::GCKind::PRECISE);
new_attr_list->attrs[0] = val;
hcattrs->hcls = HiddenClass::dict_backed;
hcattrs->attr_list = new_attr_list;
}
Box* attrwrapperKeys(Box* b) { Box* attrwrapperKeys(Box* b) {
return AttrWrapper::keys(b); return AttrWrapper::keys(b);
} }
......
...@@ -46,3 +46,6 @@ for obj in [(1, 2), "hello world", u"hola world", 1.0, 1j, 1L, 2, {1:2}, set([3] ...@@ -46,3 +46,6 @@ for obj in [(1, 2), "hello world", u"hola world", 1.0, 1j, 1L, 2, {1:2}, set([3]
import cStringIO import cStringIO
StringIO = cPickle.loads(cPickle.dumps(cStringIO.StringIO)) StringIO = cPickle.loads(cPickle.dumps(cStringIO.StringIO))
print type(StringIO()) print type(StringIO())
import thread
print cPickle.loads(cPickle.dumps(thread.error))
print compile
c = compile("a", "test.py", "eval") c = compile("a", "test.py", "eval")
print type(c), c.co_filename, c.co_name print type(c), c.co_filename, c.co_name
......
...@@ -51,6 +51,19 @@ print hasattr(c, "attr") ...@@ -51,6 +51,19 @@ print hasattr(c, "attr")
print hasattr(c, "foo") print hasattr(c, "foo")
print c.__dict__ is d1 print c.__dict__ is d1
c = C()
a = c.__dict__
c.__dict__ = c.__dict__
c.__dict__[u"uni"] = "u"
c.__dict__[u"\u20ac"] = "u"
c.__dict__[(1, 2, 3)] = "t"
print sorted(c.__dict__.keys()), sorted(a.keys())
print "all non str attributes:", sorted([item for item in dir(c) if not isinstance(item, str)])
print "can we retrieve unicode attributes by there ascii value?", c.uni, c.__dict__["uni"]
print "attrwrapper:", a["uni"], a[(1, 2, 3)]
setattr(c, "uni", 1)
print "test setattr()", c.uni, c.__dict__["uni"], a["uni"], len(c.__dict__), len(a)
dictproxy = C.__dict__ dictproxy = C.__dict__
print type(dictproxy) print type(dictproxy)
print "foo" in dictproxy print "foo" in dictproxy
......
# expected: fail
# - haven't bothered to implement this yet
# Funny case: if we get the attrwrapper of an object, then change it to be dict-backed, # Funny case: if we get the attrwrapper of an object, then change it to be dict-backed,
# the original attrwrapper should remain valid but no longer connected to that object. # the original attrwrapper should remain valid but no longer connected to that object.
...@@ -13,3 +10,10 @@ c1.a = 1 ...@@ -13,3 +10,10 @@ c1.a = 1
print aw.items() print aw.items()
c1.__dict__ = d = {} c1.__dict__ = d = {}
print aw.items() print aw.items()
c2 = C()
olddict = c2.__dict__
c2.__dict__ = { "should not be there" : 1 }
print olddict.has_key("should not be there")
import sys import sys
import os.path import os.path
print sys.excepthook, sys.displayhook
print sys.version[:3] print sys.version[:3]
print os.path.exists(sys.executable) print os.path.exists(sys.executable)
print sys.copyright[-200:] print sys.copyright[-200:]
......
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