Commit bd2ee538 authored by Kevin Modzelewski's avatar Kevin Modzelewski

Merge pull request #852 from kmod/perf4

more small exceptions optimizations
parents 93ff229e dbada809
...@@ -86,6 +86,36 @@ ...@@ -86,6 +86,36 @@
#include "warnings.h" #include "warnings.h"
#include "weakrefobject.h" #include "weakrefobject.h"
// Pyston additions:
// These new APIS give access to our fast hidden-class-based attributes implementation.
// Ideally in the future this will just be "storage strategy" of dicts and all Python
// dicts will benefit from it, but for now classes have to explicitly opt-in to having
// these kinds of attrs.
struct _hcattrs {
char _data[16];
};
#ifndef _PYSTON_API
typedef struct _hcattrs PyHcAttrs;
#else
namespace pyston {
class HCAttrs;
}
typedef int PyHcAttrs;
#endif
PyAPI_FUNC(void) PyObject_InitHcAttrs(PyHcAttrs*) PYSTON_NOEXCEPT;
PyAPI_FUNC(PyObject*) PyObject_GetAttrWrapper(PyObject*) PYSTON_NOEXCEPT;
PyAPI_FUNC(void) PyType_RequestHcAttrs(PyTypeObject*, int offset) PYSTON_NOEXCEPT;
// Sets a descriptor on the type so that the attrs are available via __dict__
PyAPI_FUNC(void) PyType_GiveHcAttrsDictDescr(PyTypeObject*) PYSTON_NOEXCEPT;
// These functions directly manipulate the hcattrs storage, bypassing any getattro
// or descriptor logic. This is the equivallent of callling PyDict_GetItemString
// on an instance's dict.
// These functions try to mimic the Dict versions as much as possible, so for example
// the PyObject_GetHcAttrString function does not set an exception.
PyAPI_FUNC(PyObject*) PyObject_GetHcAttrString(PyObject*, const char*) PYSTON_NOEXCEPT;
PyAPI_FUNC(int) PyObject_SetHcAttrString(PyObject*, const char*, PyObject*) PYSTON_NOEXCEPT;
PyAPI_FUNC(int) PyObject_DelHcAttrString(PyObject*, const char*) PYSTON_NOEXCEPT;
#include "codecs.h" #include "codecs.h"
#include "pyerrors.h" #include "pyerrors.h"
......
...@@ -10,14 +10,18 @@ extern "C" { ...@@ -10,14 +10,18 @@ extern "C" {
typedef struct { typedef struct {
PyObject_HEAD PyObject_HEAD
PyObject *dict; // Pyston change: changed from dict to hcattrs
// PyObject *dict;
struct _hcattrs hcattrs;
PyObject *args; PyObject *args;
PyObject *message; PyObject *message;
} PyBaseExceptionObject; } PyBaseExceptionObject;
typedef struct { typedef struct {
PyObject_HEAD PyObject_HEAD
PyObject *dict; // Pyston change: changed from dict to hcattrs
// PyObject *dict;
struct _hcattrs hcattrs;
PyObject *args; PyObject *args;
PyObject *message; PyObject *message;
PyObject *msg; PyObject *msg;
...@@ -31,7 +35,9 @@ typedef struct { ...@@ -31,7 +35,9 @@ typedef struct {
#ifdef Py_USING_UNICODE #ifdef Py_USING_UNICODE
typedef struct { typedef struct {
PyObject_HEAD PyObject_HEAD
PyObject *dict; // Pyston change: changed from dict to hcattrs
// PyObject *dict;
struct _hcattrs hcattrs;
PyObject *args; PyObject *args;
PyObject *message; PyObject *message;
PyObject *encoding; PyObject *encoding;
...@@ -44,7 +50,9 @@ typedef struct { ...@@ -44,7 +50,9 @@ typedef struct {
typedef struct { typedef struct {
PyObject_HEAD PyObject_HEAD
PyObject *dict; // Pyston change: changed from dict to hcattrs
// PyObject *dict;
struct _hcattrs hcattrs;
PyObject *args; PyObject *args;
PyObject *message; PyObject *message;
PyObject *code; PyObject *code;
...@@ -52,7 +60,9 @@ typedef struct { ...@@ -52,7 +60,9 @@ typedef struct {
typedef struct { typedef struct {
PyObject_HEAD PyObject_HEAD
PyObject *dict; // Pyston change: changed from dict to hcattrs
// PyObject *dict;
struct _hcattrs hcattrs;
PyObject *args; PyObject *args;
PyObject *message; PyObject *message;
PyObject *myerrno; PyObject *myerrno;
...@@ -63,7 +73,9 @@ typedef struct { ...@@ -63,7 +73,9 @@ typedef struct {
#ifdef MS_WINDOWS #ifdef MS_WINDOWS
typedef struct { typedef struct {
PyObject_HEAD PyObject_HEAD
PyObject *dict; // Pyston change: changed from dict to hcattrs
// PyObject *dict;
struct _hcattrs hcattrs;
PyObject *args; PyObject *args;
PyObject *message; PyObject *message;
PyObject *myerrno; PyObject *myerrno;
......
...@@ -36,8 +36,8 @@ BaseException_new(PyTypeObject *type, PyObject *args, PyObject *kwds) ...@@ -36,8 +36,8 @@ BaseException_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
self = (PyBaseExceptionObject *)type->tp_alloc(type, 0); self = (PyBaseExceptionObject *)type->tp_alloc(type, 0);
if (!self) if (!self)
return NULL; return NULL;
/* the dict is created on the fly in PyObject_GenericSetAttr */ self->message = NULL;
self->message = self->dict = NULL; PyObject_InitHcAttrs(&self->hcattrs);
self->args = PyTuple_New(0); self->args = PyTuple_New(0);
if (!self->args) { if (!self->args) {
...@@ -84,7 +84,7 @@ PyObject* PyErr_CreateExceptionInstance(PyObject* _type, PyObject* arg) { ...@@ -84,7 +84,7 @@ PyObject* PyErr_CreateExceptionInstance(PyObject* _type, PyObject* arg) {
if (!self) if (!self)
return NULL; return NULL;
self->dict = NULL; PyObject_InitHcAttrs(&self->hcattrs);
if (arg) { if (arg) {
self->args = PyTuple_Pack(1, arg); self->args = PyTuple_Pack(1, arg);
if (!self->args) if (!self->args)
...@@ -115,7 +115,8 @@ PyObject* PyErr_CreateExceptionInstance(PyObject* _type, PyObject* arg) { ...@@ -115,7 +115,8 @@ PyObject* PyErr_CreateExceptionInstance(PyObject* _type, PyObject* arg) {
static int static int
BaseException_clear(PyBaseExceptionObject *self) BaseException_clear(PyBaseExceptionObject *self)
{ {
Py_CLEAR(self->dict); // Pyston change:
// Py_CLEAR(self->dict);
Py_CLEAR(self->args); Py_CLEAR(self->args);
Py_CLEAR(self->message); Py_CLEAR(self->message);
return 0; return 0;
...@@ -132,7 +133,8 @@ BaseException_dealloc(PyBaseExceptionObject *self) ...@@ -132,7 +133,8 @@ BaseException_dealloc(PyBaseExceptionObject *self)
static int static int
BaseException_traverse(PyBaseExceptionObject *self, visitproc visit, void *arg) BaseException_traverse(PyBaseExceptionObject *self, visitproc visit, void *arg)
{ {
Py_VISIT(self->dict); // Pyston change:
// Py_VISIT(self->dict);
Py_VISIT(self->args); Py_VISIT(self->args);
Py_VISIT(self->message); Py_VISIT(self->message);
return 0; return 0;
...@@ -225,10 +227,16 @@ BaseException_repr(PyBaseExceptionObject *self) ...@@ -225,10 +227,16 @@ BaseException_repr(PyBaseExceptionObject *self)
static PyObject * static PyObject *
BaseException_reduce(PyBaseExceptionObject *self) BaseException_reduce(PyBaseExceptionObject *self)
{ {
/* Pyston change:
if (self->args && self->dict) if (self->args && self->dict)
return PyTuple_Pack(3, Py_TYPE(self), self->args, self->dict); return PyTuple_Pack(3, Py_TYPE(self), self->args, self->dict);
else else
return PyTuple_Pack(2, Py_TYPE(self), self->args); return PyTuple_Pack(2, Py_TYPE(self), self->args);
*/
PyObject* attr_wrapper = PyObject_GetAttrWrapper((PyObject*)self);
if (!attr_wrapper)
return NULL;
return PyTuple_Pack(3, Py_TYPE(self), self->args, attr_wrapper);
} }
/* /*
...@@ -299,6 +307,7 @@ static PySequenceMethods BaseException_as_sequence = { ...@@ -299,6 +307,7 @@ static PySequenceMethods BaseException_as_sequence = {
0 /* sq_inplace_repeat; */ 0 /* sq_inplace_repeat; */
}; };
/* Pyston change: we use the standard dict descriptor for these types now
static PyObject * static PyObject *
BaseException_get_dict(PyBaseExceptionObject *self) BaseException_get_dict(PyBaseExceptionObject *self)
{ {
...@@ -327,6 +336,7 @@ BaseException_set_dict(PyBaseExceptionObject *self, PyObject *val) ...@@ -327,6 +336,7 @@ BaseException_set_dict(PyBaseExceptionObject *self, PyObject *val)
self->dict = val; self->dict = val;
return 0; return 0;
} }
*/
static PyObject * static PyObject *
BaseException_get_args(PyBaseExceptionObject *self) BaseException_get_args(PyBaseExceptionObject *self)
...@@ -361,8 +371,7 @@ BaseException_get_message(PyBaseExceptionObject *self) ...@@ -361,8 +371,7 @@ BaseException_get_message(PyBaseExceptionObject *self)
PyObject *msg; PyObject *msg;
/* if "message" is in self->dict, accessing a user-set message attribute */ /* if "message" is in self->dict, accessing a user-set message attribute */
if (self->dict && if ((msg = PyObject_GetHcAttrString((PyObject*)self, "message"))) {
(msg = PyDict_GetItemString(self->dict, "message"))) {
Py_INCREF(msg); Py_INCREF(msg);
return msg; return msg;
} }
...@@ -387,25 +396,18 @@ BaseException_set_message(PyBaseExceptionObject *self, PyObject *val) ...@@ -387,25 +396,18 @@ BaseException_set_message(PyBaseExceptionObject *self, PyObject *val)
{ {
/* if val is NULL, delete the message attribute */ /* if val is NULL, delete the message attribute */
if (val == NULL) { if (val == NULL) {
if (self->dict && PyDict_GetItemString(self->dict, "message")) { if (PyObject_GetHcAttrString((PyObject*)self, "message")) {
if (PyDict_DelItemString(self->dict, "message") < 0) if (PyObject_DelHcAttrString((PyObject*)self, "message") < 0)
return -1; return -1;
} }
Py_CLEAR(self->message); Py_CLEAR(self->message);
return 0; return 0;
} }
/* else set it in __dict__, but may need to create the dict first */ return PyObject_SetHcAttrString((PyObject*)self, "message", val);
if (self->dict == NULL) {
self->dict = PyDict_New();
if (!self->dict)
return -1;
}
return PyDict_SetItemString(self->dict, "message", val);
} }
static PyGetSetDef BaseException_getset[] = { static PyGetSetDef BaseException_getset[] = {
{"__dict__", (getter)BaseException_get_dict, (setter)BaseException_set_dict},
{"args", (getter)BaseException_get_args, (setter)BaseException_set_args}, {"args", (getter)BaseException_get_args, (setter)BaseException_set_args},
{"message", (getter)BaseException_get_message, {"message", (getter)BaseException_get_message,
(setter)BaseException_set_message}, (setter)BaseException_set_message},
...@@ -450,7 +452,7 @@ static PyTypeObject _PyExc_BaseException = { ...@@ -450,7 +452,7 @@ static PyTypeObject _PyExc_BaseException = {
0, /* tp_dict */ 0, /* tp_dict */
0, /* tp_descr_get */ 0, /* tp_descr_get */
0, /* tp_descr_set */ 0, /* tp_descr_set */
offsetof(PyBaseExceptionObject, dict), /* tp_dictoffset */ /* Pyston change: offsetof(PyBaseExceptionObject, dict)*/ 0, /* tp_dictoffset */
(initproc)BaseException_init, /* tp_init */ (initproc)BaseException_init, /* tp_init */
0, /* tp_alloc */ 0, /* tp_alloc */
BaseException_new, /* tp_new */ BaseException_new, /* tp_new */
...@@ -474,7 +476,7 @@ static PyTypeObject _PyExc_ ## EXCNAME = { \ ...@@ -474,7 +476,7 @@ static PyTypeObject _PyExc_ ## EXCNAME = { \
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, \ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, \
PyDoc_STR(EXCDOC), (traverseproc)BaseException_traverse, \ PyDoc_STR(EXCDOC), (traverseproc)BaseException_traverse, \
(inquiry)BaseException_clear, 0, 0, 0, 0, 0, 0, 0, &_ ## EXCBASE, \ (inquiry)BaseException_clear, 0, 0, 0, 0, 0, 0, 0, &_ ## EXCBASE, \
0, 0, 0, offsetof(PyBaseExceptionObject, dict), \ 0, 0, 0, /* Pyston change: offsetof(PyBaseExceptionObject, dict) */ 0, \
(initproc)BaseException_init, 0, BaseException_new,\ (initproc)BaseException_init, 0, BaseException_new,\
}; \ }; \
PyObject *PyExc_ ## EXCNAME = (PyObject *)&_PyExc_ ## EXCNAME PyObject *PyExc_ ## EXCNAME = (PyObject *)&_PyExc_ ## EXCNAME
...@@ -490,7 +492,7 @@ static PyTypeObject _PyExc_ ## EXCNAME = { \ ...@@ -490,7 +492,7 @@ static PyTypeObject _PyExc_ ## EXCNAME = { \
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, \ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, \
PyDoc_STR(EXCDOC), (traverseproc)EXCSTORE ## _traverse, \ PyDoc_STR(EXCDOC), (traverseproc)EXCSTORE ## _traverse, \
(inquiry)EXCSTORE ## _clear, 0, 0, 0, 0, 0, 0, 0, &_ ## EXCBASE, \ (inquiry)EXCSTORE ## _clear, 0, 0, 0, 0, 0, 0, 0, &_ ## EXCBASE, \
0, 0, 0, offsetof(Py ## EXCSTORE ## Object, dict), \ 0, 0, 0, /* Pyston change: offsetof(Py ## EXCSTORE ## Object, dict) */ 0, \
(initproc)EXCSTORE ## _init, 0, BaseException_new,\ (initproc)EXCSTORE ## _init, 0, BaseException_new,\
}; \ }; \
PyObject *PyExc_ ## EXCNAME = (PyObject *)&_PyExc_ ## EXCNAME PyObject *PyExc_ ## EXCNAME = (PyObject *)&_PyExc_ ## EXCNAME
...@@ -507,7 +509,7 @@ static PyTypeObject _PyExc_ ## EXCNAME = { \ ...@@ -507,7 +509,7 @@ static PyTypeObject _PyExc_ ## EXCNAME = { \
PyDoc_STR(EXCDOC), (traverseproc)EXCSTORE ## _traverse, \ PyDoc_STR(EXCDOC), (traverseproc)EXCSTORE ## _traverse, \
(inquiry)EXCSTORE ## _clear, 0, 0, 0, 0, EXCMETHODS, \ (inquiry)EXCSTORE ## _clear, 0, 0, 0, 0, EXCMETHODS, \
EXCMEMBERS, 0, &_ ## EXCBASE, \ EXCMEMBERS, 0, &_ ## EXCBASE, \
0, 0, 0, offsetof(Py ## EXCSTORE ## Object, dict), \ 0, 0, 0, /* Pyston change: offsetof(Py ## EXCSTORE ## Object, dict) */ 0, \
(initproc)EXCSTORE ## _init, 0, BaseException_new,\ (initproc)EXCSTORE ## _init, 0, BaseException_new,\
}; \ }; \
PyObject *PyExc_ ## EXCNAME = (PyObject *)&_PyExc_ ## EXCNAME PyObject *PyExc_ ## EXCNAME = (PyObject *)&_PyExc_ ## EXCNAME
...@@ -831,12 +833,17 @@ EnvironmentError_reduce(PyEnvironmentErrorObject *self) ...@@ -831,12 +833,17 @@ EnvironmentError_reduce(PyEnvironmentErrorObject *self)
} else } else
Py_INCREF(args); Py_INCREF(args);
/* Pyston change:
if (self->dict) if (self->dict)
res = PyTuple_Pack(3, Py_TYPE(self), args, self->dict); res = PyTuple_Pack(3, Py_TYPE(self), args, self->dict);
else else
res = PyTuple_Pack(2, Py_TYPE(self), args); res = PyTuple_Pack(2, Py_TYPE(self), args);
Py_DECREF(args); Py_DECREF(args);
return res; return res; */
PyObject* attr_wrapper = PyObject_GetAttrWrapper((PyObject*)self);
if (!attr_wrapper)
return NULL;
return PyTuple_Pack(3, Py_TYPE(self), args, attr_wrapper);
} }
...@@ -1743,7 +1750,7 @@ static PyTypeObject _PyExc_UnicodeEncodeError = { ...@@ -1743,7 +1750,7 @@ static PyTypeObject _PyExc_UnicodeEncodeError = {
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC,
PyDoc_STR("Unicode encoding error."), (traverseproc)UnicodeError_traverse, PyDoc_STR("Unicode encoding error."), (traverseproc)UnicodeError_traverse,
(inquiry)UnicodeError_clear, 0, 0, 0, 0, 0, UnicodeError_members, (inquiry)UnicodeError_clear, 0, 0, 0, 0, 0, UnicodeError_members,
0, &_PyExc_UnicodeError, 0, 0, 0, offsetof(PyUnicodeErrorObject, dict), 0, &_PyExc_UnicodeError, 0, 0, 0, /* Pyston change: offsetof(PyUnicodeErrorObject, dict) */ 0,
(initproc)UnicodeEncodeError_init, 0, BaseException_new, (initproc)UnicodeEncodeError_init, 0, BaseException_new,
}; };
PyObject *PyExc_UnicodeEncodeError = (PyObject *)&_PyExc_UnicodeEncodeError; PyObject *PyExc_UnicodeEncodeError = (PyObject *)&_PyExc_UnicodeEncodeError;
...@@ -1828,7 +1835,7 @@ static PyTypeObject _PyExc_UnicodeDecodeError = { ...@@ -1828,7 +1835,7 @@ static PyTypeObject _PyExc_UnicodeDecodeError = {
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC,
PyDoc_STR("Unicode decoding error."), (traverseproc)UnicodeError_traverse, PyDoc_STR("Unicode decoding error."), (traverseproc)UnicodeError_traverse,
(inquiry)UnicodeError_clear, 0, 0, 0, 0, 0, UnicodeError_members, (inquiry)UnicodeError_clear, 0, 0, 0, 0, 0, UnicodeError_members,
0, &_PyExc_UnicodeError, 0, 0, 0, offsetof(PyUnicodeErrorObject, dict), 0, &_PyExc_UnicodeError, 0, 0, 0, /* Pyston change: offsetof(PyUnicodeErrorObject, dict) */ 0,
(initproc)UnicodeDecodeError_init, 0, BaseException_new, (initproc)UnicodeDecodeError_init, 0, BaseException_new,
}; };
PyObject *PyExc_UnicodeDecodeError = (PyObject *)&_PyExc_UnicodeDecodeError; PyObject *PyExc_UnicodeDecodeError = (PyObject *)&_PyExc_UnicodeDecodeError;
...@@ -1926,7 +1933,7 @@ static PyTypeObject _PyExc_UnicodeTranslateError = { ...@@ -1926,7 +1933,7 @@ static PyTypeObject _PyExc_UnicodeTranslateError = {
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC,
PyDoc_STR("Unicode translation error."), (traverseproc)UnicodeError_traverse, PyDoc_STR("Unicode translation error."), (traverseproc)UnicodeError_traverse,
(inquiry)UnicodeError_clear, 0, 0, 0, 0, 0, UnicodeError_members, (inquiry)UnicodeError_clear, 0, 0, 0, 0, 0, UnicodeError_members,
0, &_PyExc_UnicodeError, 0, 0, 0, offsetof(PyUnicodeErrorObject, dict), 0, &_PyExc_UnicodeError, 0, 0, 0, /* Pyston change: offsetof(PyUnicodeErrorObject, dict) */ 0,
(initproc)UnicodeTranslateError_init, 0, BaseException_new, (initproc)UnicodeTranslateError_init, 0, BaseException_new,
}; };
PyObject *PyExc_UnicodeTranslateError = (PyObject *)&_PyExc_UnicodeTranslateError; PyObject *PyExc_UnicodeTranslateError = (PyObject *)&_PyExc_UnicodeTranslateError;
...@@ -2110,7 +2117,10 @@ _PyExc_Init(void) ...@@ -2110,7 +2117,10 @@ _PyExc_Init(void)
{ {
PyObject *m, *bltinmod, *bdict; PyObject *m, *bltinmod, *bdict;
PyType_RequestHcAttrs(&_PyExc_BaseException, offsetof(PyBaseExceptionObject, hcattrs));
PRE_INIT(BaseException) PRE_INIT(BaseException)
PyType_GiveHcAttrsDictDescr(&_PyExc_BaseException);
PRE_INIT(Exception) PRE_INIT(Exception)
PRE_INIT(StandardError) PRE_INIT(StandardError)
PRE_INIT(TypeError) PRE_INIT(TypeError)
......
...@@ -797,8 +797,15 @@ extern "C" int PyObject_IsSubclass(PyObject* derived, PyObject* cls) noexcept { ...@@ -797,8 +797,15 @@ extern "C" int PyObject_IsSubclass(PyObject* derived, PyObject* cls) noexcept {
return r; return r;
} }
if (!(PyClass_Check(cls) || PyInstance_Check(cls))) { if (!(PyClass_Check(cls) || PyInstance_Check(cls))) {
PyObject* checker; PyObject* checker = NULL;
checker = _PyObject_LookupSpecial(cls, "__subclasscheck__", &name); if (cls->cls->has_subclasscheck) {
checker = _PyObject_LookupSpecial(cls, "__subclasscheck__", &name);
if (!checker && PyErr_Occurred())
return -1;
assert(checker);
}
if (checker != NULL) { if (checker != NULL) {
PyObject* res; PyObject* res;
int ok = -1; int ok = -1;
......
...@@ -1152,7 +1152,7 @@ static PyObject* slot_tp_del(PyObject* self) noexcept { ...@@ -1152,7 +1152,7 @@ static PyObject* slot_tp_del(PyObject* self) noexcept {
} }
} }
static int slot_tp_init(PyObject* self, PyObject* args, PyObject* kwds) noexcept { /* Pyston change: static */ int slot_tp_init(PyObject* self, PyObject* args, PyObject* kwds) noexcept {
STAT_TIMER(t0, "us_timer_slot_tpinit", SLOT_AVOIDABILITY(self)); STAT_TIMER(t0, "us_timer_slot_tpinit", SLOT_AVOIDABILITY(self));
static PyObject* init_str; static PyObject* init_str;
...@@ -1645,6 +1645,7 @@ static slotdef slotdefs[] ...@@ -1645,6 +1645,7 @@ static slotdef slotdefs[]
TPSLOT("__del__", tp_del, slot_tp_del, NULL, ""), TPSLOT("__del__", tp_del, slot_tp_del, NULL, ""),
FLSLOT("__class__", has___class__, NULL, NULL, "", PyWrapperFlag_BOOL), FLSLOT("__class__", has___class__, NULL, NULL, "", PyWrapperFlag_BOOL),
FLSLOT("__instancecheck__", has_instancecheck, NULL, NULL, "", PyWrapperFlag_BOOL), FLSLOT("__instancecheck__", has_instancecheck, NULL, NULL, "", PyWrapperFlag_BOOL),
FLSLOT("__subclasscheck__", has_subclasscheck, NULL, NULL, "", PyWrapperFlag_BOOL),
FLSLOT("__getattribute__", has_getattribute, NULL, NULL, "", PyWrapperFlag_BOOL), FLSLOT("__getattribute__", has_getattribute, NULL, NULL, "", PyWrapperFlag_BOOL),
TPPSLOT("__hasnext__", tpp_hasnext, slotTppHasnext, wrapInquirypred, "hasnext"), TPPSLOT("__hasnext__", tpp_hasnext, slotTppHasnext, wrapInquirypred, "hasnext"),
...@@ -3262,6 +3263,18 @@ static Box* tppProxyToTpCall(Box* self, CallRewriteArgs* rewrite_args, ArgPassSp ...@@ -3262,6 +3263,18 @@ static Box* tppProxyToTpCall(Box* self, CallRewriteArgs* rewrite_args, ArgPassSp
return r; return r;
} }
extern "C" void PyType_RequestHcAttrs(PyTypeObject* cls, int offset) noexcept {
assert(cls->attrs_offset == 0);
assert(cls->tp_dictoffset == 0);
cls->attrs_offset = offset;
}
extern "C" void PyType_GiveHcAttrsDictDescr(PyTypeObject* cls) noexcept {
static BoxedString* dict_str = internStringImmortal("__dict__");
assert(!cls->hasattr(dict_str));
cls->giveAttr(dict_str, dict_descr);
}
extern "C" int PyType_Ready(PyTypeObject* cls) noexcept { extern "C" int PyType_Ready(PyTypeObject* cls) noexcept {
ASSERT(!cls->is_pyston_class, "should not call this on Pyston classes"); ASSERT(!cls->is_pyston_class, "should not call this on Pyston classes");
...@@ -3389,11 +3402,10 @@ extern "C" int PyType_Ready(PyTypeObject* cls) noexcept { ...@@ -3389,11 +3402,10 @@ extern "C" int PyType_Ready(PyTypeObject* cls) noexcept {
// e.g. CTypes does this. // e.g. CTypes does this.
bool is_metaclass = PyType_IsSubtype(cls, type_cls); bool is_metaclass = PyType_IsSubtype(cls, type_cls);
assert(!is_metaclass || cls->instancesHaveHCAttrs() || cls->instancesHaveDictAttrs()); assert(!is_metaclass || cls->instancesHaveHCAttrs() || cls->instancesHaveDictAttrs());
} else {
// this should get automatically initialized to 0 on this path:
assert(cls->attrs_offset == 0);
} }
assert(!(cls->instancesHaveHCAttrs() && cls->instancesHaveDictAttrs()));
if (Py_TPFLAGS_BASE_EXC_SUBCLASS & cls->tp_flags) { if (Py_TPFLAGS_BASE_EXC_SUBCLASS & cls->tp_flags) {
exception_types.push_back(cls); exception_types.push_back(cls);
} }
......
...@@ -51,6 +51,7 @@ int slot_sq_contains(PyObject* self, PyObject* value) noexcept; ...@@ -51,6 +51,7 @@ int slot_sq_contains(PyObject* self, PyObject* value) noexcept;
Py_ssize_t slot_sq_length(PyObject* self) noexcept; Py_ssize_t slot_sq_length(PyObject* self) noexcept;
PyObject* slot_tp_getattr_hook(PyObject* self, PyObject* name) noexcept; PyObject* slot_tp_getattr_hook(PyObject* self, PyObject* name) noexcept;
PyObject* tp_new_wrapper(PyTypeObject* self, BoxedTuple* args, Box* kwds) noexcept; PyObject* tp_new_wrapper(PyTypeObject* self, BoxedTuple* args, Box* kwds) noexcept;
int slot_tp_init(PyObject* self, PyObject* args, PyObject* kwds) noexcept;
class GetattrRewriteArgs; class GetattrRewriteArgs;
Box* slotTpGetattrHookInternal(Box* self, BoxedString* attr, GetattrRewriteArgs* rewrite_args); Box* slotTpGetattrHookInternal(Box* self, BoxedString* attr, GetattrRewriteArgs* rewrite_args);
......
...@@ -225,15 +225,18 @@ protected: ...@@ -225,15 +225,18 @@ protected:
} else } else
++it; ++it;
} }
ASSERT(this->map.size() == this->map_elts, "%ld %d", this->map.size(), this->map_elts);
} }
public: public:
PerThreadSet(CtorArgs... ctor_args) : ctor_args(std::forward<CtorArgs>(ctor_args)...) { PerThreadSet(CtorArgs... ctor_args) : ctor_args(std::forward<CtorArgs>(ctor_args)...) {
int code = pthread_key_create(&pthread_key, &dtor); int code = pthread_key_create(&pthread_key, &dtor);
ASSERT(this->map.size() == this->map_elts, "%ld %d", this->map.size(), this->map_elts);
} }
void forEachValue(std::function<void(T*)> f) { void forEachValue(std::function<void(T*)> f) {
LOCK_REGION(&lock); LOCK_REGION(&lock);
ASSERT(this->map.size() == this->map_elts, "%ld %d", this->map.size(), this->map_elts);
for (auto& p : map) { for (auto& p : map) {
f(&p.second->val); f(&p.second->val);
...@@ -242,6 +245,7 @@ public: ...@@ -242,6 +245,7 @@ public:
template <typename... Arguments> void forEachValue(std::function<void(T*, Arguments...)> f, Arguments... args) { template <typename... Arguments> void forEachValue(std::function<void(T*, Arguments...)> f, Arguments... args) {
LOCK_REGION(&lock); LOCK_REGION(&lock);
ASSERT(this->map.size() == this->map_elts, "%ld %d", this->map.size(), this->map_elts);
for (auto& p : map) { for (auto& p : map) {
f(&p.second->val, std::forward<Arguments>(args)...); f(&p.second->val, std::forward<Arguments>(args)...);
...@@ -267,6 +271,7 @@ public: ...@@ -267,6 +271,7 @@ public:
assert(map.count(pthread_self()) == 0); assert(map.count(pthread_self()) == 0);
map[pthread_self()] = s; map[pthread_self()] = s;
ASSERT(this->map.size() == this->map_elts, "%ld %d", this->map.size(), this->map_elts);
} }
return &s->val; return &s->val;
} }
......
...@@ -505,6 +505,7 @@ public: ...@@ -505,6 +505,7 @@ public:
HCAttrs(HiddenClass* hcls = root_hcls) : hcls(hcls), attr_list(nullptr) {} HCAttrs(HiddenClass* hcls = root_hcls) : hcls(hcls), attr_list(nullptr) {}
}; };
static_assert(sizeof(HCAttrs) == sizeof(struct _hcattrs), "");
class BoxedDict; class BoxedDict;
class BoxedString; class BoxedString;
......
...@@ -984,6 +984,13 @@ extern "C" int PyErr_GivenExceptionMatches(PyObject* err, PyObject* exc) noexcep ...@@ -984,6 +984,13 @@ extern "C" int PyErr_GivenExceptionMatches(PyObject* err, PyObject* exc) noexcep
err = PyExceptionInstance_Class(err); err = PyExceptionInstance_Class(err);
if (PyExceptionClass_Check(err) && PyExceptionClass_Check(exc)) { if (PyExceptionClass_Check(err) && PyExceptionClass_Check(exc)) {
// Pyston addition: fast-path the check for if the exception exactly-matches the specifier.
// Note that we have to check that the exception specifier doesn't have a custom metaclass
// (ie it's cls is type_cls), since otherwise we would have to check for subclasscheck overloading.
// (TODO actually, that should be fast now)
if (exc->cls == type_cls && exc == err)
return 1;
int res = 0, reclimit; int res = 0, reclimit;
PyObject* exception, *value, *tb; PyObject* exception, *value, *tb;
PyErr_Fetch(&exception, &value, &tb); PyErr_Fetch(&exception, &value, &tb);
......
...@@ -75,9 +75,9 @@ static Box* propertyInit(Box* _self, Box* fget, Box* fset, Box** args) { ...@@ -75,9 +75,9 @@ static Box* propertyInit(Box* _self, Box* fget, Box* fset, Box** args) {
Box* doc = args[1]; Box* doc = args[1];
BoxedProperty* self = static_cast<BoxedProperty*>(_self); BoxedProperty* self = static_cast<BoxedProperty*>(_self);
self->prop_get = fget; self->prop_get = fget == None ? NULL : fget;
self->prop_set = fset; self->prop_set = fset == None ? NULL : fset;
self->prop_del = fdel; self->prop_del = fdel == None ? NULL : fdel;
self->prop_doc = doc; self->prop_doc = doc;
self->getter_doc = false; self->getter_doc = false;
...@@ -151,6 +151,12 @@ static Box* property_copy(BoxedProperty* old, Box* get, Box* set, Box* del) { ...@@ -151,6 +151,12 @@ static Box* property_copy(BoxedProperty* old, Box* get, Box* set, Box* del) {
return prop; return prop;
} else { } else {
if (!get)
get = None;
if (!set)
set = None;
if (!del)
del = None;
Box* doc; Box* doc;
if ((old->getter_doc && get != None) || !old->prop_doc) if ((old->getter_doc && get != None) || !old->prop_doc)
doc = None; doc = None;
......
...@@ -832,15 +832,16 @@ static Box* typeCallInner(CallRewriteArgs* rewrite_args, ArgPassSpec argspec, Bo ...@@ -832,15 +832,16 @@ static Box* typeCallInner(CallRewriteArgs* rewrite_args, ArgPassSpec argspec, Bo
RewriterVar* r_ccls = NULL; RewriterVar* r_ccls = NULL;
RewriterVar* r_new = NULL; RewriterVar* r_new = NULL;
RewriterVar* r_init = NULL; RewriterVar* r_init = NULL;
Box* new_attr, *init_attr; Box* new_attr, * init_attr = NULL;
if (rewrite_args) { if (rewrite_args) {
assert(!argspec.has_starargs); assert(!argspec.has_starargs);
assert(!argspec.has_kwargs); assert(!argspec.has_kwargs);
assert(argspec.num_args > 0); assert(argspec.num_args > 0);
r_ccls = rewrite_args->arg1; r_ccls = rewrite_args->arg1;
// This is probably a duplicate, but it's hard to really convince myself of that. // Guard on the requested class. We could potentially support multiple classes in a rewrite,
// Need to create a clear contract of who guards on what // but there are parts of this function's rewrite that currently take advantage of the fact
// that the requested class is fixed.
r_ccls->addGuard((intptr_t)arg1 /* = _cls */); r_ccls->addGuard((intptr_t)arg1 /* = _cls */);
...@@ -930,7 +931,7 @@ static Box* typeCallInner(CallRewriteArgs* rewrite_args, ArgPassSpec argspec, Bo ...@@ -930,7 +931,7 @@ static Box* typeCallInner(CallRewriteArgs* rewrite_args, ArgPassSpec argspec, Bo
// //
// For debugging, keep track of why we think we can rewrite this: // For debugging, keep track of why we think we can rewrite this:
enum { NOT_ALLOWED, VERIFIED, NO_INIT, TYPE_NEW_SPECIAL_CASE, } why_rewrite_allowed = NOT_ALLOWED; enum { NOT_ALLOWED, MAKES_CLS, NO_INIT, TYPE_NEW_SPECIAL_CASE, } why_rewrite_allowed = NOT_ALLOWED;
// These are __new__ functions that have the property that __new__(kls) always returns an instance of kls. // These are __new__ functions that have the property that __new__(kls) always returns an instance of kls.
// These are ok to call regardless of what type was requested. // These are ok to call regardless of what type was requested.
...@@ -939,32 +940,32 @@ static Box* typeCallInner(CallRewriteArgs* rewrite_args, ArgPassSpec argspec, Bo ...@@ -939,32 +940,32 @@ static Box* typeCallInner(CallRewriteArgs* rewrite_args, ArgPassSpec argspec, Bo
// type? then object.__new__ would not be able to be here: // type? then object.__new__ would not be able to be here:
// //
// this array is ok with not using StlCompatAllocator since we will manually register these objects with the GC // this array is ok with not using StlCompatAllocator since we will manually register these objects with the GC
static std::vector<Box*> allowable_news; static std::vector<Box*> class_making_news;
if (allowable_news.empty()) { if (class_making_news.empty()) {
for (BoxedClass* allowed_cls : { object_cls, enumerate_cls, xrange_cls, tuple_cls, list_cls, dict_cls }) { for (BoxedClass* allowed_cls : { object_cls, enumerate_cls, xrange_cls, tuple_cls, list_cls, dict_cls }) {
auto new_obj = typeLookup(allowed_cls, new_str, NULL); auto new_obj = typeLookup(allowed_cls, new_str, NULL);
gc::registerPermanentRoot(new_obj, /* allow_duplicates= */ true); gc::registerPermanentRoot(new_obj, /* allow_duplicates= */ true);
allowable_news.push_back(new_obj); class_making_news.push_back(new_obj);
} }
} }
if (rewrite_args) { if (rewrite_args) {
for (auto b : allowable_news) { for (auto b : class_making_news) {
if (b == new_attr) { if (b == new_attr) {
why_rewrite_allowed = VERIFIED; why_rewrite_allowed = MAKES_CLS;
break; break;
} }
} }
if (cls->tp_new == BaseException->tp_new) if (cls->tp_new == BaseException->tp_new)
why_rewrite_allowed = VERIFIED; why_rewrite_allowed = MAKES_CLS;
bool know_first_arg = !argspec.has_starargs && !argspec.has_kwargs && argspec.num_keywords == 0; bool know_first_arg = !argspec.has_starargs && !argspec.has_kwargs && argspec.num_keywords == 0;
if (know_first_arg) { if (know_first_arg) {
if (argspec.num_args == 1 if (argspec.num_args == 1
&& (cls == int_cls || cls == float_cls || cls == long_cls || cls == str_cls || cls == unicode_cls)) && (cls == int_cls || cls == float_cls || cls == long_cls || cls == str_cls || cls == unicode_cls))
why_rewrite_allowed = VERIFIED; why_rewrite_allowed = MAKES_CLS;
if (argspec.num_args == 2 && (cls == int_cls || cls == float_cls || cls == long_cls) if (argspec.num_args == 2 && (cls == int_cls || cls == float_cls || cls == long_cls)
&& (arg2->cls == int_cls || arg2->cls == str_cls || arg2->cls == float_cls && (arg2->cls == int_cls || arg2->cls == str_cls || arg2->cls == float_cls
...@@ -975,7 +976,7 @@ static Box* typeCallInner(CallRewriteArgs* rewrite_args, ArgPassSpec argspec, Bo ...@@ -975,7 +976,7 @@ static Box* typeCallInner(CallRewriteArgs* rewrite_args, ArgPassSpec argspec, Bo
// str(obj) can return str-subtypes, but for builtin types it won't: // str(obj) can return str-subtypes, but for builtin types it won't:
if (argspec.num_args == 2 && cls == str_cls && (arg2->cls == int_cls || arg2->cls == float_cls)) { if (argspec.num_args == 2 && cls == str_cls && (arg2->cls == int_cls || arg2->cls == float_cls)) {
why_rewrite_allowed = VERIFIED; why_rewrite_allowed = MAKES_CLS;
rewrite_args->arg2->addAttrGuard(offsetof(Box, cls), (intptr_t)arg2->cls); rewrite_args->arg2->addAttrGuard(offsetof(Box, cls), (intptr_t)arg2->cls);
} }
...@@ -1011,22 +1012,25 @@ static Box* typeCallInner(CallRewriteArgs* rewrite_args, ArgPassSpec argspec, Bo ...@@ -1011,22 +1012,25 @@ static Box* typeCallInner(CallRewriteArgs* rewrite_args, ArgPassSpec argspec, Bo
} }
static BoxedString* init_str = internStringImmortal("__init__"); static BoxedString* init_str = internStringImmortal("__init__");
if (rewrite_args) { if (cls->tp_init == slot_tp_init) {
GetattrRewriteArgs grewrite_args(rewrite_args->rewriter, r_ccls, rewrite_args->destination); // If there's a Python-level tp_init, try getting it, since calling it might be faster than calling
init_attr = typeLookup(cls, init_str, &grewrite_args); // tp_init if we can manage to rewrite it.
if (rewrite_args) {
GetattrRewriteArgs grewrite_args(rewrite_args->rewriter, r_ccls, rewrite_args->destination);
init_attr = typeLookup(cls, init_str, &grewrite_args);
if (!grewrite_args.out_success) if (!grewrite_args.out_success)
rewrite_args = NULL; rewrite_args = NULL;
else { else {
if (init_attr) { if (init_attr) {
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 {
init_attr = typeLookup(cls, init_str, NULL);
} }
} else {
init_attr = typeLookup(cls, init_str, NULL);
} }
// The init_attr should always resolve as well, but doesn't yet
Box* made; Box* made;
RewriterVar* r_made = NULL; RewriterVar* r_made = NULL;
...@@ -1121,60 +1125,95 @@ static Box* typeCallInner(CallRewriteArgs* rewrite_args, ArgPassSpec argspec, Bo ...@@ -1121,60 +1125,95 @@ static Box* typeCallInner(CallRewriteArgs* rewrite_args, ArgPassSpec argspec, Bo
return made; return made;
} }
bool skip_init = false;
// If __new__ returns a subclass, supposed to call that subclass's __init__. // If __new__ returns a subclass, supposed to call that subclass's __init__.
// If __new__ returns a non-subclass, not supposed to call __init__. // If __new__ returns a non-subclass, not supposed to call __init__.
if (made->cls != cls) { if (made->cls != cls) {
assert(why_rewrite_allowed != MAKES_CLS);
ASSERT(rewrite_args == NULL || (why_rewrite_allowed == NO_INIT && made->cls->tp_init == object_cls->tp_init ASSERT(rewrite_args == NULL || (why_rewrite_allowed == NO_INIT && made->cls->tp_init == object_cls->tp_init
&& cls->tp_init == object_cls->tp_init), && cls->tp_init == object_cls->tp_init),
"We should only have allowed the rewrite to continue if we were guaranteed that " "We should only have allowed the rewrite to continue if we were guaranteed that "
"made would have class cls!"); "made would have class cls!");
if (!isSubclass(made->cls, cls)) { if (!isSubclass(made->cls, cls)) {
init_attr = NULL; skip_init = true;
} else { } else {
// We could have skipped the initial __init__ lookup if (init_attr) {
init_attr = typeLookup(made->cls, init_str, NULL); // Getting here means the init_attr is wrong; set it to NULL so that we don't use it.
init_attr = NULL;
}
} }
} }
if (init_attr && made->cls->tp_init != object_cls->tp_init) { if (!skip_init && made->cls->tp_init != object_cls->tp_init) {
// TODO apply the same descriptor special-casing as in callattr?
Box* initrtn; Box* initrtn;
// Attempt to rewrite the basic case: // If there's a Python-level __init__ function, try calling it.
if (rewrite_args && init_attr->cls == function_cls) { if (init_attr && init_attr->cls == function_cls) {
// Note: this code path includes the descriptor logic if (rewrite_args) {
CallRewriteArgs srewrite_args(rewrite_args->rewriter, r_init, rewrite_args->destination); // We are going to rewrite as a call to cls.init:
srewrite_args.arg1 = r_made; assert(why_rewrite_allowed == MAKES_CLS);
if (npassed_args >= 2) assert(made->cls == cls);
srewrite_args.arg2 = rewrite_args->arg2; }
if (npassed_args >= 3)
srewrite_args.arg3 = rewrite_args->arg3;
if (npassed_args >= 4)
srewrite_args.args = rewrite_args->args;
srewrite_args.args_guarded = rewrite_args->args_guarded;
srewrite_args.func_guarded = true;
// initrtn = callattrInternal<CXX>(cls, _init_str, INST_ONLY, &srewrite_args, argspec, made, arg2, arg3, // Note: this code path includes the descriptor logic
// args, keyword_names); if (rewrite_args) {
initrtn = runtimeCallInternal<S>(init_attr, &srewrite_args, argspec, made, arg2, arg3, args, keyword_names); CallRewriteArgs srewrite_args(rewrite_args->rewriter, r_init, rewrite_args->destination);
srewrite_args.arg1 = r_made;
if (npassed_args >= 2)
srewrite_args.arg2 = rewrite_args->arg2;
if (npassed_args >= 3)
srewrite_args.arg3 = rewrite_args->arg3;
if (npassed_args >= 4)
srewrite_args.args = rewrite_args->args;
srewrite_args.args_guarded = rewrite_args->args_guarded;
srewrite_args.func_guarded = true;
initrtn
= runtimeCallInternal<S>(init_attr, &srewrite_args, argspec, made, arg2, arg3, args, keyword_names);
if (!srewrite_args.out_success) {
rewrite_args = NULL;
} else {
assert(S == CXX && "this need to be converted");
rewrite_args->rewriter->call(true, (void*)assertInitNone, srewrite_args.out_rtn);
}
} else {
initrtn = runtimeCallInternal<S>(init_attr, NULL, argspec, made, arg2, arg3, args, keyword_names);
}
if (!initrtn) { if (!initrtn) {
assert(S == CAPI); assert(S == CAPI);
return NULL; return NULL;
} }
if (!srewrite_args.out_success) { assert(initrtn);
rewrite_args = NULL;
} else { if (S == CAPI) {
assert(S == CXX && "this need to be converted"); if (initrtn != None) {
rewrite_args->rewriter->call(true, (void*)assertInitNone, srewrite_args.out_rtn); PyErr_Format(TypeError, "__init__() should return None, not '%s'", getTypeName(initrtn));
} return NULL;
}
} else
assertInitNone(initrtn);
} else { } else {
rewrite_args = NULL; // Otherwise, just call tp_init. This will work out well for extension classes, and no worse
// than failing the rewrite for Python non-extension non-functions (when does that happen?).
initproc tpinit = made->cls->tp_init;
if (rewrite_args) {
// This is the only case that should get here:
assert(why_rewrite_allowed == MAKES_CLS && made->cls == cls);
// We're going to emit a call to cls->tp_init, but really we should be calling made->cls->tp_init,
// but the MAKES_CLS condition tells us that made->cls is cls so the two tp_inits are the same.
assert(tpinit == cls->tp_init);
}
bool rewrite_success = false;
try { try {
init_attr = processDescriptor(init_attr, made, cls); rearrangeArguments(ParamReceiveSpec(1, 0, true, true), NULL, "", NULL, rewrite_args, rewrite_success,
argspec, made, arg2, arg3, args, NULL, keyword_names);
} catch (ExcInfo e) { } catch (ExcInfo e) {
if (S == CAPI) { if (S == CAPI) {
setCAPIException(e); setCAPIException(e);
...@@ -1183,30 +1222,28 @@ static Box* typeCallInner(CallRewriteArgs* rewrite_args, ArgPassSpec argspec, Bo ...@@ -1183,30 +1222,28 @@ static Box* typeCallInner(CallRewriteArgs* rewrite_args, ArgPassSpec argspec, Bo
throw e; throw e;
} }
ArgPassSpec init_argspec = argspec; if (!rewrite_success)
init_argspec.num_args--; rewrite_args = NULL;
int passed = init_argspec.totalPassed();
// If we weren't passed the args array, it's not safe to index into it assert(arg2->cls == tuple_cls);
if (passed <= 2) assert(!arg3 || arg3->cls == dict_cls);
initrtn = runtimeCallInternal<S>(init_attr, NULL, init_argspec, arg2, arg3, NULL, NULL, keyword_names);
else
initrtn = runtimeCallInternal<S>(init_attr, NULL, init_argspec, arg2, arg3, args[0], &args[1],
keyword_names);
if (!initrtn) { int err = tpinit(made, arg2, arg3);
assert(S == CAPI); if (err == -1) {
return NULL; if (S == CAPI)
return NULL;
else
throwCAPIException();
} }
}
assert(initrtn);
if (S == CAPI && initrtn != None) { if (rewrite_args) {
PyErr_Format(TypeError, "__init__() should return None, not '%s'", getTypeName(initrtn)); auto r_err
return NULL; = rewrite_args->rewriter->call(true, (void*)tpinit, r_made, rewrite_args->arg2, rewrite_args->arg3);
assert(S == CXX && "this need to be converted");
rewrite_args->rewriter->checkAndThrowCAPIException(r_err, -1);
}
} }
assertInitNone(initrtn);
} else { } else {
if (new_attr == NULL && npassed_args != 1) { if (new_attr == NULL && npassed_args != 1) {
// TODO not npassed args, since the starargs or kwargs could be null // TODO not npassed args, since the starargs or kwargs could be null
...@@ -2480,6 +2517,10 @@ Box* Box::getAttrWrapper() { ...@@ -2480,6 +2517,10 @@ Box* Box::getAttrWrapper() {
return attrs->attr_list->attrs[offset]; return attrs->attr_list->attrs[offset];
} }
extern "C" PyObject* PyObject_GetAttrWrapper(PyObject* obj) noexcept {
return obj->getAttrWrapper();
}
Box* unwrapAttrWrapper(Box* b) { Box* unwrapAttrWrapper(Box* b) {
assert(b->cls == attrwrapper_cls); assert(b->cls == attrwrapper_cls);
return static_cast<AttrWrapper*>(b)->getUnderlying(); return static_cast<AttrWrapper*>(b)->getUnderlying();
...@@ -3000,6 +3041,26 @@ inline void initUserAttrs(Box* obj, BoxedClass* cls) { ...@@ -3000,6 +3041,26 @@ inline void initUserAttrs(Box* obj, BoxedClass* cls) {
} }
} }
extern "C" void PyObject_InitHcAttrs(HCAttrs* attrs) noexcept {
new ((void*)attrs) HCAttrs();
}
extern "C" PyObject* PyObject_GetHcAttrString(PyObject* obj, const char* attr) PYSTON_NOEXCEPT {
return obj->getattr(internStringMortal(attr));
}
extern "C" int PyObject_SetHcAttrString(PyObject* obj, const char* attr, PyObject* val) PYSTON_NOEXCEPT {
obj->setattr(internStringMortal(attr), val, NULL);
return 0;
}
extern "C" int PyObject_DelHcAttrString(PyObject* obj, const char* attr) PYSTON_NOEXCEPT {
BoxedString* attr_str = internStringMortal(attr);
bool has = obj->hasattr(attr_str);
if (!has)
return -1;
obj->delattr(attr_str, NULL);
return 0;
}
extern "C" PyVarObject* PyObject_InitVar(PyVarObject* op, PyTypeObject* tp, Py_ssize_t size) noexcept { extern "C" PyVarObject* PyObject_InitVar(PyVarObject* op, PyTypeObject* tp, Py_ssize_t size) noexcept {
assert(op); assert(op);
assert(tp); assert(tp);
......
...@@ -232,6 +232,7 @@ public: ...@@ -232,6 +232,7 @@ public:
bool has___class__; // Has a custom __class__ attribute (ie different from object's __class__ descriptor) bool has___class__; // Has a custom __class__ attribute (ie different from object's __class__ descriptor)
bool has_instancecheck; bool has_instancecheck;
bool has_subclasscheck;
bool has_getattribute; bool has_getattribute;
typedef bool (*pyston_inquiry)(Box*); typedef bool (*pyston_inquiry)(Box*);
......
...@@ -104,7 +104,7 @@ f14() ...@@ -104,7 +104,7 @@ f14()
def test_set_state(): def test_set_state():
exc = BaseException() exc = BaseException()
print exc.__dict__ print sorted(exc.__dict__.items())
attrs = {"x": 1, "y": 2} attrs = {"x": 1, "y": 2}
exc.__setstate__(attrs) exc.__setstate__(attrs)
print exc.__dict__ == attrs print exc.__dict__ == attrs
......
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