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
218d8cd5
Commit
218d8cd5
authored
Nov 20, 2014
by
Kevin Modzelewski
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #228 from kmod/interp2
New AST interpreter
parents
bb3a19e1
062009c7
Changes
22
Show whitespace changes
Inline
Side-by-side
Showing
22 changed files
with
1308 additions
and
96 deletions
+1308
-96
docs/PROFILING
docs/PROFILING
+11
-0
src/analysis/function_analysis.cpp
src/analysis/function_analysis.cpp
+7
-1
src/analysis/function_analysis.h
src/analysis/function_analysis.h
+3
-1
src/analysis/scoping_analysis.cpp
src/analysis/scoping_analysis.cpp
+4
-4
src/analysis/scoping_analysis.h
src/analysis/scoping_analysis.h
+2
-2
src/codegen/ast_interpreter.cpp
src/codegen/ast_interpreter.cpp
+979
-0
src/codegen/ast_interpreter.h
src/codegen/ast_interpreter.h
+40
-0
src/codegen/irgen.cpp
src/codegen/irgen.cpp
+110
-25
src/codegen/irgen.h
src/codegen/irgen.h
+7
-0
src/codegen/irgen/hooks.cpp
src/codegen/irgen/hooks.cpp
+34
-16
src/codegen/irgen/hooks.h
src/codegen/irgen/hooks.h
+2
-0
src/codegen/irgen/irgenerator.cpp
src/codegen/irgen/irgenerator.cpp
+36
-36
src/codegen/irgen/irgenerator.h
src/codegen/irgen/irgenerator.h
+3
-0
src/codegen/llvm_interpreter.cpp
src/codegen/llvm_interpreter.cpp
+7
-4
src/codegen/llvm_interpreter.h
src/codegen/llvm_interpreter.h
+2
-0
src/codegen/unwinding.cpp
src/codegen/unwinding.cpp
+11
-3
src/core/types.h
src/core/types.h
+0
-1
src/gc/root_finder.cpp
src/gc/root_finder.cpp
+1
-1
src/runtime/objmodel.cpp
src/runtime/objmodel.cpp
+2
-1
src/runtime/set.h
src/runtime/set.h
+3
-1
test/tests/arg_unpacking.py
test/tests/arg_unpacking.py
+8
-0
test/tests/generator_thread_sharing.py
test/tests/generator_thread_sharing.py
+36
-0
No files found.
docs/PROFILING
View file @
218d8cd5
...
@@ -24,3 +24,14 @@ the JIT'd code.
...
@@ -24,3 +24,14 @@ the JIT'd code.
There's a gprof-based profile, but that doesn't support any JIT'd code. It can be quite handy for profiling the Pyston
There's a gprof-based profile, but that doesn't support any JIT'd code. It can be quite handy for profiling the Pyston
codegen + LLVM cost.
codegen + LLVM cost.
We also have a few internal timers that log important sections of code. You can see their totals by passing '-s' to
the executable (ARGS=-s to a Make recipe).
Some common ones are:
- us_compiling: total amount of time (in microseconds) spent in 'codegen', from
the time we decide we want to run some Python code to the point that we can
start executing it
- us_compiling_irgen: total time creating the LLVM IR. includes some analysis time
- us_compiling_jitting: subset of us_compiling which is spent in LLVM
compilation (time from giving LLVM its IR to when we get machine code back)
src/analysis/function_analysis.cpp
View file @
218d8cd5
...
@@ -459,7 +459,13 @@ bool PhiAnalysis::isPotentiallyUndefinedAfter(const std::string& name, CFGBlock*
...
@@ -459,7 +459,13 @@ bool PhiAnalysis::isPotentiallyUndefinedAfter(const std::string& name, CFGBlock*
if
(
block
->
successors
.
size
()
!=
1
)
if
(
block
->
successors
.
size
()
!=
1
)
return
false
;
return
false
;
for
(
CFGBlock
*
pred
:
block
->
successors
[
0
]
->
predecessors
)
{
return
isPotentiallyUndefinedAt
(
name
,
block
->
successors
[
0
]);
}
bool
PhiAnalysis
::
isPotentiallyUndefinedAt
(
const
std
::
string
&
name
,
CFGBlock
*
block
)
{
assert
(
!
startswith
(
name
,
"!"
));
for
(
CFGBlock
*
pred
:
block
->
predecessors
)
{
DefinednessAnalysis
::
DefinitionLevel
dlevel
=
definedness
.
isDefinedAtEnd
(
name
,
pred
);
DefinednessAnalysis
::
DefinitionLevel
dlevel
=
definedness
.
isDefinedAtEnd
(
name
,
pred
);
if
(
dlevel
!=
DefinednessAnalysis
::
Defined
)
if
(
dlevel
!=
DefinednessAnalysis
::
Defined
)
return
true
;
return
true
;
...
...
src/analysis/function_analysis.h
View file @
218d8cd5
...
@@ -84,8 +84,9 @@ class PhiAnalysis {
...
@@ -84,8 +84,9 @@ class PhiAnalysis {
public:
public:
typedef
std
::
unordered_set
<
std
::
string
>
RequiredSet
;
typedef
std
::
unordered_set
<
std
::
string
>
RequiredSet
;
private:
DefinednessAnalysis
definedness
;
DefinednessAnalysis
definedness
;
private:
LivenessAnalysis
*
liveness
;
LivenessAnalysis
*
liveness
;
std
::
unordered_map
<
CFGBlock
*
,
const
RequiredSet
>
required_phis
;
std
::
unordered_map
<
CFGBlock
*
,
const
RequiredSet
>
required_phis
;
...
@@ -97,6 +98,7 @@ public:
...
@@ -97,6 +98,7 @@ public:
const
RequiredSet
&
getAllRequiredAfter
(
CFGBlock
*
block
);
const
RequiredSet
&
getAllRequiredAfter
(
CFGBlock
*
block
);
const
RequiredSet
&
getAllRequiredFor
(
CFGBlock
*
block
);
const
RequiredSet
&
getAllRequiredFor
(
CFGBlock
*
block
);
bool
isPotentiallyUndefinedAfter
(
const
std
::
string
&
name
,
CFGBlock
*
block
);
bool
isPotentiallyUndefinedAfter
(
const
std
::
string
&
name
,
CFGBlock
*
block
);
bool
isPotentiallyUndefinedAt
(
const
std
::
string
&
name
,
CFGBlock
*
block
);
};
};
LivenessAnalysis
*
computeLivenessInfo
(
CFG
*
);
LivenessAnalysis
*
computeLivenessInfo
(
CFG
*
);
...
...
src/analysis/scoping_analysis.cpp
View file @
218d8cd5
...
@@ -70,8 +70,8 @@ public:
...
@@ -70,8 +70,8 @@ public:
// assert(name[0] != '#' && "should test this");
// assert(name[0] != '#' && "should test this");
return
true
;
return
true
;
}
}
bool
refersToClosure
(
const
std
::
string
name
)
override
{
return
false
;
}
bool
refersToClosure
(
const
std
::
string
&
name
)
override
{
return
false
;
}
bool
saveInClosure
(
const
std
::
string
name
)
override
{
return
false
;
}
bool
saveInClosure
(
const
std
::
string
&
name
)
override
{
return
false
;
}
const
std
::
unordered_set
<
std
::
string
>&
getClassDefLocalNames
()
override
{
RELEASE_ASSERT
(
0
,
""
);
}
const
std
::
unordered_set
<
std
::
string
>&
getClassDefLocalNames
()
override
{
RELEASE_ASSERT
(
0
,
""
);
}
};
};
...
@@ -141,13 +141,13 @@ public:
...
@@ -141,13 +141,13 @@ public:
return
true
;
return
true
;
return
usage
->
written
.
count
(
name
)
==
0
&&
usage
->
got_from_closure
.
count
(
name
)
==
0
;
return
usage
->
written
.
count
(
name
)
==
0
&&
usage
->
got_from_closure
.
count
(
name
)
==
0
;
}
}
bool
refersToClosure
(
const
std
::
string
name
)
override
{
bool
refersToClosure
(
const
std
::
string
&
name
)
override
{
// HAX
// HAX
if
(
isCompilerCreatedName
(
name
))
if
(
isCompilerCreatedName
(
name
))
return
false
;
return
false
;
return
usage
->
got_from_closure
.
count
(
name
)
!=
0
;
return
usage
->
got_from_closure
.
count
(
name
)
!=
0
;
}
}
bool
saveInClosure
(
const
std
::
string
name
)
override
{
bool
saveInClosure
(
const
std
::
string
&
name
)
override
{
// HAX
// HAX
if
(
isCompilerCreatedName
(
name
))
if
(
isCompilerCreatedName
(
name
))
return
false
;
return
false
;
...
...
src/analysis/scoping_analysis.h
View file @
218d8cd5
...
@@ -36,8 +36,8 @@ public:
...
@@ -36,8 +36,8 @@ public:
virtual
void
setTakesGenerator
(
bool
b
=
true
)
{
isGeneratorValue
=
b
;
}
virtual
void
setTakesGenerator
(
bool
b
=
true
)
{
isGeneratorValue
=
b
;
}
virtual
bool
refersToGlobal
(
const
std
::
string
&
name
)
=
0
;
virtual
bool
refersToGlobal
(
const
std
::
string
&
name
)
=
0
;
virtual
bool
refersToClosure
(
const
std
::
string
name
)
=
0
;
virtual
bool
refersToClosure
(
const
std
::
string
&
name
)
=
0
;
virtual
bool
saveInClosure
(
const
std
::
string
name
)
=
0
;
virtual
bool
saveInClosure
(
const
std
::
string
&
name
)
=
0
;
// Get the names set within a classdef that should be forwarded on to
// Get the names set within a classdef that should be forwarded on to
// the metaclass constructor.
// the metaclass constructor.
...
...
src/codegen/ast_interpreter.cpp
0 → 100644
View file @
218d8cd5
// Copyright (c) 2014 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.
#include "codegen/ast_interpreter.h"
#include <llvm/ADT/StringMap.h>
#include <unordered_map>
#include "analysis/function_analysis.h"
#include "analysis/scoping_analysis.h"
#include "codegen/codegen.h"
#include "codegen/compvars.h"
#include "codegen/irgen.h"
#include "codegen/irgen/hooks.h"
#include "codegen/irgen/irgenerator.h"
#include "codegen/irgen/util.h"
#include "codegen/osrentry.h"
#include "core/ast.h"
#include "core/cfg.h"
#include "core/common.h"
#include "core/stats.h"
#include "core/thread_utils.h"
#include "core/util.h"
#include "runtime/generator.h"
#include "runtime/import.h"
#include "runtime/inline/boxing.h"
#include "runtime/long.h"
#include "runtime/objmodel.h"
#include "runtime/set.h"
#include "runtime/types.h"
namespace
pyston
{
#define OSR_THRESHOLD 100
#define REOPT_THRESHOLD 100
union
Value
{
bool
b
;
int64_t
n
;
double
d
;
Box
*
o
;
Value
(
bool
b
)
:
b
(
b
)
{}
Value
(
int64_t
n
=
0
)
:
n
(
n
)
{}
Value
(
double
d
)
:
d
(
d
)
{}
Value
(
Box
*
o
)
:
o
(
o
)
{}
};
class
ASTInterpreter
{
public:
typedef
llvm
::
StringMap
<
Box
*>
SymMap
;
ASTInterpreter
(
CompiledFunction
*
compiled_function
,
void
*
frame_addr
);
~
ASTInterpreter
();
void
initArguments
(
int
nargs
,
BoxedClosure
*
closure
,
BoxedGenerator
*
generator
,
Box
*
arg1
,
Box
*
arg2
,
Box
*
arg3
,
Box
**
args
);
Value
execute
(
CFGBlock
*
block
=
0
);
private:
Box
*
createFunction
(
AST
*
node
,
AST_arguments
*
args
,
const
std
::
vector
<
AST_stmt
*>&
body
);
Value
doBinOp
(
Box
*
left
,
Box
*
right
,
int
op
,
BinExpType
exp_type
);
void
doStore
(
AST_expr
*
node
,
Value
value
);
void
doStore
(
const
std
::
string
&
name
,
Value
value
);
void
eraseDeadSymbols
();
Value
visit_assert
(
AST_Assert
*
node
);
Value
visit_assign
(
AST_Assign
*
node
);
Value
visit_binop
(
AST_BinOp
*
node
);
Value
visit_call
(
AST_Call
*
node
);
Value
visit_classDef
(
AST_ClassDef
*
node
);
Value
visit_compare
(
AST_Compare
*
node
);
Value
visit_delete
(
AST_Delete
*
node
);
Value
visit_functionDef
(
AST_FunctionDef
*
node
);
Value
visit_global
(
AST_Global
*
node
);
Value
visit_module
(
AST_Module
*
node
);
Value
visit_print
(
AST_Print
*
node
);
Value
visit_raise
(
AST_Raise
*
node
);
Value
visit_return
(
AST_Return
*
node
);
Value
visit_stmt
(
AST_stmt
*
node
);
Value
visit_unaryop
(
AST_UnaryOp
*
node
);
Value
visit_attribute
(
AST_Attribute
*
node
);
Value
visit_dict
(
AST_Dict
*
node
);
Value
visit_expr
(
AST_expr
*
node
);
Value
visit_expr
(
AST_Expr
*
node
);
Value
visit_index
(
AST_Index
*
node
);
Value
visit_lambda
(
AST_Lambda
*
node
);
Value
visit_list
(
AST_List
*
node
);
Value
visit_name
(
AST_Name
*
node
);
Value
visit_num
(
AST_Num
*
node
);
Value
visit_repr
(
AST_Repr
*
node
);
Value
visit_set
(
AST_Set
*
node
);
Value
visit_slice
(
AST_Slice
*
node
);
Value
visit_str
(
AST_Str
*
node
);
Value
visit_subscript
(
AST_Subscript
*
node
);
Value
visit_tuple
(
AST_Tuple
*
node
);
Value
visit_yield
(
AST_Yield
*
node
);
// pseudo
Value
visit_augBinOp
(
AST_AugBinOp
*
node
);
Value
visit_branch
(
AST_Branch
*
node
);
Value
visit_clsAttribute
(
AST_ClsAttribute
*
node
);
Value
visit_invoke
(
AST_Invoke
*
node
);
Value
visit_jump
(
AST_Jump
*
node
);
Value
visit_langPrimitive
(
AST_LangPrimitive
*
node
);
void
*
frame_addr
;
CompiledFunction
*
compiled_func
;
SourceInfo
*
source_info
;
ScopeInfo
*
scope_info
;
SymMap
sym_table
;
CFGBlock
*
next_block
,
*
current_block
;
AST
*
current_inst
;
Box
*
last_exception
;
BoxedClosure
*
passed_closure
,
*
created_closure
;
BoxedGenerator
*
generator
;
unsigned
edgecount
;
public:
LineInfo
*
getCurrentLineInfo
();
BoxedModule
*
getParentModule
()
{
return
source_info
->
parent_module
;
}
const
SymMap
&
getSymbolTable
()
{
return
sym_table
;
}
};
static_assert
(
THREADING_USE_GIL
,
"have to make the interpreter map thread safe!"
);
static
std
::
unordered_map
<
void
*
,
ASTInterpreter
*>
s_interpreterMap
;
Box
*
astInterpretFunction
(
CompiledFunction
*
cf
,
int
nargs
,
Box
*
closure
,
Box
*
generator
,
Box
*
arg1
,
Box
*
arg2
,
Box
*
arg3
,
Box
**
args
)
{
if
(
unlikely
(
cf
->
times_called
>
REOPT_THRESHOLD
))
{
CompiledFunction
*
optimized
=
reoptCompiledFuncInternal
(
cf
);
if
(
closure
&&
generator
)
return
optimized
->
closure_generator_call
((
BoxedClosure
*
)
closure
,
(
BoxedGenerator
*
)
generator
,
arg1
,
arg2
,
arg3
,
args
);
else
if
(
closure
)
return
optimized
->
closure_call
((
BoxedClosure
*
)
closure
,
arg1
,
arg2
,
arg3
,
args
);
else
if
(
generator
)
return
optimized
->
generator_call
((
BoxedGenerator
*
)
generator
,
arg1
,
arg2
,
arg3
,
args
);
return
optimized
->
call
(
arg1
,
arg2
,
arg3
,
args
);
}
++
cf
->
times_called
;
void
*
frame_addr
=
__builtin_frame_address
(
0
);
ASTInterpreter
interpreter
(
cf
,
frame_addr
);
interpreter
.
initArguments
(
nargs
,
(
BoxedClosure
*
)
closure
,
(
BoxedGenerator
*
)
generator
,
arg1
,
arg2
,
arg3
,
args
);
Value
v
=
interpreter
.
execute
();
return
v
.
o
?
v
.
o
:
None
;
}
const
LineInfo
*
getLineInfoForInterpretedFrame
(
void
*
frame_ptr
)
{
ASTInterpreter
*
interpreter
=
s_interpreterMap
[
frame_ptr
];
assert
(
interpreter
);
return
interpreter
->
getCurrentLineInfo
();
}
LineInfo
*
ASTInterpreter
::
getCurrentLineInfo
()
{
LineInfo
*
line_info
=
new
LineInfo
(
current_inst
->
lineno
,
current_inst
->
col_offset
,
source_info
->
parent_module
->
fn
,
source_info
->
getName
());
return
line_info
;
}
BoxedModule
*
getModuleForInterpretedFrame
(
void
*
frame_ptr
)
{
ASTInterpreter
*
interpreter
=
s_interpreterMap
[
frame_ptr
];
assert
(
interpreter
);
return
interpreter
->
getParentModule
();
}
BoxedDict
*
localsForInterpretedFrame
(
void
*
frame_ptr
,
bool
only_user_visible
)
{
ASTInterpreter
*
interpreter
=
s_interpreterMap
[
frame_ptr
];
assert
(
interpreter
);
BoxedDict
*
rtn
=
new
BoxedDict
();
for
(
auto
&&
l
:
interpreter
->
getSymbolTable
())
{
if
(
only_user_visible
&&
(
l
.
getKey
()[
0
]
==
'!'
||
l
.
getKey
()[
0
]
==
'#'
))
continue
;
rtn
->
d
[
new
BoxedString
(
l
.
getKey
())]
=
l
.
getValue
();
}
return
rtn
;
}
void
gatherInterpreterRoots
(
GCVisitor
*
visitor
)
{
for
(
const
auto
&
p
:
s_interpreterMap
)
{
for
(
const
auto
&
p2
:
p
.
second
->
getSymbolTable
())
{
visitor
->
visitPotential
(
p2
.
second
);
}
}
}
ASTInterpreter
::
ASTInterpreter
(
CompiledFunction
*
compiled_function
,
void
*
frame_addr
)
:
frame_addr
(
frame_addr
),
compiled_func
(
compiled_function
),
source_info
(
compiled_function
->
clfunc
->
source
),
scope_info
(
0
),
next_block
(
0
),
current_block
(
0
),
current_inst
(
0
),
last_exception
(
0
),
passed_closure
(
0
),
created_closure
(
0
),
generator
(
0
),
edgecount
(
0
)
{
s_interpreterMap
[
frame_addr
]
=
this
;
CLFunction
*
f
=
compiled_function
->
clfunc
;
if
(
!
source_info
->
cfg
)
source_info
->
cfg
=
computeCFG
(
f
->
source
,
f
->
source
->
body
);
scope_info
=
source_info
->
getScopeInfo
();
}
ASTInterpreter
::~
ASTInterpreter
()
{
assert
(
s_interpreterMap
[
frame_addr
]
==
this
);
s_interpreterMap
.
erase
(
frame_addr
);
}
void
ASTInterpreter
::
initArguments
(
int
nargs
,
BoxedClosure
*
_closure
,
BoxedGenerator
*
_generator
,
Box
*
arg1
,
Box
*
arg2
,
Box
*
arg3
,
Box
**
args
)
{
passed_closure
=
_closure
;
generator
=
_generator
;
if
(
scope_info
->
createsClosure
())
created_closure
=
createClosure
(
passed_closure
);
std
::
vector
<
Box
*>
argsArray
{
arg1
,
arg2
,
arg3
};
for
(
int
i
=
3
;
i
<
nargs
;
++
i
)
argsArray
.
push_back
(
args
[
i
-
3
]);
int
i
=
0
;
if
(
source_info
->
arg_names
.
args
)
{
for
(
AST_expr
*
e
:
*
source_info
->
arg_names
.
args
)
{
RELEASE_ASSERT
(
e
->
type
==
AST_TYPE
::
Name
,
"not implemented"
);
AST_Name
*
name
=
(
AST_Name
*
)
e
;
doStore
(
name
->
id
,
argsArray
[
i
++
]);
}
}
if
(
source_info
->
arg_names
.
vararg
&&
!
source_info
->
arg_names
.
vararg
->
empty
())
{
doStore
(
*
source_info
->
arg_names
.
vararg
,
argsArray
[
i
++
]);
}
if
(
source_info
->
arg_names
.
kwarg
&&
!
source_info
->
arg_names
.
kwarg
->
empty
())
{
doStore
(
*
source_info
->
arg_names
.
kwarg
,
argsArray
[
i
++
]);
}
}
Value
ASTInterpreter
::
execute
(
CFGBlock
*
block
)
{
if
(
!
block
)
block
=
source_info
->
cfg
->
getStartingBlock
();
Value
v
;
next_block
=
block
;
while
(
next_block
)
{
current_block
=
next_block
;
next_block
=
0
;
for
(
AST_stmt
*
s
:
current_block
->
body
)
{
current_inst
=
s
;
v
=
visit_stmt
(
s
);
}
}
return
v
;
}
void
ASTInterpreter
::
eraseDeadSymbols
()
{
if
(
source_info
->
liveness
==
NULL
)
source_info
->
liveness
=
computeLivenessInfo
(
source_info
->
cfg
);
if
(
source_info
->
phis
==
NULL
)
source_info
->
phis
=
computeRequiredPhis
(
source_info
->
arg_names
,
source_info
->
cfg
,
source_info
->
liveness
,
scope_info
);
std
::
vector
<
std
::
string
>
dead_symbols
;
for
(
auto
&&
it
:
sym_table
)
{
if
(
!
source_info
->
liveness
->
isLiveAtEnd
(
it
.
getKey
(),
current_block
))
{
dead_symbols
.
push_back
(
it
.
getKey
());
}
else
if
(
source_info
->
phis
->
isRequiredAfter
(
it
.
getKey
(),
current_block
))
{
assert
(
!
scope_info
->
refersToGlobal
(
it
.
getKey
()));
}
else
{
}
}
for
(
auto
&&
dead
:
dead_symbols
)
sym_table
.
erase
(
dead
);
}
Value
ASTInterpreter
::
doBinOp
(
Box
*
left
,
Box
*
right
,
int
op
,
BinExpType
exp_type
)
{
if
(
op
==
AST_TYPE
::
Div
&&
(
source_info
->
parent_module
->
future_flags
&
FF_DIVISION
))
{
op
=
AST_TYPE
::
TrueDiv
;
}
switch
(
exp_type
)
{
case
BinExpType
:
:
AugBinOp
:
return
augbinop
(
left
,
right
,
op
);
case
BinExpType
:
:
BinOp
:
return
binop
(
left
,
right
,
op
);
case
BinExpType
:
:
Compare
:
return
compare
(
left
,
right
,
op
);
default:
RELEASE_ASSERT
(
0
,
"not implemented"
);
}
return
Value
();
}
void
ASTInterpreter
::
doStore
(
const
std
::
string
&
name
,
Value
value
)
{
if
(
scope_info
->
refersToGlobal
(
name
))
{
setattr
(
source_info
->
parent_module
,
name
.
c_str
(),
value
.
o
);
}
else
{
sym_table
[
name
]
=
value
.
o
;
if
(
scope_info
->
saveInClosure
(
name
))
setattr
(
created_closure
,
name
.
c_str
(),
value
.
o
);
}
}
void
ASTInterpreter
::
doStore
(
AST_expr
*
node
,
Value
value
)
{
if
(
node
->
type
==
AST_TYPE
::
Name
)
{
AST_Name
*
name
=
(
AST_Name
*
)
node
;
doStore
(
name
->
id
,
value
);
}
else
if
(
node
->
type
==
AST_TYPE
::
Attribute
)
{
AST_Attribute
*
attr
=
(
AST_Attribute
*
)
node
;
setattr
(
visit_expr
(
attr
->
value
).
o
,
attr
->
attr
.
c_str
(),
value
.
o
);
}
else
if
(
node
->
type
==
AST_TYPE
::
Tuple
)
{
AST_Tuple
*
tuple
=
(
AST_Tuple
*
)
node
;
Box
**
array
=
unpackIntoArray
(
value
.
o
,
tuple
->
elts
.
size
());
unsigned
i
=
0
;
for
(
AST_expr
*
e
:
tuple
->
elts
)
doStore
(
e
,
array
[
i
++
]);
}
else
if
(
node
->
type
==
AST_TYPE
::
List
)
{
AST_List
*
list
=
(
AST_List
*
)
node
;
Box
**
array
=
unpackIntoArray
(
value
.
o
,
list
->
elts
.
size
());
unsigned
i
=
0
;
for
(
AST_expr
*
e
:
list
->
elts
)
doStore
(
e
,
array
[
i
++
]);
}
else
if
(
node
->
type
==
AST_TYPE
::
Subscript
)
{
AST_Subscript
*
subscript
=
(
AST_Subscript
*
)
node
;
Value
target
=
visit_expr
(
subscript
->
value
);
Value
slice
=
visit_expr
(
subscript
->
slice
);
setitem
(
target
.
o
,
slice
.
o
,
value
.
o
);
}
else
{
RELEASE_ASSERT
(
0
,
"not implemented"
);
}
}
Value
ASTInterpreter
::
visit_unaryop
(
AST_UnaryOp
*
node
)
{
Value
operand
=
visit_expr
(
node
->
operand
);
if
(
node
->
op_type
==
AST_TYPE
::
Not
)
return
boxBool
(
!
nonzero
(
operand
.
o
));
else
return
unaryop
(
operand
.
o
,
node
->
op_type
);
}
Value
ASTInterpreter
::
visit_binop
(
AST_BinOp
*
node
)
{
Value
left
=
visit_expr
(
node
->
left
);
Value
right
=
visit_expr
(
node
->
right
);
return
doBinOp
(
left
.
o
,
right
.
o
,
node
->
op_type
,
BinExpType
::
BinOp
);
}
Value
ASTInterpreter
::
visit_slice
(
AST_Slice
*
node
)
{
Value
lower
=
node
->
lower
?
visit_expr
(
node
->
lower
)
:
None
;
Value
upper
=
node
->
upper
?
visit_expr
(
node
->
upper
)
:
None
;
Value
step
=
node
->
step
?
visit_expr
(
node
->
step
)
:
None
;
return
createSlice
(
lower
.
o
,
upper
.
o
,
step
.
o
);
}
Value
ASTInterpreter
::
visit_branch
(
AST_Branch
*
node
)
{
if
(
nonzero
(
visit_expr
(
node
->
test
).
o
))
next_block
=
node
->
iftrue
;
else
next_block
=
node
->
iffalse
;
return
Value
();
}
Value
ASTInterpreter
::
visit_jump
(
AST_Jump
*
node
)
{
if
(
ENABLE_OSR
&&
node
->
target
->
idx
<
current_block
->
idx
&&
compiled_func
)
{
++
edgecount
;
if
(
edgecount
>
OSR_THRESHOLD
)
{
eraseDeadSymbols
();
OSRExit
exit
(
compiled_func
,
OSREntryDescriptor
::
create
(
compiled_func
,
node
));
std
::
map
<
std
::
string
,
Box
*>
sorted_symbol_table
;
auto
phis
=
compiled_func
->
clfunc
->
source
->
phis
;
for
(
auto
&
name
:
phis
->
definedness
.
getDefinedNamesAtEnd
(
current_block
))
{
auto
it
=
sym_table
.
find
(
name
);
if
(
!
compiled_func
->
clfunc
->
source
->
liveness
->
isLiveAtEnd
(
name
,
current_block
))
continue
;
if
(
phis
->
isPotentiallyUndefinedAfter
(
name
,
current_block
))
{
bool
is_defined
=
it
!=
sym_table
.
end
();
sorted_symbol_table
[
getIsDefinedName
(
name
)]
=
(
Box
*
)
is_defined
;
sorted_symbol_table
[
name
]
=
is_defined
?
it
->
getValue
()
:
NULL
;
}
else
{
ASSERT
(
it
!=
sym_table
.
end
(),
"%s"
,
name
.
c_str
());
sorted_symbol_table
[
it
->
getKey
()]
=
it
->
getValue
();
}
}
if
(
generator
)
sorted_symbol_table
[
PASSED_GENERATOR_NAME
]
=
generator
;
if
(
passed_closure
)
sorted_symbol_table
[
PASSED_CLOSURE_NAME
]
=
passed_closure
;
if
(
created_closure
)
sorted_symbol_table
[
CREATED_CLOSURE_NAME
]
=
created_closure
;
std
::
vector
<
Box
*>
arg_array
;
for
(
auto
&
it
:
sorted_symbol_table
)
{
if
(
isIsDefinedName
(
it
.
first
))
exit
.
entry
->
args
[
it
.
first
]
=
BOOL
;
else
if
(
it
.
first
==
PASSED_GENERATOR_NAME
)
exit
.
entry
->
args
[
it
.
first
]
=
GENERATOR
;
else
if
(
it
.
first
==
PASSED_CLOSURE_NAME
||
it
.
first
==
CREATED_CLOSURE_NAME
)
exit
.
entry
->
args
[
it
.
first
]
=
CLOSURE
;
else
{
assert
(
it
.
first
[
0
]
!=
'!'
);
exit
.
entry
->
args
[
it
.
first
]
=
UNKNOWN
;
}
arg_array
.
push_back
(
it
.
second
);
}
CompiledFunction
*
partial_func
=
compilePartialFuncInternal
(
&
exit
);
Box
*
arg1
=
arg_array
.
size
()
>=
1
?
arg_array
[
0
]
:
0
;
Box
*
arg2
=
arg_array
.
size
()
>=
2
?
arg_array
[
1
]
:
0
;
Box
*
arg3
=
arg_array
.
size
()
>=
3
?
arg_array
[
2
]
:
0
;
Box
**
args
=
arg_array
.
size
()
>=
4
?
&
arg_array
[
3
]
:
0
;
return
partial_func
->
call
(
arg1
,
arg2
,
arg3
,
args
);
}
}
next_block
=
node
->
target
;
return
Value
();
}
Value
ASTInterpreter
::
visit_invoke
(
AST_Invoke
*
node
)
{
Value
v
;
try
{
v
=
visit_stmt
(
node
->
stmt
);
next_block
=
node
->
normal_dest
;
}
catch
(
Box
*
b
)
{
next_block
=
node
->
exc_dest
;
last_exception
=
b
;
}
return
v
;
}
Value
ASTInterpreter
::
visit_clsAttribute
(
AST_ClsAttribute
*
node
)
{
return
getattr
(
visit_expr
(
node
->
value
).
o
,
node
->
attr
.
c_str
());
}
Value
ASTInterpreter
::
visit_augBinOp
(
AST_AugBinOp
*
node
)
{
assert
(
node
->
op_type
!=
AST_TYPE
::
Is
&&
node
->
op_type
!=
AST_TYPE
::
IsNot
&&
"not tested yet"
);
Value
left
=
visit_expr
(
node
->
left
);
Value
right
=
visit_expr
(
node
->
right
);
return
doBinOp
(
left
.
o
,
right
.
o
,
node
->
op_type
,
BinExpType
::
AugBinOp
);
}
Value
ASTInterpreter
::
visit_langPrimitive
(
AST_LangPrimitive
*
node
)
{
Value
v
;
if
(
node
->
opcode
==
AST_LangPrimitive
::
GET_ITER
)
{
assert
(
node
->
args
.
size
()
==
1
);
v
=
getiter
(
visit_expr
(
node
->
args
[
0
]).
o
);
}
else
if
(
node
->
opcode
==
AST_LangPrimitive
::
IMPORT_FROM
)
{
assert
(
node
->
args
.
size
()
==
2
);
assert
(
node
->
args
[
0
]
->
type
==
AST_TYPE
::
Name
);
assert
(
node
->
args
[
1
]
->
type
==
AST_TYPE
::
Str
);
Value
module
=
visit_expr
(
node
->
args
[
0
]);
const
std
::
string
&
name
=
ast_cast
<
AST_Str
>
(
node
->
args
[
1
])
->
s
;
assert
(
name
.
size
());
v
=
importFrom
(
module
.
o
,
&
name
);
}
else
if
(
node
->
opcode
==
AST_LangPrimitive
::
IMPORT_NAME
)
{
assert
(
node
->
args
.
size
()
==
3
);
assert
(
node
->
args
[
0
]
->
type
==
AST_TYPE
::
Num
);
assert
(
static_cast
<
AST_Num
*>
(
node
->
args
[
0
])
->
num_type
==
AST_Num
::
INT
);
assert
(
node
->
args
[
2
]
->
type
==
AST_TYPE
::
Str
);
int
level
=
static_cast
<
AST_Num
*>
(
node
->
args
[
0
])
->
n_int
;
Value
froms
=
visit_expr
(
node
->
args
[
1
]);
const
std
::
string
&
module_name
=
static_cast
<
AST_Str
*>
(
node
->
args
[
2
])
->
s
;
v
=
import
(
level
,
froms
.
o
,
&
module_name
);
}
else
if
(
node
->
opcode
==
AST_LangPrimitive
::
IMPORT_STAR
)
{
assert
(
node
->
args
.
size
()
==
1
);
assert
(
node
->
args
[
0
]
->
type
==
AST_TYPE
::
Name
);
RELEASE_ASSERT
(
source_info
->
ast
->
type
==
AST_TYPE
::
Module
,
"import * not supported in functions"
);
Value
module
=
visit_expr
(
node
->
args
[
0
]);
v
=
importStar
(
module
.
o
,
source_info
->
parent_module
);
}
else
if
(
node
->
opcode
==
AST_LangPrimitive
::
NONE
)
{
v
=
None
;
}
else
if
(
node
->
opcode
==
AST_LangPrimitive
::
LANDINGPAD
)
{
v
=
last_exception
;
last_exception
=
nullptr
;
}
else
if
(
node
->
opcode
==
AST_LangPrimitive
::
ISINSTANCE
)
{
assert
(
node
->
args
.
size
()
==
3
);
Value
obj
=
visit_expr
(
node
->
args
[
0
]);
Value
cls
=
visit_expr
(
node
->
args
[
1
]);
Value
flags
=
visit_expr
(
node
->
args
[
2
]);
v
=
boxBool
(
isinstance
(
obj
.
o
,
cls
.
o
,
unboxInt
(
flags
.
o
)));
}
else
if
(
node
->
opcode
==
AST_LangPrimitive
::
LOCALS
)
{
BoxedDict
*
dict
=
new
BoxedDict
;
for
(
auto
&
p
:
sym_table
)
{
llvm
::
StringRef
s
=
p
.
first
();
if
(
s
[
0
]
==
'!'
||
s
[
0
]
==
'#'
)
continue
;
dict
->
d
[
new
BoxedString
(
s
.
str
())]
=
p
.
second
;
}
v
=
dict
;
}
else
RELEASE_ASSERT
(
0
,
"not implemented"
);
return
v
;
}
Value
ASTInterpreter
::
visit_yield
(
AST_Yield
*
node
)
{
Value
value
=
node
->
value
?
visit_expr
(
node
->
value
)
:
None
;
assert
(
generator
&&
generator
->
cls
==
generator_cls
);
return
yield
(
generator
,
value
.
o
);
}
Value
__attribute__
((
flatten
))
ASTInterpreter
::
visit_stmt
(
AST_stmt
*
node
)
{
switch
(
node
->
type
)
{
case
AST_TYPE
:
:
Assert
:
return
visit_assert
((
AST_Assert
*
)
node
);
case
AST_TYPE
:
:
Assign
:
return
visit_assign
((
AST_Assign
*
)
node
);
case
AST_TYPE
:
:
ClassDef
:
return
visit_classDef
((
AST_ClassDef
*
)
node
);
case
AST_TYPE
:
:
Delete
:
return
visit_delete
((
AST_Delete
*
)
node
);
case
AST_TYPE
:
:
Expr
:
return
visit_expr
((
AST_Expr
*
)
node
);
case
AST_TYPE
:
:
FunctionDef
:
return
visit_functionDef
((
AST_FunctionDef
*
)
node
);
case
AST_TYPE
:
:
Pass
:
return
Value
();
// nothing todo
case
AST_TYPE
:
:
Print
:
return
visit_print
((
AST_Print
*
)
node
);
case
AST_TYPE
:
:
Raise
:
return
visit_raise
((
AST_Raise
*
)
node
);
case
AST_TYPE
:
:
Return
:
return
visit_return
((
AST_Return
*
)
node
);
case
AST_TYPE
:
:
Global
:
return
visit_global
((
AST_Global
*
)
node
);
// pseudo
case
AST_TYPE
:
:
Branch
:
return
visit_branch
((
AST_Branch
*
)
node
);
case
AST_TYPE
:
:
Jump
:
return
visit_jump
((
AST_Jump
*
)
node
);
case
AST_TYPE
:
:
Invoke
:
return
visit_invoke
((
AST_Invoke
*
)
node
);
default:
RELEASE_ASSERT
(
0
,
"not implemented"
);
};
return
Value
();
}
Value
ASTInterpreter
::
visit_return
(
AST_Return
*
node
)
{
Value
s
(
node
->
value
?
visit_expr
(
node
->
value
)
:
None
);
next_block
=
0
;
return
s
;
}
Box
*
ASTInterpreter
::
createFunction
(
AST
*
node
,
AST_arguments
*
args
,
const
std
::
vector
<
AST_stmt
*>&
body
)
{
CLFunction
*
cl
=
wrapFunction
(
node
,
args
,
body
,
source_info
);
std
::
vector
<
Box
*>
defaults
;
for
(
AST_expr
*
d
:
args
->
defaults
)
defaults
.
push_back
(
visit_expr
(
d
).
o
);
defaults
.
push_back
(
0
);
// FIXME: Using initializer_list is pretty annoying since you're not supposed to create them:
union
{
struct
{
Box
**
ptr
;
size_t
s
;
}
d
;
std
::
initializer_list
<
Box
*>
il
=
{};
}
u
;
u
.
d
.
ptr
=
&
defaults
[
0
];
u
.
d
.
s
=
defaults
.
size
()
-
1
;
ScopeInfo
*
scope_info_node
=
source_info
->
scoping
->
getScopeInfoForNode
(
node
);
bool
is_generator
=
scope_info_node
->
takesGenerator
();
BoxedClosure
*
closure
=
0
;
if
(
scope_info_node
->
takesClosure
())
{
if
(
scope_info
->
createsClosure
())
{
closure
=
created_closure
;
}
else
{
assert
(
scope_info
->
passesThroughClosure
());
closure
=
passed_closure
;
}
assert
(
closure
);
}
return
boxCLFunction
(
cl
,
closure
,
is_generator
,
u
.
il
);
}
Value
ASTInterpreter
::
visit_functionDef
(
AST_FunctionDef
*
node
)
{
AST_arguments
*
args
=
node
->
args
;
std
::
vector
<
Box
*>
decorators
;
for
(
AST_expr
*
d
:
node
->
decorator_list
)
decorators
.
push_back
(
visit_expr
(
d
).
o
);
Box
*
func
=
createFunction
(
node
,
args
,
node
->
body
);
for
(
int
i
=
decorators
.
size
()
-
1
;
i
>=
0
;
i
--
)
func
=
runtimeCall
(
decorators
[
i
],
ArgPassSpec
(
1
),
func
,
0
,
0
,
0
,
0
);
doStore
(
node
->
name
,
func
);
return
Value
();
}
Value
ASTInterpreter
::
visit_classDef
(
AST_ClassDef
*
node
)
{
ScopeInfo
*
scope_info
=
source_info
->
scoping
->
getScopeInfoForNode
(
node
);
assert
(
scope_info
);
BoxedTuple
::
GCVector
bases
;
for
(
AST_expr
*
b
:
node
->
bases
)
bases
.
push_back
(
visit_expr
(
b
).
o
);
BoxedTuple
*
basesTuple
=
new
BoxedTuple
(
std
::
move
(
bases
));
std
::
vector
<
Box
*>
decorators
;
for
(
AST_expr
*
d
:
node
->
decorator_list
)
decorators
.
push_back
(
visit_expr
(
d
).
o
);
BoxedClosure
*
closure
=
scope_info
->
takesClosure
()
?
created_closure
:
0
;
CLFunction
*
cl
=
wrapFunction
(
node
,
nullptr
,
node
->
body
,
source_info
);
Box
*
attrDict
=
runtimeCall
(
boxCLFunction
(
cl
,
closure
,
false
,
{}),
ArgPassSpec
(
0
),
0
,
0
,
0
,
0
,
0
);
Box
*
classobj
=
createUserClass
(
&
node
->
name
,
basesTuple
,
attrDict
);
for
(
int
i
=
decorators
.
size
()
-
1
;
i
>=
0
;
i
--
)
classobj
=
runtimeCall
(
decorators
[
i
],
ArgPassSpec
(
1
),
classobj
,
0
,
0
,
0
,
0
);
doStore
(
node
->
name
,
classobj
);
return
Value
();
}
Value
ASTInterpreter
::
visit_raise
(
AST_Raise
*
node
)
{
if
(
node
->
arg0
==
NULL
)
{
assert
(
!
node
->
arg1
);
assert
(
!
node
->
arg2
);
raise0
();
}
raise3
(
node
->
arg0
?
visit_expr
(
node
->
arg0
).
o
:
None
,
node
->
arg1
?
visit_expr
(
node
->
arg1
).
o
:
None
,
node
->
arg2
?
visit_expr
(
node
->
arg2
).
o
:
None
);
return
Value
();
}
Value
ASTInterpreter
::
visit_assert
(
AST_Assert
*
node
)
{
if
(
!
nonzero
(
visit_expr
(
node
->
test
).
o
))
assertFail
(
source_info
->
parent_module
,
node
->
msg
?
visit_expr
(
node
->
msg
).
o
:
0
);
return
Value
();
}
Value
ASTInterpreter
::
visit_global
(
AST_Global
*
node
)
{
for
(
std
::
string
&
name
:
node
->
names
)
sym_table
.
erase
(
name
);
return
Value
();
}
Value
ASTInterpreter
::
visit_delete
(
AST_Delete
*
node
)
{
for
(
AST_expr
*
target_
:
node
->
targets
)
{
switch
(
target_
->
type
)
{
case
AST_TYPE
:
:
Subscript
:
{
AST_Subscript
*
sub
=
(
AST_Subscript
*
)
target_
;
Value
value
=
visit_expr
(
sub
->
value
);
Value
slice
=
visit_expr
(
sub
->
slice
);
delitem
(
value
.
o
,
slice
.
o
);
break
;
}
case
AST_TYPE
:
:
Attribute
:
{
AST_Attribute
*
attr
=
(
AST_Attribute
*
)
target_
;
delattr
(
visit_expr
(
attr
->
value
).
o
,
attr
->
attr
.
c_str
());
break
;
}
case
AST_TYPE
:
:
Name
:
{
AST_Name
*
target
=
(
AST_Name
*
)
target_
;
if
(
scope_info
->
refersToGlobal
(
target
->
id
))
{
// Can't use delattr since the errors are different:
delGlobal
(
source_info
->
parent_module
,
&
target
->
id
);
continue
;
}
assert
(
!
scope_info
->
refersToClosure
(
target
->
id
));
assert
(
!
scope_info
->
saveInClosure
(
target
->
id
));
// SyntaxError: can not delete variable 'x' referenced in nested scope
// A del of a missing name generates different error messages in a function scope vs a classdef scope
bool
local_error_msg
=
(
source_info
->
ast
->
type
!=
AST_TYPE
::
ClassDef
);
if
(
sym_table
.
count
(
target
->
id
)
==
0
)
{
assertNameDefined
(
0
,
target
->
id
.
c_str
(),
NameError
,
local_error_msg
);
return
Value
();
}
sym_table
.
erase
(
target
->
id
);
break
;
}
default:
ASSERT
(
0
,
"Unsupported del target: %d"
,
target_
->
type
);
abort
();
}
}
return
Value
();
}
Value
ASTInterpreter
::
visit_assign
(
AST_Assign
*
node
)
{
Value
v
=
visit_expr
(
node
->
value
);
for
(
AST_expr
*
e
:
node
->
targets
)
doStore
(
e
,
v
);
return
Value
();
}
Value
ASTInterpreter
::
visit_print
(
AST_Print
*
node
)
{
static
const
std
::
string
write_str
(
"write"
);
static
const
std
::
string
newline_str
(
"
\n
"
);
static
const
std
::
string
space_str
(
" "
);
Box
*
dest
=
node
->
dest
?
visit_expr
(
node
->
dest
).
o
:
getSysStdout
();
int
nvals
=
node
->
values
.
size
();
for
(
int
i
=
0
;
i
<
nvals
;
i
++
)
{
Box
*
var
=
visit_expr
(
node
->
values
[
i
]).
o
;
// begin code for handling of softspace
bool
new_softspace
=
(
i
<
nvals
-
1
)
||
(
!
node
->
nl
);
if
(
softspace
(
dest
,
new_softspace
))
{
callattrInternal
(
dest
,
&
write_str
,
CLASS_OR_INST
,
0
,
ArgPassSpec
(
1
),
boxString
(
space_str
),
0
,
0
,
0
,
0
);
}
callattrInternal
(
dest
,
&
write_str
,
CLASS_OR_INST
,
0
,
ArgPassSpec
(
1
),
str
(
var
),
0
,
0
,
0
,
0
);
}
if
(
node
->
nl
)
{
callattrInternal
(
dest
,
&
write_str
,
CLASS_OR_INST
,
0
,
ArgPassSpec
(
1
),
boxString
(
newline_str
),
0
,
0
,
0
,
0
);
if
(
nvals
==
0
)
{
softspace
(
dest
,
false
);
}
}
return
Value
();
}
Value
ASTInterpreter
::
visit_compare
(
AST_Compare
*
node
)
{
RELEASE_ASSERT
(
node
->
comparators
.
size
()
==
1
,
"not implemented"
);
return
doBinOp
(
visit_expr
(
node
->
left
).
o
,
visit_expr
(
node
->
comparators
[
0
]).
o
,
node
->
ops
[
0
],
BinExpType
::
Compare
);
}
Value
__attribute__
((
flatten
))
ASTInterpreter
::
visit_expr
(
AST_expr
*
node
)
{
switch
(
node
->
type
)
{
case
AST_TYPE
:
:
Attribute
:
return
visit_attribute
((
AST_Attribute
*
)
node
);
case
AST_TYPE
:
:
BinOp
:
return
visit_binop
((
AST_BinOp
*
)
node
);
case
AST_TYPE
:
:
Call
:
return
visit_call
((
AST_Call
*
)
node
);
case
AST_TYPE
:
:
Compare
:
return
visit_compare
((
AST_Compare
*
)
node
);
case
AST_TYPE
:
:
Dict
:
return
visit_dict
((
AST_Dict
*
)
node
);
case
AST_TYPE
:
:
Index
:
return
visit_index
((
AST_Index
*
)
node
);
case
AST_TYPE
:
:
Lambda
:
return
visit_lambda
((
AST_Lambda
*
)
node
);
case
AST_TYPE
:
:
List
:
return
visit_list
((
AST_List
*
)
node
);
case
AST_TYPE
:
:
Name
:
return
visit_name
((
AST_Name
*
)
node
);
case
AST_TYPE
:
:
Num
:
return
visit_num
((
AST_Num
*
)
node
);
case
AST_TYPE
:
:
Repr
:
return
visit_repr
((
AST_Repr
*
)
node
);
case
AST_TYPE
:
:
Set
:
return
visit_set
((
AST_Set
*
)
node
);
case
AST_TYPE
:
:
Slice
:
return
visit_slice
((
AST_Slice
*
)
node
);
case
AST_TYPE
:
:
Str
:
return
visit_str
((
AST_Str
*
)
node
);
case
AST_TYPE
:
:
Subscript
:
return
visit_subscript
((
AST_Subscript
*
)
node
);
case
AST_TYPE
:
:
Tuple
:
return
visit_tuple
((
AST_Tuple
*
)
node
);
case
AST_TYPE
:
:
UnaryOp
:
return
visit_unaryop
((
AST_UnaryOp
*
)
node
);
case
AST_TYPE
:
:
Yield
:
return
visit_yield
((
AST_Yield
*
)
node
);
// pseudo
case
AST_TYPE
:
:
AugBinOp
:
return
visit_augBinOp
((
AST_AugBinOp
*
)
node
);
case
AST_TYPE
:
:
ClsAttribute
:
return
visit_clsAttribute
((
AST_ClsAttribute
*
)
node
);
case
AST_TYPE
:
:
LangPrimitive
:
return
visit_langPrimitive
((
AST_LangPrimitive
*
)
node
);
default:
RELEASE_ASSERT
(
0
,
""
);
};
return
Value
();
}
Value
ASTInterpreter
::
visit_call
(
AST_Call
*
node
)
{
Value
v
;
Value
func
;
std
::
string
*
attr
=
nullptr
;
bool
is_callattr
=
false
;
bool
callattr_clsonly
=
false
;
if
(
node
->
func
->
type
==
AST_TYPE
::
Attribute
)
{
is_callattr
=
true
;
callattr_clsonly
=
false
;
AST_Attribute
*
attr_ast
=
ast_cast
<
AST_Attribute
>
(
node
->
func
);
func
=
visit_expr
(
attr_ast
->
value
);
attr
=
&
attr_ast
->
attr
;
}
else
if
(
node
->
func
->
type
==
AST_TYPE
::
ClsAttribute
)
{
is_callattr
=
true
;
callattr_clsonly
=
true
;
AST_ClsAttribute
*
attr_ast
=
ast_cast
<
AST_ClsAttribute
>
(
node
->
func
);
func
=
visit_expr
(
attr_ast
->
value
);
attr
=
&
attr_ast
->
attr
;
}
else
func
=
visit_expr
(
node
->
func
);
std
::
vector
<
Box
*>
args
;
for
(
AST_expr
*
e
:
node
->
args
)
args
.
push_back
(
visit_expr
(
e
).
o
);
std
::
vector
<
const
std
::
string
*>
keywords
;
for
(
AST_keyword
*
k
:
node
->
keywords
)
{
keywords
.
push_back
(
&
k
->
arg
);
args
.
push_back
(
visit_expr
(
k
->
value
).
o
);
}
if
(
node
->
starargs
)
args
.
push_back
(
visit_expr
(
node
->
starargs
).
o
);
if
(
node
->
kwargs
)
args
.
push_back
(
visit_expr
(
node
->
kwargs
).
o
);
ArgPassSpec
argspec
(
node
->
args
.
size
(),
node
->
keywords
.
size
(),
node
->
starargs
,
node
->
kwargs
);
if
(
is_callattr
)
{
return
callattr
(
func
.
o
,
attr
,
CallattrFlags
({.
cls_only
=
callattr_clsonly
,
.
null_on_nonexistent
=
false
}),
argspec
,
args
.
size
()
>
0
?
args
[
0
]
:
0
,
args
.
size
()
>
1
?
args
[
1
]
:
0
,
args
.
size
()
>
2
?
args
[
2
]
:
0
,
args
.
size
()
>
3
?
&
args
[
3
]
:
0
,
&
keywords
);
}
else
{
return
runtimeCall
(
func
.
o
,
argspec
,
args
.
size
()
>
0
?
args
[
0
]
:
0
,
args
.
size
()
>
1
?
args
[
1
]
:
0
,
args
.
size
()
>
2
?
args
[
2
]
:
0
,
args
.
size
()
>
3
?
&
args
[
3
]
:
0
,
&
keywords
);
}
}
Value
ASTInterpreter
::
visit_expr
(
AST_Expr
*
node
)
{
return
visit_expr
(
node
->
value
);
}
Value
ASTInterpreter
::
visit_num
(
AST_Num
*
node
)
{
if
(
node
->
num_type
==
AST_Num
::
INT
)
return
boxInt
(
node
->
n_int
);
else
if
(
node
->
num_type
==
AST_Num
::
FLOAT
)
return
boxFloat
(
node
->
n_float
);
else
if
(
node
->
num_type
==
AST_Num
::
LONG
)
return
createLong
(
&
node
->
n_long
);
else
if
(
node
->
num_type
==
AST_Num
::
COMPLEX
)
return
boxComplex
(
0.0
,
node
->
n_float
);
RELEASE_ASSERT
(
0
,
"not implemented"
);
return
Value
();
}
Value
ASTInterpreter
::
visit_index
(
AST_Index
*
node
)
{
return
visit_expr
(
node
->
value
);
}
Value
ASTInterpreter
::
visit_repr
(
AST_Repr
*
node
)
{
return
repr
(
visit_expr
(
node
->
value
).
o
);
}
Value
ASTInterpreter
::
visit_lambda
(
AST_Lambda
*
node
)
{
AST_Return
*
expr
=
new
AST_Return
();
expr
->
value
=
node
->
body
;
std
::
vector
<
AST_stmt
*>
body
=
{
expr
};
return
createFunction
(
node
,
node
->
args
,
body
);
}
Value
ASTInterpreter
::
visit_dict
(
AST_Dict
*
node
)
{
RELEASE_ASSERT
(
node
->
keys
.
size
()
==
node
->
values
.
size
(),
"not implemented"
);
BoxedDict
*
dict
=
new
BoxedDict
();
for
(
size_t
i
=
0
;
i
<
node
->
keys
.
size
();
++
i
)
{
Box
*
v
=
visit_expr
(
node
->
values
[
i
]).
o
;
Box
*
k
=
visit_expr
(
node
->
keys
[
i
]).
o
;
dict
->
d
[
k
]
=
v
;
}
return
dict
;
}
Value
ASTInterpreter
::
visit_set
(
AST_Set
*
node
)
{
BoxedSet
::
Set
set
;
for
(
AST_expr
*
e
:
node
->
elts
)
set
.
insert
(
visit_expr
(
e
).
o
);
return
new
BoxedSet
(
std
::
move
(
set
),
set_cls
);
}
Value
ASTInterpreter
::
visit_str
(
AST_Str
*
node
)
{
return
boxString
(
node
->
s
);
}
Value
ASTInterpreter
::
visit_name
(
AST_Name
*
node
)
{
if
(
scope_info
->
refersToGlobal
(
node
->
id
))
return
getGlobal
(
source_info
->
parent_module
,
&
node
->
id
);
else
if
(
scope_info
->
refersToClosure
(
node
->
id
))
{
return
getattr
(
passed_closure
,
node
->
id
.
c_str
());
}
else
{
SymMap
::
iterator
it
=
sym_table
.
find
(
node
->
id
);
if
(
it
!=
sym_table
.
end
())
{
Box
*
value
=
it
->
second
;
if
(
!
value
)
assertNameDefined
(
value
,
node
->
id
.
c_str
(),
UnboundLocalError
,
true
);
return
value
;
}
// classdefs have different scoping rules than functions:
if
(
source_info
->
ast
->
type
==
AST_TYPE
::
ClassDef
)
return
getGlobal
(
source_info
->
parent_module
,
&
node
->
id
);
assertNameDefined
(
0
,
node
->
id
.
c_str
(),
UnboundLocalError
,
true
);
return
Value
();
}
}
Value
ASTInterpreter
::
visit_subscript
(
AST_Subscript
*
node
)
{
Value
value
=
visit_expr
(
node
->
value
);
Value
slice
=
visit_expr
(
node
->
slice
);
return
getitem
(
value
.
o
,
slice
.
o
);
}
Value
ASTInterpreter
::
visit_list
(
AST_List
*
node
)
{
BoxedList
*
list
=
new
BoxedList
;
list
->
ensure
(
node
->
elts
.
size
());
for
(
AST_expr
*
e
:
node
->
elts
)
listAppendInternal
(
list
,
visit_expr
(
e
).
o
);
return
list
;
}
Value
ASTInterpreter
::
visit_tuple
(
AST_Tuple
*
node
)
{
BoxedTuple
::
GCVector
elts
;
for
(
AST_expr
*
e
:
node
->
elts
)
elts
.
push_back
(
visit_expr
(
e
).
o
);
return
new
BoxedTuple
(
std
::
move
(
elts
));
}
Value
ASTInterpreter
::
visit_attribute
(
AST_Attribute
*
node
)
{
return
getattr
(
visit_expr
(
node
->
value
).
o
,
node
->
attr
.
c_str
());
}
}
src/codegen/ast_interpreter.h
0 → 100644
View file @
218d8cd5
// Copyright (c) 2014 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.
#ifndef PYSTON_CODEGEN_ASTINTERPRETER_H
#define PYSTON_CODEGEN_ASTINTERPRETER_H
namespace
pyston
{
namespace
gc
{
class
GCVisitor
;
}
class
Box
;
class
BoxedDict
;
class
BoxedModule
;
struct
CompiledFunction
;
struct
LineInfo
;
Box
*
astInterpretFunction
(
CompiledFunction
*
f
,
int
nargs
,
Box
*
closure
,
Box
*
generator
,
Box
*
arg1
,
Box
*
arg2
,
Box
*
arg3
,
Box
**
args
);
const
LineInfo
*
getLineInfoForInterpretedFrame
(
void
*
frame_ptr
);
BoxedModule
*
getModuleForInterpretedFrame
(
void
*
frame_ptr
);
void
gatherInterpreterRoots
(
gc
::
GCVisitor
*
visitor
);
BoxedDict
*
localsForInterpretedFrame
(
void
*
frame_ptr
,
bool
only_user_visible
);
}
#endif
src/codegen/irgen.cpp
View file @
218d8cd5
...
@@ -279,7 +279,7 @@ computeBlockTraversalOrder(const BlockSet& full_blocks, const BlockSet& partial_
...
@@ -279,7 +279,7 @@ computeBlockTraversalOrder(const BlockSet& full_blocks, const BlockSet& partial_
}
}
static
ConcreteCompilerType
*
getTypeAtBlockStart
(
TypeAnalysis
*
types
,
const
std
::
string
&
name
,
CFGBlock
*
block
)
{
static
ConcreteCompilerType
*
getTypeAtBlockStart
(
TypeAnalysis
*
types
,
const
std
::
string
&
name
,
CFGBlock
*
block
)
{
if
(
startswith
(
name
,
"!is_defined"
))
if
(
isIsDefinedName
(
name
))
return
BOOL
;
return
BOOL
;
else
if
(
name
==
PASSED_GENERATOR_NAME
)
else
if
(
name
==
PASSED_GENERATOR_NAME
)
return
GENERATOR
;
return
GENERATOR
;
...
@@ -329,9 +329,8 @@ static void emitBBs(IRGenState* irstate, const char* bb_type, GuardList& out_gua
...
@@ -329,9 +329,8 @@ static void emitBBs(IRGenState* irstate, const char* bb_type, GuardList& out_gua
// llvm::BranchInst::Create(llvm_entry_blocks[entry_descriptor->backedge->target->idx], entry_block);
// llvm::BranchInst::Create(llvm_entry_blocks[entry_descriptor->backedge->target->idx], entry_block);
llvm
::
BasicBlock
*
osr_entry_block_end
=
osr_entry_block
;
llvm
::
BasicBlock
*
osr_entry_block_end
=
osr_entry_block
;
llvm
::
BasicBlock
*
osr_unbox_block_end
=
osr_unbox_block
;
std
::
unique_ptr
<
IREmitter
>
entry_emitter
(
createIREmitter
(
irstate
,
osr_entry_block_end
));
std
::
unique_ptr
<
IREmitter
>
entry_emitter
(
createIREmitter
(
irstate
,
osr_entry_block_end
));
std
::
unique_ptr
<
IREmitter
>
unbox_emitter
(
createIREmitter
(
irstate
,
osr_unbox_block
_end
));
std
::
unique_ptr
<
IREmitter
>
unbox_emitter
(
createIREmitter
(
irstate
,
osr_unbox_block
));
CFGBlock
*
target_block
=
entry_descriptor
->
backedge
->
target
;
CFGBlock
*
target_block
=
entry_descriptor
->
backedge
->
target
;
...
@@ -409,8 +408,29 @@ static void emitBBs(IRGenState* irstate, const char* bb_type, GuardList& out_gua
...
@@ -409,8 +408,29 @@ static void emitBBs(IRGenState* irstate, const char* bb_type, GuardList& out_gua
}
}
ASSERT
(
speculated_class
,
"%s"
,
phi_type
->
debugName
().
c_str
());
ASSERT
(
speculated_class
,
"%s"
,
phi_type
->
debugName
().
c_str
());
ASSERT
(
entry_descriptor
->
args
.
count
(
"!is_defined_"
+
p
.
first
)
==
0
,
assert
(
p
.
first
[
0
]
!=
'!'
);
"This class-check-creating behavior will segfault if the argument wasn't actually defined!"
);
std
::
string
is_defined_name
=
getIsDefinedName
(
p
.
first
);
llvm
::
BasicBlock
*
defined_join
=
nullptr
,
*
defined_prev
=
nullptr
,
*
defined_check
=
nullptr
;
if
(
entry_descriptor
->
args
.
count
(
is_defined_name
))
{
// relying on the fact that we are iterating over the names in order
// and the fake names precede the real names:
assert
(
osr_syms
->
count
(
is_defined_name
));
ConcreteCompilerVariable
*
is_defined_var
=
(
*
osr_syms
)[
is_defined_name
];
assert
(
is_defined_var
->
getType
()
==
BOOL
);
llvm
::
Value
*
is_defined_i1
=
i1FromBool
(
*
entry_emitter
,
is_defined_var
);
defined_check
=
llvm
::
BasicBlock
::
Create
(
g
.
context
,
""
,
irstate
->
getLLVMFunction
());
defined_join
=
llvm
::
BasicBlock
::
Create
(
g
.
context
,
""
,
irstate
->
getLLVMFunction
());
llvm
::
BranchInst
*
br
=
entry_emitter
->
getBuilder
()
->
CreateCondBr
(
is_defined_i1
,
defined_check
,
defined_join
);
defined_prev
=
osr_entry_block_end
;
osr_entry_block_end
=
defined_check
;
entry_emitter
->
getBuilder
()
->
SetInsertPoint
(
defined_check
);
}
llvm
::
Value
*
type_check
=
ConcreteCompilerVariable
(
p
.
second
,
from_arg
,
true
)
llvm
::
Value
*
type_check
=
ConcreteCompilerVariable
(
p
.
second
,
from_arg
,
true
)
.
makeClassCheck
(
*
entry_emitter
,
speculated_class
);
.
makeClassCheck
(
*
entry_emitter
,
speculated_class
);
...
@@ -421,6 +441,18 @@ static void emitBBs(IRGenState* irstate, const char* bb_type, GuardList& out_gua
...
@@ -421,6 +441,18 @@ static void emitBBs(IRGenState* irstate, const char* bb_type, GuardList& out_gua
}
}
// entry_emitter->getBuilder()->CreateCall(g.funcs.my_assert, type_check);
// entry_emitter->getBuilder()->CreateCall(g.funcs.my_assert, type_check);
if
(
defined_join
)
{
entry_emitter
->
getBuilder
()
->
CreateBr
(
defined_join
);
osr_entry_block_end
=
defined_join
;
entry_emitter
->
getBuilder
()
->
SetInsertPoint
(
defined_join
);
auto
guard_phi
=
entry_emitter
->
getBuilder
()
->
CreatePHI
(
g
.
i1
,
2
);
guard_phi
->
addIncoming
(
getConstantInt
(
0
,
g
.
i1
),
defined_prev
);
guard_phi
->
addIncoming
(
guard_val
,
defined_check
);
guard_val
=
guard_phi
;
}
if
(
speculated_class
==
int_cls
)
{
if
(
speculated_class
==
int_cls
)
{
v
=
unbox_emitter
->
getBuilder
()
->
CreateCall
(
g
.
funcs
.
unboxInt
,
from_arg
);
v
=
unbox_emitter
->
getBuilder
()
->
CreateCall
(
g
.
funcs
.
unboxInt
,
from_arg
);
(
new
ConcreteCompilerVariable
(
BOXED_INT
,
from_arg
,
true
))
->
decvref
(
*
unbox_emitter
);
(
new
ConcreteCompilerVariable
(
BOXED_INT
,
from_arg
,
true
))
->
decvref
(
*
unbox_emitter
);
...
@@ -621,25 +653,32 @@ static void emitBBs(IRGenState* irstate, const char* bb_type, GuardList& out_gua
...
@@ -621,25 +653,32 @@ static void emitBBs(IRGenState* irstate, const char* bb_type, GuardList& out_gua
into_hax
.
insert
(
b2
);
into_hax
.
insert
(
b2
);
}
}
const
PhiAnalysis
::
RequiredSet
&
names
=
source
->
phis
->
getAllRequiredFor
(
block
);
std
::
unordered_set
<
std
::
string
>
names
;
for
(
const
auto
&
s
:
source
->
phis
->
getAllRequiredFor
(
block
))
{
names
.
insert
(
s
);
if
(
source
->
phis
->
isPotentiallyUndefinedAfter
(
s
,
block
->
predecessors
[
0
]))
{
names
.
insert
(
getIsDefinedName
(
s
));
}
}
if
(
source
->
getScopeInfo
()
->
createsClosure
())
names
.
insert
(
CREATED_CLOSURE_NAME
);
if
(
source
->
getScopeInfo
()
->
takesClosure
())
names
.
insert
(
PASSED_CLOSURE_NAME
);
if
(
source
->
getScopeInfo
()
->
takesGenerator
())
names
.
insert
(
PASSED_GENERATOR_NAME
);
for
(
const
auto
&
s
:
names
)
{
for
(
const
auto
&
s
:
names
)
{
// printf("adding guessed phi for %s\n", s.c_str());
// printf("adding guessed phi for %s\n", s.c_str());
ConcreteCompilerType
*
type
=
types
->
getTypeAtBlockStart
(
s
,
block
);
ConcreteCompilerType
*
type
=
getTypeAtBlockStart
(
types
,
s
,
block
);
llvm
::
PHINode
*
phi
=
emitter
->
getBuilder
()
->
CreatePHI
(
type
->
llvmType
(),
block
->
predecessors
.
size
(),
s
);
llvm
::
PHINode
*
phi
=
emitter
->
getBuilder
()
->
CreatePHI
(
type
->
llvmType
(),
block
->
predecessors
.
size
(),
s
);
ConcreteCompilerVariable
*
var
=
new
ConcreteCompilerVariable
(
type
,
phi
,
true
);
ConcreteCompilerVariable
*
var
=
new
ConcreteCompilerVariable
(
type
,
phi
,
true
);
generator
->
giveLocalSymbol
(
s
,
var
);
generator
->
giveLocalSymbol
(
s
,
var
);
(
*
phis
)[
s
]
=
std
::
make_pair
(
type
,
phi
);
(
*
phis
)[
s
]
=
std
::
make_pair
(
type
,
phi
);
if
(
source
->
phis
->
isPotentiallyUndefinedAfter
(
s
,
block
->
predecessors
[
0
]))
{
std
::
string
is_defined_name
=
"!is_defined_"
+
s
;
llvm
::
PHINode
*
phi
=
emitter
->
getBuilder
()
->
CreatePHI
(
BOOL
->
llvmType
(),
block
->
predecessors
.
size
(),
is_defined_name
);
ConcreteCompilerVariable
*
var
=
new
ConcreteCompilerVariable
(
BOOL
,
phi
,
true
);
generator
->
giveLocalSymbol
(
is_defined_name
,
var
);
(
*
phis
)[
is_defined_name
]
=
std
::
make_pair
(
BOOL
,
phi
);
}
}
}
}
else
{
}
else
{
assert
(
pred
);
assert
(
pred
);
...
@@ -746,7 +785,7 @@ static void emitBBs(IRGenState* irstate, const char* bb_type, GuardList& out_gua
...
@@ -746,7 +785,7 @@ static void emitBBs(IRGenState* irstate, const char* bb_type, GuardList& out_gua
if
(
full_blocks
.
count
(
b2
)
==
0
&&
partial_blocks
.
count
(
b2
)
==
0
)
if
(
full_blocks
.
count
(
b2
)
==
0
&&
partial_blocks
.
count
(
b2
)
==
0
)
continue
;
continue
;
// printf("%d %d %ld %ld\n",
i
, b2->idx, phi_ending_symbol_tables[b2]->size(), phis->size());
// printf("%d %d %ld %ld\n",
b->idx
, b2->idx, phi_ending_symbol_tables[b2]->size(), phis->size());
compareKeyset
(
phi_ending_symbol_tables
[
b2
],
phis
);
compareKeyset
(
phi_ending_symbol_tables
[
b2
],
phis
);
assert
(
phi_ending_symbol_tables
[
b2
]
->
size
()
==
phis
->
size
());
assert
(
phi_ending_symbol_tables
[
b2
]
->
size
()
==
phis
->
size
());
}
}
...
@@ -762,13 +801,18 @@ static void emitBBs(IRGenState* irstate, const char* bb_type, GuardList& out_gua
...
@@ -762,13 +801,18 @@ static void emitBBs(IRGenState* irstate, const char* bb_type, GuardList& out_gua
llvm
::
BasicBlock
*
off_ramp
=
llvm
::
BasicBlock
::
Create
(
g
.
context
,
"deopt_ramp"
,
irstate
->
getLLVMFunction
());
llvm
::
BasicBlock
*
off_ramp
=
llvm
::
BasicBlock
::
Create
(
g
.
context
,
"deopt_ramp"
,
irstate
->
getLLVMFunction
());
offramps
.
push_back
(
off_ramp
);
offramps
.
push_back
(
off_ramp
);
llvm
::
BasicBlock
*
off_ramp_end
=
off_ramp
;
IREmitter
*
emitter
=
createIREmitter
(
irstate
,
offramps
[
offramps
.
size
()
-
1
]);
IREmitter
*
emitter
=
createIREmitter
(
irstate
,
off_ramp_end
);
emitters
.
push_back
(
emitter
);
emitters
.
push_back
(
emitter
);
block_guards
[
i
]
->
branch
->
setSuccessor
(
1
,
off_ramp
);
block_guards
[
i
]
->
branch
->
setSuccessor
(
1
,
off_ramp
);
}
}
// Can't always add the phi incoming value right away, since we may have to create more
// basic blocks as part of type coercion.
// Intsead, just make a record of the phi node, value, and the location of the from-BB,
// which we won't read until after all new BBs have been added.
std
::
vector
<
std
::
tuple
<
llvm
::
PHINode
*
,
llvm
::
Value
*
,
llvm
::
BasicBlock
*&>
>
phi_args
;
for
(
PHITable
::
iterator
it
=
phis
->
begin
();
it
!=
phis
->
end
();
it
++
)
{
for
(
PHITable
::
iterator
it
=
phis
->
begin
();
it
!=
phis
->
end
();
it
++
)
{
llvm
::
PHINode
*
llvm_phi
=
it
->
second
.
second
;
llvm
::
PHINode
*
llvm_phi
=
it
->
second
.
second
;
for
(
int
j
=
0
;
j
<
b
->
predecessors
.
size
();
j
++
)
{
for
(
int
j
=
0
;
j
<
b
->
predecessors
.
size
();
j
++
)
{
...
@@ -796,12 +840,33 @@ static void emitBBs(IRGenState* irstate, const char* bb_type, GuardList& out_gua
...
@@ -796,12 +840,33 @@ static void emitBBs(IRGenState* irstate, const char* bb_type, GuardList& out_gua
llvm_phi
->
addIncoming
(
v
->
getValue
(),
osr_unbox_block
);
llvm_phi
->
addIncoming
(
v
->
getValue
(),
osr_unbox_block
);
}
}
std
::
string
is_defined_name
=
getIsDefinedName
(
it
->
first
);
for
(
int
i
=
0
;
i
<
block_guards
.
size
();
i
++
)
{
for
(
int
i
=
0
;
i
<
block_guards
.
size
();
i
++
)
{
GuardList
::
BlockEntryGuard
*
guard
=
block_guards
[
i
];
GuardList
::
BlockEntryGuard
*
guard
=
block_guards
[
i
];
IREmitter
*
emitter
=
emitters
[
i
];
IREmitter
*
emitter
=
emitters
[
i
];
ASSERT
(
phis
->
count
(
"!is_defined_"
+
it
->
first
)
==
0
,
auto
is_defined_it
=
guard
->
symbol_table
.
find
(
is_defined_name
);
"This class-check-creating behavior will segfault if the argument wasn't actually defined!"
);
ConcreteCompilerVariable
*
is_defined_var
=
nullptr
;
if
(
is_defined_it
!=
guard
->
symbol_table
.
end
())
{
auto
var
=
is_defined_it
->
second
;
assert
(
var
->
getType
()
==
BOOL
);
is_defined_var
=
static_cast
<
ConcreteCompilerVariable
*>
(
var
);
}
llvm
::
BasicBlock
*
defined_prev
=
nullptr
,
*
defined_convert
=
nullptr
,
*
defined_join
=
nullptr
;
if
(
is_defined_var
)
{
defined_prev
=
offramps
[
i
];
defined_convert
=
llvm
::
BasicBlock
::
Create
(
g
.
context
,
""
,
irstate
->
getLLVMFunction
());
defined_join
=
llvm
::
BasicBlock
::
Create
(
g
.
context
,
""
,
irstate
->
getLLVMFunction
());
llvm
::
Value
*
is_defined_val
=
i1FromBool
(
*
emitter
,
is_defined_var
);
emitter
->
getBuilder
()
->
CreateCondBr
(
is_defined_val
,
defined_convert
,
defined_join
);
offramps
[
i
]
=
defined_convert
;
emitter
->
getBuilder
()
->
SetInsertPoint
(
defined_convert
);
}
CompilerVariable
*
unconverted
=
guard
->
symbol_table
[
it
->
first
];
CompilerVariable
*
unconverted
=
guard
->
symbol_table
[
it
->
first
];
ConcreteCompilerVariable
*
v
;
ConcreteCompilerVariable
*
v
;
...
@@ -854,13 +919,31 @@ static void emitBBs(IRGenState* irstate, const char* bb_type, GuardList& out_gua
...
@@ -854,13 +919,31 @@ static void emitBBs(IRGenState* irstate, const char* bb_type, GuardList& out_gua
ASSERT
(
it
->
second
.
first
==
v
->
getType
(),
""
);
ASSERT
(
it
->
second
.
first
==
v
->
getType
(),
""
);
assert
(
it
->
second
.
first
->
llvmType
()
==
v
->
getValue
()
->
getType
());
assert
(
it
->
second
.
first
->
llvmType
()
==
v
->
getValue
()
->
getType
());
llvm_phi
->
addIncoming
(
v
->
getValue
(),
offramps
[
i
]);
llvm
::
Value
*
val
=
v
->
getValue
();
if
(
defined_prev
)
{
emitter
->
getBuilder
()
->
CreateBr
(
defined_join
);
auto
prev
=
offramps
[
i
];
offramps
[
i
]
=
defined_join
;
emitter
->
getBuilder
()
->
SetInsertPoint
(
defined_join
);
auto
phi
=
emitter
->
getBuilder
()
->
CreatePHI
(
it
->
second
.
first
->
llvmType
(),
2
);
phi
->
addIncoming
(
llvm
::
UndefValue
::
get
(
phi
->
getType
()),
defined_prev
);
phi
->
addIncoming
(
val
,
prev
);
val
=
phi
;
}
phi_args
.
emplace_back
(
llvm_phi
,
val
,
offramps
[
i
]);
// TODO not sure if this is right:
// TODO not sure if this is right:
unconverted
->
decvref
(
*
emitter
);
unconverted
->
decvref
(
*
emitter
);
delete
v
;
}
}
}
}
for
(
auto
t
:
phi_args
)
{
std
::
get
<
0
>
(
t
)
->
addIncoming
(
std
::
get
<
1
>
(
t
),
std
::
get
<
2
>
(
t
));
}
for
(
int
i
=
0
;
i
<
block_guards
.
size
();
i
++
)
{
for
(
int
i
=
0
;
i
<
block_guards
.
size
();
i
++
)
{
emitters
[
i
]
->
getBuilder
()
->
CreateBr
(
llvm_entry_blocks
[
b
]);
emitters
[
i
]
->
getBuilder
()
->
CreateBr
(
llvm_entry_blocks
[
b
]);
...
@@ -986,7 +1069,9 @@ static std::string getUniqueFunctionName(std::string nameprefix, EffortLevel::Ef
...
@@ -986,7 +1069,9 @@ static std::string getUniqueFunctionName(std::string nameprefix, EffortLevel::Ef
os
<<
nameprefix
;
os
<<
nameprefix
;
os
<<
"_e"
<<
effort
;
os
<<
"_e"
<<
effort
;
if
(
entry
)
{
if
(
entry
)
{
os
<<
"_osr"
<<
entry
->
backedge
->
target
->
idx
<<
"_from_"
<<
entry
->
cf
->
func
->
getName
().
data
();
os
<<
"_osr"
<<
entry
->
backedge
->
target
->
idx
;
if
(
entry
->
cf
->
func
)
os
<<
"_from_"
<<
entry
->
cf
->
func
->
getName
().
data
();
}
}
os
<<
'_'
<<
num_functions
;
os
<<
'_'
<<
num_functions
;
num_functions
++
;
num_functions
++
;
...
...
src/codegen/irgen.h
View file @
218d8cd5
...
@@ -79,6 +79,13 @@ public:
...
@@ -79,6 +79,13 @@ public:
ExcInfo
exc_info
)
=
0
;
ExcInfo
exc_info
)
=
0
;
};
};
extern
const
std
::
string
CREATED_CLOSURE_NAME
;
extern
const
std
::
string
PASSED_CLOSURE_NAME
;
extern
const
std
::
string
PASSED_GENERATOR_NAME
;
std
::
string
getIsDefinedName
(
const
std
::
string
&
name
);
bool
isIsDefinedName
(
const
std
::
string
&
name
);
CompiledFunction
*
doCompile
(
SourceInfo
*
source
,
const
OSREntryDescriptor
*
entry_descriptor
,
CompiledFunction
*
doCompile
(
SourceInfo
*
source
,
const
OSREntryDescriptor
*
entry_descriptor
,
EffortLevel
::
EffortLevel
effort
,
FunctionSpecialization
*
spec
,
std
::
string
nameprefix
);
EffortLevel
::
EffortLevel
effort
,
FunctionSpecialization
*
spec
,
std
::
string
nameprefix
);
...
...
src/codegen/irgen/hooks.cpp
View file @
218d8cd5
...
@@ -20,6 +20,7 @@
...
@@ -20,6 +20,7 @@
#include "analysis/function_analysis.h"
#include "analysis/function_analysis.h"
#include "analysis/scoping_analysis.h"
#include "analysis/scoping_analysis.h"
#include "asm_writing/icinfo.h"
#include "asm_writing/icinfo.h"
#include "codegen/ast_interpreter.h"
#include "codegen/codegen.h"
#include "codegen/codegen.h"
#include "codegen/compvars.h"
#include "codegen/compvars.h"
#include "codegen/irgen.h"
#include "codegen/irgen.h"
...
@@ -137,7 +138,6 @@ static std::unordered_map<std::string, CompiledFunction*> machine_name_to_cf;
...
@@ -137,7 +138,6 @@ static std::unordered_map<std::string, CompiledFunction*> machine_name_to_cf;
CompiledFunction
*
cfForMachineFunctionName
(
const
std
::
string
&
machine_name
)
{
CompiledFunction
*
cfForMachineFunctionName
(
const
std
::
string
&
machine_name
)
{
assert
(
machine_name
.
size
());
assert
(
machine_name
.
size
());
auto
r
=
machine_name_to_cf
[
machine_name
];
auto
r
=
machine_name_to_cf
[
machine_name
];
ASSERT
(
r
,
"%s"
,
machine_name
.
c_str
());
return
r
;
return
r
;
}
}
...
@@ -185,17 +185,29 @@ CompiledFunction* compileFunction(CLFunction* f, FunctionSpecialization* spec, E
...
@@ -185,17 +185,29 @@ CompiledFunction* compileFunction(CLFunction* f, FunctionSpecialization* spec, E
// Do the analysis now if we had deferred it earlier:
// Do the analysis now if we had deferred it earlier:
if
(
source
->
cfg
==
NULL
)
{
if
(
source
->
cfg
==
NULL
)
{
assert
(
source
->
ast
);
source
->
cfg
=
computeCFG
(
source
,
source
->
body
);
source
->
cfg
=
computeCFG
(
source
,
source
->
body
);
}
if
(
effort
!=
EffortLevel
::
INTERPRETED
)
{
if
(
source
->
liveness
==
NULL
)
source
->
liveness
=
computeLivenessInfo
(
source
->
cfg
);
source
->
liveness
=
computeLivenessInfo
(
source
->
cfg
);
source
->
phis
=
computeRequiredPhis
(
source
->
arg_names
,
source
->
cfg
,
source
->
liveness
,
source
->
getScopeInfo
());
if
(
source
->
phis
==
NULL
)
source
->
phis
=
computeRequiredPhis
(
source
->
arg_names
,
source
->
cfg
,
source
->
liveness
,
source
->
getScopeInfo
());
}
}
CompiledFunction
*
cf
=
doCompile
(
source
,
entry
,
effort
,
spec
,
name
);
registerMachineName
(
cf
->
func
->
getName
(),
cf
);
CompiledFunction
*
cf
=
0
;
if
(
effort
==
EffortLevel
::
INTERPRETED
)
{
cf
=
new
CompiledFunction
(
0
,
spec
,
true
,
NULL
,
NULL
,
effort
,
0
);
}
else
{
cf
=
doCompile
(
source
,
entry
,
effort
,
spec
,
name
);
registerMachineName
(
cf
->
func
->
getName
(),
cf
);
compileIR
(
cf
,
effort
);
compileIR
(
cf
,
effort
);
}
f
->
addVersion
(
cf
);
f
->
addVersion
(
cf
);
assert
(
f
->
versions
.
size
());
assert
(
f
->
versions
.
size
());
...
@@ -252,10 +264,6 @@ void compileAndRunModule(AST_Module* m, BoxedModule* bm) {
...
@@ -252,10 +264,6 @@ void compileAndRunModule(AST_Module* m, BoxedModule* bm) {
ScopingAnalysis
*
scoping
=
runScopingAnalysis
(
m
);
ScopingAnalysis
*
scoping
=
runScopingAnalysis
(
m
);
SourceInfo
*
si
=
new
SourceInfo
(
bm
,
scoping
,
m
,
m
->
body
);
SourceInfo
*
si
=
new
SourceInfo
(
bm
,
scoping
,
m
,
m
->
body
);
si
->
cfg
=
computeCFG
(
si
,
m
->
body
);
si
->
liveness
=
computeLivenessInfo
(
si
->
cfg
);
si
->
phis
=
computeRequiredPhis
(
si
->
arg_names
,
si
->
cfg
,
si
->
liveness
,
si
->
getScopeInfo
());
CLFunction
*
cl_f
=
new
CLFunction
(
0
,
0
,
false
,
false
,
si
);
CLFunction
*
cl_f
=
new
CLFunction
(
0
,
0
,
false
,
false
,
si
);
EffortLevel
::
EffortLevel
effort
=
initialEffort
();
EffortLevel
::
EffortLevel
effort
=
initialEffort
();
...
@@ -265,7 +273,7 @@ void compileAndRunModule(AST_Module* m, BoxedModule* bm) {
...
@@ -265,7 +273,7 @@ void compileAndRunModule(AST_Module* m, BoxedModule* bm) {
}
}
if
(
cf
->
is_interpreted
)
if
(
cf
->
is_interpreted
)
interpretFunction
(
cf
->
func
,
0
,
NULL
,
NULL
,
NULL
,
NULL
,
NULL
,
NULL
);
astInterpretFunction
(
cf
,
0
,
NULL
,
NULL
,
NULL
,
NULL
,
NULL
,
NULL
);
else
else
((
void
(
*
)())
cf
->
code
)();
((
void
(
*
)())
cf
->
code
)();
}
}
...
@@ -311,7 +319,7 @@ static CompiledFunction* _doReopt(CompiledFunction* cf, EffortLevel::EffortLevel
...
@@ -311,7 +319,7 @@ static CompiledFunction* _doReopt(CompiledFunction* cf, EffortLevel::EffortLevel
}
}
static
StatCounter
stat_osrexits
(
"OSR exits"
);
static
StatCounter
stat_osrexits
(
"OSR exits"
);
void
*
compilePartialFunc
(
OSRExit
*
exit
)
{
CompiledFunction
*
compilePartialFuncInternal
(
OSRExit
*
exit
)
{
LOCK_REGION
(
codegen_rwlock
.
asWrite
());
LOCK_REGION
(
codegen_rwlock
.
asWrite
());
assert
(
exit
);
assert
(
exit
);
...
@@ -334,11 +342,16 @@ void* compilePartialFunc(OSRExit* exit) {
...
@@ -334,11 +342,16 @@ void* compilePartialFunc(OSRExit* exit) {
assert
(
compiled
=
new_cf
);
assert
(
compiled
=
new_cf
);
}
}
return
new_cf
->
code
;
return
new_cf
;
}
}
void
*
compilePartialFunc
(
OSRExit
*
exit
)
{
return
compilePartialFuncInternal
(
exit
)
->
code
;
}
static
StatCounter
stat_reopt
(
"reopts"
);
static
StatCounter
stat_reopt
(
"reopts"
);
extern
"C"
char
*
reoptCompiledFunc
(
CompiledFunction
*
cf
)
{
extern
"C"
CompiledFunction
*
reoptCompiledFuncInternal
(
CompiledFunction
*
cf
)
{
if
(
VERBOSITY
(
"irgen"
)
>=
1
)
if
(
VERBOSITY
(
"irgen"
)
>=
1
)
printf
(
"In reoptCompiledFunc, %p, %ld
\n
"
,
cf
,
cf
->
times_called
);
printf
(
"In reoptCompiledFunc, %p, %ld
\n
"
,
cf
,
cf
->
times_called
);
stat_reopt
.
log
();
stat_reopt
.
log
();
...
@@ -347,7 +360,12 @@ extern "C" char* reoptCompiledFunc(CompiledFunction* cf) {
...
@@ -347,7 +360,12 @@ extern "C" char* reoptCompiledFunc(CompiledFunction* cf) {
assert
(
cf
->
clfunc
->
versions
.
size
());
assert
(
cf
->
clfunc
->
versions
.
size
());
CompiledFunction
*
new_cf
=
_doReopt
(
cf
,
(
EffortLevel
::
EffortLevel
(
cf
->
effort
+
1
)));
CompiledFunction
*
new_cf
=
_doReopt
(
cf
,
(
EffortLevel
::
EffortLevel
(
cf
->
effort
+
1
)));
assert
(
!
new_cf
->
is_interpreted
);
assert
(
!
new_cf
->
is_interpreted
);
return
(
char
*
)
new_cf
->
code
;
return
new_cf
;
}
extern
"C"
char
*
reoptCompiledFunc
(
CompiledFunction
*
cf
)
{
return
(
char
*
)
reoptCompiledFuncInternal
(
cf
)
->
code
;
}
}
CLFunction
*
createRTFunction
(
int
num_args
,
int
num_defaults
,
bool
takes_varargs
,
bool
takes_kwargs
)
{
CLFunction
*
createRTFunction
(
int
num_args
,
int
num_defaults
,
bool
takes_varargs
,
bool
takes_kwargs
)
{
...
...
src/codegen/irgen/hooks.h
View file @
218d8cd5
...
@@ -23,7 +23,9 @@ struct CompiledFunction;
...
@@ -23,7 +23,9 @@ struct CompiledFunction;
class
CLFunction
;
class
CLFunction
;
class
OSRExit
;
class
OSRExit
;
CompiledFunction
*
compilePartialFuncInternal
(
OSRExit
*
exit
);
void
*
compilePartialFunc
(
OSRExit
*
);
void
*
compilePartialFunc
(
OSRExit
*
);
extern
"C"
CompiledFunction
*
reoptCompiledFuncInternal
(
CompiledFunction
*
);
extern
"C"
char
*
reoptCompiledFunc
(
CompiledFunction
*
);
extern
"C"
char
*
reoptCompiledFunc
(
CompiledFunction
*
);
class
AST_Module
;
class
AST_Module
;
...
...
src/codegen/irgen/irgenerator.cpp
View file @
218d8cd5
...
@@ -256,6 +256,14 @@ const std::string CREATED_CLOSURE_NAME = "!created_closure";
...
@@ -256,6 +256,14 @@ const std::string CREATED_CLOSURE_NAME = "!created_closure";
const
std
::
string
PASSED_CLOSURE_NAME
=
"!passed_closure"
;
const
std
::
string
PASSED_CLOSURE_NAME
=
"!passed_closure"
;
const
std
::
string
PASSED_GENERATOR_NAME
=
"!passed_generator"
;
const
std
::
string
PASSED_GENERATOR_NAME
=
"!passed_generator"
;
std
::
string
getIsDefinedName
(
const
std
::
string
&
name
)
{
return
"!is_defined_"
+
name
;
}
bool
isIsDefinedName
(
const
std
::
string
&
name
)
{
return
startswith
(
name
,
"!is_defined_"
);
}
class
IRGeneratorImpl
:
public
IRGenerator
{
class
IRGeneratorImpl
:
public
IRGenerator
{
private:
private:
IRGenState
*
irstate
;
IRGenState
*
irstate
;
...
@@ -411,8 +419,8 @@ private:
...
@@ -411,8 +419,8 @@ private:
if
(
p
.
first
[
0
]
==
'!'
||
p
.
first
[
0
]
==
'#'
)
if
(
p
.
first
[
0
]
==
'!'
||
p
.
first
[
0
]
==
'#'
)
continue
;
continue
;
ConcreteCompilerVariable
*
is_defined_var
=
static_cast
<
ConcreteCompilerVariable
*>
(
ConcreteCompilerVariable
*
is_defined_var
_getFake
(
_getFakeName
(
"is_defined"
,
p
.
first
.
c_str
()
),
true
));
=
static_cast
<
ConcreteCompilerVariable
*>
(
_getFake
(
getIsDefinedName
(
p
.
first
),
true
));
static
const
std
::
string
setitem_str
(
"__setitem__"
);
static
const
std
::
string
setitem_str
(
"__setitem__"
);
if
(
!
is_defined_var
)
{
if
(
!
is_defined_var
)
{
...
@@ -822,7 +830,7 @@ private:
...
@@ -822,7 +830,7 @@ private:
return
undefVariable
();
return
undefVariable
();
}
}
std
::
string
defined_name
=
_getFakeName
(
"is_defined"
,
node
->
id
.
c_str
()
);
std
::
string
defined_name
=
getIsDefinedName
(
node
->
id
);
ConcreteCompilerVariable
*
is_defined_var
ConcreteCompilerVariable
*
is_defined_var
=
static_cast
<
ConcreteCompilerVariable
*>
(
_getFake
(
defined_name
,
true
));
=
static_cast
<
ConcreteCompilerVariable
*>
(
_getFake
(
defined_name
,
true
));
...
@@ -1272,12 +1280,6 @@ private:
...
@@ -1272,12 +1280,6 @@ private:
return
rtn
;
return
rtn
;
}
}
static
std
::
string
_getFakeName
(
const
char
*
prefix
,
const
char
*
token
)
{
char
buf
[
40
];
snprintf
(
buf
,
40
,
"!%s_%s"
,
prefix
,
token
);
return
std
::
string
(
buf
);
}
void
_setFake
(
std
::
string
name
,
CompilerVariable
*
val
)
{
void
_setFake
(
std
::
string
name
,
CompilerVariable
*
val
)
{
assert
(
name
[
0
]
==
'!'
);
assert
(
name
[
0
]
==
'!'
);
CompilerVariable
*&
cur
=
symbol_table
[
name
];
CompilerVariable
*&
cur
=
symbol_table
[
name
];
...
@@ -1326,8 +1328,8 @@ private:
...
@@ -1326,8 +1328,8 @@ private:
val
->
incvref
();
val
->
incvref
();
// Clear out the is_defined name since it is now definitely defined:
// Clear out the is_defined name since it is now definitely defined:
assert
(
!
startswith
(
name
,
"!is_defined"
));
assert
(
!
isIsDefinedName
(
name
));
std
::
string
defined_name
=
_getFakeName
(
"is_defined"
,
name
.
c_str
()
);
std
::
string
defined_name
=
getIsDefinedName
(
name
);
_popFake
(
defined_name
,
true
);
_popFake
(
defined_name
,
true
);
if
(
scope_info
->
saveInClosure
(
name
))
{
if
(
scope_info
->
saveInClosure
(
name
))
{
...
@@ -1496,7 +1498,7 @@ private:
...
@@ -1496,7 +1498,7 @@ private:
decorators
.
push_back
(
evalExpr
(
d
,
exc_info
));
decorators
.
push_back
(
evalExpr
(
d
,
exc_info
));
}
}
CLFunction
*
cl
=
_wrapFunction
(
node
,
nullptr
,
node
->
body
);
CLFunction
*
cl
=
wrapFunction
(
node
,
nullptr
,
node
->
body
,
irstate
->
getSourceInfo
()
);
// TODO duplication with _createFunction:
// TODO duplication with _createFunction:
CompilerVariable
*
created_closure
=
NULL
;
CompilerVariable
*
created_closure
=
NULL
;
...
@@ -1614,7 +1616,7 @@ private:
...
@@ -1614,7 +1616,7 @@ private:
return
;
return
;
}
}
std
::
string
defined_name
=
_getFakeName
(
"is_defined"
,
target
->
id
.
c_str
()
);
std
::
string
defined_name
=
getIsDefinedName
(
target
->
id
);
ConcreteCompilerVariable
*
is_defined_var
=
static_cast
<
ConcreteCompilerVariable
*>
(
_getFake
(
defined_name
,
true
));
ConcreteCompilerVariable
*
is_defined_var
=
static_cast
<
ConcreteCompilerVariable
*>
(
_getFake
(
defined_name
,
true
));
if
(
is_defined_var
)
{
if
(
is_defined_var
)
{
...
@@ -1628,27 +1630,9 @@ private:
...
@@ -1628,27 +1630,9 @@ private:
symbol_table
.
erase
(
target
->
id
);
symbol_table
.
erase
(
target
->
id
);
}
}
CLFunction
*
_wrapFunction
(
AST
*
node
,
AST_arguments
*
args
,
const
std
::
vector
<
AST_stmt
*>&
body
)
{
// Different compilations of the parent scope of a functiondef should lead
// to the same CLFunction* being used:
static
std
::
unordered_map
<
AST
*
,
CLFunction
*>
made
;
CLFunction
*&
cl
=
made
[
node
];
if
(
cl
==
NULL
)
{
SourceInfo
*
source
=
irstate
->
getSourceInfo
();
SourceInfo
*
si
=
new
SourceInfo
(
source
->
parent_module
,
source
->
scoping
,
node
,
body
);
if
(
args
)
cl
=
new
CLFunction
(
args
->
args
.
size
(),
args
->
defaults
.
size
(),
args
->
vararg
.
size
(),
args
->
kwarg
.
size
(),
si
);
else
cl
=
new
CLFunction
(
0
,
0
,
0
,
0
,
si
);
}
return
cl
;
}
CompilerVariable
*
_createFunction
(
AST
*
node
,
ExcInfo
exc_info
,
AST_arguments
*
args
,
CompilerVariable
*
_createFunction
(
AST
*
node
,
ExcInfo
exc_info
,
AST_arguments
*
args
,
const
std
::
vector
<
AST_stmt
*>&
body
)
{
const
std
::
vector
<
AST_stmt
*>&
body
)
{
CLFunction
*
cl
=
this
->
_wrapFunction
(
node
,
args
,
body
);
CLFunction
*
cl
=
wrapFunction
(
node
,
args
,
body
,
irstate
->
getSourceInfo
()
);
std
::
vector
<
ConcreteCompilerVariable
*>
defaults
;
std
::
vector
<
ConcreteCompilerVariable
*>
defaults
;
for
(
auto
d
:
args
->
defaults
)
{
for
(
auto
d
:
args
->
defaults
)
{
...
@@ -2159,7 +2143,7 @@ private:
...
@@ -2159,7 +2143,7 @@ private:
}
}
bool
allowableFakeEndingSymbol
(
const
std
::
string
&
name
)
{
bool
allowableFakeEndingSymbol
(
const
std
::
string
&
name
)
{
return
startswith
(
name
,
"!is_defined"
)
||
name
==
PASSED_CLOSURE_NAME
||
name
==
CREATED_CLOSURE_NAME
return
isIsDefinedName
(
name
)
||
name
==
PASSED_CLOSURE_NAME
||
name
==
CREATED_CLOSURE_NAME
||
name
==
PASSED_GENERATOR_NAME
;
||
name
==
PASSED_GENERATOR_NAME
;
}
}
...
@@ -2177,7 +2161,7 @@ private:
...
@@ -2177,7 +2161,7 @@ private:
continue
;
continue
;
}
}
// ASSERT(it->first[0] != '!' ||
startswith(it->first, "!is_defined"
), "left a fake variable in the real
// ASSERT(it->first[0] != '!' ||
isIsDefinedName(it->first
), "left a fake variable in the real
// symbol table? '%s'", it->first.c_str());
// symbol table? '%s'", it->first.c_str());
if
(
!
source
->
liveness
->
isLiveAtEnd
(
it
->
first
,
myblock
))
{
if
(
!
source
->
liveness
->
isLiveAtEnd
(
it
->
first
,
myblock
))
{
...
@@ -2218,7 +2202,7 @@ private:
...
@@ -2218,7 +2202,7 @@ private:
assert
(
!
scope_info
->
refersToGlobal
(
*
it
));
assert
(
!
scope_info
->
refersToGlobal
(
*
it
));
CompilerVariable
*&
cur
=
symbol_table
[
*
it
];
CompilerVariable
*&
cur
=
symbol_table
[
*
it
];
std
::
string
defined_name
=
_getFakeName
(
"is_defined"
,
it
->
c_str
()
);
std
::
string
defined_name
=
getIsDefinedName
(
*
it
);
if
(
cur
!=
NULL
)
{
if
(
cur
!=
NULL
)
{
// printf("defined on this path; ");
// printf("defined on this path; ");
...
@@ -2309,7 +2293,7 @@ public:
...
@@ -2309,7 +2293,7 @@ public:
assert
(
it
->
second
->
getVrefs
()
==
1
);
assert
(
it
->
second
->
getVrefs
()
==
1
);
// this conversion should have already happened... should refactor this.
// this conversion should have already happened... should refactor this.
ConcreteCompilerType
*
ending_type
;
ConcreteCompilerType
*
ending_type
;
if
(
startswith
(
it
->
first
,
"!is_defined"
))
{
if
(
isIsDefinedName
(
it
->
first
))
{
assert
(
it
->
second
->
getType
()
==
BOOL
);
assert
(
it
->
second
->
getType
()
==
BOOL
);
ending_type
=
BOOL
;
ending_type
=
BOOL
;
}
else
if
(
it
->
first
==
PASSED_CLOSURE_NAME
)
{
}
else
if
(
it
->
first
==
PASSED_CLOSURE_NAME
)
{
...
@@ -2456,4 +2440,20 @@ IRGenerator* createIRGenerator(IRGenState* irstate, std::unordered_map<CFGBlock*
...
@@ -2456,4 +2440,20 @@ IRGenerator* createIRGenerator(IRGenState* irstate, std::unordered_map<CFGBlock*
const
GuardList
&
in_guards
,
bool
is_partial
)
{
const
GuardList
&
in_guards
,
bool
is_partial
)
{
return
new
IRGeneratorImpl
(
irstate
,
entry_blocks
,
myblock
,
types
,
out_guards
,
in_guards
,
is_partial
);
return
new
IRGeneratorImpl
(
irstate
,
entry_blocks
,
myblock
,
types
,
out_guards
,
in_guards
,
is_partial
);
}
}
CLFunction
*
wrapFunction
(
AST
*
node
,
AST_arguments
*
args
,
const
std
::
vector
<
AST_stmt
*>&
body
,
SourceInfo
*
source
)
{
// Different compilations of the parent scope of a functiondef should lead
// to the same CLFunction* being used:
static
std
::
unordered_map
<
AST
*
,
CLFunction
*>
made
;
CLFunction
*&
cl
=
made
[
node
];
if
(
cl
==
NULL
)
{
SourceInfo
*
si
=
new
SourceInfo
(
source
->
parent_module
,
source
->
scoping
,
node
,
body
);
if
(
args
)
cl
=
new
CLFunction
(
args
->
args
.
size
(),
args
->
defaults
.
size
(),
args
->
vararg
.
size
(),
args
->
kwarg
.
size
(),
si
);
else
cl
=
new
CLFunction
(
0
,
0
,
0
,
0
,
si
);
}
return
cl
;
}
}
}
src/codegen/irgen/irgenerator.h
View file @
218d8cd5
...
@@ -46,6 +46,7 @@ extern const std::string CREATED_CLOSURE_NAME;
...
@@ -46,6 +46,7 @@ extern const std::string CREATED_CLOSURE_NAME;
extern
const
std
::
string
PASSED_CLOSURE_NAME
;
extern
const
std
::
string
PASSED_CLOSURE_NAME
;
extern
const
std
::
string
PASSED_GENERATOR_NAME
;
extern
const
std
::
string
PASSED_GENERATOR_NAME
;
// Class that holds state of the current IR generation, that might not be local
// Class that holds state of the current IR generation, that might not be local
// to the specific phase or pass we're in.
// to the specific phase or pass we're in.
// TODO this probably shouldn't be here
// TODO this probably shouldn't be here
...
@@ -205,6 +206,8 @@ IREmitter* createIREmitter(IRGenState* irstate, llvm::BasicBlock*& curblock, IRG
...
@@ -205,6 +206,8 @@ IREmitter* createIREmitter(IRGenState* irstate, llvm::BasicBlock*& curblock, IRG
IRGenerator
*
createIRGenerator
(
IRGenState
*
irstate
,
std
::
unordered_map
<
CFGBlock
*
,
llvm
::
BasicBlock
*>&
entry_blocks
,
IRGenerator
*
createIRGenerator
(
IRGenState
*
irstate
,
std
::
unordered_map
<
CFGBlock
*
,
llvm
::
BasicBlock
*>&
entry_blocks
,
CFGBlock
*
myblock
,
TypeAnalysis
*
types
,
GuardList
&
out_guards
,
CFGBlock
*
myblock
,
TypeAnalysis
*
types
,
GuardList
&
out_guards
,
const
GuardList
&
in_guards
,
bool
is_partial
);
const
GuardList
&
in_guards
,
bool
is_partial
);
CLFunction
*
wrapFunction
(
AST
*
node
,
AST_arguments
*
args
,
const
std
::
vector
<
AST_stmt
*>&
body
,
SourceInfo
*
source
);
}
}
#endif
#endif
src/codegen/llvm_interpreter.cpp
View file @
218d8cd5
...
@@ -219,8 +219,8 @@ static void set(SymMap& symbols, const llvm::BasicBlock::iterator& it, Val v) {
...
@@ -219,8 +219,8 @@ static void set(SymMap& symbols, const llvm::BasicBlock::iterator& it, Val v) {
static
std
::
unordered_map
<
void
*
,
llvm
::
Instruction
*>
cur_instruction_map
;
static
std
::
unordered_map
<
void
*
,
llvm
::
Instruction
*>
cur_instruction_map
;
typedef
std
::
vector
<
const
SymMap
*>
root_stack_t
;
typedef
std
::
vector
<
const
SymMap
*>
root_stack_t
;
threading
::
PerThreadSet
<
root_stack_t
>
root_stack_set
;
static
threading
::
PerThreadSet
<
root_stack_t
>
root_stack_set
;
/*
void gatherInterpreterRoots(GCVisitor* visitor) {
void gatherInterpreterRoots(GCVisitor* visitor) {
root_stack_set.forEachValue(std::function<void(root_stack_t*, GCVisitor*)>([](root_stack_t* v, GCVisitor* visitor) {
root_stack_set.forEachValue(std::function<void(root_stack_t*, GCVisitor*)>([](root_stack_t* v, GCVisitor* visitor) {
for (const SymMap* sym_map : *v) {
for (const SymMap* sym_map : *v) {
...
@@ -231,7 +231,8 @@ void gatherInterpreterRoots(GCVisitor* visitor) {
...
@@ -231,7 +231,8 @@ void gatherInterpreterRoots(GCVisitor* visitor) {
}),
}),
visitor);
visitor);
}
}
*/
#if 0
BoxedDict* localsForInterpretedFrame(void* frame_ptr, bool only_user_visible) {
BoxedDict* localsForInterpretedFrame(void* frame_ptr, bool only_user_visible) {
llvm::Instruction* inst = cur_instruction_map[frame_ptr];
llvm::Instruction* inst = cur_instruction_map[frame_ptr];
assert(inst);
assert(inst);
...
@@ -285,6 +286,7 @@ BoxedDict* localsForInterpretedFrame(void* frame_ptr, bool only_user_visible) {
...
@@ -285,6 +286,7 @@ BoxedDict* localsForInterpretedFrame(void* frame_ptr, bool only_user_visible) {
return rtn;
return rtn;
}
}
#endif
class
UnregisterHelper
{
class
UnregisterHelper
{
private:
private:
...
@@ -302,6 +304,7 @@ public:
...
@@ -302,6 +304,7 @@ public:
};
};
static
std
::
unordered_map
<
llvm
::
Instruction
*
,
LineInfo
*>
line_infos
;
static
std
::
unordered_map
<
llvm
::
Instruction
*
,
LineInfo
*>
line_infos
;
/*
const LineInfo* getLineInfoForInterpretedFrame(void* frame_ptr) {
const LineInfo* getLineInfoForInterpretedFrame(void* frame_ptr) {
llvm::Instruction* cur_instruction = cur_instruction_map[frame_ptr];
llvm::Instruction* cur_instruction = cur_instruction_map[frame_ptr];
assert(cur_instruction);
assert(cur_instruction);
...
@@ -319,7 +322,7 @@ const LineInfo* getLineInfoForInterpretedFrame(void* frame_ptr) {
...
@@ -319,7 +322,7 @@ const LineInfo* getLineInfoForInterpretedFrame(void* frame_ptr) {
return it->second;
return it->second;
}
}
}
}
*/
void
dumpLLVM
(
llvm
::
Value
*
v
)
{
void
dumpLLVM
(
llvm
::
Value
*
v
)
{
v
->
dump
();
v
->
dump
();
}
}
...
...
src/codegen/llvm_interpreter.h
View file @
218d8cd5
...
@@ -29,12 +29,14 @@ class Box;
...
@@ -29,12 +29,14 @@ class Box;
class
BoxedDict
;
class
BoxedDict
;
struct
LineInfo
;
struct
LineInfo
;
#if 0
Box* interpretFunction(llvm::Function* f, int nargs, Box* closure, Box* generator, Box* arg1, Box* arg2, Box* arg3,
Box* interpretFunction(llvm::Function* f, int nargs, Box* closure, Box* generator, Box* arg1, Box* arg2, Box* arg3,
Box** args);
Box** args);
void gatherInterpreterRoots(gc::GCVisitor* visitor);
void gatherInterpreterRoots(gc::GCVisitor* visitor);
const LineInfo* getLineInfoForInterpretedFrame(void* frame_ptr);
const LineInfo* getLineInfoForInterpretedFrame(void* frame_ptr);
BoxedDict* localsForInterpretedFrame(void* frame_ptr, bool only_user_visible);
BoxedDict* localsForInterpretedFrame(void* frame_ptr, bool only_user_visible);
#endif
}
}
#endif
#endif
src/codegen/unwinding.cpp
View file @
218d8cd5
...
@@ -23,6 +23,7 @@
...
@@ -23,6 +23,7 @@
#include "llvm/ExecutionEngine/ObjectImage.h"
#include "llvm/ExecutionEngine/ObjectImage.h"
#include "llvm/IR/DebugInfo.h"
#include "llvm/IR/DebugInfo.h"
#include "codegen/ast_interpreter.h"
#include "codegen/codegen.h"
#include "codegen/codegen.h"
#include "codegen/compvars.h"
#include "codegen/compvars.h"
#include "codegen/irgen/hooks.h"
#include "codegen/irgen/hooks.h"
...
@@ -307,7 +308,7 @@ public:
...
@@ -307,7 +308,7 @@ public:
int
code
=
unw_get_proc_info
(
&
this
->
cursor
,
&
pip
);
int
code
=
unw_get_proc_info
(
&
this
->
cursor
,
&
pip
);
RELEASE_ASSERT
(
code
==
0
,
"%d"
,
code
);
RELEASE_ASSERT
(
code
==
0
,
"%d"
,
code
);
if
(
pip
.
start_ip
==
(
intptr_t
)
i
nterpretFunction
)
{
if
(
pip
.
start_ip
==
(
intptr_t
)
astI
nterpretFunction
)
{
unw_word_t
bp
;
unw_word_t
bp
;
unw_get_reg
(
&
this
->
cursor
,
UNW_TDEP_BP
,
&
bp
);
unw_get_reg
(
&
this
->
cursor
,
UNW_TDEP_BP
,
&
bp
);
...
@@ -401,12 +402,19 @@ CompiledFunction* getTopCompiledFunction() {
...
@@ -401,12 +402,19 @@ CompiledFunction* getTopCompiledFunction() {
assert
(
last_entry
->
func
.
size
());
assert
(
last_entry
->
func
.
size
());
CompiledFunction
*
cf
=
cfForMachineFunctionName
(
last_entry
->
func
);
CompiledFunction
*
cf
=
cfForMachineFunctionName
(
last_entry
->
func
);
assert
(
cf
);
return
cf
;
return
cf
;
}
}
BoxedModule
*
getCurrentModule
()
{
BoxedModule
*
getCurrentModule
()
{
return
getTopCompiledFunction
()
->
clfunc
->
source
->
parent_module
;
CompiledFunction
*
compiledFunction
=
getTopCompiledFunction
();
if
(
compiledFunction
)
return
compiledFunction
->
clfunc
->
source
->
parent_module
;
else
{
std
::
unique_ptr
<
PythonFrameIterator
>
frame
=
getTopPythonFrame
();
auto
&
id
=
frame
->
getId
();
assert
(
id
.
type
==
PythonFrameId
::
INTERPRETED
);
return
getModuleForInterpretedFrame
((
void
*
)
id
.
bp
);
}
}
}
BoxedDict
*
getLocals
(
bool
only_user_visible
)
{
BoxedDict
*
getLocals
(
bool
only_user_visible
)
{
...
...
src/core/types.h
View file @
218d8cd5
...
@@ -288,7 +288,6 @@ public:
...
@@ -288,7 +288,6 @@ public:
void
addVersion
(
CompiledFunction
*
compiled
)
{
void
addVersion
(
CompiledFunction
*
compiled
)
{
assert
(
compiled
);
assert
(
compiled
);
assert
((
source
==
NULL
)
==
(
compiled
->
func
==
NULL
));
assert
(
compiled
->
spec
);
assert
(
compiled
->
spec
);
assert
(
compiled
->
spec
->
arg_types
.
size
()
==
num_args
+
(
takes_varargs
?
1
:
0
)
+
(
takes_kwargs
?
1
:
0
));
assert
(
compiled
->
spec
->
arg_types
.
size
()
==
num_args
+
(
takes_varargs
?
1
:
0
)
+
(
takes_kwargs
?
1
:
0
));
assert
(
compiled
->
clfunc
==
NULL
);
assert
(
compiled
->
clfunc
==
NULL
);
...
...
src/gc/root_finder.cpp
View file @
218d8cd5
...
@@ -21,8 +21,8 @@
...
@@ -21,8 +21,8 @@
#include <setjmp.h>
#include <setjmp.h>
#include <vector>
#include <vector>
#include "codegen/ast_interpreter.h"
#include "codegen/codegen.h"
#include "codegen/codegen.h"
#include "codegen/llvm_interpreter.h"
#include "core/common.h"
#include "core/common.h"
#include "core/threading.h"
#include "core/threading.h"
#include "gc/collector.h"
#include "gc/collector.h"
...
...
src/runtime/objmodel.cpp
View file @
218d8cd5
...
@@ -23,6 +23,7 @@
...
@@ -23,6 +23,7 @@
#include "asm_writing/icinfo.h"
#include "asm_writing/icinfo.h"
#include "asm_writing/rewriter.h"
#include "asm_writing/rewriter.h"
#include "codegen/ast_interpreter.h"
#include "codegen/codegen.h"
#include "codegen/codegen.h"
#include "codegen/compvars.h"
#include "codegen/compvars.h"
#include "codegen/irgen/hooks.h"
#include "codegen/irgen/hooks.h"
...
@@ -2486,7 +2487,7 @@ Box* callCLFunc(CLFunction* f, CallRewriteArgs* rewrite_args, int num_output_arg
...
@@ -2486,7 +2487,7 @@ Box* callCLFunc(CLFunction* f, CallRewriteArgs* rewrite_args, int num_output_arg
assert
(
chosen_cf
->
is_interpreted
==
(
chosen_cf
->
code
==
NULL
));
assert
(
chosen_cf
->
is_interpreted
==
(
chosen_cf
->
code
==
NULL
));
if
(
chosen_cf
->
is_interpreted
)
{
if
(
chosen_cf
->
is_interpreted
)
{
return
interpretFunction
(
chosen_cf
->
func
,
num_output_args
,
closure
,
generator
,
oarg1
,
oarg2
,
oarg3
,
oargs
);
return
astInterpretFunction
(
chosen_cf
,
num_output_args
,
closure
,
generator
,
oarg1
,
oarg2
,
oarg3
,
oargs
);
}
}
if
(
rewrite_args
)
{
if
(
rewrite_args
)
{
...
...
src/runtime/set.h
View file @
218d8cd5
...
@@ -31,9 +31,11 @@ extern "C" Box* createSet();
...
@@ -31,9 +31,11 @@ extern "C" Box* createSet();
class
BoxedSet
:
public
Box
{
class
BoxedSet
:
public
Box
{
public:
public:
std
::
unordered_set
<
Box
*
,
PyHasher
,
PyEq
,
StlCompatAllocator
<
Box
*>
>
s
;
typedef
std
::
unordered_set
<
Box
*
,
PyHasher
,
PyEq
,
StlCompatAllocator
<
Box
*>
>
Set
;
Set
s
;
BoxedSet
(
BoxedClass
*
cls
)
__attribute__
((
visibility
(
"default"
)))
:
Box
(
cls
)
{}
BoxedSet
(
BoxedClass
*
cls
)
__attribute__
((
visibility
(
"default"
)))
:
Box
(
cls
)
{}
BoxedSet
(
Set
&&
s
,
BoxedClass
*
cls
)
__attribute__
((
visibility
(
"default"
)))
:
Box
(
cls
),
s
(
s
)
{}
};
};
}
}
...
...
test/tests/arg_unpacking.py
0 → 100644
View file @
218d8cd5
# expected: fail
def
f
((
a
,
b
)):
print
a
,
b
f
(
range
(
2
))
f
((
1
,
2
))
test/tests/generator_thread_sharing.py
0 → 100644
View file @
218d8cd5
def
gen
():
while
True
:
for
i
in
xrange
(
100
):
range
(
100
)
*
1000
# allocate memory to force GC collections
b
=
yield
0
if
b
:
break
done
=
[]
def
thread_run
(
g
):
for
i
in
xrange
(
5
):
g
.
next
()
try
:
g
.
send
(
1
)
assert
0
except
StopIteration
:
pass
done
.
append
(
0
)
g
=
gen
()
for
i
in
xrange
(
5
):
g
.
next
()
from
thread
import
start_new_thread
t
=
start_new_thread
(
thread_run
,
(
g
,))
g
=
""
def
f
():
pass
f
()
f
()
import
time
while
not
done
:
time
.
sleep
(
0.1
)
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