Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
P
Pyston
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Boxiang Sun
Pyston
Commits
bd2ee538
Commit
bd2ee538
authored
Aug 21, 2015
by
Kevin Modzelewski
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #852 from kmod/perf4
more small exceptions optimizations
parents
93ff229e
dbada809
Changes
13
Hide whitespace changes
Inline
Side-by-side
Showing
13 changed files
with
267 additions
and
114 deletions
+267
-114
from_cpython/Include/Python.h
from_cpython/Include/Python.h
+30
-0
from_cpython/Include/pyerrors.h
from_cpython/Include/pyerrors.h
+18
-6
from_cpython/Objects/exceptions.c
from_cpython/Objects/exceptions.c
+35
-25
src/capi/abstract.cpp
src/capi/abstract.cpp
+9
-2
src/capi/typeobject.cpp
src/capi/typeobject.cpp
+16
-4
src/capi/typeobject.h
src/capi/typeobject.h
+1
-0
src/core/thread_utils.h
src/core/thread_utils.h
+5
-0
src/core/types.h
src/core/types.h
+1
-0
src/runtime/capi.cpp
src/runtime/capi.cpp
+7
-0
src/runtime/descr.cpp
src/runtime/descr.cpp
+9
-3
src/runtime/types.cpp
src/runtime/types.cpp
+134
-73
src/runtime/types.h
src/runtime/types.h
+1
-0
test/tests/exceptions_basic.py
test/tests/exceptions_basic.py
+1
-1
No files found.
from_cpython/Include/Python.h
View file @
bd2ee538
...
...
@@ -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"
...
...
from_cpython/Include/pyerrors.h
View file @
bd2ee538
...
...
@@ -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
;
...
...
from_cpython/Objects/exceptions.c
View file @
bd2ee538
...
...
@@ -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
(
Py
Dict_DelItemString
(
self
->
dict
,
"message"
)
<
0
)
if
(
PyObject_GetHcAttrString
((
PyObject
*
)
self
,
"message"
))
{
if
(
Py
Object_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
)
...
...
src/capi/abstract.cpp
View file @
bd2ee538
...
...
@@ -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
;
...
...
src/capi/typeobject.cpp
View file @
bd2ee538
...
...
@@ -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
);
}
...
...
src/capi/typeobject.h
View file @
bd2ee538
...
...
@@ -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
);
...
...
src/core/thread_utils.h
View file @
bd2ee538
...
...
@@ -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
;
}
...
...
src/core/types.h
View file @
bd2ee538
...
...
@@ -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
;
...
...
src/runtime/capi.cpp
View file @
bd2ee538
...
...
@@ -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
);
...
...
src/runtime/descr.cpp
View file @
bd2ee538
...
...
@@ -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
;
...
...
src/runtime/types.cpp
View file @
bd2ee538
...
...
@@ -832,15 +832,16 @@ static Box* typeCallInner(CallRewriteArgs* rewrite_args, ArgPassSpec argspec, Bo
RewriterVar
*
r_ccls
=
NULL
;
RewriterVar
*
r_new
=
NULL
;
RewriterVar
*
r_init
=
NULL
;
Box
*
new_attr
,
*
init_attr
;
Box
*
new_attr
,
*
init_attr
=
NULL
;
if
(
rewrite_args
)
{
assert
(
!
argspec
.
has_starargs
);
assert
(
!
argspec
.
has_kwargs
);
assert
(
argspec
.
num_args
>
0
);
r_ccls
=
rewrite_args
->
arg1
;
// This is probably a duplicate, but it's hard to really convince myself of that.
// Need to create a clear contract of who guards on what
// Guard on the requested class. We could potentially support multiple classes in a rewrite,
// 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 */
);
...
...
@@ -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:
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 ok to call regardless of what type was requested.
...
...
@@ -939,32 +940,32 @@ static Box* typeCallInner(CallRewriteArgs* rewrite_args, ArgPassSpec argspec, Bo
// 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
static
std
::
vector
<
Box
*>
allowable
_news
;
if
(
allowable
_news
.
empty
())
{
static
std
::
vector
<
Box
*>
class_making
_news
;
if
(
class_making
_news
.
empty
())
{
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
);
gc
::
registerPermanentRoot
(
new_obj
,
/* allow_duplicates= */
true
);
allowable
_news
.
push_back
(
new_obj
);
class_making
_news
.
push_back
(
new_obj
);
}
}
if
(
rewrite_args
)
{
for
(
auto
b
:
allowable
_news
)
{
for
(
auto
b
:
class_making
_news
)
{
if
(
b
==
new_attr
)
{
why_rewrite_allowed
=
VERIFIED
;
why_rewrite_allowed
=
MAKES_CLS
;
break
;
}
}
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
;
if
(
know_first_arg
)
{
if
(
argspec
.
num_args
==
1
&&
(
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
)
&&
(
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
// 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
))
{
why_rewrite_allowed
=
VERIFIED
;
why_rewrite_allowed
=
MAKES_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
}
static
BoxedString
*
init_str
=
internStringImmortal
(
"__init__"
);
if
(
rewrite_args
)
{
GetattrRewriteArgs
grewrite_args
(
rewrite_args
->
rewriter
,
r_ccls
,
rewrite_args
->
destination
);
init_attr
=
typeLookup
(
cls
,
init_str
,
&
grewrite_args
);
if
(
cls
->
tp_init
==
slot_tp_init
)
{
// If there's a Python-level tp_init, try getting it, since calling it might be faster than calling
// 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
)
rewrite_args
=
NULL
;
else
{
if
(
init_attr
)
{
r_init
=
grewrite_args
.
out_rtn
;
r_init
->
addGuard
((
intptr_t
)
init_attr
);
if
(
!
grewrite_args
.
out_success
)
rewrite_args
=
NULL
;
else
{
if
(
init_attr
)
{
r_init
=
grewrite_args
.
out_rtn
;
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
;
RewriterVar
*
r_made
=
NULL
;
...
...
@@ -1121,60 +1125,95 @@ static Box* typeCallInner(CallRewriteArgs* rewrite_args, ArgPassSpec argspec, Bo
return
made
;
}
bool
skip_init
=
false
;
// If __new__ returns a subclass, supposed to call that subclass's __init__.
// If __new__ returns a non-subclass, not supposed to call __init__.
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
&&
cls
->
tp_init
==
object_cls
->
tp_init
),
"We should only have allowed the rewrite to continue if we were guaranteed that "
"made would have class cls!"
);
if
(
!
isSubclass
(
made
->
cls
,
cls
))
{
init_attr
=
NULL
;
skip_init
=
true
;
}
else
{
// We could have skipped the initial __init__ lookup
init_attr
=
typeLookup
(
made
->
cls
,
init_str
,
NULL
);
if
(
init_attr
)
{
// 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
)
{
// TODO apply the same descriptor special-casing as in callattr?
if
(
!
skip_init
&&
made
->
cls
->
tp_init
!=
object_cls
->
tp_init
)
{
Box
*
initrtn
;
// Attempt to rewrite the basic case:
if
(
rewrite_args
&&
init_attr
->
cls
==
function_cls
)
{
// Note: this code path includes the descriptor logic
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
;
// If there's a Python-level __init__ function, try calling it.
if
(
init_attr
&&
init_attr
->
cls
==
function_cls
)
{
if
(
rewrite_args
)
{
// We are going to rewrite as a call to cls.init:
assert
(
why_rewrite_allowed
==
MAKES_CLS
);
assert
(
made
->
cls
==
cls
);
}
// initrtn = callattrInternal<CXX>(cls, _init_str, INST_ONLY, &srewrite_args, argspec, made, arg2, arg3,
// args, keyword_names);
initrtn
=
runtimeCallInternal
<
S
>
(
init_attr
,
&
srewrite_args
,
argspec
,
made
,
arg2
,
arg3
,
args
,
keyword_names
);
// Note: this code path includes the descriptor logic
if
(
rewrite_args
)
{
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
)
{
assert
(
S
==
CAPI
);
return
NULL
;
}
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
);
}
assert
(
initrtn
);
if
(
S
==
CAPI
)
{
if
(
initrtn
!=
None
)
{
PyErr_Format
(
TypeError
,
"__init__() should return None, not '%s'"
,
getTypeName
(
initrtn
));
return
NULL
;
}
}
else
assertInitNone
(
initrtn
);
}
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
{
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
)
{
if
(
S
==
CAPI
)
{
setCAPIException
(
e
);
...
...
@@ -1183,30 +1222,28 @@ static Box* typeCallInner(CallRewriteArgs* rewrite_args, ArgPassSpec argspec, Bo
throw
e
;
}
ArgPassSpec
init_argspec
=
argspec
;
init_argspec
.
num_args
--
;
int
passed
=
init_argspec
.
totalPassed
();
if
(
!
rewrite_success
)
rewrite_args
=
NULL
;
// If we weren't passed the args array, it's not safe to index into it
if
(
passed
<=
2
)
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
);
assert
(
arg2
->
cls
==
tuple_cls
);
assert
(
!
arg3
||
arg3
->
cls
==
dict_cls
);
if
(
!
initrtn
)
{
assert
(
S
==
CAPI
);
return
NULL
;
int
err
=
tpinit
(
made
,
arg2
,
arg3
);
if
(
err
==
-
1
)
{
if
(
S
==
CAPI
)
return
NULL
;
else
throwCAPIException
();
}
}
assert
(
initrtn
);
if
(
S
==
CAPI
&&
initrtn
!=
None
)
{
PyErr_Format
(
TypeError
,
"__init__() should return None, not '%s'"
,
getTypeName
(
initrtn
));
return
NULL
;
if
(
rewrite_args
)
{
auto
r_err
=
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
{
if
(
new_attr
==
NULL
&&
npassed_args
!=
1
)
{
// TODO not npassed args, since the starargs or kwargs could be null
...
...
@@ -2480,6 +2517,10 @@ Box* Box::getAttrWrapper() {
return
attrs
->
attr_list
->
attrs
[
offset
];
}
extern
"C"
PyObject
*
PyObject_GetAttrWrapper
(
PyObject
*
obj
)
noexcept
{
return
obj
->
getAttrWrapper
();
}
Box
*
unwrapAttrWrapper
(
Box
*
b
)
{
assert
(
b
->
cls
==
attrwrapper_cls
);
return
static_cast
<
AttrWrapper
*>
(
b
)
->
getUnderlying
();
...
...
@@ -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
{
assert
(
op
);
assert
(
tp
);
...
...
src/runtime/types.h
View file @
bd2ee538
...
...
@@ -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
*
);
...
...
test/tests/exceptions_basic.py
View file @
bd2ee538
...
...
@@ -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
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment