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
22759d1a
Commit
22759d1a
authored
Jul 24, 2015
by
Kevin Modzelewski
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #736 from undingen/interp_vregs4
assign fixed slots (vregs) to the symbols.
parents
b5341641
d0044180
Changes
12
Show whitespace changes
Inline
Side-by-side
Showing
12 changed files
with
383 additions
and
243 deletions
+383
-243
src/CMakeLists.txt
src/CMakeLists.txt
+1
-0
src/asm_writing/assembler.cpp
src/asm_writing/assembler.cpp
+0
-1
src/codegen/ast_interpreter.cpp
src/codegen/ast_interpreter.cpp
+171
-201
src/codegen/ast_interpreter.h
src/codegen/ast_interpreter.h
+1
-4
src/codegen/ast_interpreter_exec.S
src/codegen/ast_interpreter_exec.S
+42
-0
src/codegen/baseline_jit.cpp
src/codegen/baseline_jit.cpp
+47
-21
src/codegen/baseline_jit.h
src/codegen/baseline_jit.h
+21
-10
src/core/ast.h
src/core/ast.h
+6
-1
src/core/cfg.cpp
src/core/cfg.cpp
+81
-0
src/core/cfg.h
src/core/cfg.h
+10
-2
src/core/contiguous_map.h
src/core/contiguous_map.h
+3
-2
src/runtime/types.cpp
src/runtime/types.cpp
+0
-1
No files found.
src/CMakeLists.txt
View file @
22759d1a
...
...
@@ -34,6 +34,7 @@ add_library(PYSTON_OBJECTS OBJECT ${OPTIONAL_SRCS}
capi/object.cpp
capi/typeobject.cpp
codegen/ast_interpreter.cpp
codegen/ast_interpreter_exec.S
codegen/baseline_jit.cpp
codegen/codegen.cpp
codegen/compvars.cpp
...
...
src/asm_writing/assembler.cpp
View file @
22759d1a
...
...
@@ -838,7 +838,6 @@ void Assembler::test(Register reg1, Register reg2) {
reg1_idx
-=
8
;
}
if
(
reg2_idx
>=
8
)
{
trap
();
rex
|=
REX_B
;
reg2_idx
-=
8
;
}
...
...
src/codegen/ast_interpreter.cpp
View file @
22759d1a
...
...
@@ -55,49 +55,24 @@ namespace pyston {
namespace
{
static
BoxedClass
*
astinterpreter_cls
;
class
ASTInterpreter
;
// Map from stack frame pointers for frames corresponding to ASTInterpreter::execute() to the ASTInterpreter handling
// them. Used to look up information about that frame. This is used for getting tracebacks, for CPython introspection
// (sys._getframe & co), and for GC scanning.
static
std
::
unordered_map
<
void
*
,
ASTInterpreter
*>
s_interpreterMap
;
static_assert
(
THREADING_USE_GIL
,
"have to make the interpreter map thread safe!"
);
class
RegisterHelper
{
private:
void
*
frame_addr
;
ASTInterpreter
*
interpreter
;
public:
RegisterHelper
();
~
RegisterHelper
();
void
doRegister
(
void
*
frame_addr
,
ASTInterpreter
*
interpreter
);
static
void
deregister
(
void
*
frame_addr
);
};
extern
"C"
Box
*
executeInnerAndSetupFrame
(
ASTInterpreter
&
interpreter
,
CFGBlock
*
start_block
,
AST_stmt
*
start_at
);
/*
* ASTInterpreters exist per function frame - there's no global interpreter object that executes
* all non-jitted code!
*
*
The ASTInterpreter inherits from Box as part of garbage collection support
.
*
All ASTInterpreter instances have to live on the stack because otherwise the GC won't scan the fields
.
*/
class
ASTInterpreter
:
public
Box
{
class
ASTInterpreter
{
public:
typedef
ContiguousMap
<
InternedString
,
Box
*
,
llvm
::
SmallDenseMap
<
InternedString
,
int
,
16
>>
SymMap
;
ASTInterpreter
(
CLFunction
*
clfunc
);
ASTInterpreter
(
CLFunction
*
clfunc
,
Box
**
vregs
);
void
initArguments
(
int
nargs
,
BoxedClosure
*
closure
,
BoxedGenerator
*
generator
,
Box
*
arg1
,
Box
*
arg2
,
Box
*
arg3
,
Box
**
args
);
static
Value
execute
(
ASTInterpreter
&
interpreter
,
CFGBlock
*
start_block
=
NULL
,
AST_stmt
*
start_at
=
NULL
);
// This must not be inlined, because we rely on being able to detect when we're inside of it (by checking whether
// %rip is inside its instruction range) during a stack-trace in order to produce tracebacks inside interpreted
// code.
__attribute__
((
__no_inline__
))
__attribute__
((
noinline
))
static
Value
executeInner
(
ASTInterpreter
&
interpreter
,
CFGBlock
*
start_block
,
AST_stmt
*
start_at
,
RegisterHelper
*
reg
);
static
Box
*
execute
(
ASTInterpreter
&
interpreter
,
CFGBlock
*
start_block
=
NULL
,
AST_stmt
*
start_at
=
NULL
);
static
Box
*
executeInner
(
ASTInterpreter
&
interpreter
,
CFGBlock
*
start_block
,
AST_stmt
*
start_at
);
private:
Box
*
createFunction
(
AST
*
node
,
AST_arguments
*
args
,
const
std
::
vector
<
AST_stmt
*>&
body
);
...
...
@@ -155,8 +130,7 @@ private:
void
startJITing
(
CFGBlock
*
block
,
int
exit_offset
=
0
);
void
abortJITing
();
void
finishJITing
(
CFGBlock
*
continue_block
=
NULL
);
// This method is not allowed to get inlined into 'executeInner' otherwise tracebacks are wrong.
__attribute__
((
__no_inline__
))
__attribute__
((
noinline
))
Box
*
execJITedBlock
(
CFGBlock
*
b
);
Box
*
execJITedBlock
(
CFGBlock
*
b
);
// this variables are used by the baseline JIT, make sure they have an offset < 0x80 so we can use shorter
// instructions
...
...
@@ -168,20 +142,23 @@ private:
ScopeInfo
*
scope_info
;
PhiAnalysis
*
phis
;
SymMap
sym_table
;
Box
**
vregs
;
ExcInfo
last_exception
;
BoxedClosure
*
passed_closure
,
*
created_closure
;
BoxedGenerator
*
generator
;
unsigned
edgecount
;
FrameInfo
frame_info
;
BoxedModule
*
parent_module
;
// This is either a module or a dict
Box
*
globals
;
void
*
frame_addr
;
// used to clear entry inside the s_interpreterMap on destruction
std
::
unique_ptr
<
JitFragmentWriter
>
jit
;
public:
DEFAULT_CLASS_SIMPLE
(
astinterpreter_cls
);
llvm
::
DenseMap
<
InternedString
,
int
>&
getSymVRegMap
()
{
assert
(
source_info
->
cfg
);
return
source_info
->
cfg
->
sym_vreg_map
;
}
AST_stmt
*
getCurrentStatement
()
{
assert
(
current_inst
);
...
...
@@ -196,7 +173,7 @@ public:
CLFunction
*
getCL
()
{
return
clfunc
;
}
FrameInfo
*
getFrameInfo
()
{
return
&
frame_info
;
}
BoxedClosure
*
getPassedClosure
()
{
return
passed_closure
;
}
const
SymMap
&
getSymbolTable
()
{
return
sym_table
;
}
Box
**
getVRegs
()
{
return
vregs
;
}
const
ScopeInfo
*
getScopeInfo
()
{
return
scope_info
;
}
void
addSymbol
(
InternedString
name
,
Box
*
value
,
bool
allow_duplicates
);
...
...
@@ -207,23 +184,14 @@ public:
void
setFrameInfo
(
const
FrameInfo
*
frame_info
);
void
setGlobals
(
Box
*
globals
);
static
void
gcHandler
(
GCVisitor
*
visitor
,
Box
*
box
);
static
void
simpleDestructor
(
Box
*
box
)
{
ASTInterpreter
*
inter
=
(
ASTInterpreter
*
)
box
;
assert
(
inter
->
cls
==
astinterpreter_cls
);
if
(
inter
->
frame_addr
)
RegisterHelper
::
deregister
(
inter
->
frame_addr
);
inter
->~
ASTInterpreter
();
}
friend
class
RegisterHelper
;
friend
struct
pyston
::
ASTInterpreterJitInterface
;
};
void
ASTInterpreter
::
addSymbol
(
InternedString
name
,
Box
*
value
,
bool
allow_duplicates
)
{
assert
(
getSymVRegMap
().
count
(
name
));
if
(
!
allow_duplicates
)
assert
(
sym_table
.
count
(
name
)
==
0
);
sym_table
[
name
]
=
value
;
assert
(
vregs
[
getSymVRegMap
()[
name
]]
==
NULL
);
vregs
[
getSymVRegMap
()[
name
]
]
=
value
;
}
void
ASTInterpreter
::
setGenerator
(
Box
*
gen
)
{
...
...
@@ -257,35 +225,22 @@ void ASTInterpreter::setGlobals(Box* globals) {
this
->
globals
=
globals
;
}
void
ASTInterpreter
::
gcHandler
(
GCVisitor
*
visitor
,
Box
*
box
)
{
boxGCHandler
(
visitor
,
box
);
ASTInterpreter
*
interp
=
(
ASTInterpreter
*
)
box
;
auto
&&
vec
=
interp
->
sym_table
.
vector
();
visitor
->
visitRange
((
void
*
const
*
)
&
vec
[
0
],
(
void
*
const
*
)
&
vec
[
vec
.
size
()]);
visitor
->
visit
(
interp
->
passed_closure
);
visitor
->
visit
(
interp
->
created_closure
);
visitor
->
visit
(
interp
->
generator
);
visitor
->
visit
(
interp
->
globals
);
visitor
->
visit
(
interp
->
source_info
->
parent_module
);
interp
->
frame_info
.
gcVisit
(
visitor
);
}
ASTInterpreter
::
ASTInterpreter
(
CLFunction
*
clfunc
)
ASTInterpreter
::
ASTInterpreter
(
CLFunction
*
clfunc
,
Box
**
vregs
)
:
current_block
(
0
),
current_inst
(
0
),
clfunc
(
clfunc
),
source_info
(
clfunc
->
source
.
get
()),
scope_info
(
0
),
phis
(
NULL
),
vregs
(
vregs
),
last_exception
(
NULL
,
NULL
,
NULL
),
passed_closure
(
0
),
created_closure
(
0
),
generator
(
0
),
edgecount
(
0
),
frame_info
(
ExcInfo
(
NULL
,
NULL
,
NULL
)),
globals
(
0
),
frame_addr
(
0
)
{
parent_module
(
source_info
->
parent_module
),
globals
(
0
)
{
scope_info
=
source_info
->
getScopeInfo
();
...
...
@@ -325,31 +280,6 @@ void ASTInterpreter::initArguments(int nargs, BoxedClosure* _closure, BoxedGener
assert
(
nargs
==
i
);
}
RegisterHelper
::
RegisterHelper
()
:
frame_addr
(
NULL
),
interpreter
(
NULL
)
{
}
RegisterHelper
::~
RegisterHelper
()
{
assert
(
interpreter
);
assert
(
interpreter
->
frame_addr
==
frame_addr
);
interpreter
->
frame_addr
=
nullptr
;
deregister
(
frame_addr
);
}
void
RegisterHelper
::
doRegister
(
void
*
frame_addr
,
ASTInterpreter
*
interpreter
)
{
assert
(
!
this
->
interpreter
);
assert
(
!
this
->
frame_addr
);
this
->
frame_addr
=
frame_addr
;
this
->
interpreter
=
interpreter
;
interpreter
->
frame_addr
=
frame_addr
;
s_interpreterMap
[
frame_addr
]
=
interpreter
;
}
void
RegisterHelper
::
deregister
(
void
*
frame_addr
)
{
assert
(
frame_addr
);
assert
(
s_interpreterMap
.
count
(
frame_addr
));
s_interpreterMap
.
erase
(
frame_addr
);
}
void
ASTInterpreter
::
startJITing
(
CFGBlock
*
block
,
int
exit_offset
)
{
assert
(
ENABLE_BASELINEJIT
);
assert
(
!
jit
);
...
...
@@ -387,7 +317,7 @@ void ASTInterpreter::finishJITing(CFGBlock* continue_block) {
Box
*
ASTInterpreter
::
execJITedBlock
(
CFGBlock
*
b
)
{
try
{
UNAVOIDABLE_STAT_TIMER
(
t0
,
"us_timer_in_baseline_jitted_code"
);
std
::
pair
<
CFGBlock
*
,
Box
*>
rtn
=
b
->
entry_code
(
this
,
b
);
std
::
pair
<
CFGBlock
*
,
Box
*>
rtn
=
b
->
entry_code
(
this
,
b
,
vregs
);
next_block
=
rtn
.
first
;
if
(
!
next_block
)
return
rtn
.
second
;
...
...
@@ -405,12 +335,7 @@ Box* ASTInterpreter::execJITedBlock(CFGBlock* b) {
return
nullptr
;
}
Value
ASTInterpreter
::
executeInner
(
ASTInterpreter
&
interpreter
,
CFGBlock
*
start_block
,
AST_stmt
*
start_at
,
RegisterHelper
*
reg
)
{
void
*
frame_addr
=
__builtin_frame_address
(
0
);
reg
->
doRegister
(
frame_addr
,
&
interpreter
);
Box
*
ASTInterpreter
::
executeInner
(
ASTInterpreter
&
interpreter
,
CFGBlock
*
start_block
,
AST_stmt
*
start_at
)
{
Value
v
;
bool
should_jit
=
false
;
...
...
@@ -462,7 +387,7 @@ Value ASTInterpreter::executeInner(ASTInterpreter& interpreter, CFGBlock* start_
Box
*
rtn
=
interpreter
.
execJITedBlock
(
b
);
if
(
interpreter
.
next_block
)
continue
;
return
Value
(
rtn
,
nullptr
)
;
return
rtn
;
}
}
...
...
@@ -478,10 +403,10 @@ Value ASTInterpreter::executeInner(ASTInterpreter& interpreter, CFGBlock* start_
v
=
interpreter
.
visit_stmt
(
s
);
}
}
return
v
;
return
v
.
o
;
}
Value
ASTInterpreter
::
execute
(
ASTInterpreter
&
interpreter
,
CFGBlock
*
start_block
,
AST_stmt
*
start_at
)
{
Box
*
ASTInterpreter
::
execute
(
ASTInterpreter
&
interpreter
,
CFGBlock
*
start_block
,
AST_stmt
*
start_at
)
{
UNAVOIDABLE_STAT_TIMER
(
t0
,
"us_timer_in_interpreter"
);
// Note: due to some (avoidable) restrictions, this check is pretty constrained in where
...
...
@@ -494,8 +419,7 @@ Value ASTInterpreter::execute(ASTInterpreter& interpreter, CFGBlock* start_block
if
(
!
interpreter
.
source_info
->
cfg
)
interpreter
.
source_info
->
cfg
=
computeCFG
(
interpreter
.
source_info
,
interpreter
.
source_info
->
body
);
RegisterHelper
frame_registerer
;
return
executeInner
(
interpreter
,
start_block
,
start_at
,
&
frame_registerer
);
return
executeInnerAndSetupFrame
(
interpreter
,
start_block
,
start_at
);
}
Value
ASTInterpreter
::
doBinOp
(
Value
left
,
Value
right
,
int
op
,
BinExpType
exp_type
)
{
...
...
@@ -527,6 +451,7 @@ void ASTInterpreter::doStore(AST_Name* node, Value value) {
jit
->
emitSetItemName
(
name
.
getBox
(),
value
);
assert
(
frame_info
.
boxedLocals
!=
NULL
);
// TODO should probably pre-box the names when it's a scope that usesNameLookup
assert
(
gc
::
isValidGCObject
(
value
.
o
));
setitem
(
frame_info
.
boxedLocals
,
name
.
getBox
(),
value
.
o
);
}
else
{
bool
closure
=
vst
==
ScopeInfo
::
VarScopeType
::
CLOSURE
;
...
...
@@ -534,14 +459,17 @@ void ASTInterpreter::doStore(AST_Name* node, Value value) {
if
(
!
closure
)
{
bool
is_live
=
source_info
->
getLiveness
()
->
isLiveAtEnd
(
name
,
current_block
);
if
(
is_live
)
jit
->
emitSetLocal
(
name
,
closure
,
value
);
jit
->
emitSetLocal
(
name
,
node
->
vreg
,
closure
,
value
);
else
jit
->
emitSetBlockLocal
(
name
,
value
);
}
else
jit
->
emitSetLocal
(
name
,
closure
,
value
);
jit
->
emitSetLocal
(
name
,
node
->
vreg
,
closure
,
value
);
}
sym_table
[
name
]
=
value
.
o
;
assert
(
getSymVRegMap
().
count
(
name
));
assert
(
getSymVRegMap
()[
name
]
==
node
->
vreg
);
vregs
[
node
->
vreg
]
=
value
.
o
;
if
(
closure
)
{
created_closure
->
elts
[
scope_info
->
getClosureOffset
(
name
)]
=
value
.
o
;
}
...
...
@@ -706,17 +634,24 @@ Box* ASTInterpreter::doOSR(AST_Jump* node) {
std
::
unique_ptr
<
PhiAnalysis
>
phis
=
computeRequiredPhis
(
clfunc
->
param_names
,
source_info
->
cfg
,
liveness
,
scope_info
);
llvm
::
DenseMap
<
int
,
InternedString
>
offset_name_map
;
for
(
auto
&&
v
:
getSymVRegMap
())
{
offset_name_map
[
v
.
second
]
=
v
.
first
;
}
std
::
vector
<
InternedString
>
dead_symbols
;
for
(
auto
&
it
:
sym_table
)
{
if
(
!
liveness
->
isLiveAtEnd
(
it
.
first
,
current_block
))
{
dead_symbols
.
push_back
(
it
.
first
);
}
else
if
(
phis
->
isRequiredAfter
(
it
.
first
,
current_block
))
{
assert
(
scope_info
->
getScopeTypeOfName
(
it
.
first
)
!=
ScopeInfo
::
VarScopeType
::
GLOBAL
);
for
(
int
i
=
0
;
i
<
getSymVRegMap
().
size
();
++
i
)
{
if
(
!
liveness
->
isLiveAtEnd
(
offset_name_map
[
i
]
,
current_block
))
{
dead_symbols
.
push_back
(
offset_name_map
[
i
]
);
}
else
if
(
phis
->
isRequiredAfter
(
offset_name_map
[
i
]
,
current_block
))
{
assert
(
scope_info
->
getScopeTypeOfName
(
offset_name_map
[
i
]
)
!=
ScopeInfo
::
VarScopeType
::
GLOBAL
);
}
else
{
}
}
for
(
auto
&&
dead
:
dead_symbols
)
sym_table
.
erase
(
dead
);
for
(
auto
&&
dead
:
dead_symbols
)
{
assert
(
getSymVRegMap
().
count
(
dead
));
vregs
[
getSymVRegMap
()[
dead
]]
=
NULL
;
}
const
OSREntryDescriptor
*
found_entry
=
nullptr
;
for
(
auto
&
p
:
clfunc
->
osr_versions
)
{
...
...
@@ -732,20 +667,19 @@ Box* ASTInterpreter::doOSR(AST_Jump* node) {
static
Box
*
const
VAL_UNDEFINED
=
(
Box
*
)
-
1
;
for
(
auto
&
name
:
phis
->
definedness
.
getDefinedNamesAtEnd
(
current_block
))
{
auto
it
=
sym_table
.
find
(
name
);
assert
(
getSymVRegMap
().
count
(
name
));
Box
*
val
=
vregs
[
getSymVRegMap
()[
name
]];
if
(
!
liveness
->
isLiveAtEnd
(
name
,
current_block
))
continue
;
if
(
phis
->
isPotentiallyUndefinedAfter
(
name
,
current_block
))
{
bool
is_defined
=
it
!=
sym_table
.
end
()
;
bool
is_defined
=
val
!=
NULL
;
// TODO only mangle once
sorted_symbol_table
[
getIsDefinedName
(
name
,
source_info
->
getInternedStrings
())]
=
(
Box
*
)
is_defined
;
if
(
is_defined
)
assert
(
sym_table
.
getMapped
(
it
->
second
)
!=
NULL
);
sorted_symbol_table
[
name
]
=
is_defined
?
sym_table
.
getMapped
(
it
->
second
)
:
VAL_UNDEFINED
;
sorted_symbol_table
[
name
]
=
is_defined
?
val
:
VAL_UNDEFINED
;
}
else
{
ASSERT
(
it
!=
sym_table
.
end
()
,
"%s"
,
name
.
c_str
());
Box
*
v
=
sorted_symbol_table
[
it
->
first
]
=
sym_table
.
getMapped
(
it
->
second
)
;
ASSERT
(
val
!=
NULL
,
"%s"
,
name
.
c_str
());
Box
*
v
=
sorted_symbol_table
[
name
]
=
val
;
assert
(
gc
::
isValidGCObject
(
v
));
}
}
...
...
@@ -1158,8 +1092,10 @@ Value ASTInterpreter::visit_assert(AST_Assert* node) {
Value
ASTInterpreter
::
visit_global
(
AST_Global
*
node
)
{
abortJITing
();
for
(
auto
name
:
node
->
names
)
sym_table
.
erase
(
name
);
for
(
auto
name
:
node
->
names
)
{
if
(
getSymVRegMap
().
count
(
name
))
vregs
[
getSymVRegMap
()[
name
]]
=
NULL
;
}
return
Value
();
}
...
...
@@ -1203,12 +1139,14 @@ Value ASTInterpreter::visit_delete(AST_Delete* node) {
}
else
{
assert
(
vst
==
ScopeInfo
::
VarScopeType
::
FAST
);
if
(
sym_table
.
count
(
target
->
id
)
==
0
)
{
assert
(
getSymVRegMap
().
count
(
target
->
id
));
assert
(
getSymVRegMap
()[
target
->
id
]
==
target
->
vreg
);
if
(
vregs
[
target
->
vreg
]
==
0
)
{
assertNameDefined
(
0
,
target
->
id
.
c_str
(),
NameError
,
true
/* local_var_msg */
);
return
Value
();
}
sym_table
.
erase
(
target
->
id
)
;
vregs
[
target
->
vreg
]
=
NULL
;
}
break
;
}
...
...
@@ -1410,13 +1348,13 @@ Value ASTInterpreter::visit_expr(AST_Expr* node) {
Value
ASTInterpreter
::
visit_num
(
AST_Num
*
node
)
{
Box
*
o
=
NULL
;
if
(
node
->
num_type
==
AST_Num
::
INT
)
{
o
=
source_info
->
parent_module
->
getIntConstant
(
node
->
n_int
);
o
=
parent_module
->
getIntConstant
(
node
->
n_int
);
}
else
if
(
node
->
num_type
==
AST_Num
::
FLOAT
)
{
o
=
source_info
->
parent_module
->
getFloatConstant
(
node
->
n_float
);
o
=
parent_module
->
getFloatConstant
(
node
->
n_float
);
}
else
if
(
node
->
num_type
==
AST_Num
::
LONG
)
{
o
=
source_info
->
parent_module
->
getLongConstant
(
node
->
n_long
);
o
=
parent_module
->
getLongConstant
(
node
->
n_long
);
}
else
if
(
node
->
num_type
==
AST_Num
::
COMPLEX
)
{
o
=
source_info
->
parent_module
->
getPureImaginaryConstant
(
node
->
n_float
);
o
=
parent_module
->
getPureImaginaryConstant
(
node
->
n_float
);
}
else
RELEASE_ASSERT
(
0
,
"not implemented"
);
return
Value
(
o
,
jit
?
jit
->
imm
(
o
)
:
NULL
);
...
...
@@ -1475,9 +1413,9 @@ Value ASTInterpreter::visit_set(AST_Set* node) {
Value
ASTInterpreter
::
visit_str
(
AST_Str
*
node
)
{
Box
*
o
=
NULL
;
if
(
node
->
str_type
==
AST_Str
::
STR
)
{
o
=
source_info
->
parent_module
->
getStringConstant
(
node
->
str_data
);
o
=
parent_module
->
getStringConstant
(
node
->
str_data
);
}
else
if
(
node
->
str_type
==
AST_Str
::
UNICODE
)
{
o
=
source_info
->
parent_module
->
getUnicodeConstant
(
node
->
str_data
);
o
=
parent_module
->
getUnicodeConstant
(
node
->
str_data
);
}
else
{
RELEASE_ASSERT
(
0
,
"%d"
,
node
->
str_type
);
}
...
...
@@ -1511,19 +1449,30 @@ Value ASTInterpreter::visit_name(AST_Name* node) {
is_live
=
source_info
->
getLiveness
()
->
isLiveAtEnd
(
node
->
id
,
current_block
);
if
(
is_live
)
v
.
var
=
jit
->
emitGetLocal
(
node
->
id
);
v
.
var
=
jit
->
emitGetLocal
(
node
->
id
,
node
->
vreg
);
else
v
.
var
=
jit
->
emitGetBlockLocal
(
node
->
id
);
v
.
var
=
jit
->
emitGetBlockLocal
(
node
->
id
,
node
->
vreg
);
}
v
.
o
=
ASTInterpreterJitInterface
::
getLocalHelper
(
this
,
node
->
id
);
assert
(
node
->
vreg
>=
0
);
assert
(
getSymVRegMap
().
count
(
node
->
id
));
assert
(
getSymVRegMap
()[
node
->
id
]
==
node
->
vreg
);
Box
*
val
=
vregs
[
node
->
vreg
];
if
(
val
)
{
assert
(
gc
::
isValidGCObject
(
val
));
v
.
o
=
val
;
return
v
;
}
assertNameDefined
(
0
,
node
->
id
.
c_str
(),
UnboundLocalError
,
true
);
RELEASE_ASSERT
(
0
,
"should be unreachable"
);
}
case
ScopeInfo
:
:
VarScopeType
::
NAME
:
{
Value
v
;
if
(
jit
)
v
.
var
=
jit
->
emitGetBoxedLocal
(
node
->
id
.
getBox
());
v
.
o
=
boxedLocalsGet
(
frame_info
.
boxedLocals
,
node
->
id
.
getBox
(),
globals
);
assert
(
gc
::
isValidGCObject
(
v
.
o
));
return
v
;
}
default:
...
...
@@ -1617,20 +1566,6 @@ Box* ASTInterpreterJitInterface::doOSRHelper(void* _interpreter, AST_Jump* node)
return
NULL
;
}
Box
*
ASTInterpreterJitInterface
::
getLocalHelper
(
void
*
_interpreter
,
InternedString
id
)
{
ASTInterpreter
*
interpreter
=
(
ASTInterpreter
*
)
_interpreter
;
auto
it
=
interpreter
->
sym_table
.
find
(
id
);
if
(
it
!=
interpreter
->
sym_table
.
end
())
{
Box
*
v
=
interpreter
->
sym_table
.
getMapped
(
it
->
second
);
assert
(
gc
::
isValidGCObject
(
v
));
return
v
;
}
assertNameDefined
(
0
,
id
.
c_str
(),
UnboundLocalError
,
true
);
return
0
;
}
Box
*
ASTInterpreterJitInterface
::
landingpadHelper
(
void
*
_interpreter
)
{
ASTInterpreter
*
interpreter
=
(
ASTInterpreter
*
)
_interpreter
;
ExcInfo
&
last_exception
=
interpreter
->
last_exception
;
...
...
@@ -1654,24 +1589,40 @@ Box* ASTInterpreterJitInterface::uncacheExcInfoHelper(void* _interpreter) {
return
None
;
}
void
ASTInterpreterJitInterface
::
setLocalClosureHelper
(
void
*
_interpreter
,
InternedString
id
,
Box
*
v
)
{
void
ASTInterpreterJitInterface
::
setLocalClosureHelper
(
void
*
_interpreter
,
long
vreg
,
InternedString
id
,
Box
*
v
)
{
ASTInterpreter
*
interpreter
=
(
ASTInterpreter
*
)
_interpreter
;
assert
(
gc
::
isValidGCObject
(
v
));
interpreter
->
sym_table
[
id
]
=
v
;
assert
(
interpreter
->
getSymVRegMap
().
count
(
id
));
assert
(
interpreter
->
getSymVRegMap
()[
id
]
==
vreg
);
interpreter
->
vregs
[
vreg
]
=
v
;
interpreter
->
created_closure
->
elts
[
interpreter
->
scope_info
->
getClosureOffset
(
id
)]
=
v
;
}
void
ASTInterpreterJitInterface
::
setLocalHelper
(
void
*
_interpreter
,
InternedString
id
,
Box
*
v
)
{
ASTInterpreter
*
interpreter
=
(
ASTInterpreter
*
)
_interpreter
;
const
void
*
interpreter_instr_addr
=
(
void
*
)
&
executeInnerAndSetupFrame
;
assert
(
gc
::
isValidGCObject
(
v
));
interpreter
->
sym_table
[
id
]
=
v
;
// small wrapper around executeInner because we can not directly call the member function from asm.
extern
"C"
Box
*
executeInnerFromASM
(
ASTInterpreter
&
interpreter
,
CFGBlock
*
start_block
,
AST_stmt
*
start_at
)
{
return
ASTInterpreter
::
executeInner
(
interpreter
,
start_block
,
start_at
);
}
static
int
calculateNumVRegs
(
CLFunction
*
clfunc
)
{
ScopeInfo
*
scope_info
=
clfunc
->
source
->
getScopeInfo
();
SourceInfo
*
source_info
=
clfunc
->
source
.
get
();
const
void
*
interpreter_instr_addr
=
(
void
*
)
&
ASTInterpreter
::
executeInner
;
// Note: due to some (avoidable) restrictions, this check is pretty constrained in where
// it can go, due to the fact that it can throw an exception.
// It can't go in the ASTInterpreter constructor, since that will cause the C++ runtime to
// delete the partially-constructed memory which we don't currently handle. It can't go into
// executeInner since we want the SyntaxErrors to happen *before* the stack frame is entered.
// (For instance, throwing the exception will try to fetch the current statement, but we determine
// that by looking at the cfg.)
if
(
!
source_info
->
cfg
)
source_info
->
cfg
=
computeCFG
(
source_info
,
source_info
->
body
);
source_info
->
cfg
->
assignVRegs
(
clfunc
->
param_names
,
scope_info
);
return
source_info
->
cfg
->
sym_vreg_map
.
size
();
}
Box
*
astInterpretFunction
(
CLFunction
*
clfunc
,
int
nargs
,
Box
*
closure
,
Box
*
generator
,
Box
*
globals
,
Box
*
arg1
,
Box
*
arg2
,
Box
*
arg3
,
Box
**
args
)
{
...
...
@@ -1724,77 +1675,95 @@ Box* astInterpretFunction(CLFunction* clfunc, int nargs, Box* closure, Box* gene
return
optimized
->
call
(
arg1
,
arg2
,
arg3
,
args
);
}
Box
**
vregs
=
NULL
;
int
num_vregs
=
calculateNumVRegs
(
clfunc
);
if
(
num_vregs
>
0
)
{
vregs
=
(
Box
**
)
alloca
(
sizeof
(
Box
*
)
*
num_vregs
);
memset
(
vregs
,
0
,
sizeof
(
Box
*
)
*
num_vregs
);
}
++
clfunc
->
times_interpreted
;
ASTInterpreter
*
interpreter
=
new
ASTInterpreter
(
clfunc
);
ASTInterpreter
interpreter
(
clfunc
,
vregs
);
ScopeInfo
*
scope_info
=
clfunc
->
source
->
getScopeInfo
();
if
(
unlikely
(
scope_info
->
usesNameLookup
()))
{
interpreter
->
setBoxedLocals
(
new
BoxedDict
());
interpreter
.
setBoxedLocals
(
new
BoxedDict
());
}
assert
((
!
globals
)
==
clfunc
->
source
->
scoping
->
areGlobalsFromModule
());
if
(
globals
)
{
interpreter
->
setGlobals
(
globals
);
interpreter
.
setGlobals
(
globals
);
}
else
{
interpreter
->
setGlobals
(
source_info
->
parent_module
);
interpreter
.
setGlobals
(
source_info
->
parent_module
);
}
interpreter
->
initArguments
(
nargs
,
(
BoxedClosure
*
)
closure
,
(
BoxedGenerator
*
)
generator
,
arg1
,
arg2
,
arg3
,
args
);
Value
v
=
ASTInterpreter
::
execute
(
*
interpreter
);
return
v
.
o
?
v
.
o
:
None
;
interpreter
.
initArguments
(
nargs
,
(
BoxedClosure
*
)
closure
,
(
BoxedGenerator
*
)
generator
,
arg1
,
arg2
,
arg3
,
args
);
Box
*
v
=
ASTInterpreter
::
execute
(
interpreter
);
return
v
?
v
:
None
;
}
Box
*
astInterpretFunctionEval
(
CLFunction
*
clfunc
,
Box
*
globals
,
Box
*
boxedLocals
)
{
++
clfunc
->
times_interpreted
;
ASTInterpreter
*
interpreter
=
new
ASTInterpreter
(
clfunc
);
interpreter
->
initArguments
(
0
,
NULL
,
NULL
,
NULL
,
NULL
,
NULL
,
NULL
);
interpreter
->
setBoxedLocals
(
boxedLocals
);
Box
**
vregs
=
NULL
;
int
num_vregs
=
calculateNumVRegs
(
clfunc
);
if
(
num_vregs
>
0
)
{
vregs
=
(
Box
**
)
alloca
(
sizeof
(
Box
*
)
*
num_vregs
);
memset
(
vregs
,
0
,
sizeof
(
Box
*
)
*
num_vregs
);
}
ScopeInfo
*
scope_info
=
clfunc
->
source
->
getScopeInfo
();
SourceInfo
*
source_info
=
clfunc
->
source
.
get
();
ASTInterpreter
interpreter
(
clfunc
,
vregs
);
interpreter
.
initArguments
(
0
,
NULL
,
NULL
,
NULL
,
NULL
,
NULL
,
NULL
);
interpreter
.
setBoxedLocals
(
boxedLocals
);
assert
(
!
clfunc
->
source
->
scoping
->
areGlobalsFromModule
());
assert
(
globals
);
interpreter
->
setGlobals
(
globals
);
interpreter
.
setGlobals
(
globals
);
Value
v
=
ASTInterpreter
::
execute
(
*
interpreter
);
return
v
.
o
?
v
.
o
:
None
;
Box
*
v
=
ASTInterpreter
::
execute
(
interpreter
);
return
v
?
v
:
None
;
}
Box
*
astInterpretDeopt
(
CLFunction
*
clfunc
,
AST_expr
*
after_expr
,
AST_stmt
*
enclosing_stmt
,
Box
*
expr_val
,
FrameStackState
frame_state
)
{
RELEASE_ASSERT
(
0
,
"didn't check if this still works"
);
assert
(
clfunc
);
assert
(
enclosing_stmt
);
assert
(
frame_state
.
locals
);
assert
(
after_expr
);
assert
(
expr_val
);
ASTInterpreter
*
interpreter
=
new
ASTInterpreter
(
clfunc
);
ScopeInfo
*
scope_info
=
clfunc
->
source
->
getScopeInfo
();
SourceInfo
*
source_info
=
clfunc
->
source
.
get
();
Box
**
vregs
=
NULL
;
int
num_vregs
=
calculateNumVRegs
(
clfunc
);
if
(
num_vregs
>
0
)
{
vregs
=
(
Box
**
)
alloca
(
sizeof
(
Box
*
)
*
num_vregs
);
memset
(
vregs
,
0
,
sizeof
(
Box
*
)
*
num_vregs
);
}
ASTInterpreter
interpreter
(
clfunc
,
vregs
);
assert
(
clfunc
->
source
->
scoping
->
areGlobalsFromModule
());
interpreter
->
setGlobals
(
source_info
->
parent_module
);
interpreter
.
setGlobals
(
source_info
->
parent_module
);
for
(
const
auto
&
p
:
frame_state
.
locals
->
d
)
{
assert
(
p
.
first
->
cls
==
str_cls
);
auto
name
=
static_cast
<
BoxedString
*>
(
p
.
first
)
->
s
();
if
(
name
==
PASSED_GENERATOR_NAME
)
{
interpreter
->
setGenerator
(
p
.
second
);
interpreter
.
setGenerator
(
p
.
second
);
}
else
if
(
name
==
PASSED_CLOSURE_NAME
)
{
interpreter
->
setPassedClosure
(
p
.
second
);
interpreter
.
setPassedClosure
(
p
.
second
);
}
else
if
(
name
==
CREATED_CLOSURE_NAME
)
{
interpreter
->
setCreatedClosure
(
p
.
second
);
interpreter
.
setCreatedClosure
(
p
.
second
);
}
else
{
InternedString
interned
=
clfunc
->
source
->
getInternedStrings
().
get
(
name
);
interpreter
->
addSymbol
(
interned
,
p
.
second
,
false
);
interpreter
.
addSymbol
(
interned
,
p
.
second
,
false
);
}
}
interpreter
->
setFrameInfo
(
frame_state
.
frame_info
);
interpreter
.
setFrameInfo
(
frame_state
.
frame_info
);
CFGBlock
*
start_block
=
NULL
;
AST_stmt
*
starting_statement
=
NULL
;
...
...
@@ -1806,7 +1775,7 @@ Box* astInterpretDeopt(CLFunction* clfunc, AST_expr* after_expr, AST_stmt* enclo
assert
(
asgn
->
targets
[
0
]
->
type
==
AST_TYPE
::
Name
);
auto
name
=
ast_cast
<
AST_Name
>
(
asgn
->
targets
[
0
]);
assert
(
name
->
id
.
s
()[
0
]
==
'#'
);
interpreter
->
addSymbol
(
name
->
id
,
expr_val
,
true
);
interpreter
.
addSymbol
(
name
->
id
,
expr_val
,
true
);
break
;
}
else
if
(
enclosing_stmt
->
type
==
AST_TYPE
::
Expr
)
{
auto
expr
=
ast_cast
<
AST_Expr
>
(
enclosing_stmt
);
...
...
@@ -1844,60 +1813,61 @@ Box* astInterpretDeopt(CLFunction* clfunc, AST_expr* after_expr, AST_stmt* enclo
assert
(
starting_statement
);
}
Value
v
=
ASTInterpreter
::
execute
(
*
interpreter
,
start_block
,
starting_statement
);
Box
*
v
=
ASTInterpreter
::
execute
(
interpreter
,
start_block
,
starting_statement
);
return
v
?
v
:
None
;
}
return
v
.
o
?
v
.
o
:
None
;
static
ASTInterpreter
*
getInterpreterFromFramePtr
(
void
*
frame_ptr
)
{
// This offsets have to match the layout inside executeInnerAndSetupFrame
ASTInterpreter
**
ptr
=
(
ASTInterpreter
**
)(((
uint8_t
*
)
frame_ptr
)
-
8
);
return
*
ptr
;
}
AST_stmt
*
getCurrentStatementForInterpretedFrame
(
void
*
frame_ptr
)
{
ASTInterpreter
*
interpreter
=
s_interpreterMap
[
frame_ptr
]
;
ASTInterpreter
*
interpreter
=
getInterpreterFromFramePtr
(
frame_ptr
)
;
assert
(
interpreter
);
return
interpreter
->
getCurrentStatement
();
}
Box
*
getGlobalsForInterpretedFrame
(
void
*
frame_ptr
)
{
ASTInterpreter
*
interpreter
=
s_interpreterMap
[
frame_ptr
]
;
ASTInterpreter
*
interpreter
=
getInterpreterFromFramePtr
(
frame_ptr
)
;
assert
(
interpreter
);
return
interpreter
->
getGlobals
();
}
CLFunction
*
getCLForInterpretedFrame
(
void
*
frame_ptr
)
{
ASTInterpreter
*
interpreter
=
s_interpreterMap
[
frame_ptr
]
;
ASTInterpreter
*
interpreter
=
getInterpreterFromFramePtr
(
frame_ptr
)
;
assert
(
interpreter
);
return
interpreter
->
getCL
();
}
FrameInfo
*
getFrameInfoForInterpretedFrame
(
void
*
frame_ptr
)
{
ASTInterpreter
*
interpreter
=
s_interpreterMap
[
frame_ptr
]
;
ASTInterpreter
*
interpreter
=
getInterpreterFromFramePtr
(
frame_ptr
)
;
assert
(
interpreter
);
return
interpreter
->
getFrameInfo
();
}
BoxedDict
*
localsForInterpretedFrame
(
void
*
frame_ptr
,
bool
only_user_visible
)
{
ASTInterpreter
*
interpreter
=
s_interpreterMap
[
frame_ptr
]
;
ASTInterpreter
*
interpreter
=
getInterpreterFromFramePtr
(
frame_ptr
)
;
assert
(
interpreter
);
BoxedDict
*
rtn
=
new
BoxedDict
();
for
(
auto
&
l
:
interpreter
->
getSym
bolTable
())
{
for
(
auto
&
l
:
interpreter
->
getSym
VRegMap
())
{
if
(
only_user_visible
&&
(
l
.
first
.
s
()[
0
]
==
'!'
||
l
.
first
.
s
()[
0
]
==
'#'
))
continue
;
rtn
->
d
[
l
.
first
.
getBox
()]
=
interpreter
->
getSymbolTable
().
getMapped
(
l
.
second
);
Box
*
val
=
interpreter
->
getVRegs
()[
l
.
second
];
if
(
val
)
{
assert
(
gc
::
isValidGCObject
(
val
));
rtn
->
d
[
l
.
first
.
getBox
()]
=
val
;
}
}
return
rtn
;
}
BoxedClosure
*
passedClosureForInterpretedFrame
(
void
*
frame_ptr
)
{
ASTInterpreter
*
interpreter
=
s_interpreterMap
[
frame_ptr
]
;
ASTInterpreter
*
interpreter
=
getInterpreterFromFramePtr
(
frame_ptr
)
;
assert
(
interpreter
);
return
interpreter
->
getPassedClosure
();
}
void
setupInterpreter
()
{
astinterpreter_cls
=
BoxedHeapClass
::
create
(
type_cls
,
object_cls
,
ASTInterpreter
::
gcHandler
,
0
,
0
,
sizeof
(
ASTInterpreter
),
false
,
"astinterpreter"
);
astinterpreter_cls
->
tp_dealloc
=
ASTInterpreter
::
simpleDestructor
;
astinterpreter_cls
->
has_safe_tp_dealloc
=
true
;
astinterpreter_cls
->
freeze
();
}
}
src/codegen/ast_interpreter.h
View file @
22759d1a
...
...
@@ -43,12 +43,10 @@ struct ASTInterpreterJitInterface {
static
Box
*
derefHelper
(
void
*
interp
,
InternedString
s
);
static
Box
*
doOSRHelper
(
void
*
interp
,
AST_Jump
*
node
);
static
Box
*
getLocalHelper
(
void
*
interp
,
InternedString
id
);
static
Box
*
landingpadHelper
(
void
*
interp
);
static
Box
*
setExcInfoHelper
(
void
*
interp
,
Box
*
type
,
Box
*
value
,
Box
*
traceback
);
static
Box
*
uncacheExcInfoHelper
(
void
*
interp
);
static
void
setLocalClosureHelper
(
void
*
interp
,
InternedString
id
,
Box
*
v
);
static
void
setLocalHelper
(
void
*
interp
,
InternedString
id
,
Box
*
v
);
static
void
setLocalClosureHelper
(
void
*
interp
,
long
vreg
,
InternedString
id
,
Box
*
v
);
};
class
RewriterVar
;
...
...
@@ -70,7 +68,6 @@ struct Value {
Value
(
Box
*
o
,
RewriterVar
*
var
)
:
o
(
o
),
var
(
var
)
{}
};
void
setupInterpreter
();
Box
*
astInterpretFunction
(
CLFunction
*
f
,
int
nargs
,
Box
*
closure
,
Box
*
generator
,
Box
*
globals
,
Box
*
arg1
,
Box
*
arg2
,
Box
*
arg3
,
Box
**
args
);
Box
*
astInterpretFunctionEval
(
CLFunction
*
cf
,
Box
*
globals
,
Box
*
boxedLocals
);
...
...
src/codegen/ast_interpreter_exec.S
0 → 100644
View file @
22759d1a
//
Copyright
(
c
)
2014
-
2015
Dropbox
,
Inc
.
//
//
Licensed
under
the
Apache
License
,
Version
2
.0
(
the
"License"
)
;
//
you
may
not
use
this
file
except
in
compliance
with
the
License
.
//
You
may
obtain
a
copy
of
the
License
at
//
//
http
://
www.apache.org
/
licenses
/
LICENSE
-2.0
//
//
Unless
required
by
applicable
law
or
agreed
to
in
writing
,
software
//
distributed
under
the
License
is
distributed
on
an
"AS IS"
BASIS
,
//
WITHOUT
WARRANTIES
OR
CONDITIONS
OF
ANY
KIND
,
either
express
or
implied
.
//
See
the
License
for
the
specific
language
governing
permissions
and
//
limitations
under
the
License
.
//
This
functions
sets
up
a
fixed
stack
frame
which
we
use
to
detect
ASTInterpreter
frames
//
and
which
makes
it
easy
retrieve
the
passed
ASTInterpreter
pointer
(
stored
at
frame_ptr
-
8
)
.
//
It
'
s
written
in
ASM
to
make
sure
the
stack
layout
keeps
beeing
the
same
and
that
nothing
gets
inlined
.
//
Our
unwinder
treats
this
function
specialy
.
//
Box
*
executeInnerAndSetupFrame
(
ASTInterpreter
&
interpreter
,
CFGBlock
*
start_block
,
AST_stmt
*
start_at
)
.
text
.
globl
executeInnerAndSetupFrame
.
type
executeInnerAndSetupFrame
,@
function
.
align
16
executeInnerAndSetupFrame
:
.
cfi_startproc
push
%
rbp
.
cfi_def_cfa_offset
16
.
cfi_offset
rbp
,-
16
mov
%
rsp
,
%
rbp
.
cfi_def_cfa_register
rbp
sub
$
16
,
%
rsp
mov
%
rdi
,
-
8
(%
rbp
)
call
executeInnerFromASM
leave
.
cfi_def_cfa
rsp
,
8
ret
.
cfi_endproc
.
size
executeInnerAndSetupFrame
,.-
executeInnerAndSetupFrame
.
section
.
note.GNU
-
stack
,"",%
progbits
//
we
don
't need executable stack
src/codegen/baseline_jit.cpp
View file @
22759d1a
...
...
@@ -36,17 +36,18 @@ static llvm::DenseMap<CFGBlock*, std::vector<void*>> block_patch_locations;
//
// long foo(char* c);
// void bjit() {
// asm volatile ("" ::: "r14");
// asm volatile ("" ::: "r12");
// char scratch[256+16];
// foo(scratch);
// }
//
// It omits the frame pointer but saves R12
// It omits the frame pointer but saves R12
and R14
const
unsigned
char
eh_info
[]
=
{
0x14
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x03
,
0x7a
,
0x52
,
0x00
,
0x01
,
0x78
,
0x10
,
0x01
,
0x1b
,
0x0c
,
0x07
,
0x08
,
0x90
,
0x01
,
0x00
,
0x00
,
0x1c
,
0x00
,
0x00
,
0x00
,
0x1c
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x
1c
,
0x00
,
0x00
,
0x00
,
0x00
,
0x42
,
0x0e
,
0x10
,
0x47
,
0x0e
,
0x
a0
,
0x02
,
0x8c
,
0x02
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
};
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x
20
,
0x00
,
0x00
,
0x00
,
0x00
,
0x42
,
0x0e
,
0x10
,
0x42
,
0x0e
,
0x
18
,
0x47
,
0x0e
,
0xb0
,
0x02
,
0x8c
,
0x03
,
0x8e
,
0x02
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
};
static_assert
(
JitCodeBlock
::
num_stack_args
==
2
,
"have to update EH table!"
);
static_assert
(
JitCodeBlock
::
scratch_size
==
256
,
"have to update EH table!"
);
...
...
@@ -63,10 +64,12 @@ JitCodeBlock::JitCodeBlock(llvm::StringRef name)
num_jit_total_bytes
.
log
(
code_size
);
// emit prolog
a
.
push
(
assembler
::
R14
);
a
.
push
(
assembler
::
R12
);
static_assert
(
sp_adjustment
%
16
==
0
,
"stack isn't aligned"
);
static_assert
(
sp_adjustment
%
16
==
8
,
"stack isn't aligned"
);
a
.
sub
(
assembler
::
Immediate
(
sp_adjustment
),
assembler
::
RSP
);
a
.
mov
(
assembler
::
RDI
,
assembler
::
R12
);
// interpreter pointer
a
.
mov
(
assembler
::
RDX
,
assembler
::
R14
);
// vreg array
a
.
jmp
(
assembler
::
Indirect
(
assembler
::
RSI
,
offsetof
(
CFGBlock
,
code
)));
// jump to block
entry_offset
=
a
.
bytesWritten
();
...
...
@@ -139,6 +142,10 @@ JitFragmentWriter::JitFragmentWriter(CFGBlock* block, std::unique_ptr<ICInfo> ic
interp
=
createNewVar
();
addLocationToVar
(
interp
,
assembler
::
R12
);
interp
->
setAttr
(
ASTInterpreterJitInterface
::
getCurrentBlockOffset
(),
imm
(
block
));
vregs_array
=
createNewVar
();
addLocationToVar
(
vregs_array
,
assembler
::
R14
);
addAction
([
=
]()
{
vregs_array
->
bumpUse
();
},
vregs_array
,
ActionType
::
NORMAL
);
}
RewriterVar
*
JitFragmentWriter
::
imm
(
uint64_t
val
)
{
...
...
@@ -279,10 +286,10 @@ RewriterVar* JitFragmentWriter::emitGetAttr(RewriterVar* obj, BoxedString* s, AS
return
emitPPCall
((
void
*
)
getattr
,
{
obj
,
imm
(
s
)
},
2
,
512
,
getTypeRecorderForNode
(
node
));
}
RewriterVar
*
JitFragmentWriter
::
emitGetBlockLocal
(
InternedString
s
)
{
RewriterVar
*
JitFragmentWriter
::
emitGetBlockLocal
(
InternedString
s
,
int
vreg
)
{
auto
it
=
local_syms
.
find
(
s
);
if
(
it
==
local_syms
.
end
())
return
emitGetLocal
(
s
);
return
emitGetLocal
(
s
,
vreg
);
return
it
->
second
;
}
...
...
@@ -308,13 +315,11 @@ RewriterVar* JitFragmentWriter::emitGetItem(RewriterVar* value, RewriterVar* sli
return
emitPPCall
((
void
*
)
getitem
,
{
value
,
slice
},
2
,
512
);
}
RewriterVar
*
JitFragmentWriter
::
emitGetLocal
(
InternedString
s
)
{
return
call
(
false
,
(
void
*
)
ASTInterpreterJitInterface
::
getLocalHelper
,
getInterp
(),
#ifndef NDEBUG
imm
(
asUInt
(
s
).
first
),
imm
(
asUInt
(
s
).
second
));
#else
imm
(
asUInt
(
s
)));
#endif
RewriterVar
*
JitFragmentWriter
::
emitGetLocal
(
InternedString
s
,
int
vreg
)
{
assert
(
vreg
>=
0
);
RewriterVar
*
val_var
=
vregs_array
->
getAttr
(
vreg
*
8
);
addAction
([
=
]()
{
_emitGetLocal
(
val_var
,
s
.
c_str
());
},
{
val_var
},
ActionType
::
NORMAL
);
return
val_var
;
}
RewriterVar
*
JitFragmentWriter
::
emitGetPystonIter
(
RewriterVar
*
v
)
{
...
...
@@ -471,17 +476,19 @@ void JitFragmentWriter::emitSetItemName(BoxedString* s, RewriterVar* v) {
emitSetItem
(
emitGetBoxedLocals
(),
imm
(
s
),
v
);
}
void
JitFragmentWriter
::
emitSetLocal
(
InternedString
s
,
bool
set_closure
,
RewriterVar
*
v
)
{
void
*
func
=
set_closure
?
(
void
*
)
ASTInterpreterJitInterface
::
setLocalClosureHelper
:
(
void
*
)
ASTInterpreterJitInterface
::
setLocalHelper
;
call
(
false
,
func
,
getInterp
(),
void
JitFragmentWriter
::
emitSetLocal
(
InternedString
s
,
int
vreg
,
bool
set_closure
,
RewriterVar
*
v
)
{
assert
(
vreg
>=
0
);
if
(
set_closure
)
{
call
(
false
,
(
void
*
)
ASTInterpreterJitInterface
::
setLocalClosureHelper
,
getInterp
(),
imm
(
vreg
),
#ifndef NDEBUG
imm
(
asUInt
(
s
).
first
),
imm
(
asUInt
(
s
).
second
),
#else
imm
(
asUInt
(
s
)),
#endif
v
);
}
else
{
vregs_array
->
setAttr
(
8
*
vreg
,
v
);
}
}
void
JitFragmentWriter
::
emitSideExit
(
RewriterVar
*
v
,
Box
*
cmp_value
,
CFGBlock
*
next_block
)
{
...
...
@@ -619,6 +626,10 @@ RewriterVar* JitFragmentWriter::emitPPCall(void* func_addr, llvm::ArrayRef<Rewri
#endif
}
void
JitFragmentWriter
::
assertNameDefinedHelper
(
const
char
*
id
)
{
assertNameDefined
(
0
,
id
,
UnboundLocalError
,
true
);
}
Box
*
JitFragmentWriter
::
callattrHelper
(
Box
*
obj
,
BoxedString
*
attr
,
CallattrFlags
flags
,
TypeRecorder
*
type_recorder
,
Box
**
args
,
std
::
vector
<
BoxedString
*>*
keyword_names
)
{
auto
arg_tuple
=
getTupleFromArgsArray
(
&
args
[
0
],
flags
.
argspec
.
totalPassed
());
...
...
@@ -683,6 +694,18 @@ Box* JitFragmentWriter::runtimeCallHelper(Box* obj, ArgPassSpec argspec, TypeRec
return
recordType
(
type_recorder
,
r
);
}
void
JitFragmentWriter
::
_emitGetLocal
(
RewriterVar
*
val_var
,
const
char
*
name
)
{
assembler
::
Register
var_reg
=
val_var
->
getInReg
();
assembler
->
test
(
var_reg
,
var_reg
);
val_var
->
bumpUse
();
{
assembler
::
ForwardJump
jnz
(
*
assembler
,
assembler
::
COND_NOT_ZERO
);
assembler
->
mov
(
assembler
::
Immediate
((
uint64_t
)
name
),
assembler
::
RDI
);
assembler
->
mov
(
assembler
::
Immediate
((
void
*
)
assertNameDefinedHelper
),
assembler
::
R11
);
assembler
->
callq
(
assembler
::
R11
);
}
}
void
JitFragmentWriter
::
_emitJump
(
CFGBlock
*
b
,
RewriterVar
*
block_next
,
int
&
size_of_exit_to_interp
)
{
size_of_exit_to_interp
=
0
;
...
...
@@ -698,6 +721,7 @@ void JitFragmentWriter::_emitJump(CFGBlock* b, RewriterVar* block_next, int& siz
block_next
->
getInReg
(
assembler
::
RAX
,
true
);
assembler
->
add
(
assembler
::
Immediate
(
JitCodeBlock
::
sp_adjustment
),
assembler
::
RSP
);
assembler
->
pop
(
assembler
::
R12
);
assembler
->
pop
(
assembler
::
R14
);
assembler
->
retq
();
// make sure we have at least 'min_patch_size' of bytes available.
...
...
@@ -724,6 +748,7 @@ void JitFragmentWriter::_emitOSRPoint(RewriterVar* result, RewriterVar* node_var
assembler
->
mov
(
assembler
::
Immediate
(
0ul
),
assembler
::
RAX
);
// TODO: use xor
assembler
->
add
(
assembler
::
Immediate
(
JitCodeBlock
::
sp_adjustment
),
assembler
::
RSP
);
assembler
->
pop
(
assembler
::
R12
);
assembler
->
pop
(
assembler
::
R14
);
assembler
->
retq
();
}
...
...
@@ -794,6 +819,7 @@ void JitFragmentWriter::_emitReturn(RewriterVar* return_val) {
assembler
->
mov
(
assembler
::
Immediate
(
0ul
),
assembler
::
RAX
);
// TODO: use xor
assembler
->
add
(
assembler
::
Immediate
(
JitCodeBlock
::
sp_adjustment
),
assembler
::
RSP
);
assembler
->
pop
(
assembler
::
R12
);
assembler
->
pop
(
assembler
::
R14
);
assembler
->
retq
();
return_val
->
bumpUse
();
}
...
...
src/codegen/baseline_jit.h
View file @
22759d1a
...
...
@@ -70,12 +70,16 @@ class JitFragmentWriter;
// This also means that we are allowed to store a Python variable which only lives in the current CFGBLock* inside a
// 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:
// r12: pointer to ASTInterpreter instance
// r14: pointer to the vregs array
//
// To execute a specific CFGBlock one has to call:
// CFGBlock* block;
// block->entry_code(ast_interpreter_instance, block)
// block->entry_code(ast_interpreter_instance, block
, ast_interpreter_instance->vregs
)
//
// Signature of a JitCodeBlock:
// std::pair<CFGBlock*, Box*>(*entry_code)(ASTInterpreter* interp, CFGBlock* block)
// std::pair<CFGBlock*, Box*>(*entry_code)(ASTInterpreter* interp, CFGBlock* block
, Box** vregs
)
// args:
// interp: instance to the ASTInterpreter
// block: block to execute
...
...
@@ -87,10 +91,12 @@ class JitFragmentWriter;
//
// Basic layout of generated code block is:
// entry_code:
// push %r14 ; save r14
// push %r12 ; save r12
// sub $0x11
0,%rsp ; setup scratch, 0x110
= scratch_size + 16 = space for two func args passed on the
// stack
// sub $0x11
8,%rsp ; setup scratch, 0x118
= scratch_size + 16 = space for two func args passed on the
// stack
+ 8 byte for stack alignment
// mov %rdi,%r12 ; copy the pointer to ASTInterpreter instance into r12
// mov %rdx,%r14 ; copy the pointer to the vregs array into r14
// jmpq *0x8(%rsi) ; jump to block->code
// possible values: first_JitFragment, second_JitFragment,...
//
...
...
@@ -101,8 +107,9 @@ class JitFragmentWriter;
// cmp %rax,%rcx ; rax == True
// jne end_side_exit
// movabs $0x215bb60,%rax ; rax = CFGBlock* to interpret next (rax is the 1. return reg)
// add $0x11
0
,%rsp ; restore stack pointer
// add $0x11
8
,%rsp ; restore stack pointer
// pop %r12 ; restore r12
// pop %r14 ; restore r14
// ret ; exit to the interpreter which will interpret the specified CFGBLock*
// end_side_exit:
// ....
...
...
@@ -113,8 +120,9 @@ class JitFragmentWriter;
// mov $0,%rax ; rax contains the next block to interpret.
// in this case 0 which means we are finished
// movabs $0x1270014108,%rdx ; rdx must contain the Box* value to return
// add $0x11
0
,%rsp ; restore stack pointer
// add $0x11
8
,%rsp ; restore stack pointer
// pop %r12 ; restore r12
// pop %r14 ; restore r14
// ret
//
// nth_JitFragment:
...
...
@@ -130,7 +138,7 @@ public:
// scratch size + space for passing additional args on the stack without having to adjust the SP when calling
// functions with more than 6 args.
static
constexpr
int
sp_adjustment
=
scratch_size
+
num_stack_args
*
8
;
static
constexpr
int
sp_adjustment
=
scratch_size
+
num_stack_args
*
8
+
8
/* = alignment */
;
private:
std
::
unique_ptr
<
uint8_t
[]
>
code
;
...
...
@@ -168,6 +176,7 @@ private:
void
*
entry_code
;
// JitCodeBlock start address. Must have an offset of 0 into the code block
JitCodeBlock
&
code_block
;
RewriterVar
*
interp
;
RewriterVar
*
vregs_array
;
llvm
::
DenseMap
<
InternedString
,
RewriterVar
*>
local_syms
;
std
::
unique_ptr
<
ICInfo
>
ic_info
;
...
...
@@ -208,13 +217,13 @@ public:
RewriterVar
*
emitDeref
(
InternedString
s
);
RewriterVar
*
emitExceptionMatches
(
RewriterVar
*
v
,
RewriterVar
*
cls
);
RewriterVar
*
emitGetAttr
(
RewriterVar
*
obj
,
BoxedString
*
s
,
AST_expr
*
node
);
RewriterVar
*
emitGetBlockLocal
(
InternedString
s
);
RewriterVar
*
emitGetBlockLocal
(
InternedString
s
,
int
vreg
);
RewriterVar
*
emitGetBoxedLocal
(
BoxedString
*
s
);
RewriterVar
*
emitGetBoxedLocals
();
RewriterVar
*
emitGetClsAttr
(
RewriterVar
*
obj
,
BoxedString
*
s
);
RewriterVar
*
emitGetGlobal
(
Box
*
global
,
BoxedString
*
s
);
RewriterVar
*
emitGetItem
(
RewriterVar
*
value
,
RewriterVar
*
slice
);
RewriterVar
*
emitGetLocal
(
InternedString
s
);
RewriterVar
*
emitGetLocal
(
InternedString
s
,
int
vreg
);
RewriterVar
*
emitGetPystonIter
(
RewriterVar
*
v
);
RewriterVar
*
emitHasnext
(
RewriterVar
*
v
);
RewriterVar
*
emitLandingpad
();
...
...
@@ -241,7 +250,7 @@ public:
void
emitSetGlobal
(
Box
*
global
,
BoxedString
*
s
,
RewriterVar
*
v
);
void
emitSetItemName
(
BoxedString
*
s
,
RewriterVar
*
v
);
void
emitSetItem
(
RewriterVar
*
target
,
RewriterVar
*
slice
,
RewriterVar
*
value
);
void
emitSetLocal
(
InternedString
s
,
bool
set_closure
,
RewriterVar
*
v
);
void
emitSetLocal
(
InternedString
s
,
int
vreg
,
bool
set_closure
,
RewriterVar
*
v
);
void
emitSideExit
(
RewriterVar
*
v
,
Box
*
cmp_value
,
CFGBlock
*
next_block
);
void
emitUncacheExcInfo
();
...
...
@@ -262,6 +271,7 @@ private:
RewriterVar
*
emitPPCall
(
void
*
func_addr
,
llvm
::
ArrayRef
<
RewriterVar
*>
args
,
int
num_slots
,
int
slot_size
,
TypeRecorder
*
type_recorder
=
NULL
);
static
void
assertNameDefinedHelper
(
const
char
*
id
);
static
Box
*
callattrHelper
(
Box
*
obj
,
BoxedString
*
attr
,
CallattrFlags
flags
,
TypeRecorder
*
type_recorder
,
Box
**
args
,
std
::
vector
<
BoxedString
*>*
keyword_names
);
static
Box
*
createDictHelper
(
uint64_t
num
,
Box
**
keys
,
Box
**
values
);
...
...
@@ -275,6 +285,7 @@ private:
static
Box
*
runtimeCallHelper
(
Box
*
obj
,
ArgPassSpec
argspec
,
TypeRecorder
*
type_recorder
,
Box
**
args
,
std
::
vector
<
BoxedString
*>*
keyword_names
);
void
_emitGetLocal
(
RewriterVar
*
val_var
,
const
char
*
name
);
void
_emitJump
(
CFGBlock
*
b
,
RewriterVar
*
block_next
,
int
&
size_of_exit_to_interp
);
void
_emitOSRPoint
(
RewriterVar
*
result
,
RewriterVar
*
node_var
);
void
_emitPPCall
(
RewriterVar
*
result
,
void
*
func_addr
,
const
RewriterVar
::
SmallVector
&
args
,
int
num_slots
,
...
...
src/core/ast.h
View file @
22759d1a
...
...
@@ -703,6 +703,10 @@ public:
// different bytecodes.
ScopeInfo
::
VarScopeType
lookup_type
;
// The interpreter and baseline JIT store variables with FAST and CLOSURE scopes in an array (vregs) this specifies
// the zero based index of this variable inside the vregs array. If uninitialized it's value is -1.
int
vreg
;
virtual
void
accept
(
ASTVisitor
*
v
);
virtual
void
*
accept_expr
(
ExprVisitor
*
v
);
...
...
@@ -710,7 +714,8 @@ public:
:
AST_expr
(
AST_TYPE
::
Name
,
lineno
,
col_offset
),
ctx_type
(
ctx_type
),
id
(
id
),
lookup_type
(
ScopeInfo
::
VarScopeType
::
UNKNOWN
)
{}
lookup_type
(
ScopeInfo
::
VarScopeType
::
UNKNOWN
),
vreg
(
-
1
)
{}
static
const
AST_TYPE
::
AST_TYPE
TYPE
=
AST_TYPE
::
Name
;
};
...
...
src/core/cfg.cpp
View file @
22759d1a
...
...
@@ -2471,6 +2471,87 @@ void CFG::print() {
blocks
[
i
]
->
print
();
}
class
AssignVRegsVisitor
:
public
NoopASTVisitor
{
public:
int
index
=
0
;
llvm
::
DenseMap
<
InternedString
,
int
>
sym_vreg_map
;
ScopeInfo
*
scope_info
;
AssignVRegsVisitor
(
ScopeInfo
*
scope_info
)
:
scope_info
(
scope_info
)
{}
bool
visit_arguments
(
AST_arguments
*
node
)
override
{
for
(
AST_expr
*
d
:
node
->
defaults
)
d
->
accept
(
this
);
return
true
;
}
bool
visit_classdef
(
AST_ClassDef
*
node
)
override
{
for
(
auto
e
:
node
->
bases
)
e
->
accept
(
this
);
for
(
auto
e
:
node
->
decorator_list
)
e
->
accept
(
this
);
return
true
;
}
bool
visit_functiondef
(
AST_FunctionDef
*
node
)
override
{
for
(
auto
*
d
:
node
->
decorator_list
)
d
->
accept
(
this
);
node
->
args
->
accept
(
this
);
return
true
;
}
bool
visit_lambda
(
AST_Lambda
*
node
)
override
{
node
->
args
->
accept
(
this
);
return
true
;
}
bool
visit_name
(
AST_Name
*
node
)
override
{
if
(
node
->
vreg
!=
-
1
)
return
true
;
if
(
node
->
lookup_type
==
ScopeInfo
::
VarScopeType
::
UNKNOWN
)
node
->
lookup_type
=
scope_info
->
getScopeTypeOfName
(
node
->
id
);
if
(
node
->
lookup_type
==
ScopeInfo
::
VarScopeType
::
FAST
||
node
->
lookup_type
==
ScopeInfo
::
VarScopeType
::
CLOSURE
)
node
->
vreg
=
assignVReg
(
node
->
id
);
return
true
;
}
int
assignVReg
(
InternedString
id
)
{
auto
it
=
sym_vreg_map
.
find
(
id
);
if
(
sym_vreg_map
.
end
()
==
it
)
{
sym_vreg_map
[
id
]
=
index
;
return
index
++
;
}
return
it
->
second
;
}
};
void
CFG
::
assignVRegs
(
const
ParamNames
&
param_names
,
ScopeInfo
*
scope_info
)
{
if
(
has_vregs_assigned
)
return
;
AssignVRegsVisitor
visitor
(
scope_info
);
for
(
CFGBlock
*
b
:
blocks
)
{
for
(
AST_stmt
*
stmt
:
b
->
body
)
{
stmt
->
accept
(
&
visitor
);
}
}
for
(
auto
*
name
:
param_names
.
arg_names
)
{
name
->
accept
(
&
visitor
);
}
if
(
param_names
.
vararg_name
)
param_names
.
vararg_name
->
accept
(
&
visitor
);
if
(
param_names
.
kwarg_name
)
param_names
.
kwarg_name
->
accept
(
&
visitor
);
sym_vreg_map
=
std
::
move
(
visitor
.
sym_vreg_map
);
has_vregs_assigned
=
true
;
}
CFG
*
computeCFG
(
SourceInfo
*
source
,
std
::
vector
<
AST_stmt
*>
body
)
{
STAT_TIMER
(
t0
,
"us_timer_computecfg"
,
0
);
...
...
src/core/cfg.h
View file @
22759d1a
...
...
@@ -39,6 +39,9 @@ class AST_stmt;
class
Box
;
class
CFG
;
class
ParamNames
;
class
ScopeInfo
;
class
CFGBlock
{
private:
CFG
*
cfg
;
...
...
@@ -48,7 +51,7 @@ public:
// contains address to the start of the code of this basic block
void
*
code
;
// contains the address of the entry function
std
::
pair
<
CFGBlock
*
,
Box
*>
(
*
entry_code
)(
void
*
interpeter
,
CFGBlock
*
block
);
std
::
pair
<
CFGBlock
*
,
Box
*>
(
*
entry_code
)(
void
*
interpeter
,
CFGBlock
*
block
,
Box
**
vregs
);
std
::
vector
<
AST_stmt
*>
body
;
std
::
vector
<
CFGBlock
*>
predecessors
,
successors
;
...
...
@@ -70,11 +73,14 @@ public:
class
CFG
{
private:
int
next_idx
;
bool
has_vregs_assigned
;
public:
std
::
vector
<
CFGBlock
*>
blocks
;
CFG
()
:
next_idx
(
0
)
{}
llvm
::
DenseMap
<
InternedString
,
int
>
sym_vreg_map
;
CFG
()
:
next_idx
(
0
),
has_vregs_assigned
(
false
)
{}
CFGBlock
*
getStartingBlock
()
{
return
blocks
[
0
];
}
...
...
@@ -103,6 +109,8 @@ public:
}
void
print
();
void
assignVRegs
(
const
ParamNames
&
param_names
,
ScopeInfo
*
scope_info
);
};
class
SourceInfo
;
...
...
src/core/contiguous_map.h
View file @
22759d1a
...
...
@@ -21,9 +21,10 @@
namespace
pyston
{
template
<
class
TKey
,
class
TVal
,
class
TMap
=
llvm
::
DenseMap
<
TKey
,
int
>
>
class
ContiguousMap
{
template
<
class
TKey
,
class
TVal
,
class
TMap
=
llvm
::
DenseMap
<
TKey
,
int
>,
class
TVec
=
std
::
vector
<
TVal
>>
class
ContiguousMap
{
typedef
TMap
map_type
;
typedef
std
::
vector
<
TVal
>
vec_type
;
typedef
TVec
vec_type
;
map_type
map
;
vec_type
vec
;
...
...
src/runtime/types.cpp
View file @
22759d1a
...
...
@@ -3339,7 +3339,6 @@ void setupRuntime() {
closure_cls
->
freeze
();
setupUnwinding
();
setupInterpreter
();
setupCAPI
();
// Can't set up object methods until we set up CAPI support:
...
...
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