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
c8952247
Commit
c8952247
authored
Mar 15, 2016
by
Kevin Modzelewski
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
This makes my head hurt
parent
dfa94237
Changes
5
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
62 additions
and
24 deletions
+62
-24
docs/REFCOUNTING.md
docs/REFCOUNTING.md
+4
-0
src/runtime/objmodel.cpp
src/runtime/objmodel.cpp
+12
-18
src/runtime/types.cpp
src/runtime/types.cpp
+4
-4
src/runtime/types.h
src/runtime/types.h
+1
-0
test/tests/descr_selfdelete.py
test/tests/descr_selfdelete.py
+41
-2
No files found.
docs/REFCOUNTING.md
View file @
c8952247
...
...
@@ -22,6 +22,10 @@ Invariant: all paths through a function should leave each variable with 0 net re
Special cases:
-
Most exception-related functions steal refs. If you throw an exception in C code (via
`throw [ExcInfo] e`
), it consumes the refs.
Some things need to be ok with their arguments going away.
-
Function objects can generally get deallocated while they are running.
-
tp_descr_get functions need to keep their first argument alive.
## Refcounting in the rewriter, baseline jit, and llvm jit
## Debugging
...
...
src/runtime/objmodel.cpp
View file @
c8952247
...
...
@@ -2174,10 +2174,7 @@ Box* getattrInternalGeneric(Box* obj, BoxedString* attr, GetattrRewriteArgs* rew
descr
=
typeLookup
(
obj
->
cls
,
attr
);
}
assert
(
0
&&
"figure out what to do about `descr`, especially in the rewrite version (and maybe _get_ too)"
);
// Keep it alive just to be safe:
//Py_INCREF(descr);
//AUTO_DECREF(descr);
XKEEP_ALIVE
(
descr
);
// Check if it's a data descriptor
descrgetfunc
descr_get
=
NULL
;
...
...
@@ -2274,6 +2271,8 @@ Box* getattrInternalGeneric(Box* obj, BoxedString* attr, GetattrRewriteArgs* rew
}
}
XKEEP_ALIVE
(
_get_
);
// Maybe not necessary?
if
(
!
cls_only
)
{
if
(
!
IsType
)
{
// Look up the val in the object's dictionary and if you find it, return it.
...
...
@@ -2709,7 +2708,7 @@ void setattrGeneric(Box* obj, BoxedString* attr, STOLEN(Box*) val, SetattrRewrit
descr
=
typeLookup
(
obj
->
cls
,
attr
);
}
assert
(
0
&&
"figure out what to do about `descr`, especially in the rewrite version (and maybe _set_ too)"
);
XKEEP_ALIVE
(
descr
);
Box
*
_set_
=
NULL
;
RewriterVar
*
r_set
=
NULL
;
...
...
@@ -4491,6 +4490,8 @@ Box* callCLFunc(FunctionMetadata* md, CallRewriteArgs* rewrite_args, int num_out
rewrite_args
=
NULL
;
}
assert
(
0
&&
"I think this is where the KEEP_ALIVE should go. should also keep the rewritten version alive."
);
CompiledFunction
*
chosen_cf
=
pickVersion
(
md
,
S
,
num_output_args
,
oarg1
,
oarg2
,
oarg3
,
oargs
);
if
(
!
chosen_cf
)
{
...
...
@@ -5661,11 +5662,11 @@ static Box* callItemOrSliceAttr(Box* target, BoxedString* item_str, BoxedString*
}
// Guard on the type of the object (need to have the slice operator attribute to call it).
Box
*
slice_attr
=
NULL
;
bool
has_slice_attr
=
false
;
if
(
rewrite_args
)
{
RewriterVar
*
target_cls
=
rewrite_args
->
obj
->
getAttr
(
offsetof
(
Box
,
cls
));
GetattrRewriteArgs
grewrite_args
(
rewrite_args
->
rewriter
,
target_cls
,
Location
::
any
());
slice_attr
=
typeLookup
(
target
->
cls
,
slice_str
,
&
grewrite_args
);
has_slice_attr
=
(
bool
)
typeLookup
(
target
->
cls
,
slice_str
,
&
grewrite_args
);
if
(
!
grewrite_args
.
isSuccessful
())
{
rewrite_args
=
NULL
;
}
else
{
...
...
@@ -5676,18 +5677,16 @@ static Box* callItemOrSliceAttr(Box* target, BoxedString* item_str, BoxedString*
rewrite_args
=
NULL
;
if
(
rewrite_args
)
assert
(
(
bool
)
slice_attr
==
(
return_convention
==
ReturnConvention
::
HAS_RETURN
));
assert
(
has_
slice_attr
==
(
return_convention
==
ReturnConvention
::
HAS_RETURN
));
}
}
else
{
slice_attr
=
typeLookup
(
target
->
cls
,
slice_str
);
has_slice_attr
=
(
bool
)
typeLookup
(
target
->
cls
,
slice_str
);
}
if
(
!
slice_attr
)
{
if
(
!
has_
slice_attr
)
{
return
callItemAttr
<
S
,
rewritable
>
(
target
,
item_str
,
slice
,
value
,
rewrite_args
);
}
assert
(
0
&&
"how to keep slice_attr alive? (esp for rewrites)"
);
// Need a slice object to use the slice operators.
if
(
rewrite_args
)
{
rewrite_args
->
arg1
->
addAttrGuard
(
offsetof
(
Box
,
cls
),
(
uint64_t
)
slice
->
cls
);
...
...
@@ -6105,8 +6104,6 @@ extern "C" void delattrGeneric(Box* obj, BoxedString* attr, DelattrRewriteArgs*
static
BoxedString
*
delete_str
=
getStaticString
(
"__delete__"
);
Box
*
delAttr
=
typeLookup
(
static_cast
<
BoxedClass
*>
(
clsAttr
->
cls
),
delete_str
);
assert
(
0
&&
"how to keep delAttr alive (esp in rewrite)"
);
if
(
delAttr
!=
NULL
)
{
Box
*
rtn
=
runtimeCallInternal
<
CXX
,
NOT_REWRITABLE
>
(
delAttr
,
NULL
,
ArgPassSpec
(
2
),
clsAttr
,
obj
,
NULL
,
NULL
,
NULL
);
...
...
@@ -6115,8 +6112,6 @@ extern "C" void delattrGeneric(Box* obj, BoxedString* attr, DelattrRewriteArgs*
}
}
assert
(
0
&&
"how to keep clsAttr alive (esp in rewrite)"
);
// check if the attribute is in the instance's __dict__
Box
*
attrVal
=
obj
->
getattr
(
attr
);
if
(
attrVal
!=
NULL
)
{
...
...
@@ -6843,8 +6838,7 @@ extern "C" Box* importStar(Box* _from_module, Box* to_globals) {
if
(
!
all_getitem
)
raiseExcHelper
(
TypeError
,
"'%s' object does not support indexing"
,
getTypeName
(
all
));
Py_INCREF
(
all_getitem
);
AUTO_DECREF
(
all_getitem
);
KEEP_ALIVE
(
all_getitem
);
int
idx
=
0
;
while
(
true
)
{
...
...
src/runtime/types.cpp
View file @
c8952247
...
...
@@ -817,8 +817,8 @@ static Box* typeCallInner(CallRewriteArgs* rewrite_args, ArgPassSpec argspec, Bo
RewriterVar
*
r_ccls
=
NULL
;
RewriterVar
*
r_new
=
NULL
;
RewriterVar
*
r_init
=
NULL
;
// TODO:
is this ok? what if new causes init to get freed?
BORROWED
(
Box
*
)
init_attr
=
NULL
;
// TODO:
shouldn't cache it like this. What if __new__ changes __init__
DecrefHandle
<
Box
,
true
>
init_attr
(
nullptr
)
;
if
(
rewrite_args
)
{
assert
(
!
argspec
.
has_starargs
);
assert
(
!
argspec
.
has_kwargs
);
...
...
@@ -997,7 +997,7 @@ static Box* typeCallInner(CallRewriteArgs* rewrite_args, ArgPassSpec argspec, Bo
// tp_init if we can manage to rewrite it.
if
(
rewrite_args
&&
which_init
!=
UNKNOWN
)
{
GetattrRewriteArgs
grewrite_args
(
rewrite_args
->
rewriter
,
r_ccls
,
rewrite_args
->
destination
);
init_attr
=
typeLookup
(
cls
,
init_str
,
&
grewrite_args
);
init_attr
=
incref
(
typeLookup
(
cls
,
init_str
,
&
grewrite_args
)
);
if
(
!
grewrite_args
.
isSuccessful
())
rewrite_args
=
NULL
;
...
...
@@ -1010,7 +1010,7 @@ static Box* typeCallInner(CallRewriteArgs* rewrite_args, ArgPassSpec argspec, Bo
}
}
}
else
{
init_attr
=
typeLookup
(
cls
,
init_str
);
init_attr
=
incref
(
typeLookup
(
cls
,
init_str
)
);
}
}
...
...
src/runtime/types.h
View file @
c8952247
...
...
@@ -380,6 +380,7 @@ template <typename B> DecrefHandle<B, true> autoXDecref(B* b) {
#define AUTO_XDECREF(x) DecrefHandle<Box, true> CAT(_autodecref_, __LINE__)((x))
#define KEEP_ALIVE(x) AUTO_DECREF(incref(x))
#define XKEEP_ALIVE(x) AUTO_XDECREF(xincref(x))
template
<
bool
Nullable
=
false
>
class
AutoDecrefArray
{
private:
...
...
test/tests/descr_selfdelete.py
View file @
c8952247
...
...
@@ -13,14 +13,18 @@
# So also test it by creating a closure and make sure that that stays alive.
# - This file wraps each individual test in a function and then calls it twice -- this is to try to test
# any rewritten (traced) variants as well.
#
# Actually, looking more into CPython's behavior, it seems like CPython is very tolerant of executing a
# function object that gets deallocated during its own execution: CPython copies all the relevant info
# into the frame and then accesses it from there.
import
sys
def
make_closure
(
f
):
def
inner
(
*
args
,
**
kw
):
print
f
.
__name__
print
"starting"
,
f
.
__name__
r
=
f
(
*
args
,
**
kw
)
print
f
.
__name__
print
"ending"
,
f
.
__name__
return
r
return
inner
...
...
@@ -159,8 +163,43 @@ f()
f
()
f
()
def
f
():
class
D
(
object
):
@
make_closure
def
__get__
(
self
,
*
args
):
print
"D.__get__"
del
C
.
__contains__
del
D
.
__get__
print
self
return
lambda
*
args
:
1
class
C
(
object
):
__contains__
=
make_closure
(
D
())
print
1
in
C
()
f
()
f
()
f
()
def
f
():
class
D
(
object
):
@
make_closure
def
__get__
(
self
,
*
args
):
print
"D.__getattribute__"
del
C
.
__getattribute__
del
D
.
__get__
print
self
return
lambda
*
args
:
1
class
C
(
object
):
__getattribute__
=
D
()
print
C
().
a
f
()
f
()
f
()
# Related:
def
f
():
@
make_closure
...
...
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