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
3a8884ed
Commit
3a8884ed
authored
Aug 18, 2015
by
Kevin Modzelewski
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Call tp_init in typeCall for extension classes
Actually, for now in all cases unless __init__ is a Python function.
parent
4008df8e
Changes
4
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
121 additions
and
77 deletions
+121
-77
src/capi/typeobject.cpp
src/capi/typeobject.cpp
+1
-1
src/capi/typeobject.h
src/capi/typeobject.h
+1
-0
src/runtime/descr.cpp
src/runtime/descr.cpp
+9
-3
src/runtime/types.cpp
src/runtime/types.cpp
+110
-73
No files found.
src/capi/typeobject.cpp
View file @
3a8884ed
...
...
@@ -1152,7 +1152,7 @@ static PyObject* slot_tp_del(PyObject* self) noexcept {
}
}
static
int
slot_tp_init
(
PyObject
*
self
,
PyObject
*
args
,
PyObject
*
kwds
)
noexcept
{
/* Pyston change: static */
int
slot_tp_init
(
PyObject
*
self
,
PyObject
*
args
,
PyObject
*
kwds
)
noexcept
{
STAT_TIMER
(
t0
,
"us_timer_slot_tpinit"
,
SLOT_AVOIDABILITY
(
self
));
static
PyObject
*
init_str
;
...
...
src/capi/typeobject.h
View file @
3a8884ed
...
...
@@ -51,6 +51,7 @@ int slot_sq_contains(PyObject* self, PyObject* value) noexcept;
Py_ssize_t
slot_sq_length
(
PyObject
*
self
)
noexcept
;
PyObject
*
slot_tp_getattr_hook
(
PyObject
*
self
,
PyObject
*
name
)
noexcept
;
PyObject
*
tp_new_wrapper
(
PyTypeObject
*
self
,
BoxedTuple
*
args
,
Box
*
kwds
)
noexcept
;
int
slot_tp_init
(
PyObject
*
self
,
PyObject
*
args
,
PyObject
*
kwds
)
noexcept
;
class
GetattrRewriteArgs
;
Box
*
slotTpGetattrHookInternal
(
Box
*
self
,
BoxedString
*
attr
,
GetattrRewriteArgs
*
rewrite_args
);
...
...
src/runtime/descr.cpp
View file @
3a8884ed
...
...
@@ -75,9 +75,9 @@ static Box* propertyInit(Box* _self, Box* fget, Box* fset, Box** args) {
Box
*
doc
=
args
[
1
];
BoxedProperty
*
self
=
static_cast
<
BoxedProperty
*>
(
_self
);
self
->
prop_get
=
fget
;
self
->
prop_set
=
fset
;
self
->
prop_del
=
fdel
;
self
->
prop_get
=
fget
==
None
?
NULL
:
fget
;
self
->
prop_set
=
fset
==
None
?
NULL
:
fset
;
self
->
prop_del
=
fdel
==
None
?
NULL
:
fdel
;
self
->
prop_doc
=
doc
;
self
->
getter_doc
=
false
;
...
...
@@ -151,6 +151,12 @@ static Box* property_copy(BoxedProperty* old, Box* get, Box* set, Box* del) {
return
prop
;
}
else
{
if
(
!
get
)
get
=
None
;
if
(
!
set
)
set
=
None
;
if
(
!
del
)
del
=
None
;
Box
*
doc
;
if
((
old
->
getter_doc
&&
get
!=
None
)
||
!
old
->
prop_doc
)
doc
=
None
;
...
...
src/runtime/types.cpp
View file @
3a8884ed
...
...
@@ -832,15 +832,16 @@ static Box* typeCallInner(CallRewriteArgs* rewrite_args, ArgPassSpec argspec, Bo
RewriterVar
*
r_ccls
=
NULL
;
RewriterVar
*
r_new
=
NULL
;
RewriterVar
*
r_init
=
NULL
;
Box
*
new_attr
,
*
init_attr
;
Box
*
new_attr
,
*
init_attr
=
NULL
;
if
(
rewrite_args
)
{
assert
(
!
argspec
.
has_starargs
);
assert
(
!
argspec
.
has_kwargs
);
assert
(
argspec
.
num_args
>
0
);
r_ccls
=
rewrite_args
->
arg1
;
// This is probably a duplicate, but it's hard to really convince myself of that.
// Need to create a clear contract of who guards on what
// Guard on the requested class. We could potentially support multiple classes in a rewrite,
// but there are parts of this function's rewrite that currently take advantage of the fact
// that the requested class is fixed.
r_ccls
->
addGuard
((
intptr_t
)
arg1
/* = _cls */
);
...
...
@@ -930,7 +931,7 @@ static Box* typeCallInner(CallRewriteArgs* rewrite_args, ArgPassSpec argspec, Bo
//
// For debugging, keep track of why we think we can rewrite this:
enum
{
NOT_ALLOWED
,
VERIFIED
,
NO_INIT
,
TYPE_NEW_SPECIAL_CASE
,
}
why_rewrite_allowed
=
NOT_ALLOWED
;
enum
{
NOT_ALLOWED
,
MAKES_CLS
,
NO_INIT
,
TYPE_NEW_SPECIAL_CASE
,
}
why_rewrite_allowed
=
NOT_ALLOWED
;
// These are __new__ functions that have the property that __new__(kls) always returns an instance of kls.
// These are ok to call regardless of what type was requested.
...
...
@@ -939,32 +940,32 @@ static Box* typeCallInner(CallRewriteArgs* rewrite_args, ArgPassSpec argspec, Bo
// type? then object.__new__ would not be able to be here:
//
// this array is ok with not using StlCompatAllocator since we will manually register these objects with the GC
static
std
::
vector
<
Box
*>
allowable
_news
;
if
(
allowable
_news
.
empty
())
{
static
std
::
vector
<
Box
*>
class_making
_news
;
if
(
class_making
_news
.
empty
())
{
for
(
BoxedClass
*
allowed_cls
:
{
object_cls
,
enumerate_cls
,
xrange_cls
,
tuple_cls
,
list_cls
,
dict_cls
})
{
auto
new_obj
=
typeLookup
(
allowed_cls
,
new_str
,
NULL
);
gc
::
registerPermanentRoot
(
new_obj
,
/* allow_duplicates= */
true
);
allowable
_news
.
push_back
(
new_obj
);
class_making
_news
.
push_back
(
new_obj
);
}
}
if
(
rewrite_args
)
{
for
(
auto
b
:
allowable
_news
)
{
for
(
auto
b
:
class_making
_news
)
{
if
(
b
==
new_attr
)
{
why_rewrite_allowed
=
VERIFIED
;
why_rewrite_allowed
=
MAKES_CLS
;
break
;
}
}
if
(
cls
->
tp_new
==
BaseException
->
tp_new
)
why_rewrite_allowed
=
VERIFIED
;
why_rewrite_allowed
=
MAKES_CLS
;
bool
know_first_arg
=
!
argspec
.
has_starargs
&&
!
argspec
.
has_kwargs
&&
argspec
.
num_keywords
==
0
;
if
(
know_first_arg
)
{
if
(
argspec
.
num_args
==
1
&&
(
cls
==
int_cls
||
cls
==
float_cls
||
cls
==
long_cls
||
cls
==
str_cls
||
cls
==
unicode_cls
))
why_rewrite_allowed
=
VERIFIED
;
why_rewrite_allowed
=
MAKES_CLS
;
if
(
argspec
.
num_args
==
2
&&
(
cls
==
int_cls
||
cls
==
float_cls
||
cls
==
long_cls
)
&&
(
arg2
->
cls
==
int_cls
||
arg2
->
cls
==
str_cls
||
arg2
->
cls
==
float_cls
...
...
@@ -975,7 +976,7 @@ static Box* typeCallInner(CallRewriteArgs* rewrite_args, ArgPassSpec argspec, Bo
// str(obj) can return str-subtypes, but for builtin types it won't:
if
(
argspec
.
num_args
==
2
&&
cls
==
str_cls
&&
(
arg2
->
cls
==
int_cls
||
arg2
->
cls
==
float_cls
))
{
why_rewrite_allowed
=
VERIFIED
;
why_rewrite_allowed
=
MAKES_CLS
;
rewrite_args
->
arg2
->
addAttrGuard
(
offsetof
(
Box
,
cls
),
(
intptr_t
)
arg2
->
cls
);
}
...
...
@@ -1011,22 +1012,25 @@ static Box* typeCallInner(CallRewriteArgs* rewrite_args, ArgPassSpec argspec, Bo
}
static
BoxedString
*
init_str
=
internStringImmortal
(
"__init__"
);
if
(
rewrite_args
)
{
GetattrRewriteArgs
grewrite_args
(
rewrite_args
->
rewriter
,
r_ccls
,
rewrite_args
->
destination
);
init_attr
=
typeLookup
(
cls
,
init_str
,
&
grewrite_args
);
if
(
cls
->
tp_init
==
slot_tp_init
)
{
// If there's a Python-level tp_init, try getting it, since calling it might be faster than calling
// tp_init if we can manage to rewrite it.
if
(
rewrite_args
)
{
GetattrRewriteArgs
grewrite_args
(
rewrite_args
->
rewriter
,
r_ccls
,
rewrite_args
->
destination
);
init_attr
=
typeLookup
(
cls
,
init_str
,
&
grewrite_args
);
if
(
!
grewrite_args
.
out_success
)
rewrite_args
=
NULL
;
else
{
if
(
init_attr
)
{
r_init
=
grewrite_args
.
out_rtn
;
r_init
->
addGuard
((
intptr_t
)
init_attr
);
if
(
!
grewrite_args
.
out_success
)
rewrite_args
=
NULL
;
else
{
if
(
init_attr
)
{
r_init
=
grewrite_args
.
out_rtn
;
r_init
->
addGuard
((
intptr_t
)
init_attr
);
}
}
}
else
{
init_attr
=
typeLookup
(
cls
,
init_str
,
NULL
);
}
}
else
{
init_attr
=
typeLookup
(
cls
,
init_str
,
NULL
);
}
// The init_attr should always resolve as well, but doesn't yet
Box
*
made
;
RewriterVar
*
r_made
=
NULL
;
...
...
@@ -1121,60 +1125,95 @@ static Box* typeCallInner(CallRewriteArgs* rewrite_args, ArgPassSpec argspec, Bo
return
made
;
}
bool
skip_init
=
false
;
// If __new__ returns a subclass, supposed to call that subclass's __init__.
// If __new__ returns a non-subclass, not supposed to call __init__.
if
(
made
->
cls
!=
cls
)
{
assert
(
why_rewrite_allowed
!=
MAKES_CLS
);
ASSERT
(
rewrite_args
==
NULL
||
(
why_rewrite_allowed
==
NO_INIT
&&
made
->
cls
->
tp_init
==
object_cls
->
tp_init
&&
cls
->
tp_init
==
object_cls
->
tp_init
),
"We should only have allowed the rewrite to continue if we were guaranteed that "
"made would have class cls!"
);
if
(
!
isSubclass
(
made
->
cls
,
cls
))
{
init_attr
=
NULL
;
skip_init
=
true
;
}
else
{
// We could have skipped the initial __init__ lookup
init_attr
=
typeLookup
(
made
->
cls
,
init_str
,
NULL
);
if
(
init_attr
)
{
// Getting here means the init_attr is wrong; set it to NULL so that we don't use it.
init_attr
=
NULL
;
}
}
}
if
(
init_attr
&&
made
->
cls
->
tp_init
!=
object_cls
->
tp_init
)
{
// TODO apply the same descriptor special-casing as in callattr?
if
(
!
skip_init
&&
made
->
cls
->
tp_init
!=
object_cls
->
tp_init
)
{
Box
*
initrtn
;
// Attempt to rewrite the basic case:
if
(
rewrite_args
&&
init_attr
->
cls
==
function_cls
)
{
// Note: this code path includes the descriptor logic
CallRewriteArgs
srewrite_args
(
rewrite_args
->
rewriter
,
r_init
,
rewrite_args
->
destination
);
srewrite_args
.
arg1
=
r_made
;
if
(
npassed_args
>=
2
)
srewrite_args
.
arg2
=
rewrite_args
->
arg2
;
if
(
npassed_args
>=
3
)
srewrite_args
.
arg3
=
rewrite_args
->
arg3
;
if
(
npassed_args
>=
4
)
srewrite_args
.
args
=
rewrite_args
->
args
;
srewrite_args
.
args_guarded
=
rewrite_args
->
args_guarded
;
srewrite_args
.
func_guarded
=
true
;
// If there's a Python-level __init__ function, try calling it.
if
(
init_attr
&&
init_attr
->
cls
==
function_cls
)
{
if
(
rewrite_args
)
{
// We are going to rewrite as a call to cls.init:
assert
(
why_rewrite_allowed
==
MAKES_CLS
);
assert
(
made
->
cls
==
cls
);
}
// initrtn = callattrInternal<CXX>(cls, _init_str, INST_ONLY, &srewrite_args, argspec, made, arg2, arg3,
// args, keyword_names);
initrtn
=
runtimeCallInternal
<
S
>
(
init_attr
,
&
srewrite_args
,
argspec
,
made
,
arg2
,
arg3
,
args
,
keyword_names
);
// Note: this code path includes the descriptor logic
if
(
rewrite_args
)
{
CallRewriteArgs
srewrite_args
(
rewrite_args
->
rewriter
,
r_init
,
rewrite_args
->
destination
);
srewrite_args
.
arg1
=
r_made
;
if
(
npassed_args
>=
2
)
srewrite_args
.
arg2
=
rewrite_args
->
arg2
;
if
(
npassed_args
>=
3
)
srewrite_args
.
arg3
=
rewrite_args
->
arg3
;
if
(
npassed_args
>=
4
)
srewrite_args
.
args
=
rewrite_args
->
args
;
srewrite_args
.
args_guarded
=
rewrite_args
->
args_guarded
;
srewrite_args
.
func_guarded
=
true
;
initrtn
=
runtimeCallInternal
<
S
>
(
init_attr
,
&
srewrite_args
,
argspec
,
made
,
arg2
,
arg3
,
args
,
keyword_names
);
if
(
!
srewrite_args
.
out_success
)
{
rewrite_args
=
NULL
;
}
else
{
assert
(
S
==
CXX
&&
"this need to be converted"
);
rewrite_args
->
rewriter
->
call
(
true
,
(
void
*
)
assertInitNone
,
srewrite_args
.
out_rtn
);
}
}
else
{
initrtn
=
runtimeCallInternal
<
S
>
(
init_attr
,
NULL
,
argspec
,
made
,
arg2
,
arg3
,
args
,
keyword_names
);
}
if
(
!
initrtn
)
{
assert
(
S
==
CAPI
);
return
NULL
;
}
if
(
!
srewrite_args
.
out_success
)
{
rewrite_args
=
NULL
;
}
else
{
assert
(
S
==
CXX
&&
"this need to be converted"
);
rewrite_args
->
rewriter
->
call
(
true
,
(
void
*
)
assertInitNone
,
srewrite_args
.
out_rtn
);
}
assert
(
initrtn
);
if
(
S
==
CAPI
)
{
if
(
initrtn
!=
None
)
{
PyErr_Format
(
TypeError
,
"__init__() should return None, not '%s'"
,
getTypeName
(
initrtn
));
return
NULL
;
}
}
else
assertInitNone
(
initrtn
);
}
else
{
rewrite_args
=
NULL
;
// Otherwise, just call tp_init. This will work out well for extension classes, and no worse
// than failing the rewrite for Python non-extension non-functions (when does that happen?).
initproc
tpinit
=
made
->
cls
->
tp_init
;
if
(
rewrite_args
)
{
// This is the only case that should get here:
assert
(
why_rewrite_allowed
==
MAKES_CLS
&&
made
->
cls
==
cls
);
// We're going to emit a call to cls->tp_init, but really we should be calling made->cls->tp_init,
// but the MAKES_CLS condition tells us that made->cls is cls so the two tp_inits are the same.
assert
(
tpinit
==
cls
->
tp_init
);
}
bool
rewrite_success
=
false
;
try
{
init_attr
=
processDescriptor
(
init_attr
,
made
,
cls
);
rearrangeArguments
(
ParamReceiveSpec
(
1
,
0
,
true
,
true
),
NULL
,
""
,
NULL
,
rewrite_args
,
rewrite_success
,
argspec
,
made
,
arg2
,
arg3
,
args
,
NULL
,
keyword_names
);
}
catch
(
ExcInfo
e
)
{
if
(
S
==
CAPI
)
{
setCAPIException
(
e
);
...
...
@@ -1183,30 +1222,28 @@ static Box* typeCallInner(CallRewriteArgs* rewrite_args, ArgPassSpec argspec, Bo
throw
e
;
}
ArgPassSpec
init_argspec
=
argspec
;
init_argspec
.
num_args
--
;
int
passed
=
init_argspec
.
totalPassed
();
if
(
!
rewrite_success
)
rewrite_args
=
NULL
;
// If we weren't passed the args array, it's not safe to index into it
if
(
passed
<=
2
)
initrtn
=
runtimeCallInternal
<
S
>
(
init_attr
,
NULL
,
init_argspec
,
arg2
,
arg3
,
NULL
,
NULL
,
keyword_names
);
else
initrtn
=
runtimeCallInternal
<
S
>
(
init_attr
,
NULL
,
init_argspec
,
arg2
,
arg3
,
args
[
0
],
&
args
[
1
],
keyword_names
);
assert
(
arg2
->
cls
==
tuple_cls
);
assert
(
!
arg3
||
arg3
->
cls
==
dict_cls
);
if
(
!
initrtn
)
{
assert
(
S
==
CAPI
);
return
NULL
;
int
err
=
tpinit
(
made
,
arg2
,
arg3
);
if
(
err
==
-
1
)
{
if
(
S
==
CAPI
)
return
NULL
;
else
throwCAPIException
();
}
}
assert
(
initrtn
);
if
(
S
==
CAPI
&&
initrtn
!=
None
)
{
PyErr_Format
(
TypeError
,
"__init__() should return None, not '%s'"
,
getTypeName
(
initrtn
));
return
NULL
;
if
(
rewrite_args
)
{
auto
r_err
=
rewrite_args
->
rewriter
->
call
(
true
,
(
void
*
)
tpinit
,
r_made
,
rewrite_args
->
arg2
,
rewrite_args
->
arg3
);
assert
(
S
==
CXX
&&
"this need to be converted"
);
rewrite_args
->
rewriter
->
checkAndThrowCAPIException
(
r_err
,
-
1
);
}
}
assertInitNone
(
initrtn
);
}
else
{
if
(
new_attr
==
NULL
&&
npassed_args
!=
1
)
{
// TODO not npassed args, since the starargs or kwargs could be null
...
...
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