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 @@
#include "warnings.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 "pyerrors.h"
......
......@@ -10,14 +10,18 @@ extern "C" {
typedef struct {
PyObject_HEAD
PyObject *dict;
// Pyston change: changed from dict to hcattrs
// PyObject *dict;
struct _hcattrs hcattrs;
PyObject *args;
PyObject *message;
} PyBaseExceptionObject;
typedef struct {
PyObject_HEAD
PyObject *dict;
// Pyston change: changed from dict to hcattrs
// PyObject *dict;
struct _hcattrs hcattrs;
PyObject *args;
PyObject *message;
PyObject *msg;
......@@ -31,7 +35,9 @@ typedef struct {
#ifdef Py_USING_UNICODE
typedef struct {
PyObject_HEAD
PyObject *dict;
// Pyston change: changed from dict to hcattrs
// PyObject *dict;
struct _hcattrs hcattrs;
PyObject *args;
PyObject *message;
PyObject *encoding;
......@@ -44,7 +50,9 @@ typedef struct {
typedef struct {
PyObject_HEAD
PyObject *dict;
// Pyston change: changed from dict to hcattrs
// PyObject *dict;
struct _hcattrs hcattrs;
PyObject *args;
PyObject *message;
PyObject *code;
......@@ -52,7 +60,9 @@ typedef struct {
typedef struct {
PyObject_HEAD
PyObject *dict;
// Pyston change: changed from dict to hcattrs
// PyObject *dict;
struct _hcattrs hcattrs;
PyObject *args;
PyObject *message;
PyObject *myerrno;
......@@ -63,7 +73,9 @@ typedef struct {
#ifdef MS_WINDOWS
typedef struct {
PyObject_HEAD
PyObject *dict;
// Pyston change: changed from dict to hcattrs
// PyObject *dict;
struct _hcattrs hcattrs;
PyObject *args;
PyObject *message;
PyObject *myerrno;
......
......@@ -36,8 +36,8 @@ BaseException_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
self = (PyBaseExceptionObject *)type->tp_alloc(type, 0);
if (!self)
return NULL;
/* the dict is created on the fly in PyObject_GenericSetAttr */
self->message = self->dict = NULL;
self->message = NULL;
PyObject_InitHcAttrs(&self->hcattrs);
self->args = PyTuple_New(0);
if (!self->args) {
......@@ -84,7 +84,7 @@ PyObject* PyErr_CreateExceptionInstance(PyObject* _type, PyObject* arg) {
if (!self)
return NULL;
self->dict = NULL;
PyObject_InitHcAttrs(&self->hcattrs);
if (arg) {
self->args = PyTuple_Pack(1, arg);
if (!self->args)
......@@ -115,7 +115,8 @@ PyObject* PyErr_CreateExceptionInstance(PyObject* _type, PyObject* arg) {
static int
BaseException_clear(PyBaseExceptionObject *self)
{
Py_CLEAR(self->dict);
// Pyston change:
// Py_CLEAR(self->dict);
Py_CLEAR(self->args);
Py_CLEAR(self->message);
return 0;
......@@ -132,7 +133,8 @@ BaseException_dealloc(PyBaseExceptionObject *self)
static int
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->message);
return 0;
......@@ -225,10 +227,16 @@ BaseException_repr(PyBaseExceptionObject *self)
static PyObject *
BaseException_reduce(PyBaseExceptionObject *self)
{
/* Pyston change:
if (self->args && self->dict)
return PyTuple_Pack(3, Py_TYPE(self), self->args, self->dict);
else
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 = {
0 /* sq_inplace_repeat; */
};
/* Pyston change: we use the standard dict descriptor for these types now
static PyObject *
BaseException_get_dict(PyBaseExceptionObject *self)
{
......@@ -327,6 +336,7 @@ BaseException_set_dict(PyBaseExceptionObject *self, PyObject *val)
self->dict = val;
return 0;
}
*/
static PyObject *
BaseException_get_args(PyBaseExceptionObject *self)
......@@ -361,8 +371,7 @@ BaseException_get_message(PyBaseExceptionObject *self)
PyObject *msg;
/* if "message" is in self->dict, accessing a user-set message attribute */
if (self->dict &&
(msg = PyDict_GetItemString(self->dict, "message"))) {
if ((msg = PyObject_GetHcAttrString((PyObject*)self, "message"))) {
Py_INCREF(msg);
return msg;
}
......@@ -387,25 +396,18 @@ BaseException_set_message(PyBaseExceptionObject *self, PyObject *val)
{
/* if val is NULL, delete the message attribute */
if (val == NULL) {
if (self->dict && PyDict_GetItemString(self->dict, "message")) {
if (PyDict_DelItemString(self->dict, "message") < 0)
if (PyObject_GetHcAttrString((PyObject*)self, "message")) {
if (PyObject_DelHcAttrString((PyObject*)self, "message") < 0)
return -1;
}
Py_CLEAR(self->message);
return 0;
}
/* else set it in __dict__, but may need to create the dict first */
if (self->dict == NULL) {
self->dict = PyDict_New();
if (!self->dict)
return -1;
}
return PyDict_SetItemString(self->dict, "message", val);
return PyObject_SetHcAttrString((PyObject*)self, "message", val);
}
static PyGetSetDef BaseException_getset[] = {
{"__dict__", (getter)BaseException_get_dict, (setter)BaseException_set_dict},
{"args", (getter)BaseException_get_args, (setter)BaseException_set_args},
{"message", (getter)BaseException_get_message,
(setter)BaseException_set_message},
......@@ -450,7 +452,7 @@ static PyTypeObject _PyExc_BaseException = {
0, /* tp_dict */
0, /* tp_descr_get */
0, /* tp_descr_set */
offsetof(PyBaseExceptionObject, dict), /* tp_dictoffset */
/* Pyston change: offsetof(PyBaseExceptionObject, dict)*/ 0, /* tp_dictoffset */
(initproc)BaseException_init, /* tp_init */
0, /* tp_alloc */
BaseException_new, /* tp_new */
......@@ -474,7 +476,7 @@ static PyTypeObject _PyExc_ ## EXCNAME = { \
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, \
PyDoc_STR(EXCDOC), (traverseproc)BaseException_traverse, \
(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,\
}; \
PyObject *PyExc_ ## EXCNAME = (PyObject *)&_PyExc_ ## EXCNAME
......@@ -490,7 +492,7 @@ static PyTypeObject _PyExc_ ## EXCNAME = { \
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, \
PyDoc_STR(EXCDOC), (traverseproc)EXCSTORE ## _traverse, \
(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,\
}; \
PyObject *PyExc_ ## EXCNAME = (PyObject *)&_PyExc_ ## EXCNAME
......@@ -507,7 +509,7 @@ static PyTypeObject _PyExc_ ## EXCNAME = { \
PyDoc_STR(EXCDOC), (traverseproc)EXCSTORE ## _traverse, \
(inquiry)EXCSTORE ## _clear, 0, 0, 0, 0, EXCMETHODS, \
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,\
}; \
PyObject *PyExc_ ## EXCNAME = (PyObject *)&_PyExc_ ## EXCNAME
......@@ -831,12 +833,17 @@ EnvironmentError_reduce(PyEnvironmentErrorObject *self)
} else
Py_INCREF(args);
/* Pyston change:
if (self->dict)
res = PyTuple_Pack(3, Py_TYPE(self), args, self->dict);
else
res = PyTuple_Pack(2, Py_TYPE(self), 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 = {
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC,
PyDoc_STR("Unicode encoding error."), (traverseproc)UnicodeError_traverse,
(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,
};
PyObject *PyExc_UnicodeEncodeError = (PyObject *)&_PyExc_UnicodeEncodeError;
......@@ -1828,7 +1835,7 @@ static PyTypeObject _PyExc_UnicodeDecodeError = {
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC,
PyDoc_STR("Unicode decoding error."), (traverseproc)UnicodeError_traverse,
(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,
};
PyObject *PyExc_UnicodeDecodeError = (PyObject *)&_PyExc_UnicodeDecodeError;
......@@ -1926,7 +1933,7 @@ static PyTypeObject _PyExc_UnicodeTranslateError = {
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC,
PyDoc_STR("Unicode translation error."), (traverseproc)UnicodeError_traverse,
(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,
};
PyObject *PyExc_UnicodeTranslateError = (PyObject *)&_PyExc_UnicodeTranslateError;
......@@ -2110,7 +2117,10 @@ _PyExc_Init(void)
{
PyObject *m, *bltinmod, *bdict;
PyType_RequestHcAttrs(&_PyExc_BaseException, offsetof(PyBaseExceptionObject, hcattrs));
PRE_INIT(BaseException)
PyType_GiveHcAttrsDictDescr(&_PyExc_BaseException);
PRE_INIT(Exception)
PRE_INIT(StandardError)
PRE_INIT(TypeError)
......
......@@ -797,8 +797,15 @@ extern "C" int PyObject_IsSubclass(PyObject* derived, PyObject* cls) noexcept {
return r;
}
if (!(PyClass_Check(cls) || PyInstance_Check(cls))) {
PyObject* checker;
checker = _PyObject_LookupSpecial(cls, "__subclasscheck__", &name);
PyObject* checker = NULL;
if (cls->cls->has_subclasscheck) {
checker = _PyObject_LookupSpecial(cls, "__subclasscheck__", &name);
if (!checker && PyErr_Occurred())
return -1;
assert(checker);
}
if (checker != NULL) {
PyObject* res;
int ok = -1;
......
......@@ -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));
static PyObject* init_str;
......@@ -1645,6 +1645,7 @@ static slotdef slotdefs[]
TPSLOT("__del__", tp_del, slot_tp_del, NULL, ""),
FLSLOT("__class__", has___class__, 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),
TPPSLOT("__hasnext__", tpp_hasnext, slotTppHasnext, wrapInquirypred, "hasnext"),
......@@ -3262,6 +3263,18 @@ static Box* tppProxyToTpCall(Box* self, CallRewriteArgs* rewrite_args, ArgPassSp
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 {
ASSERT(!cls->is_pyston_class, "should not call this on Pyston classes");
......@@ -3389,11 +3402,10 @@ extern "C" int PyType_Ready(PyTypeObject* cls) noexcept {
// e.g. CTypes does this.
bool is_metaclass = PyType_IsSubtype(cls, type_cls);
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) {
exception_types.push_back(cls);
}
......
......@@ -51,6 +51,7 @@ int slot_sq_contains(PyObject* self, PyObject* value) noexcept;
Py_ssize_t slot_sq_length(PyObject* self) noexcept;
PyObject* slot_tp_getattr_hook(PyObject* self, PyObject* name) 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;
Box* slotTpGetattrHookInternal(Box* self, BoxedString* attr, GetattrRewriteArgs* rewrite_args);
......
......@@ -225,15 +225,18 @@ protected:
} else
++it;
}
ASSERT(this->map.size() == this->map_elts, "%ld %d", this->map.size(), this->map_elts);
}
public:
PerThreadSet(CtorArgs... ctor_args) : ctor_args(std::forward<CtorArgs>(ctor_args)...) {
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) {
LOCK_REGION(&lock);
ASSERT(this->map.size() == this->map_elts, "%ld %d", this->map.size(), this->map_elts);
for (auto& p : map) {
f(&p.second->val);
......@@ -242,6 +245,7 @@ public:
template <typename... Arguments> void forEachValue(std::function<void(T*, Arguments...)> f, Arguments... args) {
LOCK_REGION(&lock);
ASSERT(this->map.size() == this->map_elts, "%ld %d", this->map.size(), this->map_elts);
for (auto& p : map) {
f(&p.second->val, std::forward<Arguments>(args)...);
......@@ -267,6 +271,7 @@ public:
assert(map.count(pthread_self()) == 0);
map[pthread_self()] = s;
ASSERT(this->map.size() == this->map_elts, "%ld %d", this->map.size(), this->map_elts);
}
return &s->val;
}
......
......@@ -505,6 +505,7 @@ public:
HCAttrs(HiddenClass* hcls = root_hcls) : hcls(hcls), attr_list(nullptr) {}
};
static_assert(sizeof(HCAttrs) == sizeof(struct _hcattrs), "");
class BoxedDict;
class BoxedString;
......
......@@ -984,6 +984,13 @@ extern "C" int PyErr_GivenExceptionMatches(PyObject* err, PyObject* exc) noexcep
err = PyExceptionInstance_Class(err);
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;
PyObject* exception, *value, *tb;
PyErr_Fetch(&exception, &value, &tb);
......
......@@ -75,9 +75,9 @@ static Box* propertyInit(Box* _self, Box* fget, Box* fset, Box** args) {
Box* doc = args[1];
BoxedProperty* self = static_cast<BoxedProperty*>(_self);
self->prop_get = fget;
self->prop_set = fset;
self->prop_del = fdel;
self->prop_get = fget == None ? NULL : fget;
self->prop_set = fset == None ? NULL : fset;
self->prop_del = fdel == None ? NULL : fdel;
self->prop_doc = doc;
self->getter_doc = false;
......@@ -151,6 +151,12 @@ static Box* property_copy(BoxedProperty* old, Box* get, Box* set, Box* del) {
return prop;
} else {
if (!get)
get = None;
if (!set)
set = None;
if (!del)
del = None;
Box* doc;
if ((old->getter_doc && get != None) || !old->prop_doc)
doc = None;
......
This diff is collapsed.
......@@ -232,6 +232,7 @@ public:
bool has___class__; // Has a custom __class__ attribute (ie different from object's __class__ descriptor)
bool has_instancecheck;
bool has_subclasscheck;
bool has_getattribute;
typedef bool (*pyston_inquiry)(Box*);
......
......@@ -104,7 +104,7 @@ f14()
def test_set_state():
exc = BaseException()
print exc.__dict__
print sorted(exc.__dict__.items())
attrs = {"x": 1, "y": 2}
exc.__setstate__(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