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
a9813b80
Commit
a9813b80
authored
Jun 26, 2015
by
Kevin Modzelewski
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #648 from kmod/perf6
reduce api conversions
parents
79505a1a
76c861ad
Changes
18
Hide whitespace changes
Inline
Side-by-side
Showing
18 changed files
with
262 additions
and
139 deletions
+262
-139
microbenchmarks/itertools_chain_bench.py
microbenchmarks/itertools_chain_bench.py
+13
-0
microbenchmarks/loop.py
microbenchmarks/loop.py
+5
-0
microbenchmarks/unicode_ctor_bench.py
microbenchmarks/unicode_ctor_bench.py
+6
-0
src/asm_writing/rewriter.cpp
src/asm_writing/rewriter.cpp
+4
-1
src/capi/typeobject.cpp
src/capi/typeobject.cpp
+2
-2
src/capi/typeobject.h
src/capi/typeobject.h
+2
-0
src/capi/types.h
src/capi/types.h
+3
-54
src/core/types.h
src/core/types.h
+0
-1
src/runtime/builtin_modules/builtins.cpp
src/runtime/builtin_modules/builtins.cpp
+1
-1
src/runtime/capi.cpp
src/runtime/capi.cpp
+95
-37
src/runtime/descr.cpp
src/runtime/descr.cpp
+3
-0
src/runtime/ics.h
src/runtime/ics.h
+1
-1
src/runtime/iterators.cpp
src/runtime/iterators.cpp
+6
-17
src/runtime/iterobject.cpp
src/runtime/iterobject.cpp
+7
-13
src/runtime/list.cpp
src/runtime/list.cpp
+1
-1
src/runtime/objmodel.cpp
src/runtime/objmodel.cpp
+17
-5
src/runtime/stacktrace.cpp
src/runtime/stacktrace.cpp
+4
-0
src/runtime/types.cpp
src/runtime/types.cpp
+92
-6
No files found.
microbenchmarks/itertools_chain_bench.py
0 → 100644
View file @
a9813b80
# simple benchmark to test iteration over extension objects
import
itertools
def
f
(
c
):
for
i
in
c
:
pass
l
=
[]
for
i
in
xrange
(
100
):
l
.
append
(
itertools
.
chain
(
*
[
range
(
500
)
for
j
in
xrange
(
500
)]))
c
=
itertools
.
chain
(
*
l
)
f
(
c
)
microbenchmarks/loop.py
0 → 100644
View file @
a9813b80
def
f
(
n
):
for
i
in
xrange
(
n
):
pass
f
(
100000000
)
microbenchmarks/unicode_ctor_bench.py
0 → 100644
View file @
a9813b80
def
f
():
u
=
u"a"
*
100
c
=
unicode
for
i
in
xrange
(
2000000
):
c
(
u
)
f
()
src/asm_writing/rewriter.cpp
View file @
a9813b80
...
...
@@ -743,10 +743,13 @@ void Rewriter::_call(RewriterVar* result, bool has_side_effects, void* func_addr
if
(
has_side_effects
)
{
// We need some fixed amount of space at the beginning of the IC that we can use to invalidate
// it by writing a jmp.
//
FIXME
this check is conservative, since actually we just have to verify that the return
//
TODO
this check is conservative, since actually we just have to verify that the return
// address is at least IC_INVALDITION_HEADER_SIZE bytes past the beginning, but we're
// checking based on the beginning of the call. I think the load+call might actually
// always larger than the invalidation jmp.
while
(
assembler
->
bytesWritten
()
<
IC_INVALDITION_HEADER_SIZE
)
assembler
->
nop
();
assert
(
assembler
->
bytesWritten
()
>=
IC_INVALDITION_HEADER_SIZE
);
}
...
...
src/capi/typeobject.cpp
View file @
a9813b80
...
...
@@ -827,7 +827,7 @@ static PyObject* slot_tp_iter(PyObject* self) noexcept {
return
PySeqIter_New
(
self
);
}
static
PyObject
*
slot_tp_iternext
(
PyObject
*
self
)
noexcept
{
/* Pyston change: static */
PyObject
*
slot_tp_iternext
(
PyObject
*
self
)
noexcept
{
STAT_TIMER
(
t0
,
"us_timer_slot_tpiternext"
,
SLOT_AVOIDABILITY
(
self
));
static
PyObject
*
next_str
;
...
...
@@ -957,7 +957,7 @@ static PyObject* slot_tp_getattr_hook(PyObject* self, PyObject* name) noexcept {
return
res
;
}
static
PyObject
*
slot_tp_new
(
PyTypeObject
*
self
,
PyObject
*
args
,
PyObject
*
kwds
)
noexcept
{
/* Pyston change: static */
PyObject
*
slot_tp_new
(
PyTypeObject
*
self
,
PyObject
*
args
,
PyObject
*
kwds
)
noexcept
{
STAT_TIMER
(
t0
,
"us_timer_slot_tpnew"
,
SLOT_AVOIDABILITY
(
self
));
try
{
...
...
src/capi/typeobject.h
View file @
a9813b80
...
...
@@ -35,6 +35,8 @@ PyObject* mro_external(PyObject* self) noexcept;
int
type_set_bases
(
PyTypeObject
*
type
,
PyObject
*
value
,
void
*
context
)
noexcept
;
PyObject
*
slot_tp_richcompare
(
PyObject
*
self
,
PyObject
*
other
,
int
op
)
noexcept
;
PyObject
*
slot_tp_iternext
(
PyObject
*
self
)
noexcept
;
PyObject
*
slot_tp_new
(
PyTypeObject
*
self
,
PyObject
*
args
,
PyObject
*
kwds
)
noexcept
;
}
#endif
src/capi/types.h
View file @
a9813b80
...
...
@@ -42,57 +42,9 @@ public:
return
boxString
(
self
->
method_def
->
ml_name
);
}
static
Box
*
__call__
(
BoxedCApiFunction
*
self
,
BoxedTuple
*
varargs
,
BoxedDict
*
kwargs
)
{
STAT_TIMER
(
t0
,
"us_timer_boxedcapifunction__call__"
,
(
self
->
cls
->
is_user_defined
?
10
:
20
));
assert
(
self
->
cls
==
capifunc_cls
);
assert
(
varargs
->
cls
==
tuple_cls
);
assert
(
kwargs
->
cls
==
dict_cls
);
threading
::
GLPromoteRegion
_gil_lock
;
Box
*
rtn
;
int
flags
=
self
->
method_def
->
ml_flags
;
auto
func
=
self
->
method_def
->
ml_meth
;
if
(
flags
==
METH_VARARGS
)
{
assert
(
kwargs
->
d
.
size
()
==
0
);
rtn
=
(
Box
*
)
func
(
self
->
passthrough
,
varargs
);
}
else
if
(
flags
==
(
METH_VARARGS
|
METH_KEYWORDS
))
{
rtn
=
(
Box
*
)((
PyCFunctionWithKeywords
)
func
)(
self
->
passthrough
,
varargs
,
kwargs
);
}
else
if
(
flags
==
METH_NOARGS
)
{
assert
(
kwargs
->
d
.
size
()
==
0
);
assert
(
varargs
->
size
()
==
0
);
rtn
=
(
Box
*
)
func
(
self
->
passthrough
,
NULL
);
}
else
if
(
flags
==
METH_O
)
{
if
(
kwargs
->
d
.
size
()
!=
0
)
{
raiseExcHelper
(
TypeError
,
"%s() takes no keyword arguments"
,
self
->
method_def
->
ml_name
);
}
if
(
varargs
->
size
()
!=
1
)
{
raiseExcHelper
(
TypeError
,
"%s() takes exactly one argument (%d given)"
,
self
->
method_def
->
ml_name
,
varargs
->
size
());
}
rtn
=
(
Box
*
)
func
(
self
->
passthrough
,
varargs
->
elts
[
0
]);
}
else
if
(
flags
==
METH_OLDARGS
)
{
/* the really old style */
if
(
kwargs
==
NULL
||
PyDict_Size
(
kwargs
)
==
0
)
{
int
size
=
PyTuple_GET_SIZE
(
varargs
);
Box
*
arg
=
varargs
;
if
(
size
==
1
)
arg
=
PyTuple_GET_ITEM
(
varargs
,
0
);
else
if
(
size
==
0
)
arg
=
NULL
;
rtn
=
func
(
self
->
passthrough
,
arg
);
}
else
{
raiseExcHelper
(
TypeError
,
"%.200s() takes no keyword arguments"
,
self
->
method_def
->
ml_name
);
}
}
else
{
RELEASE_ASSERT
(
0
,
"0x%x"
,
flags
);
}
checkAndThrowCAPIException
();
assert
(
rtn
&&
"should have set + thrown an exception!"
);
return
rtn
;
}
static
Box
*
__call__
(
BoxedCApiFunction
*
self
,
BoxedTuple
*
varargs
,
BoxedDict
*
kwargs
);
static
Box
*
tppCall
(
Box
*
_self
,
CallRewriteArgs
*
rewrite_args
,
ArgPassSpec
argspec
,
Box
*
arg1
,
Box
*
arg2
,
Box
*
arg3
,
Box
**
args
,
const
std
::
vector
<
BoxedString
*>*
keyword_names
);
static
Box
*
getname
(
Box
*
b
,
void
*
)
{
RELEASE_ASSERT
(
b
->
cls
==
capifunc_cls
,
""
);
...
...
@@ -102,9 +54,6 @@ public:
return
None
;
}
static
Box
*
callInternal
(
BoxedFunctionBase
*
func
,
CallRewriteArgs
*
rewrite_args
,
ArgPassSpec
argspec
,
Box
*
arg1
,
Box
*
arg2
,
Box
*
arg3
,
Box
**
args
,
const
std
::
vector
<
BoxedString
*>*
keyword_names
);
static
void
gcHandler
(
GCVisitor
*
v
,
Box
*
_o
)
{
assert
(
_o
->
cls
==
capifunc_cls
);
BoxedCApiFunction
*
o
=
static_cast
<
BoxedCApiFunction
*>
(
_o
);
...
...
src/core/types.h
View file @
a9813b80
...
...
@@ -531,7 +531,6 @@ public:
BoxedString
*
reprICAsString
();
bool
nonzeroIC
();
Box
*
hasnextOrNullIC
();
Box
*
nextIC
();
friend
class
AttrWrapper
;
};
...
...
src/runtime/builtin_modules/builtins.cpp
View file @
a9813b80
...
...
@@ -248,7 +248,7 @@ Box* open(Box* arg1, Box* arg2, Box* arg3) {
extern
"C"
Box
*
chr
(
Box
*
arg
)
{
i64
n
=
PyInt_AsLong
(
arg
);
if
(
n
==
-
1
&&
PyErr_Occurred
())
raiseExcHelper
(
TypeError
,
"an integer is required"
);
throwCAPIException
(
);
if
(
n
<
0
||
n
>=
256
)
{
raiseExcHelper
(
ValueError
,
"chr() arg not in range(256)"
);
...
...
src/runtime/capi.cpp
View file @
a9813b80
...
...
@@ -633,25 +633,6 @@ extern "C" int PyObject_Print(PyObject* obj, FILE* fp, int flags) noexcept {
return
internal_print
(
obj
,
fp
,
flags
,
0
);
};
extern
"C"
PyObject
*
PyIter_Next
(
PyObject
*
iter
)
noexcept
{
try
{
Box
*
hasnext
=
iter
->
hasnextOrNullIC
();
if
(
hasnext
)
{
if
(
hasnext
->
nonzeroIC
())
return
iter
->
nextIC
();
else
return
NULL
;
}
else
{
return
iter
->
nextIC
();
}
}
catch
(
ExcInfo
e
)
{
if
(
e
.
matches
(
StopIteration
))
return
NULL
;
setCAPIException
(
e
);
}
return
NULL
;
}
extern
"C"
int
PyCallable_Check
(
PyObject
*
x
)
noexcept
{
if
(
x
==
NULL
)
return
0
;
...
...
@@ -1457,29 +1438,106 @@ extern "C" char* PyModule_GetFilename(PyObject* m) noexcept {
return
PyString_AsString
(
fileobj
);
}
Box
*
BoxedCApiFunction
::
callInternal
(
BoxedFunctionBase
*
func
,
CallRewriteArgs
*
rewrite_args
,
ArgPassSpec
argspec
,
Box
*
arg1
,
Box
*
arg2
,
Box
*
arg3
,
Box
**
args
,
const
std
::
vector
<
BoxedString
*>*
keyword_names
)
{
if
(
argspec
!=
ArgPassSpec
(
2
))
return
callFunc
(
func
,
rewrite_args
,
argspec
,
arg1
,
arg2
,
arg3
,
args
,
keyword_name
s
);
Box
*
BoxedCApiFunction
::
__call__
(
BoxedCApiFunction
*
self
,
BoxedTuple
*
varargs
,
BoxedDict
*
kwargs
)
{
STAT_TIMER
(
t0
,
"us_timer_boxedcapifunction__call__"
,
(
self
->
cls
->
is_user_defined
?
10
:
20
));
assert
(
self
->
cls
==
capifunc_cls
);
assert
(
varargs
->
cls
==
tuple_cls
);
assert
(
kwargs
->
cls
==
dict_cl
s
);
assert
(
arg1
->
cls
==
capifunc_cls
);
BoxedCApiFunction
*
capifunc
=
static_cast
<
BoxedCApiFunction
*>
(
arg1
);
if
(
capifunc
->
method_def
->
ml_flags
!=
METH_O
)
return
callFunc
(
func
,
rewrite_args
,
argspec
,
arg1
,
arg2
,
arg3
,
args
,
keyword_names
);
// Kind of silly to have asked callFunc to rearrange the arguments for us, just to pass things
// off to tppCall, but this case should be very uncommon (people explicitly asking for __call__)
return
BoxedCApiFunction
::
tppCall
(
self
,
NULL
,
ArgPassSpec
(
0
,
0
,
true
,
true
),
varargs
,
kwargs
,
NULL
,
NULL
,
NULL
);
}
Box
*
BoxedCApiFunction
::
tppCall
(
Box
*
_self
,
CallRewriteArgs
*
rewrite_args
,
ArgPassSpec
argspec
,
Box
*
arg1
,
Box
*
arg2
,
Box
*
arg3
,
Box
**
args
,
const
std
::
vector
<
BoxedString
*>*
keyword_names
)
{
STAT_TIMER
(
t0
,
"us_timer_boxedcapifunction__call__"
,
10
);
assert
(
_self
->
cls
==
capifunc_cls
);
BoxedCApiFunction
*
self
=
static_cast
<
BoxedCApiFunction
*>
(
_self
);
if
(
rewrite_args
)
{
rewrite_args
->
arg1
->
addGuard
((
intptr_t
)
arg1
);
RewriterVar
*
r_passthrough
=
rewrite_args
->
arg1
->
getAttr
(
offsetof
(
BoxedCApiFunction
,
passthrough
));
rewrite_args
->
out_rtn
=
rewrite_args
->
rewriter
->
call
(
true
,
(
void
*
)
capifunc
->
method_def
->
ml_meth
,
r_passthrough
,
rewrite_args
->
arg2
);
rewrite_args
->
rewriter
->
call
(
true
,
(
void
*
)
checkAndThrowCAPIException
);
rewrite_args
->
obj
->
addGuard
((
intptr_t
)
self
);
}
int
flags
=
self
->
method_def
->
ml_flags
;
auto
func
=
self
->
method_def
->
ml_meth
;
ParamReceiveSpec
paramspec
(
0
,
0
,
true
,
false
);
if
(
flags
==
METH_VARARGS
)
{
paramspec
=
ParamReceiveSpec
(
0
,
0
,
true
,
false
);
}
else
if
(
flags
==
(
METH_VARARGS
|
METH_KEYWORDS
))
{
paramspec
=
ParamReceiveSpec
(
0
,
0
,
true
,
true
);
}
else
if
(
flags
==
METH_NOARGS
)
{
paramspec
=
ParamReceiveSpec
(
0
,
0
,
false
,
false
);
}
else
if
(
flags
==
METH_O
)
{
paramspec
=
ParamReceiveSpec
(
1
,
0
,
false
,
false
);
}
else
if
(
flags
==
METH_OLDARGS
)
{
paramspec
=
ParamReceiveSpec
(
1
,
0
,
false
,
false
);
}
else
{
RELEASE_ASSERT
(
0
,
"0x%x"
,
flags
);
}
Box
*
oarg1
=
NULL
;
Box
*
oarg2
=
NULL
;
Box
*
oarg3
=
NULL
;
Box
**
oargs
=
NULL
;
bool
rewrite_success
=
false
;
rearrangeArguments
(
paramspec
,
NULL
,
self
->
method_def
->
ml_name
,
NULL
,
rewrite_args
,
rewrite_success
,
argspec
,
arg1
,
arg2
,
arg3
,
args
,
keyword_names
,
oarg1
,
oarg2
,
oarg3
,
args
);
if
(
!
rewrite_success
)
rewrite_args
=
NULL
;
RewriterVar
*
r_passthrough
;
if
(
rewrite_args
)
r_passthrough
=
rewrite_args
->
rewriter
->
loadConst
((
intptr_t
)
self
->
passthrough
,
Location
::
forArg
(
0
));
Box
*
rtn
;
if
(
flags
==
METH_VARARGS
)
{
rtn
=
(
Box
*
)
func
(
self
->
passthrough
,
oarg1
);
if
(
rewrite_args
)
rewrite_args
->
out_rtn
=
rewrite_args
->
rewriter
->
call
(
true
,
(
void
*
)
func
,
r_passthrough
,
rewrite_args
->
arg1
);
}
else
if
(
flags
==
(
METH_VARARGS
|
METH_KEYWORDS
))
{
rtn
=
(
Box
*
)((
PyCFunctionWithKeywords
)
func
)(
self
->
passthrough
,
oarg1
,
oarg2
);
if
(
rewrite_args
)
rewrite_args
->
out_rtn
=
rewrite_args
->
rewriter
->
call
(
true
,
(
void
*
)
func
,
r_passthrough
,
rewrite_args
->
arg1
,
rewrite_args
->
arg2
);
}
else
if
(
flags
==
METH_NOARGS
)
{
rtn
=
(
Box
*
)
func
(
self
->
passthrough
,
NULL
);
if
(
rewrite_args
)
rewrite_args
->
out_rtn
=
rewrite_args
->
rewriter
->
call
(
true
,
(
void
*
)
func
,
r_passthrough
,
rewrite_args
->
rewriter
->
loadConst
(
0
,
Location
::
forArg
(
1
)));
}
else
if
(
flags
==
METH_O
)
{
rtn
=
(
Box
*
)
func
(
self
->
passthrough
,
oarg1
);
if
(
rewrite_args
)
rewrite_args
->
out_rtn
=
rewrite_args
->
rewriter
->
call
(
true
,
(
void
*
)
func
,
r_passthrough
,
rewrite_args
->
arg1
);
}
else
if
(
flags
==
METH_OLDARGS
)
{
/* the really old style */
rewrite_args
=
NULL
;
int
size
=
PyTuple_GET_SIZE
(
oarg1
);
Box
*
arg
=
oarg1
;
if
(
size
==
1
)
arg
=
PyTuple_GET_ITEM
(
oarg1
,
0
);
else
if
(
size
==
0
)
arg
=
NULL
;
rtn
=
func
(
self
->
passthrough
,
arg
);
}
else
{
RELEASE_ASSERT
(
0
,
"0x%x"
,
flags
);
}
if
(
rewrite_args
)
{
rewrite_args
->
rewriter
->
call
(
false
,
(
void
*
)
checkAndThrowCAPIException
);
rewrite_args
->
out_success
=
true
;
}
Box
*
r
=
capifunc
->
method_def
->
ml_meth
(
capifunc
->
passthrough
,
arg2
);
checkAndThrowCAPIException
();
assert
(
r
);
return
r
;
assert
(
r
tn
&&
"should have set + thrown an exception!"
);
return
r
tn
;
}
/* extension modules might be compiled with GC support so these
...
...
@@ -1546,8 +1604,8 @@ void setupCAPI() {
new
BoxedFunction
(
boxRTFunction
((
void
*
)
BoxedCApiFunction
::
__repr__
,
UNKNOWN
,
1
)));
auto
capi_call
=
new
BoxedFunction
(
boxRTFunction
((
void
*
)
BoxedCApiFunction
::
__call__
,
UNKNOWN
,
1
,
0
,
true
,
true
));
capi_call
->
f
->
internal_callable
=
BoxedCApiFunction
::
callInternal
;
capifunc_cls
->
giveAttr
(
"__call__"
,
capi_call
);
capifunc_cls
->
tpp_call
=
BoxedCApiFunction
::
tppCall
;
capifunc_cls
->
giveAttr
(
"__name__"
,
new
(
pyston_getset_cls
)
BoxedGetsetDescriptor
(
BoxedCApiFunction
::
getname
,
NULL
,
NULL
));
capifunc_cls
->
giveAttr
(
...
...
src/runtime/descr.cpp
View file @
a9813b80
...
...
@@ -347,6 +347,9 @@ Box* BoxedMethodDescriptor::callInternal(BoxedFunctionBase* f, CallRewriteArgs*
RELEASE_ASSERT
(
0
,
"0x%x"
,
call_flags
);
}
if
(
!
rtn
)
throwCAPIException
();
rewrite_args
->
rewriter
->
call
(
true
,
(
void
*
)
checkAndThrowCAPIException
);
rewrite_args
->
out_rtn
=
r_rtn
;
rewrite_args
->
out_success
=
true
;
...
...
src/runtime/ics.h
View file @
a9813b80
...
...
@@ -68,7 +68,7 @@ protected:
class
CallattrIC
:
public
RuntimeIC
{
public:
CallattrIC
()
:
RuntimeIC
((
void
*
)
callattr
,
1
,
16
0
)
{}
CallattrIC
()
:
RuntimeIC
((
void
*
)
callattr
,
1
,
32
0
)
{}
Box
*
call
(
Box
*
obj
,
BoxedString
*
attr
,
CallattrFlags
flags
,
ArgPassSpec
spec
,
Box
*
arg0
,
Box
*
arg1
,
Box
*
arg2
,
Box
**
args
,
const
std
::
vector
<
BoxedString
*>*
keyword_names
)
{
...
...
src/runtime/iterators.cpp
View file @
a9813b80
...
...
@@ -41,23 +41,12 @@ public:
void
next
()
override
{
STAT_TIMER
(
t0
,
"us_timer_iteratorgeneric_next"
,
0
);
assert
(
iterator
);
Box
*
hasnext
=
iterator
->
hasnextOrNullIC
();
if
(
hasnext
)
{
if
(
hasnext
->
nonzeroIC
())
{
value
=
iterator
->
nextIC
();
}
else
{
*
this
=
*
end
();
}
}
else
{
try
{
value
=
iterator
->
nextIC
();
}
catch
(
ExcInfo
e
)
{
if
(
e
.
matches
(
StopIteration
))
*
this
=
*
end
();
else
throw
e
;
}
Box
*
next
=
PyIter_Next
(
iterator
);
if
(
next
)
value
=
next
;
else
{
checkAndThrowCAPIException
();
*
this
=
*
end
();
}
}
...
...
src/runtime/iterobject.cpp
View file @
a9813b80
...
...
@@ -132,20 +132,14 @@ bool iterwrapperHasnextUnboxed(Box* s) {
RELEASE_ASSERT
(
s
->
cls
==
iterwrapper_cls
,
""
);
BoxedIterWrapper
*
self
=
static_cast
<
BoxedIterWrapper
*>
(
s
);
static
BoxedString
*
next_str
=
static_cast
<
BoxedString
*>
(
PyString_InternFromString
(
"next"
));
Box
*
next
;
try
{
next
=
callattr
(
self
->
iter
,
next_str
,
CallattrFlags
({.
cls_only
=
true
,
.
null_on_nonexistent
=
false
}),
ArgPassSpec
(
0
),
NULL
,
NULL
,
NULL
,
NULL
,
NULL
);
}
catch
(
ExcInfo
e
)
{
if
(
e
.
matches
(
StopIteration
))
{
self
->
next
=
NULL
;
return
false
;
}
throw
e
;
}
Box
*
next
=
PyIter_Next
(
self
->
iter
);
self
->
next
=
next
;
return
true
;
if
(
!
next
)
{
if
(
PyErr_Occurred
()
&&
!
PyErr_ExceptionMatches
(
PyExc_StopIteration
))
throwCAPIException
();
PyErr_Clear
();
}
return
next
!=
NULL
;
}
Box
*
iterwrapperHasnext
(
Box
*
s
)
{
...
...
src/runtime/list.cpp
View file @
a9813b80
...
...
@@ -101,7 +101,7 @@ extern "C" Box* listPop(BoxedList* self, Box* idx) {
int64_t
n
=
PyInt_AsSsize_t
(
idx
);
if
(
n
==
-
1
&&
PyErr_Occurred
())
raiseExcHelper
(
TypeError
,
"an integer is required"
);
throwCAPIException
(
);
if
(
n
<
0
)
n
=
self
->
size
+
n
;
...
...
src/runtime/objmodel.cpp
View file @
a9813b80
...
...
@@ -2723,11 +2723,22 @@ extern "C" Box* callattrInternal(Box* obj, BoxedString* attr, LookupScope scope,
extern
"C"
Box
*
callattr
(
Box
*
obj
,
BoxedString
*
attr
,
CallattrFlags
flags
,
ArgPassSpec
argspec
,
Box
*
arg1
,
Box
*
arg2
,
Box
*
arg3
,
Box
**
args
,
const
std
::
vector
<
BoxedString
*>*
keyword_names
)
{
STAT_TIMER
(
t0
,
"us_timer_slowpath_callattr"
,
10
);
#if 0
#if 0 && STAT_TIMERS
static uint64_t* st_id = Stats::getStatCounter("us_timer_slowpath_callattr_patchable");
static uint64_t* st_id_nopatch = Stats::getStatCounter("us_timer_slowpath_callattr_nopatch");
bool havepatch = (bool)getICInfo(__builtin_extract_return_addr(__builtin_return_address(0)));
ScopedStatTimer st(havepatch ? st_id : st_id_nopatch, 10);
static uint64_t* st_id_megamorphic = Stats::getStatCounter("us_timer_slowpath_callattr_megamorphic");
ICInfo* icinfo = getICInfo(__builtin_extract_return_addr(__builtin_return_address(0)));
uint64_t* counter;
if (!icinfo)
counter = st_id_nopatch;
else if (icinfo->isMegamorphic())
counter = st_id_megamorphic;
else {
//counter = Stats::getStatCounter("us_timer_slowpath_callattr_patchable_" + std::string(obj->cls->tp_name));
counter = Stats::getStatCounter("us_timer_slowpath_callattr_patchable_" + std::string(attr->s()));
}
ScopedStatTimer st(counter, 10);
#endif
ASSERT
(
gc
::
isValidGCObject
(
obj
),
"%p"
,
obj
);
...
...
@@ -3504,6 +3515,7 @@ Box* callCLFunc(CLFunction* f, CallRewriteArgs* rewrite_args, int num_output_arg
ASSERT
(
chosen_cf
->
spec
->
rtn_type
->
isFitBy
(
r
->
cls
),
"%s (%p) was supposed to return %s, but gave a %s"
,
g
.
func_addr_registry
.
getFuncNameAtAddress
(
chosen_cf
->
code
,
true
,
NULL
).
c_str
(),
chosen_cf
->
code
,
chosen_cf
->
spec
->
rtn_type
->
debugName
().
c_str
(),
r
->
cls
->
tp_name
);
assert
(
!
PyErr_Occurred
());
return
r
;
}
...
...
@@ -3514,13 +3526,13 @@ Box* runtimeCallInternal(Box* obj, CallRewriteArgs* rewrite_args, ArgPassSpec ar
int
npassed_args
=
argspec
.
totalPassed
();
if
(
obj
->
cls
!=
function_cls
&&
obj
->
cls
!=
builtin_function_or_method_cls
&&
obj
->
cls
!=
instancemethod_cls
)
{
STAT_TIMER
(
t0
,
"us_timer_slowpath_runtimecall_nonfunction"
,
20
);
// TODO: maybe eventually runtimeCallInternal should just be the default tpp_call?
if
(
obj
->
cls
->
tpp_call
)
{
return
obj
->
cls
->
tpp_call
(
obj
,
rewrite_args
,
argspec
,
arg1
,
arg2
,
arg3
,
args
,
keyword_names
);
}
STAT_TIMER
(
t0
,
"us_timer_slowpath_runtimecall_nonfunction"
,
20
);
#if 0
std::string per_name_stat_name = "zzz_runtimecall_nonfunction_" + std::string(obj->cls->tp_name);
uint64_t* counter = Stats::getStatCounter(per_name_stat_name);
...
...
src/runtime/stacktrace.cpp
View file @
a9813b80
...
...
@@ -47,6 +47,7 @@ void showBacktrace() {
}
void
raiseExc
(
Box
*
exc_obj
)
{
assert
(
!
PyErr_Occurred
());
throw
ExcInfo
(
exc_obj
->
cls
,
exc_obj
,
None
);
}
...
...
@@ -56,6 +57,7 @@ void raiseSyntaxError(const char* msg, int lineno, int col_offset, llvm::StringR
Box
*
exc
=
runtimeCall
(
SyntaxError
,
ArgPassSpec
(
1
),
boxString
(
msg
),
NULL
,
NULL
,
NULL
,
NULL
);
auto
tb
=
new
BoxedTraceback
(
LineInfo
(
lineno
,
col_offset
,
file
,
func
),
None
);
assert
(
!
PyErr_Occurred
());
throw
ExcInfo
(
exc
->
cls
,
exc
,
tb
);
}
...
...
@@ -175,6 +177,7 @@ extern "C" void raise0() {
raiseExcHelper
(
TypeError
,
"exceptions must be old-style classes or derived from BaseException, not NoneType"
);
exc_info
->
reraise
=
true
;
assert
(
!
PyErr_Occurred
());
throw
*
exc_info
;
}
...
...
@@ -256,6 +259,7 @@ extern "C" void raise3(Box* arg0, Box* arg1, Box* arg2) {
auto
exc_info
=
excInfoForRaise
(
arg0
,
arg1
,
arg2
);
exc_info
.
reraise
=
reraise
;
assert
(
!
PyErr_Occurred
());
throw
exc_info
;
}
...
...
src/runtime/types.cpp
View file @
a9813b80
...
...
@@ -238,9 +238,38 @@ Box* BoxedClass::callHasnextIC(Box* obj, bool null_on_nonexistent) {
ArgPassSpec
(
0
),
nullptr
,
nullptr
,
nullptr
,
nullptr
,
nullptr
);
}
extern
"C"
PyObject
*
PyIter_Next
(
PyObject
*
iter
)
noexcept
{
if
(
iter
->
cls
->
tp_iternext
!=
slot_tp_iternext
)
{
PyObject
*
result
;
result
=
(
*
iter
->
cls
->
tp_iternext
)(
iter
);
if
(
result
==
NULL
&&
PyErr_Occurred
()
&&
PyErr_ExceptionMatches
(
PyExc_StopIteration
))
PyErr_Clear
();
return
result
;
}
try
{
Box
*
hasnext
=
iter
->
hasnextOrNullIC
();
if
(
hasnext
)
{
if
(
hasnext
->
nonzeroIC
())
return
iter
->
cls
->
callNextIC
(
iter
);
else
return
NULL
;
}
else
{
return
iter
->
cls
->
callNextIC
(
iter
);
}
}
catch
(
ExcInfo
e
)
{
if
(
!
e
.
matches
(
StopIteration
))
setCAPIException
(
e
);
return
NULL
;
}
}
Box
*
BoxedClass
::
callNextIC
(
Box
*
obj
)
{
assert
(
obj
->
cls
==
this
);
// This would work, but it would have been better to just call tp_iternext
assert
(
this
->
tp_iternext
==
slot_tp_iternext
);
auto
ic
=
next_ic
.
get
();
if
(
!
ic
)
{
ic
=
new
CallattrIC
();
...
...
@@ -303,11 +332,6 @@ Box* Box::hasnextOrNullIC() {
return
this
->
cls
->
callHasnextIC
(
this
,
true
);
}
Box
*
Box
::
nextIC
()
{
return
this
->
cls
->
callNextIC
(
this
);
}
std
::
string
builtinStr
(
"__builtin__"
);
extern
"C"
BoxedFunctionBase
::
BoxedFunctionBase
(
CLFunction
*
f
)
...
...
@@ -580,6 +604,42 @@ static void assertInitNone(Box* obj) {
}
}
static
PyObject
*
cpython_type_call
(
PyTypeObject
*
type
,
PyObject
*
args
,
PyObject
*
kwds
)
noexcept
{
PyObject
*
obj
;
if
(
type
->
tp_new
==
NULL
)
{
PyErr_Format
(
PyExc_TypeError
,
"cannot create '%.100s' instances"
,
type
->
tp_name
);
return
NULL
;
}
obj
=
type
->
tp_new
(
type
,
args
,
kwds
);
if
(
obj
!=
NULL
)
{
/* Ugly exception: when the call was type(something),
* don't call tp_init on the result. */
if
(
type
==
&
PyType_Type
&&
PyTuple_Check
(
args
)
&&
PyTuple_GET_SIZE
(
args
)
==
1
&&
(
kwds
==
NULL
||
(
PyDict_Check
(
kwds
)
&&
PyDict_Size
(
kwds
)
==
0
)))
return
obj
;
/* If the returned object is not an instance of type,
* it won't be initialized. */
if
(
!
PyType_IsSubtype
(
obj
->
cls
,
type
))
return
obj
;
type
=
obj
->
cls
;
if
(
PyType_HasFeature
(
type
,
Py_TPFLAGS_HAVE_CLASS
)
&&
type
->
tp_init
!=
NULL
&&
type
->
tp_init
(
obj
,
args
,
kwds
)
<
0
)
{
Py_DECREF
(
obj
);
obj
=
NULL
;
}
}
return
obj
;
}
static
PyObject
*
cpythonTypeCall
(
BoxedClass
*
type
,
PyObject
*
args
,
PyObject
*
kwds
)
{
Box
*
r
=
cpython_type_call
(
type
,
args
,
kwds
);
if
(
!
r
)
throwCAPIException
();
return
r
;
}
static
Box
*
typeCallInner
(
CallRewriteArgs
*
rewrite_args
,
ArgPassSpec
argspec
,
Box
*
arg1
,
Box
*
arg2
,
Box
*
arg3
,
Box
**
args
,
const
std
::
vector
<
BoxedString
*>*
keyword_names
)
{
int
npassed_args
=
argspec
.
totalPassed
();
...
...
@@ -594,6 +654,29 @@ static Box* typeCallInner(CallRewriteArgs* rewrite_args, ArgPassSpec argspec, Bo
BoxedClass
*
cls
=
static_cast
<
BoxedClass
*>
(
_cls
);
if
(
cls
->
tp_new
!=
object_cls
->
tp_new
&&
cls
->
tp_new
!=
slot_tp_new
)
{
// Looks like we're calling an extension class and we're not going to be able to
// separately rewrite the new + init calls. But we can rewrite the fact that we
// should just call the cpython version, which will end up working pretty well.
ParamReceiveSpec
paramspec
(
1
,
false
,
true
,
true
);
bool
rewrite_success
=
false
;
Box
*
oarg1
,
*
oarg2
,
*
oarg3
,
**
oargs
=
NULL
;
rearrangeArguments
(
paramspec
,
NULL
,
""
,
NULL
,
rewrite_args
,
rewrite_success
,
argspec
,
arg1
,
arg2
,
arg3
,
args
,
keyword_names
,
oarg1
,
oarg2
,
oarg3
,
oargs
);
assert
(
oarg1
==
cls
);
if
(
!
rewrite_success
)
rewrite_args
=
NULL
;
if
(
rewrite_args
)
{
rewrite_args
->
out_rtn
=
rewrite_args
->
rewriter
->
call
(
true
,
(
void
*
)
cpythonTypeCall
,
rewrite_args
->
arg1
,
rewrite_args
->
arg2
,
rewrite_args
->
arg3
);
rewrite_args
->
out_success
=
true
;
}
return
cpythonTypeCall
(
cls
,
oarg2
,
oarg3
);
}
RewriterVar
*
r_ccls
=
NULL
;
RewriterVar
*
r_new
=
NULL
;
RewriterVar
*
r_init
=
NULL
;
...
...
@@ -769,7 +852,10 @@ static Box* typeCallInner(CallRewriteArgs* rewrite_args, ArgPassSpec argspec, Bo
"We should only have allowed the rewrite to continue if we were guaranteed that made "
"would have class cls!"
);
}
else
{
made
=
runtimeCallInternal
(
new_attr
,
NULL
,
new_argspec
,
cls
,
arg2
,
arg3
,
args
,
keyword_names
);
if
(
cls
->
tp_new
==
object_cls
->
tp_new
&&
cls
->
tp_init
!=
object_cls
->
tp_init
)
made
=
objectNewNoArgs
(
cls
);
else
made
=
runtimeCallInternal
(
new_attr
,
NULL
,
new_argspec
,
cls
,
arg2
,
arg3
,
args
,
keyword_names
);
}
assert
(
made
);
...
...
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