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
49ee07fa
Commit
49ee07fa
authored
Jan 08, 2015
by
Kevin Modzelewski
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'tp_as_number'
parents
76210a33
b679d358
Changes
8
Hide whitespace changes
Inline
Side-by-side
Showing
8 changed files
with
635 additions
and
31 deletions
+635
-31
Makefile
Makefile
+5
-1
from_cpython/Include/intobject.h
from_cpython/Include/intobject.h
+1
-1
src/capi/object.cpp
src/capi/object.cpp
+25
-0
src/capi/typeobject.cpp
src/capi/typeobject.cpp
+327
-3
src/runtime/objmodel.cpp
src/runtime/objmodel.cpp
+21
-20
test/test_extension/slots_test.c
test/test_extension/slots_test.c
+215
-2
test/tests/capi_slots.py
test/tests/capi_slots.py
+38
-3
tools/tester.py
tools/tester.py
+3
-1
No files found.
Makefile
View file @
49ee07fa
...
...
@@ -321,7 +321,7 @@ NONSTDLIB_SRCS := $(MAIN_SRCS) $(OPTIONAL_SRCS) $(TOOL_SRCS) $(UNITTEST_SRCS)
# all: pyston_dbg pyston_release pyston_oprof pyston_prof $(OPTIONAL_SRCS:.cpp=.o) ext_python ext_pyston
all
:
pyston_dbg pyston_release pyston_prof ext_python ext_pyston unittests
ALL_HEADERS
:=
$(
wildcard
src/
*
/
*
.h
)
$(
wildcard
src/
*
/
*
/
*
.h
)
$(
wildcard
cpython2.7
/Include/
*
.h
)
ALL_HEADERS
:=
$(
wildcard
src/
*
/
*
.h
)
$(
wildcard
src/
*
/
*
/
*
.h
)
$(
wildcard
from_cpython
/Include/
*
.h
)
tags
:
$(SRCS) $(OPTIONAL_SRCS) $(FROM_CPYTHON_SRCS) $(ALL_HEADERS)
$(ECHO)
Calculating tags...
$(VERB)
ctags
$^
...
...
@@ -865,6 +865,10 @@ $(call make_target,_grwl)
$(call
make_target,_grwl_dbg)
$(call
make_target,_nosync)
runpy_%
:
%.py ext_python
PYTHONPATH
=
test
/test_extension/build/lib.linux-x86_64-2.7 python
$<
$(call
make_search,runpy_%)
# "kill valgrind":
kv
:
ps aux |
awk
'/[v]algrind/ {print $$2}'
| xargs
kill
-9
;
true
...
...
from_cpython/Include/intobject.h
View file @
49ee07fa
...
...
@@ -42,7 +42,7 @@ PyAPI_FUNC(bool) PyInt_Check(PyObject*);
#define PyInt_Check(op) \
PyType_FastSubclass((op)->ob_type, Py_TPFLAGS_INT_SUBCLASS)
#endif
#define PyInt_CheckExact(op) (
(op)->ob_type
== &PyInt_Type)
#define PyInt_CheckExact(op) (
Py_TYPE(op)
== &PyInt_Type)
PyAPI_FUNC
(
PyObject
*
)
PyInt_FromString
(
char
*
,
char
**
,
int
);
#ifdef Py_USING_UNICODE
...
...
src/capi/object.cpp
View file @
49ee07fa
...
...
@@ -75,4 +75,29 @@ extern "C" int PyObject_GenericSetAttr(PyObject* obj, PyObject* name, PyObject*
extern
"C"
int
PyObject_AsWriteBuffer
(
PyObject
*
obj
,
void
**
buffer
,
Py_ssize_t
*
buffer_len
)
{
Py_FatalError
(
"unimplemented"
);
}
/* Return -1 if error; 1 if v op w; 0 if not (v op w). */
extern
"C"
int
PyObject_RichCompareBool
(
PyObject
*
v
,
PyObject
*
w
,
int
op
)
{
PyObject
*
res
;
int
ok
;
/* Quick result when objects are the same.
Guarantees that identity implies equality. */
if
(
v
==
w
)
{
if
(
op
==
Py_EQ
)
return
1
;
else
if
(
op
==
Py_NE
)
return
0
;
}
res
=
PyObject_RichCompare
(
v
,
w
,
op
);
if
(
res
==
NULL
)
return
-
1
;
if
(
PyBool_Check
(
res
))
ok
=
(
res
==
Py_True
);
else
ok
=
PyObject_IsTrue
(
res
);
Py_DECREF
(
res
);
return
ok
;
}
}
src/capi/typeobject.cpp
View file @
49ee07fa
...
...
@@ -79,6 +79,30 @@ RICHCMP_WRAPPER(ne, Py_NE)
RICHCMP_WRAPPER
(
gt
,
Py_GT
)
RICHCMP_WRAPPER
(
ge
,
Py_GE
)
static
PyObject
*
wrap_ternaryfunc
(
PyObject
*
self
,
PyObject
*
args
,
void
*
wrapped
)
noexcept
{
ternaryfunc
func
=
(
ternaryfunc
)
wrapped
;
PyObject
*
other
;
PyObject
*
third
=
Py_None
;
/* Note: This wrapper only works for __pow__() */
if
(
!
PyArg_UnpackTuple
(
args
,
""
,
1
,
2
,
&
other
,
&
third
))
return
NULL
;
return
(
*
func
)(
self
,
other
,
third
);
}
static
PyObject
*
wrap_ternaryfunc_r
(
PyObject
*
self
,
PyObject
*
args
,
void
*
wrapped
)
noexcept
{
ternaryfunc
func
=
(
ternaryfunc
)
wrapped
;
PyObject
*
other
;
PyObject
*
third
=
Py_None
;
/* Note: This wrapper only works for __pow__() */
if
(
!
PyArg_UnpackTuple
(
args
,
""
,
1
,
2
,
&
other
,
&
third
))
return
NULL
;
return
(
*
func
)(
other
,
self
,
third
);
}
static
PyObject
*
wrap_unaryfunc
(
PyObject
*
self
,
PyObject
*
args
,
void
*
wrapped
)
noexcept
{
unaryfunc
func
=
(
unaryfunc
)
wrapped
;
...
...
@@ -87,6 +111,18 @@ static PyObject* wrap_unaryfunc(PyObject* self, PyObject* args, void* wrapped) n
return
(
*
func
)(
self
);
}
static
PyObject
*
wrap_inquirypred
(
PyObject
*
self
,
PyObject
*
args
,
void
*
wrapped
)
noexcept
{
inquiry
func
=
(
inquiry
)
wrapped
;
int
res
;
if
(
!
check_num_args
(
args
,
0
))
return
NULL
;
res
=
(
*
func
)(
self
);
if
(
res
==
-
1
&&
PyErr_Occurred
())
return
NULL
;
return
PyBool_FromLong
((
long
)
res
);
}
static
PyObject
*
wrap_binaryfunc
(
PyObject
*
self
,
PyObject
*
args
,
void
*
wrapped
)
noexcept
{
binaryfunc
func
=
(
binaryfunc
)
wrapped
;
PyObject
*
other
;
...
...
@@ -97,6 +133,34 @@ static PyObject* wrap_binaryfunc(PyObject* self, PyObject* args, void* wrapped)
return
(
*
func
)(
self
,
other
);
}
static
PyObject
*
wrap_binaryfunc_l
(
PyObject
*
self
,
PyObject
*
args
,
void
*
wrapped
)
{
binaryfunc
func
=
(
binaryfunc
)
wrapped
;
PyObject
*
other
;
if
(
!
check_num_args
(
args
,
1
))
return
NULL
;
other
=
PyTuple_GET_ITEM
(
args
,
0
);
if
(
!
(
self
->
cls
->
tp_flags
&
Py_TPFLAGS_CHECKTYPES
)
&&
!
PyType_IsSubtype
(
other
->
cls
,
self
->
cls
))
{
Py_INCREF
(
Py_NotImplemented
);
return
Py_NotImplemented
;
}
return
(
*
func
)(
self
,
other
);
}
static
PyObject
*
wrap_binaryfunc_r
(
PyObject
*
self
,
PyObject
*
args
,
void
*
wrapped
)
{
binaryfunc
func
=
(
binaryfunc
)
wrapped
;
PyObject
*
other
;
if
(
!
check_num_args
(
args
,
1
))
return
NULL
;
other
=
PyTuple_GET_ITEM
(
args
,
0
);
if
(
!
(
self
->
cls
->
tp_flags
&
Py_TPFLAGS_CHECKTYPES
)
&&
!
PyType_IsSubtype
(
other
->
cls
,
self
->
cls
))
{
Py_INCREF
(
Py_NotImplemented
);
return
Py_NotImplemented
;
}
return
(
*
func
)(
other
,
self
);
}
static
Py_ssize_t
getindex
(
PyObject
*
self
,
PyObject
*
arg
)
noexcept
{
Py_ssize_t
i
;
...
...
@@ -343,6 +407,41 @@ static PyObject* call_method(PyObject* o, const char* name, PyObject** nameobj,
return
retval
;
}
/* Clone of call_method() that returns NotImplemented when the lookup fails. */
static
PyObject
*
call_maybe
(
PyObject
*
o
,
const
char
*
name
,
PyObject
**
nameobj
,
const
char
*
format
,
...)
noexcept
{
va_list
va
;
PyObject
*
args
,
*
func
=
0
,
*
retval
;
va_start
(
va
,
format
);
func
=
lookup_maybe
(
o
,
name
,
nameobj
);
if
(
func
==
NULL
)
{
va_end
(
va
);
if
(
!
PyErr_Occurred
())
{
Py_INCREF
(
Py_NotImplemented
);
return
Py_NotImplemented
;
}
return
NULL
;
}
if
(
format
&&
*
format
)
args
=
Py_VaBuildValue
(
format
,
va
);
else
args
=
PyTuple_New
(
0
);
va_end
(
va
);
if
(
args
==
NULL
)
return
NULL
;
assert
(
PyTuple_Check
(
args
));
retval
=
PyObject_Call
(
func
,
args
,
NULL
);
Py_DECREF
(
args
);
Py_DECREF
(
func
);
return
retval
;
}
PyObject
*
slot_tp_repr
(
PyObject
*
self
)
noexcept
{
try
{
...
...
@@ -352,6 +451,14 @@ PyObject* slot_tp_repr(PyObject* self) noexcept {
}
}
PyObject
*
slot_tp_str
(
PyObject
*
self
)
noexcept
{
try
{
return
str
(
self
);
}
catch
(
Box
*
e
)
{
abort
();
}
}
static
long
slot_tp_hash
(
PyObject
*
self
)
noexcept
{
PyObject
*
func
;
static
PyObject
*
hash_str
,
*
eq_str
,
*
cmp_str
;
...
...
@@ -591,6 +698,73 @@ static int slot_sq_contains(PyObject* self, PyObject* value) {
return call_method(self, OPSTR, &cache_str, "(" ARGCODES ")", arg1); \
}
/* Boolean helper for SLOT1BINFULL().
right.__class__ is a nontrivial subclass of left.__class__. */
static
int
method_is_overloaded
(
PyObject
*
left
,
PyObject
*
right
,
const
char
*
name
)
{
PyObject
*
a
,
*
b
;
int
ok
;
b
=
PyObject_GetAttrString
((
PyObject
*
)(
Py_TYPE
(
right
)),
name
);
if
(
b
==
NULL
)
{
PyErr_Clear
();
/* If right doesn't have it, it's not overloaded */
return
0
;
}
a
=
PyObject_GetAttrString
((
PyObject
*
)(
Py_TYPE
(
left
)),
name
);
if
(
a
==
NULL
)
{
PyErr_Clear
();
Py_DECREF
(
b
);
/* If right has it but left doesn't, it's overloaded */
return
1
;
}
ok
=
PyObject_RichCompareBool
(
a
,
b
,
Py_NE
);
Py_DECREF
(
a
);
Py_DECREF
(
b
);
if
(
ok
<
0
)
{
PyErr_Clear
();
return
0
;
}
return
ok
;
}
#define SLOT1BINFULL(FUNCNAME, TESTFUNC, SLOTNAME, OPSTR, ROPSTR) \
static PyObject* FUNCNAME(PyObject* self, PyObject* other) { \
static PyObject* cache_str, *rcache_str; \
int do_other = Py_TYPE(self) != Py_TYPE(other) && Py_TYPE(other)->tp_as_number != NULL \
&& Py_TYPE(other)->tp_as_number->SLOTNAME == TESTFUNC; \
if (Py_TYPE(self)->tp_as_number != NULL && Py_TYPE(self)->tp_as_number->SLOTNAME == TESTFUNC) { \
PyObject* r; \
if (do_other && PyType_IsSubtype(Py_TYPE(other), Py_TYPE(self)) \
&& method_is_overloaded(self, other, ROPSTR)) { \
r = call_maybe(other, ROPSTR, &rcache_str, "(O)", self); \
if (r != Py_NotImplemented) \
return r; \
Py_DECREF(r); \
do_other = 0; \
} \
r = call_maybe(self, OPSTR, &cache_str, "(O)", other); \
if (r != Py_NotImplemented || Py_TYPE(other) == Py_TYPE(self)) \
return r; \
Py_DECREF(r); \
} \
if (do_other) { \
return call_maybe(other, ROPSTR, &rcache_str, "(O)", self); \
} \
Py_INCREF(Py_NotImplemented); \
return Py_NotImplemented; \
}
#define SLOT1BIN(FUNCNAME, SLOTNAME, OPSTR, ROPSTR) SLOT1BINFULL(FUNCNAME, FUNCNAME, SLOTNAME, OPSTR, ROPSTR)
#define SLOT2(FUNCNAME, OPSTR, ARG1TYPE, ARG2TYPE, ARGCODES) \
static PyObject* FUNCNAME(PyObject* self, ARG1TYPE arg1, ARG2TYPE arg2) { \
static PyObject* cache_str; \
return call_method(self, OPSTR, &cache_str, "(" ARGCODES ")", arg1, arg2); \
}
#define slot_mp_length slot_sq_length
SLOT1
(
slot_mp_subscript
,
"__getitem__"
,
PyObject
*
,
"O"
)
...
...
@@ -609,6 +783,85 @@ static int slot_mp_ass_subscript(PyObject* self, PyObject* key, PyObject* value)
return
0
;
}
SLOT1BIN
(
slot_nb_add
,
nb_add
,
"__add__"
,
"__radd__"
)
SLOT1BIN
(
slot_nb_subtract
,
nb_subtract
,
"__sub__"
,
"__rsub__"
)
SLOT1BIN
(
slot_nb_multiply
,
nb_multiply
,
"__mul__"
,
"__rmul__"
)
SLOT1BIN
(
slot_nb_divide
,
nb_divide
,
"__div__"
,
"__rdiv__"
)
SLOT1BIN
(
slot_nb_remainder
,
nb_remainder
,
"__mod__"
,
"__rmod__"
)
SLOT1BIN
(
slot_nb_divmod
,
nb_divmod
,
"__divmod__"
,
"__rdivmod__"
)
static
PyObject
*
slot_nb_power
(
PyObject
*
,
PyObject
*
,
PyObject
*
);
SLOT1BINFULL
(
slot_nb_power_binary
,
slot_nb_power
,
nb_power
,
"__pow__"
,
"__rpow__"
)
static
PyObject
*
slot_nb_power
(
PyObject
*
self
,
PyObject
*
other
,
PyObject
*
modulus
)
{
static
PyObject
*
pow_str
;
if
(
modulus
==
Py_None
)
return
slot_nb_power_binary
(
self
,
other
);
/* Three-arg power doesn't use __rpow__. But ternary_op
can call this when the second argument's type uses
slot_nb_power, so check before calling self.__pow__. */
if
(
Py_TYPE
(
self
)
->
tp_as_number
!=
NULL
&&
Py_TYPE
(
self
)
->
tp_as_number
->
nb_power
==
slot_nb_power
)
{
return
call_method
(
self
,
"__pow__"
,
&
pow_str
,
"(OO)"
,
other
,
modulus
);
}
Py_INCREF
(
Py_NotImplemented
);
return
Py_NotImplemented
;
}
SLOT0
(
slot_nb_negative
,
"__neg__"
)
SLOT0
(
slot_nb_positive
,
"__pos__"
)
SLOT0
(
slot_nb_absolute
,
"__abs__"
)
static
int
slot_nb_nonzero
(
PyObject
*
self
)
noexcept
{
PyObject
*
func
,
*
args
;
static
PyObject
*
nonzero_str
,
*
len_str
;
int
result
=
-
1
;
int
using_len
=
0
;
func
=
lookup_maybe
(
self
,
"__nonzero__"
,
&
nonzero_str
);
if
(
func
==
NULL
)
{
if
(
PyErr_Occurred
())
return
-
1
;
func
=
lookup_maybe
(
self
,
"__len__"
,
&
len_str
);
if
(
func
==
NULL
)
return
PyErr_Occurred
()
?
-
1
:
1
;
using_len
=
1
;
}
args
=
PyTuple_New
(
0
);
if
(
args
!=
NULL
)
{
PyObject
*
temp
=
PyObject_Call
(
func
,
args
,
NULL
);
Py_DECREF
(
args
);
if
(
temp
!=
NULL
)
{
if
(
PyInt_CheckExact
(
temp
)
||
PyBool_Check
(
temp
))
result
=
PyObject_IsTrue
(
temp
);
else
{
PyErr_Format
(
PyExc_TypeError
,
"%s should return "
"bool or int, returned %s"
,
(
using_len
?
"__len__"
:
"__nonzero__"
),
temp
->
cls
->
tp_name
);
result
=
-
1
;
}
Py_DECREF
(
temp
);
}
}
Py_DECREF
(
func
);
return
result
;
}
SLOT0
(
slot_nb_invert
,
"__invert__"
)
SLOT1BIN
(
slot_nb_lshift
,
nb_lshift
,
"__lshift__"
,
"__rlshift__"
)
SLOT1BIN
(
slot_nb_rshift
,
nb_rshift
,
"__rshift__"
,
"__rrshift__"
)
SLOT1BIN
(
slot_nb_and
,
nb_and
,
"__and__"
,
"__rand__"
)
SLOT1BIN
(
slot_nb_xor
,
nb_xor
,
"__xor__"
,
"__rxor__"
)
SLOT1BIN
(
slot_nb_or
,
nb_or
,
"__or__"
,
"__ror__"
)
static
int
slot_nb_coerce
(
PyObject
**
a
,
PyObject
**
b
);
SLOT0
(
slot_nb_int
,
"__int__"
)
SLOT0
(
slot_nb_long
,
"__long__"
)
SLOT0
(
slot_nb_float
,
"__float__"
)
SLOT0
(
slot_nb_oct
,
"__oct__"
)
SLOT0
(
slot_nb_hex
,
"__hex__"
)
typedef
wrapper_def
slotdef
;
...
...
@@ -687,6 +940,7 @@ static slotdef slotdefs[] = {
TPSLOT
(
"__hash__"
,
tp_hash
,
slot_tp_hash
,
wrap_hashfunc
,
"x.__hash__() <==> hash(x)"
),
FLSLOT
(
"__call__"
,
tp_call
,
slot_tp_call
,
(
wrapperfunc
)
wrap_call
,
"x.__call__(...) <==> x(...)"
,
PyWrapperFlag_KEYWORDS
),
TPSLOT
(
"__str__"
,
tp_str
,
slot_tp_str
,
wrap_unaryfunc
,
"x.__str__() <==> str(x)"
),
TPSLOT
(
"__lt__"
,
tp_richcompare
,
slot_tp_richcompare
,
richcmp_lt
,
"x.__lt__(y) <==> x<y"
),
TPSLOT
(
"__le__"
,
tp_richcompare
,
slot_tp_richcompare
,
richcmp_le
,
"x.__le__(y) <==> x<=y"
),
TPSLOT
(
"__eq__"
,
tp_richcompare
,
slot_tp_richcompare
,
richcmp_eq
,
"x.__eq__(y) <==> x==y"
),
...
...
@@ -699,6 +953,41 @@ static slotdef slotdefs[] = {
PyWrapperFlag_KEYWORDS
),
TPSLOT
(
"__new__"
,
tp_new
,
slot_tp_new
,
NULL
,
""
),
BINSLOT
(
"__add__"
,
nb_add
,
slot_nb_add
,
"+"
),
// [force clang-format to line break]
RBINSLOT
(
"__radd__"
,
nb_add
,
slot_nb_add
,
"+"
),
//
BINSLOT
(
"__sub__"
,
nb_subtract
,
slot_nb_subtract
,
"-"
),
//
RBINSLOT
(
"__rsub__"
,
nb_subtract
,
slot_nb_subtract
,
"-"
),
//
BINSLOT
(
"__mul__"
,
nb_multiply
,
slot_nb_multiply
,
"*"
),
//
RBINSLOT
(
"__rmul__"
,
nb_multiply
,
slot_nb_multiply
,
"*"
),
//
BINSLOT
(
"__div__"
,
nb_divide
,
slot_nb_divide
,
"/"
),
//
RBINSLOT
(
"__rdiv__"
,
nb_divide
,
slot_nb_divide
,
"/"
),
//
BINSLOT
(
"__mod__"
,
nb_remainder
,
slot_nb_remainder
,
"%"
),
//
RBINSLOT
(
"__rmod__"
,
nb_remainder
,
slot_nb_remainder
,
"%"
),
//
BINSLOTNOTINFIX
(
"__divmod__"
,
nb_divmod
,
slot_nb_divmod
,
"divmod(x, y)"
),
RBINSLOTNOTINFIX
(
"__rdivmod__"
,
nb_divmod
,
slot_nb_divmod
,
"divmod(y, x)"
),
NBSLOT
(
"__pow__"
,
nb_power
,
slot_nb_power
,
wrap_ternaryfunc
,
"x.__pow__(y[, z]) <==> pow(x, y[, z])"
),
NBSLOT
(
"__rpow__"
,
nb_power
,
slot_nb_power
,
wrap_ternaryfunc_r
,
"y.__rpow__(x[, z]) <==> pow(x, y[, z])"
),
UNSLOT
(
"__neg__"
,
nb_negative
,
slot_nb_negative
,
wrap_unaryfunc
,
"-x"
),
//
UNSLOT
(
"__pos__"
,
nb_positive
,
slot_nb_positive
,
wrap_unaryfunc
,
"+x"
),
//
UNSLOT
(
"__abs__"
,
nb_absolute
,
slot_nb_absolute
,
wrap_unaryfunc
,
"abs(x)"
),
//
UNSLOT
(
"__nonzero__"
,
nb_nonzero
,
slot_nb_nonzero
,
wrap_inquirypred
,
"x != 0"
),
//
UNSLOT
(
"__invert__"
,
nb_invert
,
slot_nb_invert
,
wrap_unaryfunc
,
"~x"
),
//
BINSLOT
(
"__lshift__"
,
nb_lshift
,
slot_nb_lshift
,
"<<"
),
//
RBINSLOT
(
"__rlshift__"
,
nb_lshift
,
slot_nb_lshift
,
"<<"
),
//
BINSLOT
(
"__rshift__"
,
nb_rshift
,
slot_nb_rshift
,
">>"
),
//
RBINSLOT
(
"__rrshift__"
,
nb_rshift
,
slot_nb_rshift
,
">>"
),
//
BINSLOT
(
"__and__"
,
nb_and
,
slot_nb_and
,
"&"
),
//
RBINSLOT
(
"__rand__"
,
nb_and
,
slot_nb_and
,
"&"
),
//
BINSLOT
(
"__xor__"
,
nb_xor
,
slot_nb_xor
,
"^"
),
//
RBINSLOT
(
"__rxor__"
,
nb_xor
,
slot_nb_xor
,
"^"
),
//
BINSLOT
(
"__or__"
,
nb_or
,
slot_nb_or
,
"|"
),
//
RBINSLOT
(
"__ror__"
,
nb_or
,
slot_nb_or
,
"|"
),
//
UNSLOT
(
"__int__"
,
nb_int
,
slot_nb_int
,
wrap_unaryfunc
,
"int(x)"
),
//
UNSLOT
(
"__long__"
,
nb_long
,
slot_nb_long
,
wrap_unaryfunc
,
"long(x)"
),
//
UNSLOT
(
"__float__"
,
nb_float
,
slot_nb_float
,
wrap_unaryfunc
,
"float(x)"
),
//
UNSLOT
(
"__oct__"
,
nb_oct
,
slot_nb_oct
,
wrap_unaryfunc
,
"oct(x)"
),
//
UNSLOT
(
"__hex__"
,
nb_hex
,
slot_nb_hex
,
wrap_unaryfunc
,
"hex(x)"
),
//
MPSLOT
(
"__len__"
,
mp_length
,
slot_mp_length
,
wrap_lenfunc
,
"x.__len__() <==> len(x)"
),
MPSLOT
(
"__getitem__"
,
mp_subscript
,
slot_mp_subscript
,
wrap_binaryfunc
,
"x.__getitem__(y) <==> x[y]"
),
MPSLOT
(
"__setitem__"
,
mp_ass_subscript
,
slot_mp_ass_subscript
,
wrap_objobjargproc
,
...
...
@@ -739,6 +1028,17 @@ static void init_slotdefs() {
for
(
int
i
=
0
;
i
<
sizeof
(
slotdefs
)
/
sizeof
(
slotdefs
[
0
]);
i
++
)
{
if
(
i
>
0
)
{
#ifndef NDEBUG
if
(
slotdefs
[
i
-
1
].
offset
>
slotdefs
[
i
].
offset
)
{
printf
(
"slotdef for %s in the wrong place
\n
"
,
slotdefs
[
i
-
1
].
name
);
for
(
int
j
=
i
;
j
<
sizeof
(
slotdefs
)
/
sizeof
(
slotdefs
[
0
]);
j
++
)
{
if
(
slotdefs
[
i
-
1
].
offset
<=
slotdefs
[
j
].
offset
)
{
printf
(
"Should go before %s
\n
"
,
slotdefs
[
j
].
name
);
break
;
}
}
}
#endif
ASSERT
(
slotdefs
[
i
].
offset
>=
slotdefs
[
i
-
1
].
offset
,
"%d %s"
,
i
,
slotdefs
[
i
-
1
].
name
);
// CPython interns the name here
}
...
...
@@ -839,14 +1139,38 @@ extern "C" int PyType_Ready(PyTypeObject* cls) {
RELEASE_ASSERT
(
cls
->
tp_getattr
==
NULL
,
""
);
RELEASE_ASSERT
(
cls
->
tp_setattr
==
NULL
,
""
);
RELEASE_ASSERT
(
cls
->
tp_compare
==
NULL
,
""
);
RELEASE_ASSERT
(
cls
->
tp_as_number
==
NULL
,
""
);
RELEASE_ASSERT
(
cls
->
tp_str
==
NULL
,
""
);
if
(
cls
->
tp_as_number
)
{
auto
num
=
cls
->
tp_as_number
;
// Members not added yet:
assert
(
num
->
nb_coerce
==
NULL
);
assert
(
num
->
nb_inplace_add
==
NULL
);
assert
(
num
->
nb_inplace_subtract
==
NULL
);
assert
(
num
->
nb_inplace_multiply
==
NULL
);
assert
(
num
->
nb_inplace_divide
==
NULL
);
assert
(
num
->
nb_inplace_remainder
==
NULL
);
assert
(
num
->
nb_inplace_power
==
NULL
);
assert
(
num
->
nb_inplace_lshift
==
NULL
);
assert
(
num
->
nb_inplace_rshift
==
NULL
);
assert
(
num
->
nb_inplace_and
==
NULL
);
assert
(
num
->
nb_inplace_xor
==
NULL
);
assert
(
num
->
nb_inplace_or
==
NULL
);
assert
(
num
->
nb_floor_divide
==
NULL
);
assert
(
num
->
nb_true_divide
==
NULL
);
assert
(
num
->
nb_inplace_floor_divide
==
NULL
);
assert
(
num
->
nb_inplace_true_divide
==
NULL
);
assert
(
num
->
nb_index
==
NULL
);
}
RELEASE_ASSERT
(
cls
->
tp_getattro
==
NULL
||
cls
->
tp_getattro
==
PyObject_GenericGetAttr
,
""
);
RELEASE_ASSERT
(
cls
->
tp_setattro
==
NULL
||
cls
->
tp_setattro
==
PyObject_GenericSetAttr
,
""
);
RELEASE_ASSERT
(
cls
->
tp_as_buffer
==
NULL
,
""
);
int
ALLOWABLE_FLAGS
=
Py_TPFLAGS_DEFAULT
|
Py_TPFLAGS_BASETYPE
|
Py_TPFLAGS_HAVE_GC
;
int
ALLOWABLE_FLAGS
=
Py_TPFLAGS_DEFAULT
|
Py_TPFLAGS_BASETYPE
|
Py_TPFLAGS_HAVE_GC
|
Py_TPFLAGS_CHECKTYPES
;
RELEASE_ASSERT
((
cls
->
tp_flags
&
~
ALLOWABLE_FLAGS
)
==
0
,
""
);
if
(
cls
->
tp_as_number
)
{
RELEASE_ASSERT
(
cls
->
tp_flags
&
Py_TPFLAGS_CHECKTYPES
,
"Pyston doesn't yet support non-checktypes behavior"
);
}
RELEASE_ASSERT
(
cls
->
tp_iter
==
NULL
,
""
);
RELEASE_ASSERT
(
cls
->
tp_iternext
==
NULL
,
""
);
...
...
src/runtime/objmodel.cpp
View file @
49ee07fa
...
...
@@ -353,6 +353,7 @@ BoxedClass::BoxedClass(BoxedClass* metaclass, BoxedClass* base, gcvisit_func gc_
tp_basicsize
=
instance_size
;
tp_flags
|=
Py_TPFLAGS_HEAPTYPE
;
tp_flags
|=
Py_TPFLAGS_CHECKTYPES
;
if
(
metaclass
==
NULL
)
{
assert
(
type_cls
==
NULL
);
...
...
@@ -1456,26 +1457,6 @@ void setattrInternal(Box* obj, const std::string& attr, Box* val, SetattrRewrite
descr
=
typeLookup
(
obj
->
cls
,
attr
,
NULL
);
}
if
(
isSubclass
(
obj
->
cls
,
type_cls
))
{
BoxedClass
*
self
=
static_cast
<
BoxedClass
*>
(
obj
);
if
(
attr
==
_getattr_str
||
attr
==
_getattribute_str
)
{
// Will have to embed the clear in the IC, so just disable the patching for now:
rewrite_args
=
NULL
;
// TODO should put this clearing behavior somewhere else, since there are probably more
// cases in which we want to do it.
self
->
dependent_icgetattrs
.
invalidateAll
();
}
if
(
attr
==
"__base__"
&&
self
->
getattr
(
"__base__"
))
raiseExcHelper
(
TypeError
,
"readonly attribute"
);
bool
touched_slot
=
update_slot
(
self
,
attr
);
if
(
touched_slot
)
rewrite_args
=
NULL
;
}
Box
*
_set_
=
NULL
;
RewriterVar
*
r_set
=
NULL
;
if
(
descr
)
{
...
...
@@ -1511,6 +1492,26 @@ void setattrInternal(Box* obj, const std::string& attr, Box* val, SetattrRewrite
}
else
{
obj
->
setattr
(
attr
,
val
,
rewrite_args
);
}
if
(
isSubclass
(
obj
->
cls
,
type_cls
))
{
BoxedClass
*
self
=
static_cast
<
BoxedClass
*>
(
obj
);
if
(
attr
==
_getattr_str
||
attr
==
_getattribute_str
)
{
// Will have to embed the clear in the IC, so just disable the patching for now:
rewrite_args
=
NULL
;
// TODO should put this clearing behavior somewhere else, since there are probably more
// cases in which we want to do it.
self
->
dependent_icgetattrs
.
invalidateAll
();
}
if
(
attr
==
"__base__"
&&
self
->
getattr
(
"__base__"
))
raiseExcHelper
(
TypeError
,
"readonly attribute"
);
bool
touched_slot
=
update_slot
(
self
,
attr
);
if
(
touched_slot
)
rewrite_args
=
NULL
;
}
}
extern
"C"
void
setattr
(
Box
*
obj
,
const
char
*
attr
,
Box
*
attr_val
)
{
...
...
test/test_extension/slots_test.c
View file @
49ee07fa
...
...
@@ -61,6 +61,14 @@ slots_tester_seq_repr(slots_tester_object *obj)
return
PyString_FromString
(
buf
);
}
static
PyObject
*
slots_tester_seq_str
(
slots_tester_object
*
obj
)
{
char
buf
[
80
];
snprintf
(
buf
,
sizeof
(
buf
),
"<my custom str: %d>"
,
obj
->
n
);
return
PyString_FromString
(
buf
);
}
static
PyObject
*
slots_tester_seq_call
(
slots_tester_object
*
obj
,
PyObject
*
args
,
PyObject
*
kw
)
{
...
...
@@ -111,7 +119,7 @@ static PyTypeObject slots_tester_seq = {
0
,
/* tp_as_mapping */
(
hashfunc
)
slots_tester_seq_hash
,
/* tp_hash */
(
ternaryfunc
)
slots_tester_seq_call
,
/* tp_call */
0
,
/* tp_str */
(
reprfunc
)
slots_tester_seq_str
,
/* tp_str */
0
,
/* tp_getattro */
0
,
/* tp_setattro */
0
,
/* tp_as_buffer */
...
...
@@ -170,7 +178,7 @@ static PyTypeObject slots_tester_map= {
0
,
/* tp_getattr */
0
,
/* tp_setattr */
0
,
/* tp_compare */
0
,
/* tp_repr */
(
reprfunc
)
slots_tester_seq_repr
,
/* tp_repr */
0
,
/* tp_as_number */
0
,
/* tp_as_sequence */
&
slots_tester_map_asmapping
,
/* tp_as_mapping */
...
...
@@ -202,6 +210,143 @@ static PyTypeObject slots_tester_map= {
0
,
/* tp_free */
};
#define _PYSTON_STRINGIFY(N) #N
#define PYSTON_STRINGIFY(N) _PYSTON_STRINGIFY(N)
#define CREATE_UN(N, R) \
static PyObject* N(slots_tester_object* lhs) { \
printf(PYSTON_STRINGIFY(N) ", %d\n", lhs->n); \
Py_INCREF(R); \
return (PyObject*)R; \
}
#define CREATE_BIN(N) \
static PyObject* N(slots_tester_object* lhs, PyObject* rhs) { \
printf(PYSTON_STRINGIFY(N) ", %d %s\n", lhs->n, Py_TYPE(rhs)->tp_name); \
Py_INCREF(lhs); \
return (PyObject*)lhs; \
}
CREATE_BIN
(
s_add
);
CREATE_BIN
(
s_subtract
);
CREATE_BIN
(
s_multiply
);
CREATE_BIN
(
s_divide
);
CREATE_BIN
(
s_remainder
);
CREATE_BIN
(
s_divmod
);
CREATE_UN
(
s_negative
,
lhs
);
CREATE_UN
(
s_positive
,
lhs
);
CREATE_UN
(
s_absolute
,
lhs
);
static
int
s_nonzero
(
slots_tester_object
*
self
)
{
printf
(
"s_nonzero, %d
\n
"
,
self
->
n
);
return
self
->
n
!=
0
;
}
CREATE_UN
(
s_invert
,
lhs
);
static
PyObject
*
s_power
(
slots_tester_object
*
lhs
,
PyObject
*
rhs
,
PyObject
*
mod
)
{
printf
(
"s_power, %d %s %s
\n
"
,
lhs
->
n
,
Py_TYPE
(
rhs
)
->
tp_name
,
Py_TYPE
(
mod
)
->
tp_name
);
Py_INCREF
(
lhs
);
return
(
PyObject
*
)
lhs
;
}
CREATE_BIN
(
s_lshift
);
CREATE_BIN
(
s_rshift
);
CREATE_BIN
(
s_and
);
CREATE_BIN
(
s_xor
);
CREATE_BIN
(
s_or
);
CREATE_UN
(
s_int
,
Py_True
);
CREATE_UN
(
s_long
,
Py_True
);
CREATE_UN
(
s_float
,
PyFloat_FromDouble
(
1
.
0
));
CREATE_UN
(
s_oct
,
PyString_FromString
(
"oct"
));
CREATE_UN
(
s_hex
,
PyString_FromString
(
"hex"
));
#undef CREATE_BIN
static
PyNumberMethods
slots_tester_as_number
=
{
(
binaryfunc
)
s_add
,
/* nb_add */
(
binaryfunc
)
s_subtract
,
/* nb_subtract */
(
binaryfunc
)
s_multiply
,
/* nb_multiply */
(
binaryfunc
)
s_divide
,
/* nb_divide */
(
binaryfunc
)
s_remainder
,
/* nb_remainder */
(
binaryfunc
)
s_divmod
,
/* nb_divmod */
(
ternaryfunc
)
s_power
,
/* nb_power */
(
unaryfunc
)
s_negative
,
/* nb_negative */
(
unaryfunc
)
s_positive
,
/* nb_positive */
(
unaryfunc
)
s_absolute
,
/* nb_absolute */
(
inquiry
)
s_nonzero
,
/* nb_nonzero */
(
unaryfunc
)
s_invert
,
/*nb_invert*/
(
binaryfunc
)
s_lshift
,
/*nb_lshift*/
(
binaryfunc
)
s_rshift
,
/*nb_rshift*/
(
binaryfunc
)
s_and
,
/*nb_and*/
(
binaryfunc
)
s_xor
,
/*nb_xor*/
(
binaryfunc
)
s_or
,
/*nb_or*/
0
,
/*nb_coerce*/
(
unaryfunc
)
s_int
,
/*nb_int*/
(
unaryfunc
)
s_long
,
/*nb_long*/
(
unaryfunc
)
s_float
,
/*nb_float*/
(
unaryfunc
)
s_oct
,
/*nb_oct*/
(
unaryfunc
)
s_hex
,
/*nb_hex*/
0
,
/*nb_inplace_add*/
0
,
/*nb_inplace_subtract*/
0
,
/*nb_inplace_multiply*/
0
,
/*nb_inplace_divide*/
0
,
/*nb_inplace_remainder*/
0
,
/*nb_inplace_power*/
0
,
/*nb_inplace_lshift*/
0
,
/*nb_inplace_rshift*/
0
,
/*nb_inplace_and*/
0
,
/*nb_inplace_xor*/
0
,
/*nb_inplace_or*/
0
,
/* nb_floor_divide */
0
,
/* nb_true_divide */
0
,
/* nb_inplace_floor_divide */
0
,
/* nb_inplace_true_divide */
};
static
PyTypeObject
slots_tester_num
=
{
PyVarObject_HEAD_INIT
(
NULL
,
0
)
"slots_test.slots_tester_num"
,
/* tp_name */
sizeof
(
slots_tester_object
),
/* tp_basicsize */
0
,
/* tp_itemsize */
/* methods */
0
,
/* tp_dealloc */
0
,
/* tp_print */
0
,
/* tp_getattr */
0
,
/* tp_setattr */
0
,
/* tp_compare */
0
,
/* tp_repr */
&
slots_tester_as_number
,
/* tp_as_number */
0
,
/* tp_as_sequence */
0
,
/* tp_as_mapping */
0
,
/* tp_hash */
0
,
/* tp_call */
(
reprfunc
)
slots_tester_seq_str
,
/* tp_str */
0
,
/* tp_getattro */
0
,
/* tp_setattro */
0
,
/* tp_as_buffer */
Py_TPFLAGS_DEFAULT
|
Py_TPFLAGS_CHECKTYPES
,
/* tp_flags */
0
,
/* tp_doc */
0
,
/* tp_traverse */
0
,
/* tp_clear */
0
,
/* tp_richcompare */
0
,
/* tp_weaklistoffset */
0
,
/* tp_iter */
0
,
/* tp_iternext */
0
,
/* tp_methods */
0
,
/* tp_members */
0
,
/* tp_getset */
0
,
/* tp_base */
0
,
/* tp_dict */
0
,
/* tp_descr_get */
0
,
/* tp_descr_set */
0
,
/* tp_dictoffset */
0
,
/* tp_init */
0
,
/* tp_alloc */
slots_tester_new
,
/* tp_new */
0
,
/* tp_free */
};
// Tests the correctness of the CAPI slots when the attributes get set in Python code:
static
PyObject
*
call_funcs
(
PyObject
*
_module
,
PyObject
*
args
)
{
...
...
@@ -282,6 +427,69 @@ call_funcs(PyObject* _module, PyObject* args) {
printf
(
"tp_as_sequence doesnt exist
\n
"
);
}
if
(
cls
->
tp_as_number
)
{
printf
(
"tp_as_number exists
\n
"
);
PyNumberMethods
*
num
=
cls
->
tp_as_number
;
if
(
!
(
cls
->
tp_flags
&
Py_TPFLAGS_CHECKTYPES
))
{
printf
(
"CHECKTYPES is not set!
\n
"
);
}
#define CHECK_UN(N) \
if (num->N) { \
PyObject* res = num->N(obj); \
printf(PYSTON_STRINGIFY(N) " exists and returned a %s\n", Py_TYPE(res)->tp_name); \
Py_DECREF(res); \
}
#define CHECK_BIN(N) \
if (num->N) { \
PyObject* res = num->N(obj, obj); \
printf(PYSTON_STRINGIFY(N) " exists and returned a %s\n", Py_TYPE(res)->tp_name); \
Py_DECREF(res); \
}
CHECK_BIN
(
nb_add
);
CHECK_BIN
(
nb_subtract
);
CHECK_BIN
(
nb_multiply
);
CHECK_BIN
(
nb_divide
);
CHECK_BIN
(
nb_remainder
);
CHECK_BIN
(
nb_divmod
);
CHECK_UN
(
nb_negative
);
CHECK_UN
(
nb_positive
);
CHECK_UN
(
nb_absolute
);
if
(
num
->
nb_nonzero
)
{
int
n
=
num
->
nb_nonzero
(
obj
);
printf
(
"nb_nonzero exists and returned %d
\n
"
,
n
);
}
CHECK_UN
(
nb_invert
);
if
(
num
->
nb_power
)
{
PyObject
*
res
=
num
->
nb_power
(
obj
,
obj
,
Py_None
);
printf
(
"nb_power exists and returned a %s
\n
"
,
Py_TYPE
(
res
)
->
tp_name
);
Py_DECREF
(
res
);
}
CHECK_BIN
(
nb_lshift
);
CHECK_BIN
(
nb_rshift
);
CHECK_BIN
(
nb_and
);
CHECK_BIN
(
nb_xor
);
CHECK_BIN
(
nb_or
);
CHECK_UN
(
nb_int
);
CHECK_UN
(
nb_long
);
CHECK_UN
(
nb_float
);
CHECK_UN
(
nb_oct
);
CHECK_UN
(
nb_hex
);
#undef CHECK_BIN
}
else
{
printf
(
"tp_as_number doesnt exist
\n
"
);
}
Py_RETURN_NONE
;
}
...
...
@@ -307,9 +515,14 @@ initslots_test(void)
if
(
res
<
0
)
return
;
res
=
PyType_Ready
(
&
slots_tester_num
);
if
(
res
<
0
)
return
;
// Not sure if the result of PyInt_FromLong needs to be decref'd
PyDict_SetItemString
(
slots_tester_seq
.
tp_dict
,
"set_through_tpdict"
,
PyInt_FromLong
(
123
));
PyModule_AddObject
(
m
,
"SlotsTesterSeq"
,
(
PyObject
*
)
&
slots_tester_seq
);
PyModule_AddObject
(
m
,
"SlotsTesterMap"
,
(
PyObject
*
)
&
slots_tester_map
);
PyModule_AddObject
(
m
,
"SlotsTesterNum"
,
(
PyObject
*
)
&
slots_tester_num
);
}
test/tests/capi_slots.py
View file @
49ee07fa
...
...
@@ -2,18 +2,43 @@ import slots_test
for
i
in
xrange
(
3
):
t
=
slots_test
.
SlotsTesterSeq
(
i
+
5
)
print
t
,
repr
(
t
),
t
(),
t
[
2
]
print
hash
(
t
),
t
<
1
,
t
>
2
,
t
!=
3
print
t
,
repr
(
t
),
str
(
t
),
t
(),
t
[
2
]
print
hash
(
t
),
t
<
1
,
t
>
2
,
t
!=
3
,
bool
(
t
)
# print slots_test.SlotsTesterSeq.__doc__
print
slots_test
.
SlotsTesterSeq
.
set_through_tpdict
,
slots_test
.
SlotsTesterSeq
(
5
).
set_through_tpdict
for
i
in
xrange
(
3
):
t
=
slots_test
.
SlotsTesterMap
(
i
+
5
)
print
len
(
t
),
t
[
2
]
print
len
(
t
),
t
[
2
]
,
repr
(
t
),
str
(
t
)
t
[
1
]
=
5
del
t
[
2
]
for
i
in
xrange
(
3
):
t
=
slots_test
.
SlotsTesterNum
(
i
)
print
bool
(
t
)
print
t
+
5
print
t
-
5
print
t
*
5
print
t
/
5
print
t
%
5
print
divmod
(
t
,
5
)
print
t
**
5
print
t
<<
5
print
t
>>
5
print
t
&
5
print
t
^
5
print
t
|
5
print
+
t
print
-
t
print
abs
(
t
)
print
~
t
print
int
(
t
)
print
long
(
t
)
print
float
(
t
)
print
hex
(
t
)
print
oct
(
t
)
class
C
(
object
):
def
__repr__
(
self
):
print
"__repr__()"
...
...
@@ -33,4 +58,14 @@ slots_test.call_funcs(C())
def
repr2
(
self
):
return
"repr2()"
C
.
__repr__
=
repr2
def
nonzero
(
self
):
print
"nonzero"
return
True
C
.
__nonzero__
=
nonzero
def
add
(
self
,
rhs
):
print
"add"
,
self
,
rhs
C
.
__add__
=
add
slots_test
.
call_funcs
(
C
())
tools/tester.py
View file @
49ee07fa
...
...
@@ -350,7 +350,7 @@ if __name__ == "__main__":
run_memcheck = False
start = 1
opts, patterns = getopt.gnu_getopt(sys.argv[1:], "j:a:t:mR:k")
opts, patterns = getopt.gnu_getopt(sys.argv[1:], "j:a:t:mR:k
K
")
for (t, v) in opts:
if t == '-m':
run_memcheck = True
...
...
@@ -361,6 +361,8 @@ if __name__ == "__main__":
IMAGE = v
elif t == '-k':
KEEP_GOING = True
elif t == '-K':
KEEP_GOING = False
elif t == '-a':
EXTRA_JIT_ARGS.append(v)
elif t == '-t':
...
...
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