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
767a5193
Commit
767a5193
authored
Jun 19, 2015
by
Kevin Modzelewski
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #626 from kmod/perf2
make a couple more places successfully rewrite
parents
5294816c
2c93ce12
Changes
6
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
127 additions
and
19 deletions
+127
-19
src/asm_writing/rewriter.cpp
src/asm_writing/rewriter.cpp
+22
-4
src/asm_writing/rewriter.h
src/asm_writing/rewriter.h
+6
-0
src/codegen/ast_interpreter.cpp
src/codegen/ast_interpreter.cpp
+2
-0
src/runtime/long.cpp
src/runtime/long.cpp
+4
-0
src/runtime/long.h
src/runtime/long.h
+2
-0
src/runtime/objmodel.cpp
src/runtime/objmodel.cpp
+91
-15
No files found.
src/asm_writing/rewriter.cpp
View file @
767a5193
...
...
@@ -726,6 +726,8 @@ void Rewriter::_call(RewriterVar* result, bool can_call_into_python, void* func_
{
// this forces the register allocator to spill this register:
assembler
::
Register
r2
=
allocReg
(
l
);
if
(
failed
)
return
;
assert
(
r
==
r2
);
assert
(
vars_by_location
.
count
(
l
)
==
0
);
}
...
...
@@ -886,6 +888,11 @@ void Rewriter::commit() {
assert
(
!
finished
);
initPhaseEmitting
();
if
(
failed
)
{
this
->
abort
();
return
;
}
static
StatCounter
ic_rewrites_aborted_assemblyfail
(
"ic_rewrites_aborted_assemblyfail"
);
auto
on_assemblyfail
=
[
&
]()
{
...
...
@@ -936,6 +943,11 @@ void Rewriter::commit() {
for
(
int
i
=
0
;
i
<
actions
.
size
();
i
++
)
{
actions
[
i
].
action
();
if
(
failed
)
{
this
->
abort
();
return
;
}
assertConsistent
();
if
(
i
==
last_guard_action
)
{
on_done_guarding
();
...
...
@@ -1116,7 +1128,9 @@ Location Rewriter::allocScratch() {
return
l
;
}
}
RELEASE_ASSERT
(
0
,
"Using all %d bytes of scratch!"
,
scratch_size
);
failed
=
true
;
return
Location
(
Location
::
None
,
0
);
}
RewriterVar
*
Rewriter
::
add
(
RewriterVar
*
a
,
int64_t
b
,
Location
dest
)
{
...
...
@@ -1301,6 +1315,9 @@ void Rewriter::spillRegister(assembler::Register reg, Location preserve) {
}
Location
scratch
=
allocScratch
();
if
(
failed
)
return
;
assembler
::
Indirect
mem
=
indirectFor
(
scratch
);
assembler
->
mov
(
reg
,
mem
);
addLocationToVar
(
var
,
scratch
);
...
...
@@ -1366,7 +1383,7 @@ assembler::Register Rewriter::allocReg(Location dest, Location otherThan) {
spillRegister
(
reg
);
}
assert
(
vars_by_location
.
count
(
reg
)
==
0
);
assert
(
failed
||
vars_by_location
.
count
(
reg
)
==
0
);
return
reg
;
}
else
{
RELEASE_ASSERT
(
0
,
"%d"
,
dest
.
type
);
...
...
@@ -1499,6 +1516,7 @@ Rewriter::Rewriter(ICSlotRewrite* rewrite, int num_args, const std::vector<int>&
assembler
(
rewrite
->
getAssembler
()),
const_loader
(
this
),
return_location
(
rewrite
->
returnRegister
()),
failed
(
false
),
added_changing_action
(
false
),
marked_inside_ic
(
false
),
last_guard_action
(
-
1
),
...
...
@@ -1626,10 +1644,10 @@ Rewriter* Rewriter::createRewriter(void* rtn_addr, int num_args, const char* deb
// Horrible non-robust optimization: addresses below this address are probably in the binary (ex the interpreter),
// so don't do the more-expensive hash table lookup to find it.
if
(
rtn_addr
>
(
void
*
)
0x1
0
00000
)
{
if
(
rtn_addr
>
(
void
*
)
0x1
8
00000
)
{
ic
=
getICInfo
(
rtn_addr
);
}
else
{
assert
(
!
getICInfo
(
rtn_addr
)
);
ASSERT
(
!
getICInfo
(
rtn_addr
),
"%p"
,
rtn_addr
);
}
log_ic_attempts
(
debug_name
);
...
...
src/asm_writing/rewriter.h
View file @
767a5193
...
...
@@ -332,6 +332,7 @@ private:
const
Location
return_location
;
bool
failed
;
// if we tried to generate an invalid rewrite.
bool
finished
;
// committed or aborted
#ifndef NDEBUG
int
start_vars
;
...
...
@@ -366,6 +367,10 @@ private:
if
(
type
==
ActionType
::
MUTATION
)
{
added_changing_action
=
true
;
}
else
if
(
type
==
ActionType
::
GUARD
)
{
if
(
added_changing_action
)
{
failed
=
true
;
return
;
}
assert
(
!
added_changing_action
);
last_guard_action
=
(
int
)
actions
.
size
();
}
...
...
@@ -483,6 +488,7 @@ public:
RewriterVar
*
call
(
bool
can_call_into_python
,
void
*
func_addr
,
RewriterVar
*
arg0
,
RewriterVar
*
arg1
,
RewriterVar
*
arg2
);
RewriterVar
*
add
(
RewriterVar
*
a
,
int64_t
b
,
Location
dest
);
// Allocates n pointer-sized stack slots:
RewriterVar
*
allocate
(
int
n
);
RewriterVar
*
allocateAndCopy
(
RewriterVar
*
array
,
int
n
);
RewriterVar
*
allocateAndCopyPlus1
(
RewriterVar
*
first_elem
,
RewriterVar
*
rest
,
int
n_rest
);
...
...
src/codegen/ast_interpreter.cpp
View file @
767a5193
...
...
@@ -1295,6 +1295,8 @@ const void* interpreter_instr_addr = (void*)&ASTInterpreter::executeInner;
Box
*
astInterpretFunction
(
CompiledFunction
*
cf
,
int
nargs
,
Box
*
closure
,
Box
*
generator
,
Box
*
globals
,
Box
*
arg1
,
Box
*
arg2
,
Box
*
arg3
,
Box
**
args
)
{
UNAVOIDABLE_STAT_TIMER
(
t0
,
"us_timer_astInterpretFunction"
);
assert
((
!
globals
)
==
cf
->
clfunc
->
source
->
scoping
->
areGlobalsFromModule
());
bool
can_reopt
=
ENABLE_REOPT
&&
!
FORCE_INTERPRETER
&&
(
globals
==
NULL
);
if
(
unlikely
(
can_reopt
&&
cf
->
times_called
>
REOPT_THRESHOLD_INTERPRETER
))
{
...
...
src/runtime/long.cpp
View file @
767a5193
...
...
@@ -1237,6 +1237,10 @@ Box* longNonzero(BoxedLong* self) {
return
True
;
}
bool
longNonzeroUnboxed
(
BoxedLong
*
self
)
{
return
mpz_sgn
(
self
->
n
)
!=
0
;
}
Box
*
longHash
(
BoxedLong
*
self
)
{
if
(
!
isSubclass
(
self
->
cls
,
long_cls
))
raiseExcHelper
(
TypeError
,
"descriptor '__pow__' requires a 'long' object but received a '%s'"
,
...
...
src/runtime/long.h
View file @
767a5193
...
...
@@ -54,6 +54,8 @@ Box* longRshift(BoxedLong* lhs, Box* rhs);
Box
*
longHex
(
BoxedLong
*
v
);
Box
*
longOct
(
BoxedLong
*
v
);
Box
*
longStr
(
BoxedLong
*
v
);
bool
longNonzeroUnboxed
(
BoxedLong
*
n
);
}
#endif
src/runtime/objmodel.cpp
View file @
767a5193
...
...
@@ -2131,6 +2131,9 @@ extern "C" bool nonzero(Box* obj) {
r_obj
->
addAttrGuard
(
BOX_CLS_OFFSET
,
(
intptr_t
)
obj
->
cls
);
}
// Note: it feels silly to have all these special cases here, and we should probably be
// able to at least generate rewrites that are as good as the ones we write here.
// But for now we can't and these should be a bit faster:
if
(
obj
->
cls
==
bool_cls
)
{
// TODO: is it faster to compare to True? (especially since it will be a constant we can embed in the rewrite)
if
(
rewriter
.
get
())
{
...
...
@@ -2142,9 +2145,6 @@ extern "C" bool nonzero(Box* obj) {
return
bool_obj
->
n
;
}
else
if
(
obj
->
cls
==
int_cls
)
{
if
(
rewriter
.
get
())
{
// TODO should do:
// test %rsi, %rsi
// setne %al
RewriterVar
*
n
=
r_obj
->
getAttr
(
INT_N_OFFSET
,
rewriter
->
getReturnDestination
());
RewriterVar
*
b
=
n
->
toBool
(
rewriter
->
getReturnDestination
());
rewriter
->
commitReturning
(
b
);
...
...
@@ -2164,18 +2164,47 @@ extern "C" bool nonzero(Box* obj) {
rewriter
->
commitReturning
(
b
);
}
return
false
;
}
}
else
if
(
obj
->
cls
==
long_cls
)
{
BoxedLong
*
long_obj
=
static_cast
<
BoxedLong
*>
(
obj
);
bool
r
=
longNonzeroUnboxed
(
long_obj
);
// FIXME we have internal functions calling this method;
// instead, we should break this out into an external and internal function.
// slowpath_* counters are supposed to count external calls; putting it down
// here gets a better representation of that.
// TODO move internal callers to nonzeroInternal, and log *all* calls to nonzero
slowpath_nonzero
.
log
();
if
(
rewriter
.
get
())
{
RewriterVar
*
r_rtn
=
rewriter
->
call
(
false
,
(
void
*
)
longNonzeroUnboxed
,
r_obj
);
rewriter
->
commitReturning
(
r_rtn
);
}
return
r
;
}
else
if
(
obj
->
cls
==
tuple_cls
)
{
BoxedTuple
*
tuple_obj
=
static_cast
<
BoxedTuple
*>
(
obj
);
bool
r
=
(
tuple_obj
->
ob_size
!=
0
);
// int id = Stats::getStatId("slowpath_nonzero_" + *getTypeName(obj));
// Stats::log(id);
if
(
rewriter
.
get
())
{
RewriterVar
*
r_rtn
=
r_obj
->
getAttr
(
offsetof
(
BoxedTuple
,
ob_size
))
->
toBool
(
rewriter
->
getReturnDestination
());
rewriter
->
commitReturning
(
r_rtn
);
}
return
r
;
}
else
if
(
obj
->
cls
==
list_cls
)
{
BoxedList
*
list_obj
=
static_cast
<
BoxedList
*>
(
obj
);
bool
r
=
(
list_obj
->
size
!=
0
);
if
(
rewriter
.
get
())
{
RewriterVar
*
r_rtn
=
r_obj
->
getAttr
(
offsetof
(
BoxedList
,
size
))
->
toBool
(
rewriter
->
getReturnDestination
());
rewriter
->
commitReturning
(
r_rtn
);
}
return
r
;
}
else
if
(
obj
->
cls
==
str_cls
)
{
BoxedString
*
str_obj
=
static_cast
<
BoxedString
*>
(
obj
);
bool
r
=
(
str_obj
->
ob_size
!=
0
);
if
(
rewriter
.
get
())
{
RewriterVar
*
r_rtn
=
r_obj
->
getAttr
(
offsetof
(
BoxedString
,
ob_size
))
->
toBool
(
rewriter
->
getReturnDestination
());
rewriter
->
commitReturning
(
r_rtn
);
}
return
r
;
}
// TODO: rewrite these.
static
BoxedString
*
nonzero_str
=
static_cast
<
BoxedString
*>
(
PyString_InternFromString
(
"__nonzero__"
));
static
BoxedString
*
len_str
=
static_cast
<
BoxedString
*>
(
PyString_InternFromString
(
"__len__"
));
// go through descriptor logic
...
...
@@ -2743,6 +2772,12 @@ 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
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);
#endif
ASSERT
(
gc
::
isValidGCObject
(
obj
),
"%p"
,
obj
);
...
...
@@ -2786,16 +2821,16 @@ extern "C" Box* callattr(Box* obj, BoxedString* attr, CallattrFlags flags, ArgPa
rewrite_args
.
arg3
=
rewriter
->
getArg
(
6
);
if
(
npassed_args
>=
4
)
rewrite_args
.
args
=
rewriter
->
getArg
(
7
);
// XXX whole point is to not have to do this!
rtn
=
callattrInternal
(
obj
,
attr
,
scope
,
&
rewrite_args
,
argspec
,
arg1
,
arg2
,
arg3
,
args
,
keyword_names
);
if
(
!
rewrite_args
.
out_success
)
{
rewriter
.
reset
(
NULL
);
}
else
if
(
rtn
)
{
rewriter
->
commitReturning
(
rewrite_args
.
out_rtn
);
}
else
if
(
flags
.
null_on_nonexistent
)
{
rewriter
->
commitReturning
(
rewriter
->
loadConst
(
0
,
rewriter
->
getReturnDestination
()));
}
}
else
{
// XXX whole point is to not have to do this!
rtn
=
callattrInternal
(
obj
,
attr
,
scope
,
NULL
,
argspec
,
arg1
,
arg2
,
arg3
,
args
,
keyword_names
);
}
...
...
@@ -3299,13 +3334,54 @@ static Box* callChosenCF(CompiledFunction* chosen_cf, BoxedClosure* closure, Box
return
chosen_cf
->
call
(
oarg1
,
oarg2
,
oarg3
,
oargs
);
}
// This function exists for the rewriter: astInterpretFunction takes 9 args, but the rewriter
// only supports calling functions with at most 6 since it can currently only pass arguments
// in registers.
static
Box
*
astInterpretHelper
(
CompiledFunction
*
f
,
int
num_args
,
BoxedClosure
*
closure
,
BoxedGenerator
*
generator
,
Box
*
globals
,
Box
**
_args
)
{
Box
*
arg1
=
_args
[
0
];
Box
*
arg2
=
_args
[
1
];
Box
*
arg3
=
_args
[
2
];
Box
*
args
=
_args
[
3
];
return
astInterpretFunction
(
f
,
num_args
,
closure
,
generator
,
globals
,
arg1
,
arg2
,
arg3
,
(
Box
**
)
args
);
}
Box
*
callCLFunc
(
CLFunction
*
f
,
CallRewriteArgs
*
rewrite_args
,
int
num_output_args
,
BoxedClosure
*
closure
,
BoxedGenerator
*
generator
,
Box
*
globals
,
Box
*
oarg1
,
Box
*
oarg2
,
Box
*
oarg3
,
Box
**
oargs
)
{
CompiledFunction
*
chosen_cf
=
pickVersion
(
f
,
num_output_args
,
oarg1
,
oarg2
,
oarg3
,
oargs
);
assert
(
chosen_cf
->
is_interpreted
==
(
chosen_cf
->
code
==
NULL
));
if
(
chosen_cf
->
is_interpreted
)
{
UNAVOIDABLE_STAT_TIMER
(
t0
,
"us_timer_astInterpretFunction"
);
if
(
rewrite_args
)
{
rewrite_args
->
rewriter
->
addDependenceOn
(
chosen_cf
->
dependent_callsites
);
RewriterVar
::
SmallVector
arg_vec
;
// TODO this kind of embedded reference needs to be tracked by the GC somehow?
// Or maybe it's ok, since we've guarded on the function object?
arg_vec
.
push_back
(
rewrite_args
->
rewriter
->
loadConst
((
intptr_t
)
chosen_cf
,
Location
::
forArg
(
0
)));
arg_vec
.
push_back
(
rewrite_args
->
rewriter
->
loadConst
((
intptr_t
)
num_output_args
,
Location
::
forArg
(
1
)));
arg_vec
.
push_back
(
rewrite_args
->
rewriter
->
loadConst
((
intptr_t
)
closure
,
Location
::
forArg
(
2
)));
arg_vec
.
push_back
(
rewrite_args
->
rewriter
->
loadConst
((
intptr_t
)
generator
,
Location
::
forArg
(
3
)));
arg_vec
.
push_back
(
rewrite_args
->
rewriter
->
loadConst
((
intptr_t
)
globals
,
Location
::
forArg
(
4
)));
// Hacky workaround: the rewriter can only pass arguments in registers, so use this helper function
// to unpack some of the additional arguments:
RewriterVar
*
arg_array
=
rewrite_args
->
rewriter
->
allocate
(
4
);
arg_vec
.
push_back
(
arg_array
);
if
(
num_output_args
>=
1
)
arg_array
->
setAttr
(
0
,
rewrite_args
->
arg1
);
if
(
num_output_args
>=
2
)
arg_array
->
setAttr
(
8
,
rewrite_args
->
arg2
);
if
(
num_output_args
>=
3
)
arg_array
->
setAttr
(
16
,
rewrite_args
->
arg3
);
if
(
num_output_args
>=
4
)
arg_array
->
setAttr
(
24
,
rewrite_args
->
args
);
rewrite_args
->
out_rtn
=
rewrite_args
->
rewriter
->
call
(
true
,
(
void
*
)
astInterpretHelper
,
arg_vec
);
rewrite_args
->
out_success
=
true
;
}
return
astInterpretFunction
(
chosen_cf
,
num_output_args
,
closure
,
generator
,
globals
,
oarg1
,
oarg2
,
oarg3
,
oargs
);
...
...
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