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
151d1c84
Commit
151d1c84
authored
Jan 10, 2015
by
Kevin Modzelewski
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'nonzero'
parents
eae111dd
c27db779
Changes
11
Hide whitespace changes
Inline
Side-by-side
Showing
11 changed files
with
231 additions
and
29 deletions
+231
-29
src/analysis/type_analysis.cpp
src/analysis/type_analysis.cpp
+2
-0
src/codegen/ast_interpreter.cpp
src/codegen/ast_interpreter.cpp
+18
-5
src/codegen/irgen.cpp
src/codegen/irgen.cpp
+1
-1
src/codegen/irgen/irgenerator.cpp
src/codegen/irgen/irgenerator.cpp
+17
-10
src/core/ast.cpp
src/core/ast.cpp
+7
-0
src/core/ast.h
src/core/ast.h
+11
-0
src/core/cfg.cpp
src/core/cfg.cpp
+46
-12
src/runtime/objmodel.cpp
src/runtime/objmodel.cpp
+5
-0
test/tests/boolops.py
test/tests/boolops.py
+13
-1
test/tests/exception_subclasscheck.py
test/tests/exception_subclasscheck.py
+21
-0
test/tests/nonzero_exceptions.py
test/tests/nonzero_exceptions.py
+90
-0
No files found.
src/analysis/type_analysis.cpp
View file @
151d1c84
...
...
@@ -372,6 +372,8 @@ private:
return
UNKNOWN
;
case
AST_LangPrimitive
:
:
NONE
:
return
NONE
;
case
AST_LangPrimitive
:
:
NONZERO
:
return
BOOL
;
default:
RELEASE_ASSERT
(
0
,
"%d"
,
node
->
opcode
);
}
...
...
src/codegen/ast_interpreter.cpp
View file @
151d1c84
...
...
@@ -403,7 +403,10 @@ Value ASTInterpreter::visit_slice(AST_Slice* node) {
}
Value
ASTInterpreter
::
visit_branch
(
AST_Branch
*
node
)
{
if
(
nonzero
(
visit_expr
(
node
->
test
).
o
))
Value
v
=
visit_expr
(
node
->
test
);
ASSERT
(
v
.
o
==
True
||
v
.
o
==
False
,
"Should have called NONZERO before this branch"
);
if
(
v
.
o
==
True
)
next_block
=
node
->
iftrue
;
else
next_block
=
node
->
iffalse
;
...
...
@@ -441,6 +444,8 @@ Value ASTInterpreter::visit_jump(AST_Jump* node) {
if
(
phis
->
isPotentiallyUndefinedAfter
(
name
,
current_block
))
{
bool
is_defined
=
it
!=
sym_table
.
end
();
sorted_symbol_table
[
getIsDefinedName
(
name
)]
=
(
Box
*
)
is_defined
;
if
(
is_defined
)
assert
(
it
->
getValue
()
!=
NULL
);
sorted_symbol_table
[
name
]
=
is_defined
?
it
->
getValue
()
:
NULL
;
}
else
{
ASSERT
(
it
!=
sym_table
.
end
(),
"%s"
,
name
.
c_str
());
...
...
@@ -567,6 +572,7 @@ Value ASTInterpreter::visit_langPrimitive(AST_LangPrimitive* node) {
v
=
boxBool
(
isinstance
(
obj
.
o
,
cls
.
o
,
unboxInt
(
flags
.
o
)));
}
else
if
(
node
->
opcode
==
AST_LangPrimitive
::
LOCALS
)
{
assert
(
node
->
args
.
size
()
==
0
);
BoxedDict
*
dict
=
new
BoxedDict
;
for
(
auto
&
p
:
sym_table
)
{
llvm
::
StringRef
s
=
p
.
first
();
...
...
@@ -576,6 +582,10 @@ Value ASTInterpreter::visit_langPrimitive(AST_LangPrimitive* node) {
dict
->
d
[
new
BoxedString
(
s
.
str
())]
=
p
.
second
;
}
v
=
dict
;
}
else
if
(
node
->
opcode
==
AST_LangPrimitive
::
NONZERO
)
{
assert
(
node
->
args
.
size
()
==
1
);
Value
obj
=
visit_expr
(
node
->
args
[
0
]);
v
=
boxBool
(
nonzero
(
obj
.
o
));
}
else
RELEASE_ASSERT
(
0
,
"not implemented"
);
return
v
;
...
...
@@ -735,8 +745,13 @@ Value ASTInterpreter::visit_raise(AST_Raise* node) {
}
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
);
#ifndef NDEBUG
// Currently we only generate "assert 0" statements
Value
v
=
visit_expr
(
node
->
test
);
assert
(
v
.
o
->
cls
==
int_cls
&&
static_cast
<
BoxedInt
*>
(
v
.
o
)
->
n
==
0
);
#endif
assertFail
(
source_info
->
parent_module
,
node
->
msg
?
visit_expr
(
node
->
msg
).
o
:
0
);
return
Value
();
}
...
...
@@ -1002,8 +1017,6 @@ Value ASTInterpreter::visit_name(AST_Name* node) {
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
;
}
...
...
src/codegen/irgen.cpp
View file @
151d1c84
...
...
@@ -752,7 +752,7 @@ static void emitBBs(IRGenState* irstate, const char* bb_type, GuardList& out_gua
// TODO: inneficient
sym_table
=
new
SymbolTable
(
*
sym_table
);
assert
(
sym_table
->
count
(
name
->
id
));
ASSERT
(
sym_table
->
count
(
name
->
id
),
"%d %s
\n
"
,
block
->
idx
,
name
->
id
.
c_str
(
));
sym_table
->
erase
(
name
->
id
);
created_new_sym_table
=
true
;
}
...
...
src/codegen/irgen/irgenerator.cpp
View file @
151d1c84
...
...
@@ -543,6 +543,17 @@ private:
case
AST_LangPrimitive
:
:
NONE
:
{
return
getNone
();
}
case
AST_LangPrimitive
:
:
NONZERO
:
{
assert
(
node
->
args
.
size
()
==
1
);
CompilerVariable
*
obj
=
evalExpr
(
node
->
args
[
0
],
unw_info
);
ConcreteCompilerVariable
*
rtn
=
obj
->
nonzero
(
emitter
,
getOpInfoForNode
(
node
,
unw_info
));
assert
(
rtn
->
getType
()
==
BOOL
);
llvm
::
Value
*
v
=
i1FromBool
(
emitter
,
rtn
);
assert
(
v
->
getType
()
==
g
.
i1
);
return
boolFromI1
(
emitter
,
v
);
}
default:
RELEASE_ASSERT
(
0
,
"%d"
,
node
->
opcode
);
}
...
...
@@ -1812,22 +1823,18 @@ private:
assert
(
state
!=
PARTIAL
);
assert
(
val
);
// ASSERT(val->getType() == BOOL, "%s", val->getType()->debugName().c_str());
// We could call nonzero here if there is no try-catch block?
ASSERT
(
val
->
getType
()
==
BOOL
,
"should have called NONZERO before this; is %s"
,
val
->
getType
()
->
debugName
().
c_str
());
llvm
::
Value
*
v
=
i1FromBool
(
emitter
,
static_cast
<
ConcreteCompilerVariable
*>
(
val
));
assert
(
v
->
getType
()
==
g
.
i1
);
ConcreteCompilerVariable
*
nonzero
=
val
->
nonzero
(
emitter
,
getOpInfoForNode
(
node
,
unw_info
));
ASSERT
(
nonzero
->
getType
()
==
BOOL
,
"%s %s"
,
val
->
getType
()
->
debugName
().
c_str
(),
nonzero
->
getType
()
->
debugName
().
c_str
());
val
->
decvref
(
emitter
);
llvm
::
Value
*
llvm_nonzero
=
i1FromBool
(
emitter
,
nonzero
);
llvm
::
BasicBlock
*
iftrue
=
entry_blocks
[
node
->
iftrue
];
llvm
::
BasicBlock
*
iffalse
=
entry_blocks
[
node
->
iffalse
];
nonzero
->
decvref
(
emitter
);
endBlock
(
FINISHED
);
emitter
.
getBuilder
()
->
CreateCondBr
(
llvm_nonzero
,
iftrue
,
iffalse
);
emitter
.
getBuilder
()
->
CreateCondBr
(
v
,
iftrue
,
iffalse
);
}
void
doExpr
(
AST_Expr
*
node
,
UnwindInfo
unw_info
)
{
...
...
src/core/ast.cpp
View file @
151d1c84
...
...
@@ -24,6 +24,10 @@
namespace
pyston
{
#ifndef NDEBUG
int
AST
::
next_lineno
=
100000
;
#endif
llvm
::
StringRef
getOpSymbol
(
int
op_type
)
{
switch
(
op_type
)
{
case
AST_TYPE
:
:
Add
:
...
...
@@ -1448,6 +1452,9 @@ bool PrintVisitor::visit_langprimitive(AST_LangPrimitive* node) {
case
AST_LangPrimitive
:
:
NONE
:
printf
(
"NONE"
);
break
;
case
AST_LangPrimitive
:
:
NONZERO
:
printf
(
"NONZERO"
);
break
;
default:
RELEASE_ASSERT
(
0
,
"%d"
,
node
->
opcode
);
}
...
...
src/core/ast.h
View file @
151d1c84
...
...
@@ -148,7 +148,17 @@ public:
virtual
void
accept
(
ASTVisitor
*
v
)
=
0
;
#ifndef NDEBUG
private:
static
int
next_lineno
;
public:
// In debug mode, initialize lineno to something unique, so that if we see something ridiculous
// appear in the traceback, we can isolate the allocation which created it.
AST
(
AST_TYPE
::
AST_TYPE
type
)
:
type
(
type
),
lineno
(
++
next_lineno
)
{}
#else
AST
(
AST_TYPE
::
AST_TYPE
type
)
:
type
(
type
)
{}
#endif
};
class
AST_expr
:
public
AST
{
...
...
@@ -966,6 +976,7 @@ public:
IMPORT_NAME
,
IMPORT_STAR
,
NONE
,
NONZERO
,
}
opcode
;
std
::
vector
<
AST_expr
*>
args
;
...
...
src/core/cfg.cpp
View file @
151d1c84
...
...
@@ -131,6 +131,22 @@ private:
return
NULL
;
}
AST_expr
*
callNonzero
(
AST_expr
*
e
)
{
AST_LangPrimitive
*
call
=
new
AST_LangPrimitive
(
AST_LangPrimitive
::
NONZERO
);
call
->
args
.
push_back
(
e
);
call
->
lineno
=
e
->
lineno
;
call
->
col_offset
=
e
->
col_offset
;
// Simple optimization: allow the generation of nested nodes if there isn't a
// current exc handler.
if
(
exc_handlers
.
size
()
==
0
)
return
call
;
auto
name
=
nodeName
(
e
);
pushAssign
(
name
,
call
);
return
makeName
(
name
,
AST_TYPE
::
Load
);
}
AST_expr
*
applyComprehensionCall
(
AST_DictComp
*
node
,
AST_Name
*
name
)
{
AST_expr
*
key
=
remapExpr
(
node
->
key
);
AST_expr
*
value
=
remapExpr
(
node
->
value
);
...
...
@@ -179,7 +195,7 @@ private:
push_back
(
j
);
curblock
=
test_block
;
AST_expr
*
test_call
=
remapExpr
(
makeCall
(
hasnext_attr
));
AST_expr
*
test_call
=
callNonzero
(
remapExpr
(
makeCall
(
hasnext_attr
)
));
CFGBlock
*
body_block
=
cfg
->
addBlock
();
body_block
->
info
=
"comprehension_body"
;
...
...
@@ -204,7 +220,7 @@ private:
pushAssign
(
c
->
target
,
makeName
(
next_name
,
AST_TYPE
::
Load
));
for
(
AST_expr
*
if_condition
:
c
->
ifs
)
{
AST_expr
*
remapped
=
remapExpr
(
if_condition
);
AST_expr
*
remapped
=
callNonzero
(
remapExpr
(
if_condition
)
);
AST_Branch
*
br
=
new
AST_Branch
();
br
->
test
=
remapped
;
push_back
(
br
);
...
...
@@ -284,7 +300,7 @@ private:
AST_Branch
*
makeBranch
(
AST_expr
*
test
)
{
AST_Branch
*
rtn
=
new
AST_Branch
();
rtn
->
test
=
test
;
rtn
->
test
=
callNonzero
(
test
)
;
rtn
->
col_offset
=
test
->
col_offset
;
rtn
->
lineno
=
test
->
lineno
;
return
rtn
;
...
...
@@ -520,7 +536,7 @@ private:
pushAssign
(
name
,
val
);
AST_Branch
*
br
=
new
AST_Branch
();
br
->
test
=
_dup
(
val
);
br
->
test
=
callNonzero
(
_dup
(
val
)
);
push_back
(
br
);
CFGBlock
*
was_block
=
curblock
;
...
...
@@ -637,7 +653,7 @@ private:
pushAssign
(
name
,
val
);
AST_Branch
*
br
=
new
AST_Branch
();
br
->
test
=
makeName
(
name
,
AST_TYPE
::
Load
);
br
->
test
=
callNonzero
(
makeName
(
name
,
AST_TYPE
::
Load
)
);
push_back
(
br
);
CFGBlock
*
was_block
=
curblock
;
...
...
@@ -725,6 +741,9 @@ private:
for
(
AST_expr
*
if_condition
:
c
->
ifs
)
{
AST_If
*
if_block
=
new
AST_If
();
// Note: don't call callNonzero here, since we are generating
// AST inside a new functiondef which will go through the CFG
// process again.
if_block
->
test
=
if_condition
;
insert_point
->
push_back
(
if_block
);
...
...
@@ -751,13 +770,14 @@ private:
AST_expr
*
remapIfExp
(
AST_IfExp
*
node
)
{
std
::
string
rtn_name
=
nodeName
(
node
);
CFGBlock
*
starting_block
=
curblock
;
AST_Branch
*
br
=
new
AST_Branch
();
br
->
col_offset
=
node
->
col_offset
;
br
->
lineno
=
node
->
lineno
;
br
->
test
=
remapExpr
(
node
->
test
);
br
->
test
=
callNonzero
(
remapExpr
(
node
->
test
)
);
push_back
(
br
);
CFGBlock
*
starting_block
=
curblock
;
CFGBlock
*
iftrue
=
cfg
->
addBlock
();
iftrue
->
info
=
"iftrue"
;
br
->
iftrue
=
iftrue
;
...
...
@@ -1055,6 +1075,10 @@ public:
#endif
curblock
->
push_back
(
node
);
return
;
}
else
if
(
asgn
->
value
->
type
==
AST_TYPE
::
Name
&&
ast_cast
<
AST_Name
>
(
asgn
->
value
)
->
id
[
0
]
==
'#'
)
{
// Assigning from one temporary name to another:
curblock
->
push_back
(
node
);
return
;
}
}
}
...
...
@@ -1246,7 +1270,7 @@ public:
bool
visit_assert
(
AST_Assert
*
node
)
override
{
AST_Branch
*
br
=
new
AST_Branch
();
br
->
test
=
remapExpr
(
node
->
test
);
br
->
test
=
callNonzero
(
remapExpr
(
node
->
test
)
);
push_back
(
br
);
CFGBlock
*
iffalse
=
cfg
->
addBlock
();
...
...
@@ -1498,7 +1522,7 @@ public:
AST_Branch
*
br
=
new
AST_Branch
();
br
->
col_offset
=
node
->
col_offset
;
br
->
lineno
=
node
->
lineno
;
br
->
test
=
remapExpr
(
node
->
test
);
br
->
test
=
callNonzero
(
remapExpr
(
node
->
test
)
);
push_back
(
br
);
CFGBlock
*
starting_block
=
curblock
;
...
...
@@ -1827,7 +1851,7 @@ public:
is_caught_here
->
args
.
push_back
(
makeNum
(
1
));
// flag: false_on_noncls
AST_Branch
*
br
=
new
AST_Branch
();
br
->
test
=
remapExpr
(
is_caught_here
);
br
->
test
=
callNonzero
(
remapExpr
(
is_caught_here
)
);
CFGBlock
*
exc_handle
=
cfg
->
addBlock
();
exc_next
=
cfg
->
addDeferredBlock
();
...
...
@@ -2153,8 +2177,18 @@ CFG* computeCFG(SourceInfo* source, std::vector<AST_stmt*> body) {
for
(
auto
b
:
rtn
->
blocks
)
flatten
(
b
->
body
,
flattened
,
true
);
std
::
unordered_set
<
AST
*>
deduped
(
flattened
.
begin
(),
flattened
.
end
());
assert
(
deduped
.
size
()
==
flattened
.
size
());
std
::
unordered_map
<
AST
*
,
int
>
deduped
;
bool
no_dups
=
true
;
for
(
auto
e
:
flattened
)
{
deduped
[
e
]
++
;
if
(
deduped
[
e
]
==
2
)
{
printf
(
"Duplicated: "
);
print_ast
(
e
);
printf
(
"
\n
"
);
no_dups
=
false
;
}
}
assert
(
no_dups
);
// TODO make sure the result of Invoke nodes are not used on the exceptional path
#endif
...
...
src/runtime/objmodel.cpp
View file @
151d1c84
...
...
@@ -1631,6 +1631,8 @@ bool isUserDefined(BoxedClass* cls) {
}
extern
"C"
bool
nonzero
(
Box
*
obj
)
{
assert
(
gc
::
isValidGCObject
(
obj
));
static
StatCounter
slowpath_nonzero
(
"slowpath_nonzero"
);
std
::
unique_ptr
<
Rewriter
>
rewriter
(
...
...
@@ -1689,6 +1691,8 @@ extern "C" bool nonzero(Box* obj) {
// go through descriptor logic
Box
*
func
=
getclsattr_internal
(
obj
,
"__nonzero__"
,
NULL
);
if
(
!
func
)
func
=
getclsattr_internal
(
obj
,
"__len__"
,
NULL
);
if
(
func
==
NULL
)
{
ASSERT
(
isUserDefined
(
obj
->
cls
)
||
obj
->
cls
==
classobj_cls
,
"%s.__nonzero__"
,
...
...
@@ -1697,6 +1701,7 @@ extern "C" bool nonzero(Box* obj) {
}
Box
*
r
=
runtimeCall0
(
func
,
ArgPassSpec
(
0
));
// I believe this behavior is handled by the slot wrappers in CPython:
if
(
r
->
cls
==
bool_cls
)
{
BoxedBool
*
b
=
static_cast
<
BoxedBool
*>
(
r
);
bool
rtn
=
b
->
n
;
...
...
test/tests/boolops.py
View file @
151d1c84
...
...
@@ -34,4 +34,16 @@ if 0:
print
bool
(
c
)
# this will fail
print
1
and
c
# Note: nonzero isn't called on the second argument!
print
C
(
True
)
or
1
# prints the object repr, not the nonzero repr
print
c
and
1
print
# nonzero should fall back on __len__ if that exists but __nonzero__ doesn't:
class
D
(
object
):
def
__init__
(
self
,
n
):
self
.
n
=
n
def
__len__
(
self
):
print
"__len__"
return
self
.
n
for
i
in
xrange
(
0
,
3
):
print
i
,
bool
(
D
(
i
))
test/tests/exception_subclasscheck.py
View file @
151d1c84
...
...
@@ -3,6 +3,9 @@
# Exception-catching is supposed to go through __subclasscheck__
class
MyException
(
Exception
):
pass
class
M
(
type
):
def
__instancecheck__
(
self
,
instance
):
print
"instancecheck"
,
instance
...
...
@@ -10,10 +13,19 @@ class M(type):
def
__subclasscheck__
(
self
,
sub
):
print
"subclasscheck"
,
sub
if
self
.
throw_on_subclasscheck
:
raise
MyException
()
return
True
class
E
(
Exception
):
__metaclass__
=
M
throw_on_subclasscheck
=
False
class
F
(
Exception
):
__metaclass__
=
M
throw_on_subclasscheck
=
True
print
1
print
isinstance
(
E
(),
E
)
# does not print anything due to special-casing
...
...
@@ -35,3 +47,12 @@ except E:
pass
print
5
# Exceptions in __subclasscheck__ should get ignored:
try
:
1
/
0
except
F
:
print
"shouldn't get here"
except
ZeroDivisionError
:
print
"ok"
test/tests/nonzero_exceptions.py
0 → 100644
View file @
151d1c84
class
MyException
(
Exception
):
pass
class
C
(
object
):
def
__init__
(
self
,
x
):
self
.
x
=
x
def
__nonzero__
(
self
):
raise
MyException
(
self
.
x
)
def
__repr__
(
self
):
return
"<C %r>"
%
self
.
x
# Make sure that we can handle nonzero() throwing an exception wherever it occurs:
try
:
print
C
(
1
)
and
1
except
MyException
,
e
:
print
e
try
:
print
C
(
2
)
or
1
except
MyException
,
e
:
print
e
try
:
if
C
(
3
):
pass
except
MyException
,
e
:
print
e
try
:
while
C
(
4
):
pass
except
MyException
,
e
:
print
e
try
:
assert
C
(
5
)
except
MyException
,
e
:
print
e
try
:
print
[
1
for
i
in
range
(
5
)
if
C
(
6
)]
except
MyException
,
e
:
print
e
try
:
print
list
(
1
for
i
in
range
(
5
)
if
C
(
7
))
except
MyException
,
e
:
print
e
try
:
print
1
if
C
(
8
)
else
0
except
MyException
,
e
:
print
e
class
M
(
type
):
def
__instancecheck__
(
self
,
instance
):
print
"instancecheck"
,
instance
return
C
(
9
)
def
__subclasscheck__
(
self
,
sub
):
print
"subclasscheck"
,
sub
return
C
(
10
)
class
F
(
Exception
):
__metaclass__
=
M
try
:
try
:
1
/
0
except
C
(
"a"
)
or
1
:
print
"shouldn't get here"
print
"shouldn't get here 2"
except
MyException
,
e
:
print
e
class
E
(
object
):
def
__lt__
(
self
,
rhs
):
return
C
(
"false"
)
# This is ok because it doesn't evaluate the result of the comparison:
print
E
()
<
1
try
:
# This is not ok because it will!
print
E
()
<
1
<
1
except
MyException
,
e
:
print
e
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