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
e7174486
Commit
e7174486
authored
Jun 08, 2016
by
Marius Wachtler
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #1227 from undingen/bjit_opt2
major bjit improvements
parents
820dd0cd
9fd4924f
Changes
10
Show whitespace changes
Inline
Side-by-side
Showing
10 changed files
with
398 additions
and
337 deletions
+398
-337
src/asm_writing/assembler.cpp
src/asm_writing/assembler.cpp
+5
-0
src/asm_writing/rewriter.cpp
src/asm_writing/rewriter.cpp
+131
-143
src/asm_writing/rewriter.h
src/asm_writing/rewriter.h
+53
-22
src/codegen/ast_interpreter.cpp
src/codegen/ast_interpreter.cpp
+14
-14
src/codegen/ast_interpreter.h
src/codegen/ast_interpreter.h
+1
-0
src/codegen/baseline_jit.cpp
src/codegen/baseline_jit.cpp
+137
-122
src/codegen/baseline_jit.h
src/codegen/baseline_jit.h
+32
-11
src/codegen/unwinding.cpp
src/codegen/unwinding.cpp
+1
-5
src/runtime/objmodel.cpp
src/runtime/objmodel.cpp
+22
-19
test/tests/iter_del_time.py
test/tests/iter_del_time.py
+2
-1
No files found.
src/asm_writing/assembler.cpp
View file @
e7174486
...
@@ -755,6 +755,7 @@ void Assembler::incq(Indirect mem) {
...
@@ -755,6 +755,7 @@ void Assembler::incq(Indirect mem) {
}
}
assert
(
src_idx
>=
0
&&
src_idx
<
8
);
assert
(
src_idx
>=
0
&&
src_idx
<
8
);
bool
needssib
=
(
src_idx
==
0b100
);
if
(
rex
)
if
(
rex
)
emitRex
(
rex
);
emitRex
(
rex
);
...
@@ -763,8 +764,12 @@ void Assembler::incq(Indirect mem) {
...
@@ -763,8 +764,12 @@ void Assembler::incq(Indirect mem) {
assert
(
-
0x80
<=
mem
.
offset
&&
mem
.
offset
<
0x80
);
assert
(
-
0x80
<=
mem
.
offset
&&
mem
.
offset
<
0x80
);
if
(
mem
.
offset
==
0
)
{
if
(
mem
.
offset
==
0
)
{
emitModRM
(
0b00
,
0
,
src_idx
);
emitModRM
(
0b00
,
0
,
src_idx
);
if
(
needssib
)
emitSIB
(
0b00
,
0b100
,
src_idx
);
}
else
{
}
else
{
emitModRM
(
0b01
,
0
,
src_idx
);
emitModRM
(
0b01
,
0
,
src_idx
);
if
(
needssib
)
emitSIB
(
0b00
,
0b100
,
src_idx
);
emitByte
(
mem
.
offset
);
emitByte
(
mem
.
offset
);
}
}
}
}
...
...
src/asm_writing/rewriter.cpp
View file @
e7174486
...
@@ -24,7 +24,7 @@
...
@@ -24,7 +24,7 @@
namespace
pyston
{
namespace
pyston
{
static
const
assembler
::
Register
allocatable_regs
[]
=
{
static
const
assembler
::
Register
std_
allocatable_regs
[]
=
{
assembler
::
RAX
,
assembler
::
RCX
,
assembler
::
RDX
,
assembler
::
RAX
,
assembler
::
RCX
,
assembler
::
RDX
,
// no RSP
// no RSP
// no RBP
// no RBP
...
@@ -540,8 +540,8 @@ void Rewriter::_incref(RewriterVar* var, int num_refs) {
...
@@ -540,8 +540,8 @@ void Rewriter::_incref(RewriterVar* var, int num_refs) {
// this->_trap();
// this->_trap();
// this->_call(NULL, true,
(void*)Helper::incref, llvm::ArrayRef<RewriterVar*>(&var, 1),
// this->_call(NULL, true,
false /* can't throw */, (void*)Helper::incref, { var });
// llvm::ArrayRef<RewriterVar*>());
#ifdef Py_REF_DEBUG
#ifdef Py_REF_DEBUG
// assembler->trap();
// assembler->trap();
for
(
int
i
=
0
;
i
<
num_refs
;
++
i
)
for
(
int
i
=
0
;
i
<
num_refs
;
++
i
)
...
@@ -569,16 +569,13 @@ void Rewriter::_decref(RewriterVar* var) {
...
@@ -569,16 +569,13 @@ void Rewriter::_decref(RewriterVar* var) {
assert
(
!
var
->
nullable
);
assert
(
!
var
->
nullable
);
// assembler->trap();
// assembler->trap();
// this->_call(NULL, true, (void*)Helper::decref, llvm::ArrayRef<RewriterVar*>(&var, 1),
// this->_call(NULL, true, false /* can't throw */, (void*)Helper::decref, { var });
// llvm::ArrayRef<RewriterVar*>(NULL, (int)0));
#ifdef Py_REF_DEBUG
#ifdef Py_REF_DEBUG
// assembler->trap();
// assembler->trap();
assembler
->
decq
(
assembler
::
Immediate
(
&
_Py_RefTotal
));
assembler
->
decq
(
assembler
::
Immediate
(
&
_Py_RefTotal
));
#endif
#endif
_setupCall
(
true
,
{
var
},
{},
assembler
::
RAX
);
_setupCall
(
true
,
llvm
::
ArrayRef
<
RewriterVar
*>
(
&
var
,
1
),
llvm
::
ArrayRef
<
RewriterVar
*>
(
NULL
,
(
size_t
)
0
),
assembler
::
RAX
);
#ifdef Py_REF_DEBUG
#ifdef Py_REF_DEBUG
...
@@ -612,8 +609,7 @@ void Rewriter::_xdecref(RewriterVar* var) {
...
@@ -612,8 +609,7 @@ void Rewriter::_xdecref(RewriterVar* var) {
assert
(
var
->
nullable
);
assert
(
var
->
nullable
);
// assembler->trap();
// assembler->trap();
this
->
_call
(
NULL
,
true
,
(
void
*
)
Helper
::
xdecref
,
llvm
::
ArrayRef
<
RewriterVar
*>
(
&
var
,
1
),
this
->
_call
(
NULL
,
true
,
false
/* can't throw */
,
(
void
*
)
Helper
::
xdecref
,
{
var
});
llvm
::
ArrayRef
<
RewriterVar
*>
(
NULL
,
(
size_t
)
0
));
// Doesn't call bumpUse, since this function is designed to be callable from other emitting functions.
// Doesn't call bumpUse, since this function is designed to be callable from other emitting functions.
// (ie the caller should call bumpUse)
// (ie the caller should call bumpUse)
...
@@ -632,14 +628,18 @@ void Rewriter::_cmp(RewriterVar* result, RewriterVar* v1, AST_TYPE::AST_TYPE cmp
...
@@ -632,14 +628,18 @@ void Rewriter::_cmp(RewriterVar* result, RewriterVar* v1, AST_TYPE::AST_TYPE cmp
if
(
LOG_IC_ASSEMBLY
)
if
(
LOG_IC_ASSEMBLY
)
assembler
->
comment
(
"_cmp"
);
assembler
->
comment
(
"_cmp"
);
assembler
::
Register
v1_reg
=
v1
->
getInReg
();
assembler
::
Register
v1_reg
=
v1
->
getInReg
(
Location
::
any
(),
false
,
dest
);
assembler
::
Register
v2_reg
=
v2
->
getInReg
();
assembler
::
Register
v2_reg
=
v2
->
getInReg
(
Location
::
any
(),
false
,
dest
);
assert
(
v1_reg
!=
v2_reg
);
// TODO how do we ensure this?
assert
(
v1_reg
!=
v2_reg
);
// TODO how do we ensure this?
v1
->
bumpUseEarlyIfPossible
();
v1
->
bumpUseEarlyIfPossible
();
v2
->
bumpUseEarlyIfPossible
();
v2
->
bumpUseEarlyIfPossible
();
assembler
::
Register
newvar_reg
=
allocReg
(
dest
);
// sete and setne has special register requirements (can't use r8-r15)
const
assembler
::
Register
valid_registers
[]
=
{
assembler
::
RAX
,
assembler
::
RCX
,
assembler
::
RDX
,
assembler
::
RSI
,
assembler
::
RDI
,
};
assembler
::
Register
newvar_reg
=
allocReg
(
dest
,
Location
::
any
(),
valid_registers
);
result
->
initializeInReg
(
newvar_reg
);
result
->
initializeInReg
(
newvar_reg
);
assembler
->
cmp
(
v1_reg
,
v2_reg
);
assembler
->
cmp
(
v1_reg
,
v2_reg
);
switch
(
cmp_type
)
{
switch
(
cmp_type
)
{
...
@@ -916,116 +916,76 @@ RewriterVar* Rewriter::loadConst(int64_t val, Location dest) {
...
@@ -916,116 +916,76 @@ RewriterVar* Rewriter::loadConst(int64_t val, Location dest) {
return
const_loader_var
;
return
const_loader_var
;
}
}
RewriterVar
*
Rewriter
::
call
(
bool
has_side_effects
,
void
*
func_addr
)
{
RewriterVar
*
Rewriter
::
call
(
bool
has_side_effects
,
void
*
func_addr
,
llvm
::
ArrayRef
<
RewriterVar
*>
args
,
llvm
::
ArrayRef
<
RewriterVar
*>
args_xmm
,
llvm
::
ArrayRef
<
RewriterVar
*>
additional_uses
)
{
STAT_TIMER
(
t0
,
"us_timer_rewriter"
,
10
);
STAT_TIMER
(
t0
,
"us_timer_rewriter"
,
10
);
RewriterVar
*
result
=
createNewVar
();
RewriterVar
::
SmallVector
args
;
ActionType
type
;
RewriterVar
::
SmallVector
args_xmm
;
if
(
has_side_effects
)
return
call
(
has_side_effects
,
func_addr
,
args
,
args_xmm
);
type
=
ActionType
::
MUTATION
;
}
else
type
=
ActionType
::
NORMAL
;
RewriterVar
*
Rewriter
::
call
(
bool
has_side_effects
,
void
*
func_addr
,
RewriterVar
*
arg0
)
{
STAT_TIMER
(
t0
,
"us_timer_rewriter"
,
10
);
RewriterVar
::
SmallVector
args
;
RewriterVar
::
SmallVector
args_xmm
;
args
.
push_back
(
arg0
);
return
call
(
has_side_effects
,
func_addr
,
args
,
args_xmm
);
}
RewriterVar
*
Rewriter
::
call
(
bool
has_side_effects
,
void
*
func_addr
,
RewriterVar
*
arg0
,
RewriterVar
*
arg1
)
{
// TODO: we don't need to generate the decref info for calls which can't throw
STAT_TIMER
(
t0
,
"us_timer_rewriter"
,
10
);
bool
can_throw
=
true
;
auto
args_array_ref
=
regionAllocArgs
(
args
,
args_xmm
,
additional_uses
);
RewriterVar
::
SmallVector
args
;
// Hack: explicitly order the closure arguments so they pad nicer
RewriterVar
::
SmallVector
args_xmm
;
struct
LambdaClosure
{
args
.
push_back
(
arg0
);
RewriterVar
**
args_array
;
args
.
push_back
(
arg1
);
return
call
(
has_side_effects
,
func_addr
,
args
,
args_xmm
);
struct
{
}
unsigned
int
has_side_effects
:
1
;
unsigned
int
can_throw
:
1
;
unsigned
int
num_args
:
16
;
unsigned
int
num_args_xmm
:
16
;
unsigned
int
num_additional_uses
:
16
;
};
RewriterVar
*
Rewriter
::
call
(
bool
has_side_effects
,
void
*
func_addr
,
RewriterVar
*
arg0
,
RewriterVar
*
arg1
,
llvm
::
ArrayRef
<
RewriterVar
*>
allArgs
()
const
{
RewriterVar
*
arg2
)
{
return
llvm
::
makeArrayRef
(
args_array
,
num_args
+
num_args_xmm
+
num_additional_uses
);
STAT_TIMER
(
t0
,
"us_timer_rewriter"
,
10
);
}
RewriterVar
::
SmallVector
args
;
llvm
::
ArrayRef
<
RewriterVar
*>
args
()
const
{
return
allArgs
().
slice
(
0
,
num_args
);
}
RewriterVar
::
SmallVector
args_xmm
;
args
.
push_back
(
arg0
);
args
.
push_back
(
arg1
);
args
.
push_back
(
arg2
);
return
call
(
has_side_effects
,
func_addr
,
args
,
args_xmm
);
}
RewriterVar
*
Rewriter
::
call
(
bool
has_side_effects
,
void
*
func_addr
,
RewriterVar
*
arg0
,
RewriterVar
*
arg1
,
llvm
::
ArrayRef
<
RewriterVar
*>
argsXmm
()
const
{
return
allArgs
().
slice
(
num_args
,
num_args_xmm
);
}
RewriterVar
*
arg2
,
RewriterVar
*
arg3
)
{
STAT_TIMER
(
t0
,
"us_timer_rewriter"
,
10
);
RewriterVar
::
SmallVector
args
;
llvm
::
ArrayRef
<
RewriterVar
*>
additionalUses
()
const
{
RewriterVar
::
SmallVector
args_xmm
;
return
allArgs
().
slice
((
int
)
num_args
+
(
int
)
num_args_xmm
,
num_additional_uses
);
args
.
push_back
(
arg0
);
args
.
push_back
(
arg1
);
args
.
push_back
(
arg2
);
args
.
push_back
(
arg3
);
return
call
(
has_side_effects
,
func_addr
,
args
,
args_xmm
);
}
RewriterVar
*
Rewriter
::
call
(
bool
has_side_effects
,
void
*
func_addr
,
RewriterVar
*
arg0
,
RewriterVar
*
arg1
,
RewriterVar
*
arg2
,
RewriterVar
*
arg3
,
RewriterVar
*
arg4
)
{
RewriterVar
::
SmallVector
args
;
RewriterVar
::
SmallVector
args_xmm
;
args
.
push_back
(
arg0
);
args
.
push_back
(
arg1
);
args
.
push_back
(
arg2
);
args
.
push_back
(
arg3
);
args
.
push_back
(
arg4
);
return
call
(
has_side_effects
,
func_addr
,
args
,
args_xmm
);
}
RewriterVar
*
Rewriter
::
call
(
bool
has_side_effects
,
void
*
func_addr
,
const
RewriterVar
::
SmallVector
&
args
,
const
RewriterVar
::
SmallVector
&
args_xmm
)
{
RewriterVar
*
result
=
createNewVar
();
RewriterVar
::
SmallVector
uses
;
for
(
RewriterVar
*
v
:
args
)
{
assert
(
v
!=
NULL
);
uses
.
push_back
(
v
);
}
}
for
(
RewriterVar
*
v
:
args_xmm
)
{
assert
(
v
!=
NULL
);
uses
.
push_back
(
v
);
}
ActionType
type
;
if
(
has_side_effects
)
type
=
ActionType
::
MUTATION
;
else
type
=
ActionType
::
NORMAL
;
// It's not nice to pass llvm::SmallVectors through a closure, especially with our SmallFunction
LambdaClosure
(
llvm
::
MutableArrayRef
<
RewriterVar
*>
args_array_ref
,
llvm
::
ArrayRef
<
RewriterVar
*>
_args
,
// optimization, so just regionAlloc them and copy the data in:
llvm
::
ArrayRef
<
RewriterVar
*>
_args_xmm
,
llvm
::
ArrayRef
<
RewriterVar
*>
_addition_uses
,
RewriterVar
**
_args
=
(
RewriterVar
**
)
this
->
regionAlloc
(
sizeof
(
RewriterVar
*
)
*
args
.
size
());
bool
has_side_effects
,
bool
can_throw
)
memcpy
(
_args
,
args
.
begin
(),
sizeof
(
RewriterVar
*
)
*
args
.
size
());
:
args_array
(
args_array_ref
.
data
()),
RewriterVar
**
_args_xmm
=
(
RewriterVar
**
)
this
->
regionAlloc
(
sizeof
(
RewriterVar
*
)
*
args_xmm
.
size
());
has_side_effects
(
has_side_effects
),
memcpy
(
_args_xmm
,
args_xmm
.
begin
(),
sizeof
(
RewriterVar
*
)
*
args_xmm
.
size
());
can_throw
(
can_throw
),
num_args
(
_args
.
size
()),
num_args_xmm
(
_args_xmm
.
size
()),
num_additional_uses
(
_addition_uses
.
size
())
{
assert
(
_args
.
size
()
<
1
<<
16
);
assert
(
_args_xmm
.
size
()
<
1
<<
16
);
assert
(
_addition_uses
.
size
()
<
1
<<
16
);
}
int
args_size
=
args
.
size
(
);
}
lambda_closure
(
args_array_ref
,
args
,
args_xmm
,
additional_uses
,
has_side_effects
,
can_throw
);
assert
(
args_xmm
.
size
()
<=
0x7fff
);
assert
(
lambda_closure
.
args
().
size
()
==
args
.
size
()
);
// Hack: pack this into a short to make sure it fits in the closure
assert
(
lambda_closure
.
argsXmm
().
size
()
==
args_xmm
.
size
());
short
xmm_args_size
=
args_xmm
.
size
(
);
assert
(
lambda_closure
.
additionalUses
().
size
()
==
additional_uses
.
size
()
);
// Hack: explicitly order the closure arguments so they pad nicer
addAction
([
this
,
result
,
func_addr
,
lambda_closure
]()
{
addAction
([
args_size
,
xmm_args_size
,
has_side_effects
,
this
,
result
,
func_addr
,
_args
,
_args_xmm
]()
{
this
->
_call
(
result
,
lambda_closure
.
has_side_effects
,
lambda_closure
.
can_throw
,
func_addr
,
lambda_closure
.
args
(),
this
->
_call
(
result
,
has_side_effects
,
func_addr
,
llvm
::
ArrayRef
<
RewriterVar
*>
(
_args
,
args_size
),
lambda_closure
.
argsXmm
(),
lambda_closure
.
allArgs
());
llvm
::
ArrayRef
<
RewriterVar
*>
(
_args_xmm
,
xmm_args_size
));
},
lambda_closure
.
allArgs
(),
type
);
for
(
int
i
=
0
;
i
<
args_size
;
i
++
)
_args
[
i
]
->
bumpUse
();
for
(
int
i
=
0
;
i
<
xmm_args_size
;
i
++
)
_args_xmm
[
i
]
->
bumpUse
();
},
uses
,
type
);
return
result
;
return
result
;
}
}
void
Rewriter
::
_setupCall
(
bool
has_side_effects
,
llvm
::
ArrayRef
<
RewriterVar
*>
args
,
void
Rewriter
::
_setupCall
(
bool
has_side_effects
,
llvm
::
ArrayRef
<
RewriterVar
*>
args
,
llvm
::
ArrayRef
<
RewriterVar
*>
args_xmm
,
Location
preserve
)
{
llvm
::
ArrayRef
<
RewriterVar
*>
args_xmm
,
Location
preserve
,
llvm
::
ArrayRef
<
RewriterVar
*>
bump_if_possible
)
{
if
(
has_side_effects
)
if
(
has_side_effects
)
assert
(
done_guarding
);
assert
(
done_guarding
);
...
@@ -1112,6 +1072,10 @@ void Rewriter::_setupCall(bool has_side_effects, llvm::ArrayRef<RewriterVar*> ar
...
@@ -1112,6 +1072,10 @@ void Rewriter::_setupCall(bool has_side_effects, llvm::ArrayRef<RewriterVar*> ar
}
}
#endif
#endif
for
(
auto
&&
use
:
bump_if_possible
)
{
use
->
bumpUseEarlyIfPossible
();
}
// Spill caller-saved registers:
// Spill caller-saved registers:
for
(
auto
check_reg
:
caller_save_registers
)
{
for
(
auto
check_reg
:
caller_save_registers
)
{
// check_reg.dump();
// check_reg.dump();
...
@@ -1173,8 +1137,9 @@ void Rewriter::_setupCall(bool has_side_effects, llvm::ArrayRef<RewriterVar*> ar
...
@@ -1173,8 +1137,9 @@ void Rewriter::_setupCall(bool has_side_effects, llvm::ArrayRef<RewriterVar*> ar
#endif
#endif
}
}
void
Rewriter
::
_call
(
RewriterVar
*
result
,
bool
has_side_effects
,
void
*
func_addr
,
llvm
::
ArrayRef
<
RewriterVar
*>
args
,
void
Rewriter
::
_call
(
RewriterVar
*
result
,
bool
has_side_effects
,
bool
can_throw
,
void
*
func_addr
,
llvm
::
ArrayRef
<
RewriterVar
*>
args_xmm
)
{
llvm
::
ArrayRef
<
RewriterVar
*>
args
,
llvm
::
ArrayRef
<
RewriterVar
*>
args_xmm
,
llvm
::
ArrayRef
<
RewriterVar
*>
vars_to_bump
)
{
if
(
LOG_IC_ASSEMBLY
)
if
(
LOG_IC_ASSEMBLY
)
assembler
->
comment
(
"_call"
);
assembler
->
comment
(
"_call"
);
...
@@ -1183,17 +1148,7 @@ void Rewriter::_call(RewriterVar* result, bool has_side_effects, void* func_addr
...
@@ -1183,17 +1148,7 @@ void Rewriter::_call(RewriterVar* result, bool has_side_effects, void* func_addr
if
(
failed
)
if
(
failed
)
return
;
return
;
_setupCall
(
has_side_effects
,
args
,
args_xmm
,
assembler
::
R11
);
_setupCall
(
has_side_effects
,
args
,
args_xmm
,
assembler
::
R11
,
vars_to_bump
);
// This duty is now on the caller:
/*
for (RewriterVar* arg : args) {
arg->bumpUse();
}
for (RewriterVar* arg_xmm : args_xmm) {
arg_xmm->bumpUse();
}
*/
assertConsistent
();
assertConsistent
();
...
@@ -1211,7 +1166,7 @@ void Rewriter::_call(RewriterVar* result, bool has_side_effects, void* func_addr
...
@@ -1211,7 +1166,7 @@ void Rewriter::_call(RewriterVar* result, bool has_side_effects, void* func_addr
assert
(
assembler
->
hasFailed
()
||
asm_address
==
(
uint64_t
)
assembler
->
curInstPointer
());
assert
(
assembler
->
hasFailed
()
||
asm_address
==
(
uint64_t
)
assembler
->
curInstPointer
());
}
}
// TODO: we don't need to generate the decref info for calls which can't throw
if
(
can_throw
)
registerDecrefInfoHere
();
registerDecrefInfoHere
();
if
(
!
failed
)
{
if
(
!
failed
)
{
...
@@ -1224,24 +1179,39 @@ void Rewriter::_call(RewriterVar* result, bool has_side_effects, void* func_addr
...
@@ -1224,24 +1179,39 @@ void Rewriter::_call(RewriterVar* result, bool has_side_effects, void* func_addr
if
(
result
)
if
(
result
)
result
->
releaseIfNoUses
();
result
->
releaseIfNoUses
();
for
(
RewriterVar
*
var
:
vars_to_bump
)
{
var
->
bumpUseLateIfNecessary
();
}
}
}
std
::
vector
<
Location
>
Rewriter
::
getDecrefLocations
()
{
std
::
vector
<
Location
>
Rewriter
::
getDecrefLocations
()
{
std
::
vector
<
Location
>
decref_infos
;
std
::
vector
<
Location
>
decref_infos
;
for
(
RewriterVar
&
var
:
vars
)
{
for
(
RewriterVar
&
var
:
vars
)
{
if
(
var
.
locations
.
size
()
&&
var
.
needsDecref
())
{
if
(
var
.
locations
.
size
()
&&
var
.
needsDecref
(
current_action_idx
))
{
// TODO: add code to handle other location types and choose best location if there are several
bool
found_location
=
false
;
Location
l
=
*
var
.
locations
.
begin
();
for
(
Location
l
:
var
.
locations
)
{
if
(
l
.
type
==
Location
::
Scratch
)
{
if
(
l
.
type
==
Location
::
Scratch
)
{
// convert to stack based location because later on we may not know the offset of the scratch area from
// convert to stack based location because later on we may not know the offset of the scratch area
//
the SP.
// from
the SP.
decref_infos
.
emplace_back
(
Location
::
Stack
,
indirectFor
(
l
).
offset
);
decref_infos
.
emplace_back
(
Location
::
Stack
,
indirectFor
(
l
).
offset
);
found_location
=
true
;
break
;
}
else
if
(
l
.
type
==
Location
::
Register
)
{
}
else
if
(
l
.
type
==
Location
::
Register
)
{
// CSRs shouldn't be getting allocated, and we should only be calling this at a callsite:
// we only allow registers which are not clobbered by a call
RELEASE_ASSERT
(
0
,
"we shouldn't be trying to decref anything in a register"
);
if
(
l
.
isClobberedByCall
())
continue
;
decref_infos
.
emplace_back
(
l
);
found_location
=
true
;
break
;
}
else
}
else
RELEASE_ASSERT
(
0
,
"not implemented"
);
RELEASE_ASSERT
(
0
,
"not implemented"
);
}
}
if
(
!
found_location
)
{
// this is very rare. just fail the rewrite for now
failed
=
true
;
}
}
}
}
for
(
auto
&&
p
:
owned_attrs
)
{
for
(
auto
&&
p
:
owned_attrs
)
{
...
@@ -1335,16 +1305,25 @@ void RewriterVar::refConsumed(RewriterAction* action) {
...
@@ -1335,16 +1305,25 @@ void RewriterVar::refConsumed(RewriterAction* action) {
last_refconsumed_numuses
=
uses
.
size
();
last_refconsumed_numuses
=
uses
.
size
();
if
(
!
action
)
if
(
!
action
)
action
=
rewriter
->
getLastAction
();
action
=
rewriter
->
getLastAction
();
action
->
consumed_refs
.
emplace_back
(
this
);
action
->
consumed_refs
.
push_front
(
this
);
}
}
void
RewriterVar
::
refUsed
()
{
bool
RewriterVar
::
needsDecref
(
int
current_action_index
)
{
// TODO: This is a pretty silly implementation that might prevent other optimizations?
rewriter
->
assertPhaseEmitting
();
rewriter
->
addAction
([
=
]()
{
this
->
bumpUse
();
},
{
this
},
ActionType
::
NORMAL
);
}
if
(
reftype
!=
RefType
::
OWNED
)
return
false
;
// if nothing consumes this reference we need to create a decref entry
if
(
num_refs_consumed
==
0
)
return
true
;
// don't create decref entry if the currenty action hands off the ownership
int
reference_handed_off_action_index
=
uses
[
last_refconsumed_numuses
-
1
];
if
(
reference_handed_off_action_index
==
current_action_index
)
return
false
;
bool
RewriterVar
::
needsDecref
()
{
return
true
;
return
reftype
==
RefType
::
OWNED
&&
!
this
->
refHandedOff
();
}
}
void
RewriterVar
::
registerOwnedAttr
(
int
byte_offset
)
{
void
RewriterVar
::
registerOwnedAttr
(
int
byte_offset
)
{
...
@@ -1497,6 +1476,7 @@ void Rewriter::commit() {
...
@@ -1497,6 +1476,7 @@ void Rewriter::commit() {
_incref
(
var
,
1
);
_incref
(
var
,
1
);
}
}
current_action_idx
=
i
;
actions
[
i
].
action
();
actions
[
i
].
action
();
if
(
failed
)
{
if
(
failed
)
{
...
@@ -1926,7 +1906,7 @@ void Rewriter::_checkAndThrowCAPIException(RewriterVar* r, int64_t exc_val, asse
...
@@ -1926,7 +1906,7 @@ void Rewriter::_checkAndThrowCAPIException(RewriterVar* r, int64_t exc_val, asse
}
else
}
else
assembler
->
cmp
(
var_reg
,
assembler
::
Immediate
(
exc_val
),
type
);
assembler
->
cmp
(
var_reg
,
assembler
::
Immediate
(
exc_val
),
type
);
_setupCall
(
false
,
RewriterVar
::
SmallVector
(),
RewriterVar
::
SmallVector
()
);
_setupCall
(
false
,
{}
);
{
{
assembler
::
ForwardJump
jnz
(
*
assembler
,
assembler
::
COND_NOT_ZERO
);
assembler
::
ForwardJump
jnz
(
*
assembler
,
assembler
::
COND_NOT_ZERO
);
assembler
->
mov
(
assembler
::
Immediate
((
void
*
)
throwCAPIException
),
assembler
::
R11
);
assembler
->
mov
(
assembler
::
Immediate
((
void
*
)
throwCAPIException
),
assembler
::
R11
);
...
@@ -2004,6 +1984,11 @@ void Rewriter::spillRegister(assembler::XMMRegister reg) {
...
@@ -2004,6 +1984,11 @@ void Rewriter::spillRegister(assembler::XMMRegister reg) {
}
}
assembler
::
Register
Rewriter
::
allocReg
(
Location
dest
,
Location
otherThan
)
{
assembler
::
Register
Rewriter
::
allocReg
(
Location
dest
,
Location
otherThan
)
{
return
allocReg
(
dest
,
otherThan
,
allocatable_regs
);
}
assembler
::
Register
Rewriter
::
allocReg
(
Location
dest
,
Location
otherThan
,
llvm
::
ArrayRef
<
assembler
::
Register
>
valid_registers
)
{
assertPhaseEmitting
();
assertPhaseEmitting
();
if
(
dest
.
type
==
Location
::
AnyReg
)
{
if
(
dest
.
type
==
Location
::
AnyReg
)
{
...
@@ -2012,7 +1997,7 @@ assembler::Register Rewriter::allocReg(Location dest, Location otherThan) {
...
@@ -2012,7 +1997,7 @@ assembler::Register Rewriter::allocReg(Location dest, Location otherThan) {
assembler
::
Register
best_reg
(
0
);
assembler
::
Register
best_reg
(
0
);
// TODO prioritize spilling a constant register?
// TODO prioritize spilling a constant register?
for
(
assembler
::
Register
reg
:
allocatable_reg
s
)
{
for
(
assembler
::
Register
reg
:
valid_register
s
)
{
if
(
Location
(
reg
)
!=
otherThan
)
{
if
(
Location
(
reg
)
!=
otherThan
)
{
if
(
vars_by_location
.
count
(
reg
)
==
0
)
{
if
(
vars_by_location
.
count
(
reg
)
==
0
)
{
return
reg
;
return
reg
;
...
@@ -2042,6 +2027,7 @@ assembler::Register Rewriter::allocReg(Location dest, Location otherThan) {
...
@@ -2042,6 +2027,7 @@ assembler::Register Rewriter::allocReg(Location dest, Location otherThan) {
assert
(
failed
||
vars_by_location
.
count
(
best_reg
)
==
0
);
assert
(
failed
||
vars_by_location
.
count
(
best_reg
)
==
0
);
return
best_reg
;
return
best_reg
;
}
else
if
(
dest
.
type
==
Location
::
Register
)
{
}
else
if
(
dest
.
type
==
Location
::
Register
)
{
assert
(
std
::
find
(
valid_registers
.
begin
(),
valid_registers
.
end
(),
dest
.
asRegister
())
!=
valid_registers
.
end
());
assembler
::
Register
reg
(
dest
.
regnum
);
assembler
::
Register
reg
(
dest
.
regnum
);
if
(
vars_by_location
.
count
(
reg
))
{
if
(
vars_by_location
.
count
(
reg
))
{
...
@@ -2193,12 +2179,14 @@ Rewriter::Rewriter(std::unique_ptr<ICSlotRewrite> rewrite, int num_args, const L
...
@@ -2193,12 +2179,14 @@ Rewriter::Rewriter(std::unique_ptr<ICSlotRewrite> rewrite, int num_args, const L
return_location
(
this
->
rewrite
->
returnRegister
()),
return_location
(
this
->
rewrite
->
returnRegister
()),
failed
(
false
),
failed
(
false
),
needs_invalidation_support
(
needs_invalidation_support
),
needs_invalidation_support
(
needs_invalidation_support
),
current_action_idx
(
-
1
),
added_changing_action
(
false
),
added_changing_action
(
false
),
marked_inside_ic
(
false
),
marked_inside_ic
(
false
),
done_guarding
(
false
),
done_guarding
(
false
),
last_guard_action
(
-
1
),
last_guard_action
(
-
1
),
offset_eq_jmp_slowpath
(
-
1
),
offset_eq_jmp_slowpath
(
-
1
),
offset_ne_jmp_slowpath
(
-
1
)
{
offset_ne_jmp_slowpath
(
-
1
),
allocatable_regs
(
std_allocatable_regs
)
{
initPhaseCollecting
();
initPhaseCollecting
();
finished
=
false
;
finished
=
false
;
...
...
src/asm_writing/rewriter.h
View file @
e7174486
...
@@ -16,6 +16,7 @@
...
@@ -16,6 +16,7 @@
#define PYSTON_ASMWRITING_REWRITER_H
#define PYSTON_ASMWRITING_REWRITER_H
#include <deque>
#include <deque>
#include <forward_list>
#include <list>
#include <list>
#include <map>
#include <map>
#include <memory>
#include <memory>
...
@@ -192,8 +193,6 @@ public:
...
@@ -192,8 +193,6 @@ public:
// if no action is specified it will assume the last action consumed the reference
// if no action is specified it will assume the last action consumed the reference
void
refConsumed
(
RewriterAction
*
action
=
NULL
);
void
refConsumed
(
RewriterAction
*
action
=
NULL
);
void
refUsed
();
// registerOwnedAttr tells the refcounter that a certain memory location holds a pointer
// registerOwnedAttr tells the refcounter that a certain memory location holds a pointer
// to an owned reference. This must be paired with a call to deregisterOwnedAttr
// to an owned reference. This must be paired with a call to deregisterOwnedAttr
// Call these right before emitting the store (for register) or decref (for deregister).
// Call these right before emitting the store (for register) or decref (for deregister).
...
@@ -237,11 +236,11 @@ private:
...
@@ -237,11 +236,11 @@ private:
// /* some code */
// /* some code */
// bumpUseLateIfNecessary();
// bumpUseLateIfNecessary();
void
bumpUseEarlyIfPossible
()
{
void
bumpUseEarlyIfPossible
()
{
if
(
reftype
!=
RefType
::
OWNED
)
if
(
reftype
!=
RefType
::
OWNED
&&
!
hasScratchAllocation
()
)
bumpUse
();
bumpUse
();
}
}
void
bumpUseLateIfNecessary
()
{
void
bumpUseLateIfNecessary
()
{
if
(
reftype
==
RefType
::
OWNED
)
if
(
reftype
==
RefType
::
OWNED
||
hasScratchAllocation
()
)
bumpUse
();
bumpUse
();
}
}
...
@@ -254,7 +253,7 @@ private:
...
@@ -254,7 +253,7 @@ private:
bool
isDoneUsing
()
{
return
next_use
==
uses
.
size
();
}
bool
isDoneUsing
()
{
return
next_use
==
uses
.
size
();
}
bool
hasScratchAllocation
()
const
{
return
scratch_allocation
.
second
>
0
;
}
bool
hasScratchAllocation
()
const
{
return
scratch_allocation
.
second
>
0
;
}
void
resetHasScratchAllocation
()
{
scratch_allocation
=
std
::
make_pair
(
0
,
0
);
}
void
resetHasScratchAllocation
()
{
scratch_allocation
=
std
::
make_pair
(
0
,
0
);
}
bool
needsDecref
();
bool
needsDecref
(
int
current_action_index
);
// Indicates if this variable is an arg, and if so, what location the arg is from.
// Indicates if this variable is an arg, and if so, what location the arg is from.
bool
is_arg
;
bool
is_arg
;
...
@@ -339,8 +338,9 @@ public:
...
@@ -339,8 +338,9 @@ public:
class
RewriterAction
{
class
RewriterAction
{
public:
public:
SmallFunction
<
56
>
action
;
SmallFunction
<
48
>
action
;
std
::
vector
<
RewriterVar
*>
consumed_refs
;
std
::
forward_list
<
RewriterVar
*>
consumed_refs
;
template
<
typename
F
>
RewriterAction
(
F
&&
action
)
:
action
(
std
::
forward
<
F
>
(
action
))
{}
template
<
typename
F
>
RewriterAction
(
F
&&
action
)
:
action
(
std
::
forward
<
F
>
(
action
))
{}
...
@@ -367,7 +367,33 @@ private:
...
@@ -367,7 +367,33 @@ private:
protected:
protected:
// Allocates `bytes` bytes of data. The allocation will get freed when the rewriter gets freed.
// Allocates `bytes` bytes of data. The allocation will get freed when the rewriter gets freed.
void
*
regionAlloc
(
size_t
bytes
)
{
return
allocator
.
Allocate
(
bytes
,
16
/* alignment */
);
}
void
*
regionAlloc
(
size_t
bytes
,
int
alignment
=
16
)
{
return
allocator
.
Allocate
(
bytes
,
alignment
);
}
template
<
typename
T
>
llvm
::
MutableArrayRef
<
T
>
regionAlloc
(
size_t
num_elements
)
{
return
llvm
::
MutableArrayRef
<
T
>
(
allocator
.
Allocate
<
T
>
(
num_elements
),
num_elements
);
}
// This takes a variable number of llvm::ArrayRef<RewriterVar*> and copies in all elements into a single contiguous
// memory location.
template
<
typename
...
Args
>
llvm
::
MutableArrayRef
<
RewriterVar
*>
regionAllocArgs
(
llvm
::
ArrayRef
<
RewriterVar
*>
arg1
,
Args
...
args
)
{
size_t
num_total_args
=
0
;
for
(
auto
&&
array
:
{
arg1
,
args
...
})
{
num_total_args
+=
array
.
size
();
}
if
(
num_total_args
==
0
)
return
llvm
::
MutableArrayRef
<
RewriterVar
*>
();
auto
args_array_ref
=
regionAlloc
<
RewriterVar
*>
(
num_total_args
);
auto
insert_point
=
args_array_ref
;
for
(
auto
&&
array
:
{
arg1
,
args
...
})
{
if
(
!
array
.
empty
())
{
memcpy
(
insert_point
.
data
(),
array
.
data
(),
array
.
size
()
*
sizeof
(
RewriterVar
*
));
insert_point
=
insert_point
.
slice
(
array
.
size
());
}
}
assert
(
insert_point
.
size
()
==
0
);
return
args_array_ref
;
}
// Helps generating the best code for loading a const integer value.
// Helps generating the best code for loading a const integer value.
// By keeping track of the last known value of every register and reusing it.
// By keeping track of the last known value of every register and reusing it.
...
@@ -432,6 +458,8 @@ protected:
...
@@ -432,6 +458,8 @@ protected:
bool
needs_invalidation_support
=
true
);
bool
needs_invalidation_support
=
true
);
std
::
deque
<
RewriterAction
>
actions
;
std
::
deque
<
RewriterAction
>
actions
;
int
current_action_idx
;
// in the emitting phase get's set to index of currently executed action
template
<
typename
F
>
RewriterAction
*
addAction
(
F
&&
action
,
llvm
::
ArrayRef
<
RewriterVar
*>
vars
,
ActionType
type
)
{
template
<
typename
F
>
RewriterAction
*
addAction
(
F
&&
action
,
llvm
::
ArrayRef
<
RewriterVar
*>
vars
,
ActionType
type
)
{
assertPhaseCollecting
();
assertPhaseCollecting
();
for
(
RewriterVar
*
var
:
vars
)
{
for
(
RewriterVar
*
var
:
vars
)
{
...
@@ -483,6 +511,8 @@ protected:
...
@@ -483,6 +511,8 @@ protected:
// Allocates a register. dest must be of type Register or AnyReg
// Allocates a register. dest must be of type Register or AnyReg
// If otherThan is a register, guaranteed to not use that register.
// If otherThan is a register, guaranteed to not use that register.
assembler
::
Register
allocReg
(
Location
dest
,
Location
otherThan
=
Location
::
any
());
assembler
::
Register
allocReg
(
Location
dest
,
Location
otherThan
=
Location
::
any
());
assembler
::
Register
allocReg
(
Location
dest
,
Location
otherThan
,
llvm
::
ArrayRef
<
assembler
::
Register
>
valid_registers
);
assembler
::
XMMRegister
allocXMMReg
(
Location
dest
,
Location
otherThan
=
Location
::
any
());
assembler
::
XMMRegister
allocXMMReg
(
Location
dest
,
Location
otherThan
=
Location
::
any
());
// Allocates an 8-byte region in the scratch space
// Allocates an 8-byte region in the scratch space
Location
allocScratch
();
Location
allocScratch
();
...
@@ -507,11 +537,13 @@ protected:
...
@@ -507,11 +537,13 @@ protected:
void
_slowpathJump
(
bool
condition_eq
);
void
_slowpathJump
(
bool
condition_eq
);
void
_trap
();
void
_trap
();
void
_loadConst
(
RewriterVar
*
result
,
int64_t
val
);
void
_loadConst
(
RewriterVar
*
result
,
int64_t
val
);
void
_setupCall
(
bool
has_side_effects
,
llvm
::
ArrayRef
<
RewriterVar
*>
args
,
llvm
::
ArrayRef
<
RewriterVar
*>
args_xmm
,
void
_setupCall
(
bool
has_side_effects
,
llvm
::
ArrayRef
<
RewriterVar
*>
args
=
{},
Location
preserve
=
Location
::
any
());
llvm
::
ArrayRef
<
RewriterVar
*>
args_xmm
=
{},
Location
preserve
=
Location
::
any
(),
llvm
::
ArrayRef
<
RewriterVar
*>
bump_if_possible
=
{});
// _call does not call bumpUse on its arguments:
// _call does not call bumpUse on its arguments:
void
_call
(
RewriterVar
*
result
,
bool
has_side_effects
,
void
*
func_addr
,
llvm
::
ArrayRef
<
RewriterVar
*>
args
,
void
_call
(
RewriterVar
*
result
,
bool
has_side_effects
,
bool
can_throw
,
void
*
func_addr
,
llvm
::
ArrayRef
<
RewriterVar
*>
args_xmm
);
llvm
::
ArrayRef
<
RewriterVar
*>
args
,
llvm
::
ArrayRef
<
RewriterVar
*>
args_xmm
=
{},
llvm
::
ArrayRef
<
RewriterVar
*>
vars_to_bump
=
{});
void
_add
(
RewriterVar
*
result
,
RewriterVar
*
a
,
int64_t
b
,
Location
dest
);
void
_add
(
RewriterVar
*
result
,
RewriterVar
*
a
,
int64_t
b
,
Location
dest
);
int
_allocate
(
RewriterVar
*
result
,
int
n
);
int
_allocate
(
RewriterVar
*
result
,
int
n
);
void
_allocateAndCopy
(
RewriterVar
*
result
,
RewriterVar
*
array
,
int
n
);
void
_allocateAndCopy
(
RewriterVar
*
result
,
RewriterVar
*
array
,
int
n
);
...
@@ -565,6 +597,8 @@ protected:
...
@@ -565,6 +597,8 @@ protected:
#endif
#endif
}
}
llvm
::
ArrayRef
<
assembler
::
Register
>
allocatable_regs
;
public:
public:
// This should be called exactly once for each argument
// This should be called exactly once for each argument
RewriterVar
*
getArg
(
int
argnum
);
RewriterVar
*
getArg
(
int
argnum
);
...
@@ -606,16 +640,13 @@ public:
...
@@ -606,16 +640,13 @@ public:
// 2) does not have any side-effects that would be user-visible if we bailed out from the middle of the
// 2) does not have any side-effects that would be user-visible if we bailed out from the middle of the
// inline cache. (Extra allocations don't count even though they're potentially visible if you look
// inline cache. (Extra allocations don't count even though they're potentially visible if you look
// hard enough.)
// hard enough.)
RewriterVar
*
call
(
bool
has_side_effects
,
void
*
func_addr
,
const
RewriterVar
::
SmallVector
&
args
,
RewriterVar
*
call
(
bool
has_side_effects
,
void
*
func_addr
,
llvm
::
ArrayRef
<
RewriterVar
*>
args
=
{},
const
RewriterVar
::
SmallVector
&
args_xmm
=
RewriterVar
::
SmallVector
());
llvm
::
ArrayRef
<
RewriterVar
*>
args_xmm
=
{},
llvm
::
ArrayRef
<
RewriterVar
*>
additional_uses
=
{});
RewriterVar
*
call
(
bool
has_side_effects
,
void
*
func_addr
);
template
<
typename
...
Args
>
RewriterVar
*
call
(
bool
has_side_effects
,
void
*
func_addr
,
RewriterVar
*
arg0
);
RewriterVar
*
call
(
bool
has_side_effects
,
void
*
func_addr
,
RewriterVar
*
arg1
,
Args
...
args
)
{
RewriterVar
*
call
(
bool
has_side_effects
,
void
*
func_addr
,
RewriterVar
*
arg0
,
RewriterVar
*
arg1
);
return
call
(
has_side_effects
,
func_addr
,
llvm
::
ArrayRef
<
RewriterVar
*>
({
arg1
,
args
...
}),
{});
RewriterVar
*
call
(
bool
has_side_effects
,
void
*
func_addr
,
RewriterVar
*
arg0
,
RewriterVar
*
arg1
,
RewriterVar
*
arg2
);
}
RewriterVar
*
call
(
bool
has_side_effects
,
void
*
func_addr
,
RewriterVar
*
arg0
,
RewriterVar
*
arg1
,
RewriterVar
*
arg2
,
RewriterVar
*
arg3
);
RewriterVar
*
call
(
bool
has_side_effects
,
void
*
func_addr
,
RewriterVar
*
arg0
,
RewriterVar
*
arg1
,
RewriterVar
*
arg2
,
RewriterVar
*
arg3
,
RewriterVar
*
arg4
);
RewriterVar
*
add
(
RewriterVar
*
a
,
int64_t
b
,
Location
dest
);
RewriterVar
*
add
(
RewriterVar
*
a
,
int64_t
b
,
Location
dest
);
// Allocates n pointer-sized stack slots:
// Allocates n pointer-sized stack slots:
RewriterVar
*
allocate
(
int
n
);
RewriterVar
*
allocate
(
int
n
);
...
...
src/codegen/ast_interpreter.cpp
View file @
e7174486
...
@@ -458,7 +458,7 @@ void ASTInterpreter::doStore(AST_Name* node, STOLEN(Value) value) {
...
@@ -458,7 +458,7 @@ void ASTInterpreter::doStore(AST_Name* node, STOLEN(Value) value) {
ScopeInfo
::
VarScopeType
vst
=
node
->
lookup_type
;
ScopeInfo
::
VarScopeType
vst
=
node
->
lookup_type
;
if
(
vst
==
ScopeInfo
::
VarScopeType
::
GLOBAL
)
{
if
(
vst
==
ScopeInfo
::
VarScopeType
::
GLOBAL
)
{
if
(
jit
)
if
(
jit
)
jit
->
emitSetGlobal
(
frame_info
.
globals
,
name
.
getBox
(),
value
);
jit
->
emitSetGlobal
(
name
.
getBox
(),
value
,
getMD
()
->
source
->
scoping
->
areGlobalsFromModule
()
);
setGlobal
(
frame_info
.
globals
,
name
.
getBox
(),
value
.
o
);
setGlobal
(
frame_info
.
globals
,
name
.
getBox
(),
value
.
o
);
}
else
if
(
vst
==
ScopeInfo
::
VarScopeType
::
NAME
)
{
}
else
if
(
vst
==
ScopeInfo
::
VarScopeType
::
NAME
)
{
if
(
jit
)
if
(
jit
)
...
@@ -471,13 +471,12 @@ void ASTInterpreter::doStore(AST_Name* node, STOLEN(Value) value) {
...
@@ -471,13 +471,12 @@ void ASTInterpreter::doStore(AST_Name* node, STOLEN(Value) value) {
bool
closure
=
vst
==
ScopeInfo
::
VarScopeType
::
CLOSURE
;
bool
closure
=
vst
==
ScopeInfo
::
VarScopeType
::
CLOSURE
;
if
(
jit
)
{
if
(
jit
)
{
bool
is_live
=
true
;
bool
is_live
=
true
;
// TODO: turn this optimization back on.
if
(
!
closure
)
// if (!closure)
is_live
=
source_info
->
getLiveness
()
->
isLiveAtEnd
(
name
,
current_block
);
// is_live = source_info->getLiveness()->isLiveAtEnd(name, current_block);
if
(
is_live
)
if
(
is_live
)
jit
->
emitSetLocal
(
name
,
node
->
vreg
,
closure
,
value
);
jit
->
emitSetLocal
(
name
,
node
->
vreg
,
closure
,
value
);
else
else
jit
->
emitSetBlockLocal
(
name
,
value
);
jit
->
emitSetBlockLocal
(
name
,
node
->
vreg
,
value
);
}
}
if
(
closure
)
{
if
(
closure
)
{
...
@@ -686,12 +685,12 @@ Value ASTInterpreter::visit_jump(AST_Jump* node) {
...
@@ -686,12 +685,12 @@ Value ASTInterpreter::visit_jump(AST_Jump* node) {
if
(
backedge
)
if
(
backedge
)
++
edgecount
;
++
edgecount
;
if
(
ENABLE_BASELINEJIT
&&
backedge
&&
edgecount
=
=
OSR_THRESHOLD_INTERPRETER
&&
!
jit
&&
!
node
->
target
->
code
)
{
if
(
ENABLE_BASELINEJIT
&&
backedge
&&
edgecount
>
=
OSR_THRESHOLD_INTERPRETER
&&
!
jit
&&
!
node
->
target
->
code
)
{
should_jit
=
true
;
should_jit
=
true
;
startJITing
(
node
->
target
);
startJITing
(
node
->
target
);
}
}
if
(
backedge
&&
edgecount
=
=
OSR_THRESHOLD_BASELINE
)
{
if
(
backedge
&&
edgecount
>
=
OSR_THRESHOLD_BASELINE
)
{
Box
*
rtn
=
doOSR
(
node
);
Box
*
rtn
=
doOSR
(
node
);
if
(
rtn
)
if
(
rtn
)
return
Value
(
rtn
,
NULL
);
return
Value
(
rtn
,
NULL
);
...
@@ -1173,12 +1172,9 @@ Value ASTInterpreter::createFunction(AST* node, AST_arguments* args, const std::
...
@@ -1173,12 +1172,9 @@ Value ASTInterpreter::createFunction(AST* node, AST_arguments* args, const std::
closure_var
=
jit
->
imm
(
0ul
);
closure_var
=
jit
->
imm
(
0ul
);
if
(
!
passed_globals_var
)
if
(
!
passed_globals_var
)
passed_globals_var
=
jit
->
imm
(
0ul
);
passed_globals_var
=
jit
->
imm
(
0ul
);
rtn
.
var
=
jit
->
call
(
false
,
(
void
*
)
createFunctionFromMetadata
,
jit
->
imm
(
md
),
closure_var
,
passed_globals_var
,
rtn
.
var
=
jit
->
call
(
false
,
(
void
*
)
createFunctionFromMetadata
,
{
jit
->
imm
(
md
),
closure_var
,
passed_globals_var
,
defaults_var
,
jit
->
imm
(
args
->
defaults
.
size
()))
->
setType
(
RefType
::
OWNED
);
defaults_var
,
jit
->
imm
(
args
->
defaults
.
size
())
},
{},
defaults_vars
)
->
setType
(
RefType
::
OWNED
);
for
(
auto
d_var
:
defaults_vars
)
{
d_var
->
refUsed
();
}
}
}
rtn
.
o
=
createFunctionFromMetadata
(
md
,
closure
,
passed_globals
,
u
.
il
);
rtn
.
o
=
createFunctionFromMetadata
(
md
,
closure
,
passed_globals
,
u
.
il
);
...
@@ -1661,7 +1657,7 @@ Value ASTInterpreter::visit_name(AST_Name* node) {
...
@@ -1661,7 +1657,7 @@ Value ASTInterpreter::visit_name(AST_Name* node) {
assert
(
!
node
->
is_kill
);
assert
(
!
node
->
is_kill
);
Value
v
;
Value
v
;
if
(
jit
)
if
(
jit
)
v
.
var
=
jit
->
emitGetGlobal
(
frame_info
.
globals
,
node
->
id
.
getBox
());
v
.
var
=
jit
->
emitGetGlobal
(
node
->
id
.
getBox
());
v
.
o
=
getGlobal
(
frame_info
.
globals
,
node
->
id
.
getBox
());
v
.
o
=
getGlobal
(
frame_info
.
globals
,
node
->
id
.
getBox
());
return
v
;
return
v
;
...
@@ -1781,6 +1777,10 @@ int ASTInterpreterJitInterface::getBoxedLocalsOffset() {
...
@@ -1781,6 +1777,10 @@ int ASTInterpreterJitInterface::getBoxedLocalsOffset() {
return
offsetof
(
ASTInterpreter
,
frame_info
.
boxedLocals
);
return
offsetof
(
ASTInterpreter
,
frame_info
.
boxedLocals
);
}
}
int
ASTInterpreterJitInterface
::
getCreatedClosureOffset
()
{
return
offsetof
(
ASTInterpreter
,
created_closure
);
}
int
ASTInterpreterJitInterface
::
getCurrentBlockOffset
()
{
int
ASTInterpreterJitInterface
::
getCurrentBlockOffset
()
{
return
offsetof
(
ASTInterpreter
,
current_block
);
return
offsetof
(
ASTInterpreter
,
current_block
);
}
}
...
...
src/codegen/ast_interpreter.h
View file @
e7174486
...
@@ -39,6 +39,7 @@ struct ASTInterpreterJitInterface {
...
@@ -39,6 +39,7 @@ struct ASTInterpreterJitInterface {
static
constexpr
uint64_t
osr_dummy_value
=
-
1
;
static
constexpr
uint64_t
osr_dummy_value
=
-
1
;
static
int
getBoxedLocalsOffset
();
static
int
getBoxedLocalsOffset
();
static
int
getCreatedClosureOffset
();
static
int
getCurrentBlockOffset
();
static
int
getCurrentBlockOffset
();
static
int
getCurrentInstOffset
();
static
int
getCurrentInstOffset
();
static
int
getEdgeCountOffset
();
static
int
getEdgeCountOffset
();
...
...
src/codegen/baseline_jit.cpp
View file @
e7174486
...
@@ -16,6 +16,7 @@
...
@@ -16,6 +16,7 @@
#include <llvm/ADT/DenseMap.h>
#include <llvm/ADT/DenseMap.h>
#include <llvm/ADT/DenseSet.h>
#include <llvm/ADT/DenseSet.h>
#include <sys/mman.h>
#include "codegen/irgen/hooks.h"
#include "codegen/irgen/hooks.h"
#include "codegen/memmgr.h"
#include "codegen/memmgr.h"
...
@@ -38,30 +39,43 @@ static llvm::DenseMap<CFGBlock*, std::vector<void*>> block_patch_locations;
...
@@ -38,30 +39,43 @@ static llvm::DenseMap<CFGBlock*, std::vector<void*>> block_patch_locations;
//
//
// long foo(char* c);
// long foo(char* c);
// void bjit() {
// void bjit() {
// asm volatile ("" ::: "r15");
// asm volatile ("" ::: "r14");
// asm volatile ("" ::: "r14");
// asm volatile ("" ::: "r13");
// asm volatile ("" ::: "r13");
// asm volatile ("" ::: "r12");
// char scratch[256+16];
// char scratch[256+16];
// foo(scratch);
// foo(scratch);
// }
// }
//
//
// It omits the frame pointer but saves r1
3 and r14
// It omits the frame pointer but saves r1
2, r13, r14 and r15
// use 'objdump -s -j .eh_frame <obj.file>' to dump it
// use 'objdump -s -j .eh_frame <obj.file>' to dump it
const
unsigned
char
eh_info
[]
const
unsigned
char
eh_info
[]
=
{
0x14
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x03
,
0x7a
,
0x52
,
0x00
,
0x01
,
0x78
,
0x10
,
=
{
0x14
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x03
,
0x7a
,
0x52
,
0x00
,
0x01
,
0x78
,
0x10
,
0x01
,
0x01
,
0x1b
,
0x0c
,
0x07
,
0x08
,
0x90
,
0x01
,
0x00
,
0x00
,
0x1c
,
0x00
,
0x00
,
0x00
,
0x1c
,
0x00
,
0x1b
,
0x0c
,
0x07
,
0x08
,
0x90
,
0x01
,
0x00
,
0x00
,
0x2c
,
0x00
,
0x00
,
0x00
,
0x1c
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x20
,
0x00
,
0x00
,
0x00
,
0x00
,
0x42
,
0x0e
,
0x10
,
0x42
,
0x00
,
0x00
,
0x00
,
0x00
,
0x28
,
0x00
,
0x00
,
0x00
,
0x00
,
0x42
,
0x0e
,
0x10
,
0x42
,
0x0e
,
0x18
,
0x42
,
0x0e
,
0x18
,
0x47
,
0x0e
,
0xb0
,
0x02
,
0x8d
,
0x03
,
0x8e
,
0x02
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
};
0x0e
,
0x20
,
0x42
,
0x0e
,
0x28
,
0x47
,
0x0e
,
0xc0
,
0x02
,
0x8c
,
0x05
,
0x8d
,
0x04
,
0x8e
,
0x03
,
0x8f
,
0x02
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
};
static_assert
(
JitCodeBlock
::
num_stack_args
==
2
,
"have to update EH table!"
);
static_assert
(
JitCodeBlock
::
num_stack_args
==
2
,
"have to update EH table!"
);
static_assert
(
JitCodeBlock
::
scratch_size
==
256
,
"have to update EH table!"
);
static_assert
(
JitCodeBlock
::
scratch_size
==
256
,
"have to update EH table!"
);
constexpr
int
code_size
=
JitCodeBlock
::
memory_size
-
sizeof
(
eh_info
);
constexpr
int
code_size
=
JitCodeBlock
::
memory_size
-
sizeof
(
eh_info
);
JitCodeBlock
::
MemoryManager
::
MemoryManager
()
{
int
protection
=
PROT_READ
|
PROT_WRITE
|
PROT_EXEC
;
int
flags
=
MAP_PRIVATE
|
MAP_ANONYMOUS
;
#if ENABLE_BASELINEJIT_MAP_32BIT
flags
|=
MAP_32BIT
;
#endif
addr
=
(
uint8_t
*
)
mmap
(
NULL
,
JitCodeBlock
::
memory_size
,
protection
,
flags
,
-
1
,
0
);
}
JitCodeBlock
::
MemoryManager
::~
MemoryManager
()
{
munmap
(
addr
,
JitCodeBlock
::
memory_size
);
addr
=
NULL
;
}
JitCodeBlock
::
JitCodeBlock
(
llvm
::
StringRef
name
)
JitCodeBlock
::
JitCodeBlock
(
llvm
::
StringRef
name
)
:
memory
(
new
uint8_t
[
memory_size
]),
:
entry_offset
(
0
),
a
(
memory
.
get
()
+
sizeof
(
eh_info
),
code_size
),
is_currently_writing
(
false
),
asm_failed
(
false
)
{
entry_offset
(
0
),
a
(
memory
.
get
()
+
sizeof
(
eh_info
),
code_size
),
is_currently_writing
(
false
),
asm_failed
(
false
)
{
static
StatCounter
num_jit_code_blocks
(
"num_baselinejit_code_blocks"
);
static
StatCounter
num_jit_code_blocks
(
"num_baselinejit_code_blocks"
);
num_jit_code_blocks
.
log
();
num_jit_code_blocks
.
log
();
static
StatCounter
num_jit_total_bytes
(
"num_baselinejit_total_bytes"
);
static
StatCounter
num_jit_total_bytes
(
"num_baselinejit_total_bytes"
);
...
@@ -70,8 +84,10 @@ JitCodeBlock::JitCodeBlock(llvm::StringRef name)
...
@@ -70,8 +84,10 @@ JitCodeBlock::JitCodeBlock(llvm::StringRef name)
uint8_t
*
code
=
a
.
curInstPointer
();
uint8_t
*
code
=
a
.
curInstPointer
();
// emit prolog
// emit prolog
a
.
push
(
assembler
::
R15
);
a
.
push
(
assembler
::
R14
);
a
.
push
(
assembler
::
R14
);
a
.
push
(
assembler
::
R13
);
a
.
push
(
assembler
::
R13
);
a
.
push
(
assembler
::
R12
);
static_assert
(
sp_adjustment
%
16
==
8
,
"stack isn't aligned"
);
static_assert
(
sp_adjustment
%
16
==
8
,
"stack isn't aligned"
);
a
.
sub
(
assembler
::
Immediate
(
sp_adjustment
),
assembler
::
RSP
);
a
.
sub
(
assembler
::
Immediate
(
sp_adjustment
),
assembler
::
RSP
);
a
.
mov
(
assembler
::
RDI
,
assembler
::
R13
);
// interpreter pointer
a
.
mov
(
assembler
::
RDI
,
assembler
::
R13
);
// interpreter pointer
...
@@ -136,6 +152,12 @@ void JitCodeBlock::fragmentFinished(int bytes_written, int num_bytes_overlapping
...
@@ -136,6 +152,12 @@ void JitCodeBlock::fragmentFinished(int bytes_written, int num_bytes_overlapping
ic_info
.
appendDecrefInfosTo
(
decref_infos
);
ic_info
.
appendDecrefInfosTo
(
decref_infos
);
}
}
static
const
assembler
::
Register
bjit_allocatable_regs
[]
=
{
assembler
::
RAX
,
assembler
::
RCX
,
assembler
::
RDX
,
// no RSP
// no RBP
assembler
::
RDI
,
assembler
::
RSI
,
assembler
::
R8
,
assembler
::
R9
,
assembler
::
R10
,
assembler
::
R11
,
assembler
::
R12
,
assembler
::
R15
};
JitFragmentWriter
::
JitFragmentWriter
(
CFGBlock
*
block
,
std
::
unique_ptr
<
ICInfo
>
ic_info
,
JitFragmentWriter
::
JitFragmentWriter
(
CFGBlock
*
block
,
std
::
unique_ptr
<
ICInfo
>
ic_info
,
std
::
unique_ptr
<
ICSlotRewrite
>
rewrite
,
int
code_offset
,
int
num_bytes_overlapping
,
std
::
unique_ptr
<
ICSlotRewrite
>
rewrite
,
int
code_offset
,
int
num_bytes_overlapping
,
...
@@ -149,6 +171,8 @@ JitFragmentWriter::JitFragmentWriter(CFGBlock* block, std::unique_ptr<ICInfo> ic
...
@@ -149,6 +171,8 @@ JitFragmentWriter::JitFragmentWriter(CFGBlock* block, std::unique_ptr<ICInfo> ic
code_block
(
code_block
),
code_block
(
code_block
),
interp
(
0
),
interp
(
0
),
ic_info
(
std
::
move
(
ic_info
))
{
ic_info
(
std
::
move
(
ic_info
))
{
allocatable_regs
=
bjit_allocatable_regs
;
if
(
LOG_BJIT_ASSEMBLY
)
if
(
LOG_BJIT_ASSEMBLY
)
comment
(
"BJIT: JitFragmentWriter() start"
);
comment
(
"BJIT: JitFragmentWriter() start"
);
interp
=
createNewVar
();
interp
=
createNewVar
();
...
@@ -198,10 +222,10 @@ RewriterVar* JitFragmentWriter::emitCallattr(AST_expr* node, RewriterVar* obj, B
...
@@ -198,10 +222,10 @@ RewriterVar* JitFragmentWriter::emitCallattr(AST_expr* node, RewriterVar* obj, B
call_args
.
push_back
(
args
.
size
()
>
1
?
args
[
1
]
:
imm
(
0ul
));
call_args
.
push_back
(
args
.
size
()
>
1
?
args
[
1
]
:
imm
(
0ul
));
call_args
.
push_back
(
args
.
size
()
>
2
?
args
[
2
]
:
imm
(
0ul
));
call_args
.
push_back
(
args
.
size
()
>
2
?
args
[
2
]
:
imm
(
0ul
));
llvm
::
ArrayRef
<
RewriterVar
*>
additional_uses
;
if
(
args
.
size
()
>
3
)
{
if
(
args
.
size
()
>
3
)
{
RewriterVar
*
scratch
=
allocate
(
args
.
size
()
-
3
);
additional_uses
=
args
.
slice
(
3
);
for
(
int
i
=
0
;
i
<
args
.
size
()
-
3
;
++
i
)
RewriterVar
*
scratch
=
allocArgs
(
additional_uses
,
RewriterVar
::
SetattrType
::
REF_USED
);
scratch
->
setAttr
(
i
*
sizeof
(
void
*
),
args
[
i
+
3
],
RewriterVar
::
SetattrType
::
REF_USED
);
call_args
.
push_back
(
scratch
);
call_args
.
push_back
(
scratch
);
}
else
if
(
keyword_names
)
{
}
else
if
(
keyword_names
)
{
call_args
.
push_back
(
imm
(
0ul
));
call_args
.
push_back
(
imm
(
0ul
));
...
@@ -210,11 +234,8 @@ RewriterVar* JitFragmentWriter::emitCallattr(AST_expr* node, RewriterVar* obj, B
...
@@ -210,11 +234,8 @@ RewriterVar* JitFragmentWriter::emitCallattr(AST_expr* node, RewriterVar* obj, B
if
(
keyword_names
)
if
(
keyword_names
)
call_args
.
push_back
(
imm
(
keyword_names
));
call_args
.
push_back
(
imm
(
keyword_names
));
auto
r
=
emitPPCall
((
void
*
)
callattr
,
call_args
,
2
,
640
,
node
,
type_recorder
).
first
->
setType
(
RefType
::
OWNED
);
return
emitPPCall
((
void
*
)
callattr
,
call_args
,
2
,
640
,
node
,
type_recorder
,
additional_uses
)
for
(
int
i
=
3
;
i
<
args
.
size
();
i
++
)
{
.
first
->
setType
(
RefType
::
OWNED
);
args
[
i
]
->
refUsed
();
}
return
r
;
#else
#else
// We could make this faster but for now: keep it simple, stupid...
// We could make this faster but for now: keep it simple, stupid...
RewriterVar
*
attr_var
=
imm
(
attr
);
RewriterVar
*
attr_var
=
imm
(
attr
);
...
@@ -223,7 +244,7 @@ RewriterVar* JitFragmentWriter::emitCallattr(AST_expr* node, RewriterVar* obj, B
...
@@ -223,7 +244,7 @@ RewriterVar* JitFragmentWriter::emitCallattr(AST_expr* node, RewriterVar* obj, B
RewriterVar
*
args_array
=
nullptr
;
RewriterVar
*
args_array
=
nullptr
;
if
(
args
.
size
())
if
(
args
.
size
())
args_array
=
allocArgs
(
args
);
args_array
=
allocArgs
(
args
,
RewriterVar
::
SetattrType
::
REF_USED
);
else
else
RELEASE_ASSERT
(
!
keyword_names_var
,
"0 args but keyword names are set"
);
RELEASE_ASSERT
(
!
keyword_names_var
,
"0 args but keyword names are set"
);
...
@@ -244,7 +265,10 @@ RewriterVar* JitFragmentWriter::emitCallattr(AST_expr* node, RewriterVar* obj, B
...
@@ -244,7 +265,10 @@ RewriterVar* JitFragmentWriter::emitCallattr(AST_expr* node, RewriterVar* obj, B
}
}
RewriterVar
*
JitFragmentWriter
::
emitCompare
(
AST_expr
*
node
,
RewriterVar
*
lhs
,
RewriterVar
*
rhs
,
int
op_type
)
{
RewriterVar
*
JitFragmentWriter
::
emitCompare
(
AST_expr
*
node
,
RewriterVar
*
lhs
,
RewriterVar
*
rhs
,
int
op_type
)
{
// TODO: can directly emit the assembly for Is/IsNot
if
(
op_type
==
AST_TYPE
::
Is
||
op_type
==
AST_TYPE
::
IsNot
)
{
RewriterVar
*
cmp_result
=
lhs
->
cmp
(
op_type
==
AST_TYPE
::
IsNot
?
AST_TYPE
::
NotEq
:
AST_TYPE
::
Eq
,
rhs
);
return
call
(
false
,
(
void
*
)
boxBool
,
cmp_result
)
->
setType
(
RefType
::
OWNED
);
}
return
emitPPCall
((
void
*
)
compare
,
{
lhs
,
rhs
,
imm
(
op_type
)
},
2
,
240
,
node
).
first
->
setType
(
RefType
::
OWNED
);
return
emitPPCall
((
void
*
)
compare
,
{
lhs
,
rhs
,
imm
(
op_type
)
},
2
,
240
,
node
).
first
->
setType
(
RefType
::
OWNED
);
}
}
...
@@ -258,42 +282,9 @@ void JitFragmentWriter::emitDictSet(RewriterVar* dict, RewriterVar* k, RewriterV
...
@@ -258,42 +282,9 @@ void JitFragmentWriter::emitDictSet(RewriterVar* dict, RewriterVar* k, RewriterV
v
->
refConsumed
();
v
->
refConsumed
();
}
}
// TODO: merge this function's functionality with refUsed
RewriterVar
*
JitFragmentWriter
::
emitCallWithAllocatedArgs
(
void
*
func_addr
,
const
llvm
::
ArrayRef
<
RewriterVar
*>
args
,
RewriterVar
*
JitFragmentWriter
::
emitCallWithAllocatedArgs
(
void
*
func_addr
,
const
llvm
::
ArrayRef
<
RewriterVar
*>
args
,
const
llvm
::
ArrayRef
<
RewriterVar
*>
additional_uses
)
{
const
llvm
::
ArrayRef
<
RewriterVar
*>
additional_uses
)
{
RewriterVar
*
result
=
createNewVar
();
return
call
(
false
,
func_addr
,
args
,
{},
additional_uses
);
RewriterVar
::
SmallVector
uses
;
for
(
RewriterVar
*
v
:
args
)
{
assert
(
v
!=
NULL
);
uses
.
push_back
(
v
);
}
for
(
RewriterVar
*
v
:
additional_uses
)
{
assert
(
v
!=
NULL
);
uses
.
push_back
(
v
);
}
// It's not nice to pass llvm::SmallVectors through a closure, especially with our SmallFunction
// optimization, so just regionAlloc them and copy the data in:
RewriterVar
**
_args
=
(
RewriterVar
**
)
this
->
regionAlloc
(
sizeof
(
RewriterVar
*
)
*
args
.
size
());
memcpy
(
_args
,
args
.
begin
(),
sizeof
(
RewriterVar
*
)
*
args
.
size
());
RewriterVar
**
_args_additional
=
(
RewriterVar
**
)
this
->
regionAlloc
(
sizeof
(
RewriterVar
*
)
*
additional_uses
.
size
());
memcpy
(
_args_additional
,
additional_uses
.
begin
(),
sizeof
(
RewriterVar
*
)
*
additional_uses
.
size
());
int
args_size
=
args
.
size
();
assert
(
additional_uses
.
size
()
<=
0x7fff
);
// Hack: pack this into a short to make sure it fits in the closure
short
args_additional_size
=
additional_uses
.
size
();
// Hack: explicitly order the closure arguments so they pad nicer
addAction
([
args_size
,
args_additional_size
,
func_addr
,
this
,
result
,
_args
,
_args_additional
]()
{
this
->
_call
(
result
,
false
,
func_addr
,
llvm
::
ArrayRef
<
RewriterVar
*>
(
_args
,
args_size
),
llvm
::
ArrayRef
<
RewriterVar
*>
());
for
(
int
i
=
0
;
i
<
args_size
;
i
++
)
_args
[
i
]
->
bumpUse
();
for
(
int
i
=
0
;
i
<
args_additional_size
;
i
++
)
_args_additional
[
i
]
->
bumpUse
();
},
uses
,
ActionType
::
NORMAL
);
return
result
;
}
}
RewriterVar
*
JitFragmentWriter
::
emitCreateList
(
const
llvm
::
ArrayRef
<
RewriterVar
*>
values
)
{
RewriterVar
*
JitFragmentWriter
::
emitCreateList
(
const
llvm
::
ArrayRef
<
RewriterVar
*>
values
)
{
...
@@ -361,7 +352,7 @@ RewriterVar* JitFragmentWriter::emitExceptionMatches(RewriterVar* v, RewriterVar
...
@@ -361,7 +352,7 @@ RewriterVar* JitFragmentWriter::emitExceptionMatches(RewriterVar* v, RewriterVar
}
}
RewriterVar
*
JitFragmentWriter
::
emitGetAttr
(
RewriterVar
*
obj
,
BoxedString
*
s
,
AST_expr
*
node
)
{
RewriterVar
*
JitFragmentWriter
::
emitGetAttr
(
RewriterVar
*
obj
,
BoxedString
*
s
,
AST_expr
*
node
)
{
return
emitPPCall
((
void
*
)
getattr
,
{
obj
,
imm
(
s
)
},
2
,
512
,
node
,
getTypeRecorderForNode
(
node
))
return
emitPPCall
((
void
*
)
getattr
,
{
obj
,
imm
(
s
)
},
2
,
256
,
node
,
getTypeRecorderForNode
(
node
))
.
first
->
setType
(
RefType
::
OWNED
);
.
first
->
setType
(
RefType
::
OWNED
);
}
}
...
@@ -369,16 +360,15 @@ RewriterVar* JitFragmentWriter::emitGetBlockLocal(InternedString s, int vreg) {
...
@@ -369,16 +360,15 @@ RewriterVar* JitFragmentWriter::emitGetBlockLocal(InternedString s, int vreg) {
auto
it
=
local_syms
.
find
(
s
);
auto
it
=
local_syms
.
find
(
s
);
if
(
it
==
local_syms
.
end
())
{
if
(
it
==
local_syms
.
end
())
{
auto
r
=
emitGetLocal
(
s
,
vreg
);
auto
r
=
emitGetLocal
(
s
,
vreg
);
// TODO: clear out the vreg?
assert
(
r
->
reftype
==
RefType
::
OWNED
);
// assert(r->reftype == RefType::OWNED);
emitSetBlockLocal
(
s
,
vreg
,
r
);
// emitSetLocal(s, vreg, false, imm(nullptr));
// emitSetBlockLocal(s, r);
return
r
;
return
r
;
}
}
return
it
->
second
;
return
it
->
second
;
}
}
void
JitFragmentWriter
::
emitKillTemporary
(
InternedString
s
,
int
vreg
)
{
void
JitFragmentWriter
::
emitKillTemporary
(
InternedString
s
,
int
vreg
)
{
if
(
!
local_syms
.
count
(
s
))
emitSetLocal
(
s
,
vreg
,
false
,
imm
(
nullptr
));
emitSetLocal
(
s
,
vreg
,
false
,
imm
(
nullptr
));
}
}
...
@@ -393,23 +383,21 @@ RewriterVar* JitFragmentWriter::emitGetBoxedLocals() {
...
@@ -393,23 +383,21 @@ RewriterVar* JitFragmentWriter::emitGetBoxedLocals() {
}
}
RewriterVar
*
JitFragmentWriter
::
emitGetClsAttr
(
RewriterVar
*
obj
,
BoxedString
*
s
)
{
RewriterVar
*
JitFragmentWriter
::
emitGetClsAttr
(
RewriterVar
*
obj
,
BoxedString
*
s
)
{
return
emitPPCall
((
void
*
)
getclsattr
,
{
obj
,
imm
(
s
)
},
2
,
512
).
first
->
setType
(
RefType
::
OWNED
);
return
emitPPCall
((
void
*
)
getclsattr
,
{
obj
,
imm
(
s
)
},
2
,
256
).
first
->
setType
(
RefType
::
OWNED
);
}
}
RewriterVar
*
JitFragmentWriter
::
emitGetGlobal
(
Box
*
global
,
Box
edString
*
s
)
{
RewriterVar
*
JitFragmentWriter
::
emitGetGlobal
(
BoxedString
*
s
)
{
if
(
s
->
s
()
==
"None"
)
{
if
(
s
->
s
()
==
"None"
)
{
RewriterVar
*
r
=
imm
(
None
)
->
setType
(
RefType
::
BORROWED
);
RewriterVar
*
r
=
imm
(
None
)
->
setType
(
RefType
::
BORROWED
);
return
r
;
return
r
;
}
}
RewriterVar
*
args
[]
=
{
NULL
,
NULL
};
RewriterVar
*
globals
=
getInterp
()
->
getAttr
(
ASTInterpreterJitInterface
::
getGlobalsOffset
());
args
[
0
]
=
imm
(
global
);
return
emitPPCall
((
void
*
)
getGlobal
,
{
globals
,
imm
(
s
)
},
1
,
128
).
first
->
setType
(
RefType
::
OWNED
);
args
[
1
]
=
imm
(
s
);
return
emitPPCall
((
void
*
)
getGlobal
,
args
,
2
,
512
).
first
->
setType
(
RefType
::
OWNED
);
}
}
RewriterVar
*
JitFragmentWriter
::
emitGetItem
(
AST_expr
*
node
,
RewriterVar
*
value
,
RewriterVar
*
slice
)
{
RewriterVar
*
JitFragmentWriter
::
emitGetItem
(
AST_expr
*
node
,
RewriterVar
*
value
,
RewriterVar
*
slice
)
{
return
emitPPCall
((
void
*
)
getitem
,
{
value
,
slice
},
2
,
512
,
node
).
first
->
setType
(
RefType
::
OWNED
);
return
emitPPCall
((
void
*
)
getitem
,
{
value
,
slice
},
1
,
256
,
node
).
first
->
setType
(
RefType
::
OWNED
);
}
}
RewriterVar
*
JitFragmentWriter
::
emitGetLocal
(
InternedString
s
,
int
vreg
)
{
RewriterVar
*
JitFragmentWriter
::
emitGetLocal
(
InternedString
s
,
int
vreg
)
{
...
@@ -453,11 +441,11 @@ RewriterVar* JitFragmentWriter::emitLandingpad() {
...
@@ -453,11 +441,11 @@ RewriterVar* JitFragmentWriter::emitLandingpad() {
RewriterVar
*
JitFragmentWriter
::
emitNonzero
(
RewriterVar
*
v
)
{
RewriterVar
*
JitFragmentWriter
::
emitNonzero
(
RewriterVar
*
v
)
{
// nonzeroHelper returns bool
// nonzeroHelper returns bool
return
call
(
false
,
(
void
*
)
nonzeroHelper
,
v
)
->
setType
(
RefType
::
OWN
ED
);
return
call
(
false
,
(
void
*
)
nonzeroHelper
,
v
)
->
setType
(
RefType
::
BORROW
ED
);
}
}
RewriterVar
*
JitFragmentWriter
::
emitNotNonzero
(
RewriterVar
*
v
)
{
RewriterVar
*
JitFragmentWriter
::
emitNotNonzero
(
RewriterVar
*
v
)
{
return
call
(
false
,
(
void
*
)
notHelper
,
v
)
->
setType
(
RefType
::
OWN
ED
);
return
call
(
false
,
(
void
*
)
notHelper
,
v
)
->
setType
(
RefType
::
BORROW
ED
);
}
}
RewriterVar
*
JitFragmentWriter
::
emitRepr
(
RewriterVar
*
v
)
{
RewriterVar
*
JitFragmentWriter
::
emitRepr
(
RewriterVar
*
v
)
{
...
@@ -478,21 +466,18 @@ RewriterVar* JitFragmentWriter::emitRuntimeCall(AST_expr* node, RewriterVar* obj
...
@@ -478,21 +466,18 @@ RewriterVar* JitFragmentWriter::emitRuntimeCall(AST_expr* node, RewriterVar* obj
call_args
.
push_back
(
args
.
size
()
>
1
?
args
[
1
]
:
imm
(
0ul
));
call_args
.
push_back
(
args
.
size
()
>
1
?
args
[
1
]
:
imm
(
0ul
));
call_args
.
push_back
(
args
.
size
()
>
2
?
args
[
2
]
:
imm
(
0ul
));
call_args
.
push_back
(
args
.
size
()
>
2
?
args
[
2
]
:
imm
(
0ul
));
llvm
::
ArrayRef
<
RewriterVar
*>
additional_uses
;
if
(
args
.
size
()
>
3
)
{
if
(
args
.
size
()
>
3
)
{
RewriterVar
*
scratch
=
allocate
(
args
.
size
()
-
3
);
additional_uses
=
args
.
slice
(
3
);
for
(
int
i
=
0
;
i
<
args
.
size
()
-
3
;
++
i
)
RewriterVar
*
scratch
=
allocArgs
(
additional_uses
,
RewriterVar
::
SetattrType
::
REF_USED
);
scratch
->
setAttr
(
i
*
sizeof
(
void
*
),
args
[
i
+
3
],
RewriterVar
::
SetattrType
::
REF_USED
);
call_args
.
push_back
(
scratch
);
call_args
.
push_back
(
scratch
);
}
else
}
else
call_args
.
push_back
(
imm
(
0ul
));
call_args
.
push_back
(
imm
(
0ul
));
if
(
keyword_names
)
if
(
keyword_names
)
call_args
.
push_back
(
imm
(
keyword_names
));
call_args
.
push_back
(
imm
(
keyword_names
));
auto
r
=
emitPPCall
((
void
*
)
runtimeCall
,
call_args
,
2
,
640
,
node
,
type_recorder
).
first
->
setType
(
RefType
::
OWNED
);
return
emitPPCall
((
void
*
)
runtimeCall
,
call_args
,
2
,
640
,
node
,
type_recorder
,
additional_uses
)
for
(
int
i
=
3
;
i
<
args
.
size
();
i
++
)
{
.
first
->
setType
(
RefType
::
OWNED
);
args
[
i
]
->
refUsed
();
}
return
r
;
#else
#else
RewriterVar
*
argspec_var
=
imm
(
argspec
.
asInt
());
RewriterVar
*
argspec_var
=
imm
(
argspec
.
asInt
());
RewriterVar
*
keyword_names_var
=
keyword_names
?
imm
(
keyword_names
)
:
nullptr
;
RewriterVar
*
keyword_names_var
=
keyword_names
?
imm
(
keyword_names
)
:
nullptr
;
...
@@ -535,22 +520,40 @@ std::vector<RewriterVar*> JitFragmentWriter::emitUnpackIntoArray(RewriterVar* v,
...
@@ -535,22 +520,40 @@ std::vector<RewriterVar*> JitFragmentWriter::emitUnpackIntoArray(RewriterVar* v,
}
}
RewriterVar
*
JitFragmentWriter
::
emitYield
(
RewriterVar
*
v
)
{
RewriterVar
*
JitFragmentWriter
::
emitYield
(
RewriterVar
*
v
)
{
auto
rtn
=
call
(
false
,
(
void
*
)
ASTInterpreterJitInterface
::
yieldHelper
,
getInterp
(),
v
)
->
setType
(
RefType
::
OWNED
);
llvm
::
SmallVector
<
RewriterVar
*
,
16
>
local_args
;
local_args
.
push_back
(
interp
->
getAttr
(
ASTInterpreterJitInterface
::
getCreatedClosureOffset
()));
// we have to pass all owned references which are not stored in the vregs to yield() so that the GC can traverse it
for
(
auto
&&
sym
:
local_syms
)
{
if
(
sym
.
second
==
v
)
continue
;
if
(
sym
.
second
->
reftype
==
RefType
::
OWNED
)
local_args
.
push_back
(
sym
.
second
);
}
// erase duplicate entries
std
::
sort
(
local_args
.
begin
(),
local_args
.
end
());
local_args
.
erase
(
std
::
unique
(
local_args
.
begin
(),
local_args
.
end
()),
local_args
.
end
());
auto
&&
args
=
allocArgs
(
local_args
,
RewriterVar
::
SetattrType
::
REF_USED
);
RewriterVar
*
generator
=
interp
->
getAttr
(
ASTInterpreterJitInterface
::
getGeneratorOffset
());
auto
rtn
=
call
(
false
,
(
void
*
)
yield
,
{
generator
,
v
,
args
,
imm
(
local_args
.
size
())
},
{},
local_args
)
->
setType
(
RefType
::
OWNED
);
v
->
refConsumed
();
v
->
refConsumed
();
return
rtn
;
return
rtn
;
}
}
void
JitFragmentWriter
::
emitDelAttr
(
RewriterVar
*
target
,
BoxedString
*
attr
)
{
void
JitFragmentWriter
::
emitDelAttr
(
RewriterVar
*
target
,
BoxedString
*
attr
)
{
emitPPCall
((
void
*
)
delattr
,
{
target
,
imm
(
attr
)
},
1
,
512
).
first
;
emitPPCall
((
void
*
)
delattr
,
{
target
,
imm
(
attr
)
},
1
,
144
).
first
;
}
}
void
JitFragmentWriter
::
emitDelGlobal
(
BoxedString
*
name
)
{
void
JitFragmentWriter
::
emitDelGlobal
(
BoxedString
*
name
)
{
RewriterVar
*
globals
=
getInterp
()
->
getAttr
(
ASTInterpreterJitInterface
::
getGlobalsOffset
());
RewriterVar
*
globals
=
getInterp
()
->
getAttr
(
ASTInterpreterJitInterface
::
getGlobalsOffset
());
emitPPCall
((
void
*
)
delGlobal
,
{
globals
,
imm
(
name
)
},
1
,
512
).
first
;
// does not get rewriten yet
// emitPPCall((void*)delGlobal, { globals, imm(name) }, 1, 512).first;
call
(
false
,
(
void
*
)
delGlobal
,
globals
,
imm
(
name
));
}
}
void
JitFragmentWriter
::
emitDelItem
(
RewriterVar
*
target
,
RewriterVar
*
slice
)
{
void
JitFragmentWriter
::
emitDelItem
(
RewriterVar
*
target
,
RewriterVar
*
slice
)
{
emitPPCall
((
void
*
)
delitem
,
{
target
,
slice
},
1
,
512
).
first
;
emitPPCall
((
void
*
)
delitem
,
{
target
,
slice
},
1
,
256
).
first
;
}
}
void
JitFragmentWriter
::
emitDelName
(
InternedString
name
)
{
void
JitFragmentWriter
::
emitDelName
(
InternedString
name
)
{
...
@@ -623,14 +626,16 @@ void JitFragmentWriter::emitReturn(RewriterVar* v) {
...
@@ -623,14 +626,16 @@ void JitFragmentWriter::emitReturn(RewriterVar* v) {
}
}
void
JitFragmentWriter
::
emitSetAttr
(
AST_expr
*
node
,
RewriterVar
*
obj
,
BoxedString
*
s
,
STOLEN
(
RewriterVar
*
)
attr
)
{
void
JitFragmentWriter
::
emitSetAttr
(
AST_expr
*
node
,
RewriterVar
*
obj
,
BoxedString
*
s
,
STOLEN
(
RewriterVar
*
)
attr
)
{
auto
rtn
=
emitPPCall
((
void
*
)
setattr
,
{
obj
,
imm
(
s
),
attr
},
2
,
512
,
node
);
auto
rtn
=
emitPPCall
((
void
*
)
setattr
,
{
obj
,
imm
(
s
),
attr
},
2
,
256
,
node
);
attr
->
refConsumed
(
rtn
.
second
);
attr
->
refConsumed
(
rtn
.
second
);
}
}
void
JitFragmentWriter
::
emitSetBlockLocal
(
InternedString
s
,
STOLEN
(
RewriterVar
*
)
v
)
{
void
JitFragmentWriter
::
emitSetBlockLocal
(
InternedString
s
,
int
vreg
,
STOLEN
(
RewriterVar
*
)
v
)
{
if
(
LOG_BJIT_ASSEMBLY
)
if
(
LOG_BJIT_ASSEMBLY
)
comment
(
"BJIT: emitSetBlockLocal() start"
);
comment
(
"BJIT: emitSetBlockLocal() start"
);
RewriterVar
*
prev
=
local_syms
[
s
];
RewriterVar
*
prev
=
local_syms
[
s
];
if
(
!
prev
)
emitSetLocal
(
s
,
vreg
,
false
,
imm
(
nullptr
));
// clear out the vreg
local_syms
[
s
]
=
v
;
local_syms
[
s
]
=
v
;
if
(
LOG_BJIT_ASSEMBLY
)
if
(
LOG_BJIT_ASSEMBLY
)
comment
(
"BJIT: emitSetBlockLocal() end"
);
comment
(
"BJIT: emitSetBlockLocal() end"
);
...
@@ -647,8 +652,13 @@ void JitFragmentWriter::emitSetExcInfo(RewriterVar* type, RewriterVar* value, Re
...
@@ -647,8 +652,13 @@ void JitFragmentWriter::emitSetExcInfo(RewriterVar* type, RewriterVar* value, Re
traceback
->
refConsumed
();
traceback
->
refConsumed
();
}
}
void
JitFragmentWriter
::
emitSetGlobal
(
Box
*
global
,
BoxedString
*
s
,
STOLEN
(
RewriterVar
*
)
v
)
{
void
JitFragmentWriter
::
emitSetGlobal
(
BoxedString
*
s
,
STOLEN
(
RewriterVar
*
)
v
,
bool
are_globals_from_module
)
{
auto
rtn
=
emitPPCall
((
void
*
)
setGlobal
,
{
imm
(
global
),
imm
(
s
),
v
},
2
,
512
);
RewriterVar
*
globals
=
getInterp
()
->
getAttr
(
ASTInterpreterJitInterface
::
getGlobalsOffset
());
std
::
pair
<
RewriterVar
*
,
RewriterAction
*>
rtn
;
if
(
are_globals_from_module
)
rtn
=
emitPPCall
((
void
*
)
setattr
,
{
globals
,
imm
(
s
),
v
},
1
,
256
);
else
rtn
=
emitPPCall
((
void
*
)
setGlobal
,
{
globals
,
imm
(
s
),
v
},
1
,
256
);
v
->
refConsumed
(
rtn
.
second
);
v
->
refConsumed
(
rtn
.
second
);
}
}
...
@@ -853,31 +863,38 @@ uint64_t JitFragmentWriter::asUInt(InternedString s) {
...
@@ -853,31 +863,38 @@ uint64_t JitFragmentWriter::asUInt(InternedString s) {
}
}
#endif
#endif
std
::
pair
<
RewriterVar
*
,
RewriterAction
*>
JitFragmentWriter
::
emitPPCall
(
void
*
func_addr
,
std
::
pair
<
RewriterVar
*
,
RewriterAction
*>
llvm
::
ArrayRef
<
RewriterVar
*>
args
,
int
num_slots
,
JitFragmentWriter
::
emitPPCall
(
void
*
func_addr
,
llvm
::
ArrayRef
<
RewriterVar
*>
args
,
unsigned
char
num_slots
,
int
slot_size
,
AST
*
ast_node
,
unsigned
short
slot_size
,
AST
*
ast_node
,
TypeRecorder
*
type_recorder
,
TypeRecorder
*
type_recorder
)
{
llvm
::
ArrayRef
<
RewriterVar
*>
additional_uses
)
{
if
(
LOG_BJIT_ASSEMBLY
)
if
(
LOG_BJIT_ASSEMBLY
)
comment
(
"BJIT: emitPPCall() start"
);
comment
(
"BJIT: emitPPCall() start"
);
RewriterVar
::
SmallVector
args_vec
(
args
.
begin
(),
args
.
end
());
RewriterVar
::
SmallVector
args_vec
(
args
.
begin
(),
args
.
end
());
#if ENABLE_BASELINEJIT_ICS
#if ENABLE_BASELINEJIT_ICS
RewriterVar
*
result
=
createNewVar
();
RewriterVar
*
result
=
createNewVar
();
auto
args_array_ref
=
regionAllocArgs
(
args
,
additional_uses
);
assert
(
args
.
size
()
<
1ul
<<
32
);
int
args_size
=
args
.
size
();
int
args_size
=
args
.
size
();
RewriterVar
**
_args
=
(
RewriterVar
**
)
regionAlloc
(
sizeof
(
RewriterVar
*
)
*
args_size
);
assert
(
additional_uses
.
size
()
<
1
<<
8
);
memcpy
(
_args
,
args
.
begin
(),
sizeof
(
RewriterVar
*
)
*
args_size
);
unsigned
char
num_additional
=
additional_uses
.
size
();
RewriterVar
**
args_array
=
args_array_ref
.
data
();
RewriterAction
*
call_action
=
addAction
([
=
]()
{
RewriterAction
*
call_action
this
->
_emitPPCall
(
result
,
func_addr
,
llvm
::
ArrayRef
<
RewriterVar
*>
(
_args
,
args_size
),
num_slots
,
slot_size
,
=
addAction
([
this
,
result
,
func_addr
,
ast_node
,
args_array
,
args_size
,
slot_size
,
num_slots
,
num_additional
]()
{
ast_node
);
auto
all_args
=
llvm
::
makeArrayRef
(
args_array
,
args_size
+
num_additional
);
},
args
,
ActionType
::
NORMAL
);
auto
args
=
all_args
.
slice
(
0
,
args_size
);
this
->
_emitPPCall
(
result
,
func_addr
,
args
,
num_slots
,
slot_size
,
ast_node
,
all_args
);
},
args_array_ref
,
ActionType
::
NORMAL
);
if
(
type_recorder
)
{
if
(
type_recorder
)
{
RewriterVar
*
type_recorder_var
=
imm
(
type_recorder
);
RewriterVar
*
type_recorder_var
=
imm
(
type_recorder
);
RewriterVar
*
obj_cls_var
=
result
->
getAttr
(
offsetof
(
Box
,
cls
));
RewriterVar
*
obj_cls_var
=
result
->
getAttr
(
offsetof
(
Box
,
cls
));
addAction
([
=
]()
{
_emitRecordType
(
type_recorder_var
,
obj_cls_var
);
},
{
type_recorder_var
,
obj_cls_var
},
addAction
([
=
]()
{
ActionType
::
NORMAL
);
_emitRecordType
(
type_recorder_var
,
obj_cls_var
);
result
->
refUsed
();
result
->
bumpUse
();
},
{
type_recorder_var
,
obj_cls_var
,
result
},
ActionType
::
NORMAL
);
emitPendingCallsCheck
();
emitPendingCallsCheck
();
return
std
::
make_pair
(
result
,
call_action
);
return
std
::
make_pair
(
result
,
call_action
);
...
@@ -952,12 +969,12 @@ Box* JitFragmentWriter::hasnextHelper(Box* b) {
...
@@ -952,12 +969,12 @@ Box* JitFragmentWriter::hasnextHelper(Box* b) {
return
boxBool
(
pyston
::
hasnext
(
b
));
return
boxBool
(
pyston
::
hasnext
(
b
));
}
}
B
ox
*
JitFragmentWriter
::
nonzeroHelper
(
Box
*
b
)
{
B
ORROWED
(
Box
*
)
JitFragmentWriter
::
nonzeroHelper
(
Box
*
b
)
{
return
b
oxBool
(
b
->
nonzeroIC
())
;
return
b
->
nonzeroIC
()
?
True
:
False
;
}
}
B
ox
*
JitFragmentWriter
::
notHelper
(
Box
*
b
)
{
B
ORROWED
(
Box
*
)
JitFragmentWriter
::
notHelper
(
Box
*
b
)
{
return
b
oxBool
(
!
b
->
nonzeroIC
())
;
return
b
->
nonzeroIC
()
?
False
:
True
;
}
}
Box
*
JitFragmentWriter
::
runtimeCallHelper
(
Box
*
obj
,
ArgPassSpec
argspec
,
TypeRecorder
*
type_recorder
,
Box
**
args
,
Box
*
JitFragmentWriter
::
runtimeCallHelper
(
Box
*
obj
,
ArgPassSpec
argspec
,
TypeRecorder
*
type_recorder
,
Box
**
args
,
...
@@ -972,7 +989,7 @@ void JitFragmentWriter::_emitGetLocal(RewriterVar* val_var, const char* name) {
...
@@ -972,7 +989,7 @@ void JitFragmentWriter::_emitGetLocal(RewriterVar* val_var, const char* name) {
assembler
::
Register
var_reg
=
val_var
->
getInReg
();
assembler
::
Register
var_reg
=
val_var
->
getInReg
();
assembler
->
test
(
var_reg
,
var_reg
);
assembler
->
test
(
var_reg
,
var_reg
);
_setupCall
(
false
,
RewriterVar
::
SmallVector
(),
RewriterVar
::
SmallVector
()
);
_setupCall
(
false
,
{}
);
{
{
assembler
::
ForwardJump
jnz
(
*
assembler
,
assembler
::
COND_NOT_ZERO
);
assembler
::
ForwardJump
jnz
(
*
assembler
,
assembler
::
COND_NOT_ZERO
);
assembler
->
mov
(
assembler
::
Immediate
((
uint64_t
)
name
),
assembler
::
RDI
);
assembler
->
mov
(
assembler
::
Immediate
((
uint64_t
)
name
),
assembler
::
RDI
);
...
@@ -1001,8 +1018,10 @@ void JitFragmentWriter::_emitJump(CFGBlock* b, RewriterVar* block_next, ExitInfo
...
@@ -1001,8 +1018,10 @@ void JitFragmentWriter::_emitJump(CFGBlock* b, RewriterVar* block_next, ExitInfo
exit_info
.
exit_start
=
assembler
->
curInstPointer
();
exit_info
.
exit_start
=
assembler
->
curInstPointer
();
block_next
->
getInReg
(
assembler
::
RAX
,
true
);
block_next
->
getInReg
(
assembler
::
RAX
,
true
);
assembler
->
add
(
assembler
::
Immediate
(
JitCodeBlock
::
sp_adjustment
),
assembler
::
RSP
);
assembler
->
add
(
assembler
::
Immediate
(
JitCodeBlock
::
sp_adjustment
),
assembler
::
RSP
);
assembler
->
pop
(
assembler
::
R12
);
assembler
->
pop
(
assembler
::
R13
);
assembler
->
pop
(
assembler
::
R13
);
assembler
->
pop
(
assembler
::
R14
);
assembler
->
pop
(
assembler
::
R14
);
assembler
->
pop
(
assembler
::
R15
);
assembler
->
retq
();
assembler
->
retq
();
// make sure we have at least 'min_patch_size' of bytes available.
// make sure we have at least 'min_patch_size' of bytes available.
...
@@ -1034,8 +1053,10 @@ void JitFragmentWriter::_emitOSRPoint() {
...
@@ -1034,8 +1053,10 @@ void JitFragmentWriter::_emitOSRPoint() {
assembler
->
clear_reg
(
assembler
::
RAX
);
// = next block to execute
assembler
->
clear_reg
(
assembler
::
RAX
);
// = next block to execute
assembler
->
mov
(
assembler
::
Immediate
(
ASTInterpreterJitInterface
::
osr_dummy_value
),
assembler
::
RDX
);
assembler
->
mov
(
assembler
::
Immediate
(
ASTInterpreterJitInterface
::
osr_dummy_value
),
assembler
::
RDX
);
assembler
->
add
(
assembler
::
Immediate
(
JitCodeBlock
::
sp_adjustment
),
assembler
::
RSP
);
assembler
->
add
(
assembler
::
Immediate
(
JitCodeBlock
::
sp_adjustment
),
assembler
::
RSP
);
assembler
->
pop
(
assembler
::
R12
);
assembler
->
pop
(
assembler
::
R13
);
assembler
->
pop
(
assembler
::
R13
);
assembler
->
pop
(
assembler
::
R14
);
assembler
->
pop
(
assembler
::
R14
);
assembler
->
pop
(
assembler
::
R15
);
assembler
->
retq
();
assembler
->
retq
();
}
}
interp
->
bumpUse
();
interp
->
bumpUse
();
...
@@ -1043,7 +1064,8 @@ void JitFragmentWriter::_emitOSRPoint() {
...
@@ -1043,7 +1064,8 @@ void JitFragmentWriter::_emitOSRPoint() {
}
}
void
JitFragmentWriter
::
_emitPPCall
(
RewriterVar
*
result
,
void
*
func_addr
,
llvm
::
ArrayRef
<
RewriterVar
*>
args
,
void
JitFragmentWriter
::
_emitPPCall
(
RewriterVar
*
result
,
void
*
func_addr
,
llvm
::
ArrayRef
<
RewriterVar
*>
args
,
int
num_slots
,
int
slot_size
,
AST
*
ast_node
)
{
int
num_slots
,
int
slot_size
,
AST
*
ast_node
,
llvm
::
ArrayRef
<
RewriterVar
*>
vars_to_bump
)
{
assembler
::
Register
r
=
allocReg
(
assembler
::
R11
);
assembler
::
Register
r
=
allocReg
(
assembler
::
R11
);
if
(
args
.
size
()
>
6
)
{
// only 6 args can get passed in registers.
if
(
args
.
size
()
>
6
)
{
// only 6 args can get passed in registers.
...
@@ -1052,11 +1074,9 @@ void JitFragmentWriter::_emitPPCall(RewriterVar* result, void* func_addr, llvm::
...
@@ -1052,11 +1074,9 @@ void JitFragmentWriter::_emitPPCall(RewriterVar* result, void* func_addr, llvm::
assembler
::
Register
reg
=
args
[
i
]
->
getInReg
(
Location
::
any
(),
true
);
assembler
::
Register
reg
=
args
[
i
]
->
getInReg
(
Location
::
any
(),
true
);
assembler
->
mov
(
reg
,
assembler
::
Indirect
(
assembler
::
RSP
,
sizeof
(
void
*
)
*
(
i
-
6
)));
assembler
->
mov
(
reg
,
assembler
::
Indirect
(
assembler
::
RSP
,
sizeof
(
void
*
)
*
(
i
-
6
)));
}
}
RewriterVar
::
SmallVector
reg_args
(
args
.
begin
(),
args
.
begin
()
+
6
);
_setupCall
(
false
,
args
.
slice
(
0
,
6
),
{},
Location
::
any
(),
vars_to_bump
);
assert
(
reg_args
.
size
()
==
6
);
_setupCall
(
false
,
reg_args
,
RewriterVar
::
SmallVector
());
}
else
}
else
_setupCall
(
false
,
args
,
RewriterVar
::
SmallVector
()
);
_setupCall
(
false
,
args
,
{},
Location
::
any
(),
vars_to_bump
);
if
(
failed
)
if
(
failed
)
return
;
return
;
...
@@ -1101,15 +1121,8 @@ void JitFragmentWriter::_emitPPCall(RewriterVar* result, void* func_addr, llvm::
...
@@ -1101,15 +1121,8 @@ void JitFragmentWriter::_emitPPCall(RewriterVar* result, void* func_addr, llvm::
result
->
releaseIfNoUses
();
result
->
releaseIfNoUses
();
// TODO: it would be nice to be able to bumpUse on these earlier so that we could potentially avoid spilling
for
(
RewriterVar
*
use
:
vars_to_bump
)
{
// the args across the call if we don't need to.
use
->
bumpUseLateIfNecessary
();
// This had to get moved to the very end of this function due to the fact that bumpUse can cause refcounting
// operations to happen.
// I'm not sure though that just moving this earlier is good enough though -- we also might need to teach setupCall
// that the args might not be needed afterwards?
// Anyway this feels like micro-optimizations at the moment and we can figure it out later.
for
(
RewriterVar
*
arg
:
args
)
{
arg
->
bumpUse
();
}
}
}
}
...
@@ -1137,8 +1150,10 @@ void JitFragmentWriter::_emitReturn(RewriterVar* return_val) {
...
@@ -1137,8 +1150,10 @@ void JitFragmentWriter::_emitReturn(RewriterVar* return_val) {
return_val
->
getInReg
(
assembler
::
RDX
,
true
);
return_val
->
getInReg
(
assembler
::
RDX
,
true
);
assembler
->
clear_reg
(
assembler
::
RAX
);
assembler
->
clear_reg
(
assembler
::
RAX
);
assembler
->
add
(
assembler
::
Immediate
(
JitCodeBlock
::
sp_adjustment
),
assembler
::
RSP
);
assembler
->
add
(
assembler
::
Immediate
(
JitCodeBlock
::
sp_adjustment
),
assembler
::
RSP
);
assembler
->
pop
(
assembler
::
R12
);
assembler
->
pop
(
assembler
::
R13
);
assembler
->
pop
(
assembler
::
R13
);
assembler
->
pop
(
assembler
::
R14
);
assembler
->
pop
(
assembler
::
R14
);
assembler
->
pop
(
assembler
::
R15
);
assembler
->
retq
();
assembler
->
retq
();
return_val
->
bumpUse
();
return_val
->
bumpUse
();
}
}
...
@@ -1156,12 +1171,12 @@ void JitFragmentWriter::_emitSideExit(STOLEN(RewriterVar*) var, RewriterVar* val
...
@@ -1156,12 +1171,12 @@ void JitFragmentWriter::_emitSideExit(STOLEN(RewriterVar*) var, RewriterVar* val
// Really, we should probably do a decref on either side post-jump.
// Really, we should probably do a decref on either side post-jump.
// But the automatic refcounter doesn't support that, and since the value is either True or False,
// But the automatic refcounter doesn't support that, and since the value is either True or False,
// we can get away with doing the decref early.
// we can get away with doing the decref early.
// TODO: better solution is to just make NONZERO return a borrowed ref, so we don't have to decref at all.
if
(
var
->
reftype
==
RefType
::
OWNED
)
{
_decref
(
var
);
_decref
(
var
);
// Hax: override the automatic refcount system
// Hax: override the automatic refcount system
assert
(
var
->
reftype
==
RefType
::
OWNED
);
assert
(
var
->
num_refs_consumed
==
0
);
var
->
reftype
=
RefType
::
BORROWED
;
var
->
reftype
=
RefType
::
BORROWED
;
}
assert
(
var
->
num_refs_consumed
==
0
);
assembler
::
Register
var_reg
=
var
->
getInReg
();
assembler
::
Register
var_reg
=
var
->
getInReg
();
if
(
isLargeConstant
(
val
))
{
if
(
isLargeConstant
(
val
))
{
...
...
src/codegen/baseline_jit.h
View file @
e7174486
...
@@ -23,6 +23,9 @@
...
@@ -23,6 +23,9 @@
namespace
pyston
{
namespace
pyston
{
// passes MAP_32BIT to mmap when allocating the memory for the bjit code.
// it's nice for inspecting the generated asm because the debugger is able to show the name of called C/C++ functions
#define ENABLE_BASELINEJIT_MAP_32BIT 1
#define ENABLE_BASELINEJIT_ICS 1
#define ENABLE_BASELINEJIT_ICS 1
class
AST_stmt
;
class
AST_stmt
;
...
@@ -70,6 +73,7 @@ class JitFragmentWriter;
...
@@ -70,6 +73,7 @@ class JitFragmentWriter;
// register or stack slot but we aren't if it outlives the block - we have to store it in the interpreter instance.
// register or stack slot but we aren't if it outlives the block - we have to store it in the interpreter instance.
//
//
// We use the following callee-save regs to speed up the generated code:
// We use the following callee-save regs to speed up the generated code:
// r12, r15: temporary values
// r13: pointer to ASTInterpreter instance
// r13: pointer to ASTInterpreter instance
// r14: pointer to the vregs array
// r14: pointer to the vregs array
//
//
...
@@ -90,8 +94,10 @@ class JitFragmentWriter;
...
@@ -90,8 +94,10 @@ class JitFragmentWriter;
//
//
// Basic layout of generated code block is:
// Basic layout of generated code block is:
// entry_code:
// entry_code:
// push %r15 ; save r15
// push %r14 ; save r14
// push %r14 ; save r14
// push %r13 ; save r13
// push %r13 ; save r13
// push %r12 ; save r12
// sub $0x118,%rsp ; setup scratch, 0x118 = scratch_size + 16 = space for two func args passed on the
// sub $0x118,%rsp ; setup scratch, 0x118 = scratch_size + 16 = space for two func args passed on the
// stack + 8 byte for stack alignment
// stack + 8 byte for stack alignment
// mov %rdi,%r13 ; copy the pointer to ASTInterpreter instance into r13
// mov %rdi,%r13 ; copy the pointer to ASTInterpreter instance into r13
...
@@ -107,8 +113,10 @@ class JitFragmentWriter;
...
@@ -107,8 +113,10 @@ class JitFragmentWriter;
// jne end_side_exit
// jne end_side_exit
// movabs $0x215bb60,%rax ; rax = CFGBlock* to interpret next (rax is the 1. return reg)
// movabs $0x215bb60,%rax ; rax = CFGBlock* to interpret next (rax is the 1. return reg)
// add $0x118,%rsp ; restore stack pointer
// add $0x118,%rsp ; restore stack pointer
// pop %r12 ; restore r12
// pop %r13 ; restore r13
// pop %r13 ; restore r13
// pop %r14 ; restore r14
// pop %r14 ; restore r14
// pop %r15 ; restore r15
// ret ; exit to the interpreter which will interpret the specified CFGBLock*
// ret ; exit to the interpreter which will interpret the specified CFGBLock*
// end_side_exit:
// end_side_exit:
// ....
// ....
...
@@ -120,8 +128,10 @@ class JitFragmentWriter;
...
@@ -120,8 +128,10 @@ class JitFragmentWriter;
// in this case 0 which means we are finished
// in this case 0 which means we are finished
// movabs $0x1270014108,%rdx ; rdx must contain the Box* value to return
// movabs $0x1270014108,%rdx ; rdx must contain the Box* value to return
// add $0x118,%rsp ; restore stack pointer
// add $0x118,%rsp ; restore stack pointer
// pop %r12 ; restore r12
// pop %r13 ; restore r13
// pop %r13 ; restore r13
// pop %r14 ; restore r14
// pop %r14 ; restore r14
// pop %r15 ; restore r15
// ret
// ret
//
//
// nth_JitFragment:
// nth_JitFragment:
...
@@ -140,8 +150,18 @@ public:
...
@@ -140,8 +150,18 @@ public:
static
constexpr
int
sp_adjustment
=
scratch_size
+
num_stack_args
*
8
+
8
/* = alignment */
;
static
constexpr
int
sp_adjustment
=
scratch_size
+
num_stack_args
*
8
+
8
/* = alignment */
;
private:
private:
struct
MemoryManager
{
private:
uint8_t
*
addr
;
public:
MemoryManager
();
~
MemoryManager
();
uint8_t
*
get
()
{
return
addr
;
}
};
// the memory block contains the EH frame directly followed by the generated machine code.
// the memory block contains the EH frame directly followed by the generated machine code.
std
::
unique_ptr
<
uint8_t
[]
>
memory
;
MemoryManager
memory
;
int
entry_offset
;
int
entry_offset
;
assembler
::
Assembler
a
;
assembler
::
Assembler
a
;
bool
is_currently_writing
;
bool
is_currently_writing
;
...
@@ -234,7 +254,7 @@ public:
...
@@ -234,7 +254,7 @@ public:
RewriterVar
*
emitGetBoxedLocal
(
BoxedString
*
s
);
RewriterVar
*
emitGetBoxedLocal
(
BoxedString
*
s
);
RewriterVar
*
emitGetBoxedLocals
();
RewriterVar
*
emitGetBoxedLocals
();
RewriterVar
*
emitGetClsAttr
(
RewriterVar
*
obj
,
BoxedString
*
s
);
RewriterVar
*
emitGetClsAttr
(
RewriterVar
*
obj
,
BoxedString
*
s
);
RewriterVar
*
emitGetGlobal
(
Box
*
global
,
Box
edString
*
s
);
RewriterVar
*
emitGetGlobal
(
BoxedString
*
s
);
RewriterVar
*
emitGetItem
(
AST_expr
*
node
,
RewriterVar
*
value
,
RewriterVar
*
slice
);
RewriterVar
*
emitGetItem
(
AST_expr
*
node
,
RewriterVar
*
value
,
RewriterVar
*
slice
);
RewriterVar
*
emitGetLocal
(
InternedString
s
,
int
vreg
);
RewriterVar
*
emitGetLocal
(
InternedString
s
,
int
vreg
);
RewriterVar
*
emitGetPystonIter
(
RewriterVar
*
v
);
RewriterVar
*
emitGetPystonIter
(
RewriterVar
*
v
);
...
@@ -265,10 +285,10 @@ public:
...
@@ -265,10 +285,10 @@ public:
void
emitRaise3
(
RewriterVar
*
arg0
,
RewriterVar
*
arg1
,
RewriterVar
*
arg2
);
void
emitRaise3
(
RewriterVar
*
arg0
,
RewriterVar
*
arg1
,
RewriterVar
*
arg2
);
void
emitReturn
(
RewriterVar
*
v
);
void
emitReturn
(
RewriterVar
*
v
);
void
emitSetAttr
(
AST_expr
*
node
,
RewriterVar
*
obj
,
BoxedString
*
s
,
STOLEN
(
RewriterVar
*
)
attr
);
void
emitSetAttr
(
AST_expr
*
node
,
RewriterVar
*
obj
,
BoxedString
*
s
,
STOLEN
(
RewriterVar
*
)
attr
);
void
emitSetBlockLocal
(
InternedString
s
,
STOLEN
(
RewriterVar
*
)
v
);
void
emitSetBlockLocal
(
InternedString
s
,
int
vreg
,
STOLEN
(
RewriterVar
*
)
v
);
void
emitSetCurrentInst
(
AST_stmt
*
node
);
void
emitSetCurrentInst
(
AST_stmt
*
node
);
void
emitSetExcInfo
(
RewriterVar
*
type
,
RewriterVar
*
value
,
RewriterVar
*
traceback
);
void
emitSetExcInfo
(
RewriterVar
*
type
,
RewriterVar
*
value
,
RewriterVar
*
traceback
);
void
emitSetGlobal
(
Box
*
global
,
BoxedString
*
s
,
STOLEN
(
RewriterVar
*
)
v
);
void
emitSetGlobal
(
Box
edString
*
s
,
STOLEN
(
RewriterVar
*
)
v
,
bool
are_globals_from_module
);
void
emitSetItemName
(
BoxedString
*
s
,
RewriterVar
*
v
);
void
emitSetItemName
(
BoxedString
*
s
,
RewriterVar
*
v
);
void
emitSetItem
(
RewriterVar
*
target
,
RewriterVar
*
slice
,
RewriterVar
*
value
);
void
emitSetItem
(
RewriterVar
*
target
,
RewriterVar
*
slice
,
RewriterVar
*
value
);
void
emitSetLocal
(
InternedString
s
,
int
vreg
,
bool
set_closure
,
STOLEN
(
RewriterVar
*
)
v
);
void
emitSetLocal
(
InternedString
s
,
int
vreg
,
bool
set_closure
,
STOLEN
(
RewriterVar
*
)
v
);
...
@@ -296,8 +316,9 @@ private:
...
@@ -296,8 +316,9 @@ private:
RewriterVar
*
emitCallWithAllocatedArgs
(
void
*
func_addr
,
const
llvm
::
ArrayRef
<
RewriterVar
*>
args
,
RewriterVar
*
emitCallWithAllocatedArgs
(
void
*
func_addr
,
const
llvm
::
ArrayRef
<
RewriterVar
*>
args
,
const
llvm
::
ArrayRef
<
RewriterVar
*>
additional_uses
);
const
llvm
::
ArrayRef
<
RewriterVar
*>
additional_uses
);
std
::
pair
<
RewriterVar
*
,
RewriterAction
*>
emitPPCall
(
void
*
func_addr
,
llvm
::
ArrayRef
<
RewriterVar
*>
args
,
std
::
pair
<
RewriterVar
*
,
RewriterAction
*>
emitPPCall
(
void
*
func_addr
,
llvm
::
ArrayRef
<
RewriterVar
*>
args
,
int
num_slots
,
int
slot_size
,
AST
*
ast_node
=
NULL
,
unsigned
char
num_slots
,
unsigned
short
slot_size
,
TypeRecorder
*
type_recorder
=
NULL
);
AST
*
ast_node
=
NULL
,
TypeRecorder
*
type_recorder
=
NULL
,
llvm
::
ArrayRef
<
RewriterVar
*>
additional_uses
=
{});
static
void
assertNameDefinedHelper
(
const
char
*
id
);
static
void
assertNameDefinedHelper
(
const
char
*
id
);
static
Box
*
callattrHelper
(
Box
*
obj
,
BoxedString
*
attr
,
CallattrFlags
flags
,
TypeRecorder
*
type_recorder
,
static
Box
*
callattrHelper
(
Box
*
obj
,
BoxedString
*
attr
,
CallattrFlags
flags
,
TypeRecorder
*
type_recorder
,
...
@@ -308,8 +329,8 @@ private:
...
@@ -308,8 +329,8 @@ private:
static
Box
*
createTupleHelper
(
uint64_t
num
,
Box
**
data
);
static
Box
*
createTupleHelper
(
uint64_t
num
,
Box
**
data
);
static
Box
*
exceptionMatchesHelper
(
Box
*
obj
,
Box
*
cls
);
static
Box
*
exceptionMatchesHelper
(
Box
*
obj
,
Box
*
cls
);
static
Box
*
hasnextHelper
(
Box
*
b
);
static
Box
*
hasnextHelper
(
Box
*
b
);
static
B
ox
*
nonzeroHelper
(
Box
*
b
);
static
B
ORROWED
(
Box
*
)
nonzeroHelper
(
Box
*
b
);
static
B
ox
*
notHelper
(
Box
*
b
);
static
B
ORROWED
(
Box
*
)
notHelper
(
Box
*
b
);
static
Box
*
runtimeCallHelper
(
Box
*
obj
,
ArgPassSpec
argspec
,
TypeRecorder
*
type_recorder
,
Box
**
args
,
static
Box
*
runtimeCallHelper
(
Box
*
obj
,
ArgPassSpec
argspec
,
TypeRecorder
*
type_recorder
,
Box
**
args
,
std
::
vector
<
BoxedString
*>*
keyword_names
);
std
::
vector
<
BoxedString
*>*
keyword_names
);
...
@@ -317,7 +338,7 @@ private:
...
@@ -317,7 +338,7 @@ private:
void
_emitJump
(
CFGBlock
*
b
,
RewriterVar
*
block_next
,
ExitInfo
&
exit_info
);
void
_emitJump
(
CFGBlock
*
b
,
RewriterVar
*
block_next
,
ExitInfo
&
exit_info
);
void
_emitOSRPoint
();
void
_emitOSRPoint
();
void
_emitPPCall
(
RewriterVar
*
result
,
void
*
func_addr
,
llvm
::
ArrayRef
<
RewriterVar
*>
args
,
int
num_slots
,
void
_emitPPCall
(
RewriterVar
*
result
,
void
*
func_addr
,
llvm
::
ArrayRef
<
RewriterVar
*>
args
,
int
num_slots
,
int
slot_size
,
AST
*
ast_node
);
int
slot_size
,
AST
*
ast_node
,
llvm
::
ArrayRef
<
RewriterVar
*>
vars_to_bump
);
void
_emitRecordType
(
RewriterVar
*
type_recorder_var
,
RewriterVar
*
obj_cls_var
);
void
_emitRecordType
(
RewriterVar
*
type_recorder_var
,
RewriterVar
*
obj_cls_var
);
void
_emitReturn
(
RewriterVar
*
v
);
void
_emitReturn
(
RewriterVar
*
v
);
void
_emitSideExit
(
STOLEN
(
RewriterVar
*
)
var
,
RewriterVar
*
val_constant
,
CFGBlock
*
next_block
,
void
_emitSideExit
(
STOLEN
(
RewriterVar
*
)
var
,
RewriterVar
*
val_constant
,
CFGBlock
*
next_block
,
...
...
src/codegen/unwinding.cpp
View file @
e7174486
...
@@ -593,11 +593,7 @@ public:
...
@@ -593,11 +593,7 @@ public:
assert
(
l
.
stack_second_offset
%
8
==
0
);
assert
(
l
.
stack_second_offset
%
8
==
0
);
b
=
b_ptr
[
l
.
stack_second_offset
/
8
];
b
=
b_ptr
[
l
.
stack_second_offset
/
8
];
}
else
if
(
l
.
type
==
Location
::
Register
)
{
}
else
if
(
l
.
type
==
Location
::
Register
)
{
RELEASE_ASSERT
(
0
,
"untested"
);
b
=
(
Box
*
)
get_cursor_reg
(
cursor
,
l
.
regnum
);
// This branch should never get hit since we shouldn't generate Register locations,
// since we don't allow allocating callee-save registers.
// If we did, this code might be right:
// b = (Box*)get_cursor_reg(cursor, l.regnum);
}
else
{
}
else
{
RELEASE_ASSERT
(
0
,
"not implemented"
);
RELEASE_ASSERT
(
0
,
"not implemented"
);
}
}
...
...
src/runtime/objmodel.cpp
View file @
e7174486
...
@@ -4870,32 +4870,32 @@ Box* callCLFunc(FunctionMetadata* md, CallRewriteArgs* rewrite_args, int num_out
...
@@ -4870,32 +4870,32 @@ Box* callCLFunc(FunctionMetadata* md, CallRewriteArgs* rewrite_args, int num_out
}
else
{
}
else
{
// Hacky workaround: the rewriter can only pass arguments in registers, so use this helper function
// Hacky workaround: the rewriter can only pass arguments in registers, so use this helper function
// to unpack some of the additional arguments:
// to unpack some of the additional arguments:
llvm
::
SmallVector
<
RewriterVar
*
,
4
>
additional_uses
;
RewriterVar
*
arg_array
=
rewrite_args
->
rewriter
->
allocate
(
4
);
RewriterVar
*
arg_array
=
rewrite_args
->
rewriter
->
allocate
(
4
);
arg_vec
.
push_back
(
arg_array
);
arg_vec
.
push_back
(
arg_array
);
if
(
num_output_args
>=
1
)
if
(
num_output_args
>=
1
)
{
arg_array
->
setAttr
(
0
,
rewrite_args
->
arg1
,
RewriterVar
::
SetattrType
::
REF_USED
);
arg_array
->
setAttr
(
0
,
rewrite_args
->
arg1
,
RewriterVar
::
SetattrType
::
REF_USED
);
if
(
num_output_args
>=
2
)
additional_uses
.
push_back
(
rewrite_args
->
arg1
);
}
if
(
num_output_args
>=
2
)
{
arg_array
->
setAttr
(
8
,
rewrite_args
->
arg2
,
RewriterVar
::
SetattrType
::
REF_USED
);
arg_array
->
setAttr
(
8
,
rewrite_args
->
arg2
,
RewriterVar
::
SetattrType
::
REF_USED
);
if
(
num_output_args
>=
3
)
additional_uses
.
push_back
(
rewrite_args
->
arg2
);
}
if
(
num_output_args
>=
3
)
{
arg_array
->
setAttr
(
16
,
rewrite_args
->
arg3
,
RewriterVar
::
SetattrType
::
REF_USED
);
arg_array
->
setAttr
(
16
,
rewrite_args
->
arg3
,
RewriterVar
::
SetattrType
::
REF_USED
);
if
(
num_output_args
>=
4
)
additional_uses
.
push_back
(
rewrite_args
->
arg3
);
}
if
(
num_output_args
>=
4
)
{
arg_array
->
setAttr
(
24
,
rewrite_args
->
args
,
RewriterVar
::
SetattrType
::
REF_USED
);
arg_array
->
setAttr
(
24
,
rewrite_args
->
args
,
RewriterVar
::
SetattrType
::
REF_USED
);
additional_uses
.
push_back
(
rewrite_args
->
args
);
}
if
(
S
==
CXX
)
if
(
S
==
CXX
)
rewrite_args
->
out_rtn
=
rewrite_args
->
rewriter
->
call
(
true
,
(
void
*
)
astInterpretHelper
,
arg_vec
)
rewrite_args
->
out_rtn
=
rewrite_args
->
rewriter
->
call
(
true
,
(
void
*
)
astInterpretHelper
,
arg_vec
,
{},
->
setType
(
RefType
::
OWNED
);
additional_uses
)
->
setType
(
RefType
::
OWNED
);
else
else
rewrite_args
->
out_rtn
=
rewrite_args
->
rewriter
->
call
(
true
,
(
void
*
)
astInterpretHelperCapi
,
arg_vec
)
rewrite_args
->
out_rtn
=
rewrite_args
->
rewriter
->
call
(
true
,
(
void
*
)
astInterpretHelperCapi
,
arg_vec
,
->
setType
(
RefType
::
OWNED
);
{},
additional_uses
)
->
setType
(
RefType
::
OWNED
);
if
(
num_output_args
>=
1
)
rewrite_args
->
arg1
->
refUsed
();
if
(
num_output_args
>=
2
)
rewrite_args
->
arg2
->
refUsed
();
if
(
num_output_args
>=
3
)
rewrite_args
->
arg3
->
refUsed
();
if
(
num_output_args
>=
4
)
rewrite_args
->
args
->
refUsed
();
}
}
rewrite_args
->
out_success
=
true
;
rewrite_args
->
out_success
=
true
;
...
@@ -5732,8 +5732,8 @@ Box* compareInternal(Box* lhs, Box* rhs, int op_type, CompareRewriteArgs* rewrit
...
@@ -5732,8 +5732,8 @@ Box* compareInternal(Box* lhs, Box* rhs, int op_type, CompareRewriteArgs* rewrit
bool
neg
=
(
op_type
==
AST_TYPE
::
IsNot
);
bool
neg
=
(
op_type
==
AST_TYPE
::
IsNot
);
if
(
rewrite_args
)
{
if
(
rewrite_args
)
{
RewriterVar
*
cmpres
=
rewrite_args
->
lhs
->
cmp
(
neg
?
AST_TYPE
::
NotEq
:
AST_TYPE
::
Eq
,
rewrite_args
->
rhs
,
RewriterVar
*
cmpres
rewrite_args
->
destination
);
=
rewrite_args
->
lhs
->
cmp
(
neg
?
AST_TYPE
::
NotEq
:
AST_TYPE
::
Eq
,
rewrite_args
->
rhs
,
assembler
::
RDI
);
rewrite_args
->
out_rtn
rewrite_args
->
out_rtn
=
rewrite_args
->
rewriter
->
call
(
false
,
(
void
*
)
boxBool
,
cmpres
)
->
setType
(
RefType
::
OWNED
);
=
rewrite_args
->
rewriter
->
call
(
false
,
(
void
*
)
boxBool
,
cmpres
)
->
setType
(
RefType
::
OWNED
);
rewrite_args
->
out_success
=
true
;
rewrite_args
->
out_success
=
true
;
...
@@ -7302,6 +7302,9 @@ extern "C" Box* getGlobal(Box* globals, BoxedString* name) {
...
@@ -7302,6 +7302,9 @@ extern "C" Box* getGlobal(Box* globals, BoxedString* name) {
}
}
extern
"C"
void
setGlobal
(
Box
*
globals
,
BoxedString
*
name
,
STOLEN
(
Box
*
)
value
)
{
extern
"C"
void
setGlobal
(
Box
*
globals
,
BoxedString
*
name
,
STOLEN
(
Box
*
)
value
)
{
static
StatCounter
slowpath_setglobal
(
"slowpath_setglobal"
);
slowpath_setglobal
.
log
();
if
(
globals
->
cls
==
attrwrapper_cls
)
{
if
(
globals
->
cls
==
attrwrapper_cls
)
{
globals
=
unwrapAttrWrapper
(
globals
);
globals
=
unwrapAttrWrapper
(
globals
);
RELEASE_ASSERT
(
globals
->
cls
==
module_cls
,
"%s"
,
globals
->
cls
->
tp_name
);
RELEASE_ASSERT
(
globals
->
cls
==
module_cls
,
"%s"
,
globals
->
cls
->
tp_name
);
...
...
test/tests/iter_del_time.py
View file @
e7174486
# fail-if: '-n' in EXTRA_JIT_ARGS or '-O' in EXTRA_JIT_ARGS
# expected: fail
# this only works in the interpreter and not in the bjit and llvm jit
class
C
(
object
):
class
C
(
object
):
def
next
(
self
):
def
next
(
self
):
...
...
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