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
4e5e1dba
Commit
4e5e1dba
authored
Dec 13, 2014
by
Kevin Modzelewski
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Import more code from CPython, and add the slotdef for mp_subscript
parent
198d0f6b
Changes
5
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
247 additions
and
10 deletions
+247
-10
src/capi/modsupport.cpp
src/capi/modsupport.cpp
+145
-9
src/capi/typeobject.cpp
src/capi/typeobject.cpp
+70
-0
src/runtime/capi.cpp
src/runtime/capi.cpp
+4
-1
test/test_extension/slots_test.c
test/test_extension/slots_test.c
+24
-0
test/tests/capi_slots.py
test/tests/capi_slots.py
+4
-0
No files found.
src/capi/modsupport.cpp
View file @
4e5e1dba
...
...
@@ -32,24 +32,160 @@ namespace pyston {
#define FLAG_SIZE_T 1
static
PyObject
*
va_build_value
(
const
char
*
fmt
,
va_list
va
,
int
flags
)
{
int
len
=
strlen
(
fmt
);
if
(
len
==
0
)
return
None
;
static
int
countformat
(
const
char
*
format
,
int
endchar
)
{
int
count
=
0
;
int
level
=
0
;
while
(
level
>
0
||
*
format
!=
endchar
)
{
switch
(
*
format
)
{
case
'\0'
:
/* Premature end */
PyErr_SetString
(
PyExc_SystemError
,
"unmatched paren in format"
);
return
-
1
;
case
'('
:
case
'['
:
case
'{'
:
if
(
level
==
0
)
count
++
;
level
++
;
break
;
case
')'
:
case
']'
:
case
'}'
:
level
--
;
break
;
case
'#'
:
case
'&'
:
case
','
:
case
':'
:
case
' '
:
case
'\t'
:
break
;
default:
if
(
level
==
0
)
count
++
;
}
format
++
;
}
return
count
;
}
static
PyObject
*
do_mktuple
(
const
char
**
,
va_list
*
,
int
,
int
,
int
)
noexcept
;
// static PyObject *do_mklist(const char**, va_list *, int, int, int) noexcept;
// static PyObject *do_mkdict(const char**, va_list *, int, int, int) noexcept;
static
PyObject
*
do_mkvalue
(
const
char
**
,
va_list
*
,
int
)
noexcept
;
static
PyObject
*
do_mkvalue
(
const
char
**
p_format
,
va_list
*
p_va
,
int
flags
)
noexcept
{
for
(;;)
{
switch
(
*
(
*
p_format
)
++
)
{
case
'('
:
return
do_mktuple
(
p_format
,
p_va
,
')'
,
countformat
(
*
p_format
,
')'
),
flags
);
#if 0
case '[':
return do_mklist(p_format, p_va, ']', countformat(*p_format, ']'), flags);
case '{':
return do_mkdict(p_format, p_va, '}', countformat(*p_format, '}'), flags);
#endif
if
(
len
==
1
)
{
switch
(
*
fmt
)
{
case
'b'
:
case
'B'
:
case
'h'
:
case
'i'
:
return
PyInt_FromLong
((
long
)
va_arg
(
va
,
int
));
return
PyInt_FromLong
((
long
)
va_arg
(
*
p_va
,
int
));
case
'H'
:
return
PyInt_FromLong
((
long
)
va_arg
(
*
p_va
,
unsigned
int
));
case
'N'
:
case
'S'
:
case
'O'
:
if
(
**
p_format
==
'&'
)
{
typedef
PyObject
*
(
*
converter
)(
void
*
);
converter
func
=
va_arg
(
*
p_va
,
converter
);
void
*
arg
=
va_arg
(
*
p_va
,
void
*
);
++*
p_format
;
return
(
*
func
)(
arg
);
}
else
{
PyObject
*
v
;
v
=
va_arg
(
*
p_va
,
PyObject
*
);
if
(
v
!=
NULL
)
{
if
(
*
(
*
p_format
-
1
)
!=
'N'
)
Py_INCREF
(
v
);
}
else
if
(
!
PyErr_Occurred
())
/* If a NULL was passed
* because a call that should
* have constructed a value
* failed, that's OK, and we
* pass the error on; but if
* no error occurred it's not
* clear that the caller knew
* what she was doing. */
PyErr_SetString
(
PyExc_SystemError
,
"NULL object passed to Py_BuildValue"
);
return
v
;
}
default:
RELEASE_ASSERT
(
0
,
"%c"
,
*
fmt
);
RELEASE_ASSERT
(
0
,
"%c"
,
*
((
*
p_format
)
-
1
)
);
}
}
abort
();
}
static
PyObject
*
do_mktuple
(
const
char
**
p_format
,
va_list
*
p_va
,
int
endchar
,
int
n
,
int
flags
)
noexcept
{
PyObject
*
v
;
int
i
;
int
itemfailed
=
0
;
if
(
n
<
0
)
return
NULL
;
if
((
v
=
PyTuple_New
(
n
))
==
NULL
)
return
NULL
;
/* Note that we can't bail immediately on error as this will leak
refcounts on any 'N' arguments. */
for
(
i
=
0
;
i
<
n
;
i
++
)
{
PyObject
*
w
=
do_mkvalue
(
p_format
,
p_va
,
flags
);
if
(
w
==
NULL
)
{
itemfailed
=
1
;
Py_INCREF
(
Py_None
);
w
=
Py_None
;
}
PyTuple_SET_ITEM
(
v
,
i
,
w
);
}
if
(
itemfailed
)
{
/* do_mkvalue() should have already set an error */
Py_DECREF
(
v
);
return
NULL
;
}
if
(
**
p_format
!=
endchar
)
{
Py_DECREF
(
v
);
PyErr_SetString
(
PyExc_SystemError
,
"Unmatched paren in format"
);
return
NULL
;
}
if
(
endchar
)
++*
p_format
;
return
v
;
}
static
PyObject
*
va_build_value
(
const
char
*
fmt
,
va_list
va
,
int
flags
)
{
int
n
=
countformat
(
fmt
,
'\0'
);
if
(
n
<
0
)
return
NULL
;
if
(
n
==
0
)
return
None
;
va_list
lva
;
__va_copy
(
lva
,
va
);
if
(
n
==
1
)
return
do_mkvalue
(
&
fmt
,
&
lva
,
flags
);
return
do_mktuple
(
&
fmt
,
&
lva
,
'\0'
,
n
,
flags
);
}
RELEASE_ASSERT
(
0
,
""
);
extern
"C"
PyObject
*
Py_VaBuildValue
(
const
char
*
format
,
va_list
va
)
{
return
va_build_value
(
format
,
va
,
0
);
}
extern
"C"
PyObject
*
_Py_BuildValue_SizeT
(
const
char
*
fmt
,
...)
{
...
...
src/capi/typeobject.cpp
View file @
4e5e1dba
...
...
@@ -52,6 +52,16 @@ static PyObject* wrap_unaryfunc(PyObject* self, PyObject* args, void* wrapped) {
return
(
*
func
)(
self
);
}
static
PyObject
*
wrap_binaryfunc
(
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
);
return
(
*
func
)(
self
,
other
);
}
static
Py_ssize_t
getindex
(
PyObject
*
self
,
PyObject
*
arg
)
noexcept
{
Py_ssize_t
i
;
...
...
@@ -127,6 +137,64 @@ PyObject* slot_sq_item(PyObject* self, Py_ssize_t i) noexcept {
}
}
static
PyObject
*
lookup_maybe
(
PyObject
*
self
,
const
char
*
attrstr
,
PyObject
**
attrobj
)
{
PyObject
*
res
;
// TODO: CPython uses the attrobj as a cache
Box
*
obj
=
typeLookup
(
self
->
cls
,
attrstr
,
NULL
);
if
(
obj
)
return
processDescriptor
(
obj
,
self
,
self
->
cls
);
return
obj
;
}
// Copied from CPython:
static
PyObject
*
call_method
(
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
())
PyErr_SetObject
(
PyExc_AttributeError
,
*
nameobj
);
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
;
}
// Copied from CPython:
#define SLOT0(FUNCNAME, OPSTR) \
static PyObject* FUNCNAME(PyObject* self) noexcept { \
static PyObject* cache_str; \
return call_method(self, OPSTR, &cache_str, "()"); \
}
#define SLOT1(FUNCNAME, OPSTR, ARG1TYPE, ARGCODES) \
static PyObject* FUNCNAME(PyObject* self, ARG1TYPE arg1) noexcept { \
static PyObject* cache_str; \
return call_method(self, OPSTR, &cache_str, "(" ARGCODES ")", arg1); \
}
SLOT1
(
slot_mp_subscript
,
"__getitem__"
,
PyObject
*
,
"O"
)
typedef
wrapper_def
slotdef
;
static
void
**
slotptr
(
BoxedClass
*
type
,
int
offset
)
{
...
...
@@ -198,6 +266,8 @@ static slotdef slotdefs[] = {
PyWrapperFlag_KEYWORDS
),
TPSLOT
(
"__new__"
,
tp_new
,
slot_tp_new
,
NULL
,
""
),
MPSLOT
(
"__getitem__"
,
mp_subscript
,
slot_mp_subscript
,
wrap_binaryfunc
,
"x.__getitem__(y) <==> x[y]"
),
// SQSLOT("__len__", sq_length, slot_sq_length, wrap_lenfunc, "x.__len__() <==> len(x)"),
/* Heap types defining __add__/__mul__ have sq_concat/sq_repeat == NULL.
The logic in abstract.c always falls back to nb_add/nb_multiply in
...
...
src/runtime/capi.cpp
View file @
4e5e1dba
...
...
@@ -322,7 +322,10 @@ extern "C" int PyObject_Not(PyObject* o) {
extern
"C"
PyObject
*
PyObject_Call
(
PyObject
*
callable_object
,
PyObject
*
args
,
PyObject
*
kw
)
{
try
{
return
runtimeCall
(
callable_object
,
ArgPassSpec
(
0
,
0
,
true
,
true
),
args
,
kw
,
NULL
,
NULL
,
NULL
);
if
(
kw
)
return
runtimeCall
(
callable_object
,
ArgPassSpec
(
0
,
0
,
true
,
true
),
args
,
kw
,
NULL
,
NULL
,
NULL
);
else
return
runtimeCall
(
callable_object
,
ArgPassSpec
(
0
,
0
,
true
,
false
),
args
,
NULL
,
NULL
,
NULL
,
NULL
);
}
catch
(
Box
*
b
)
{
Py_FatalError
(
"unimplemented"
);
}
...
...
test/test_extension/slots_test.c
View file @
4e5e1dba
...
...
@@ -142,6 +142,30 @@ call_funcs(PyObject* _module, PyObject* args) {
printf
(
"tp_call doesnt exist
\n
"
);
}
if
(
cls
->
tp_as_mapping
)
{
printf
(
"tp_as_mapping exists
\n
"
);
if
(
cls
->
tp_as_mapping
->
mp_subscript
)
{
PyObject
*
rtn
=
cls
->
tp_as_mapping
->
mp_subscript
(
obj
,
PyInt_FromLong
(
1
));
printf
(
"mp_subscript exists and returned
\n
"
);
Py_DECREF
(
rtn
);
}
else
{
printf
(
"mp_subscript does not exist
\n
"
);
}
}
else
{
printf
(
"tp_as_mapping doesnt exist
\n
"
);
}
if
(
cls
->
tp_as_sequence
)
{
printf
(
"tp_as_sequence exists
\n
"
);
if
(
cls
->
tp_as_sequence
->
sq_item
)
{
PyObject
*
rtn
=
cls
->
tp_as_sequence
->
sq_item
(
obj
,
1
);
printf
(
"sq_item exists and returned
\n
"
);
Py_DECREF
(
rtn
);
}
}
else
{
printf
(
"tp_as_sequence doesnt exist
\n
"
);
}
Py_DECREF
(
obj
);
Py_RETURN_NONE
;
...
...
test/tests/capi_slots.py
View file @
4e5e1dba
...
...
@@ -14,6 +14,10 @@ class C(object):
print
"__repr__()"
return
"<C object>"
def
__getitem__
(
self
,
idx
):
print
"__getitem__"
,
idx
return
idx
-
5
slots_test
.
call_funcs
(
C
())
# Test to make sure that updating an existing class also updates the tp_* slots:
...
...
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