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
3e8f2520
Commit
3e8f2520
authored
May 26, 2015
by
Kevin Modzelewski
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Switch to cpython's object_init and object_new
parent
0c0a7da1
Changes
4
Show whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
64 additions
and
56 deletions
+64
-56
src/runtime/objmodel.cpp
src/runtime/objmodel.cpp
+11
-27
src/runtime/types.cpp
src/runtime/types.cpp
+39
-18
test/tests/class_noctor.py
test/tests/class_noctor.py
+5
-6
test/tests/object_new_arguments.py
test/tests/object_new_arguments.py
+9
-5
No files found.
src/runtime/objmodel.cpp
View file @
3e8f2520
...
@@ -4513,23 +4513,10 @@ Box* typeCallInternal(BoxedFunctionBase* f, CallRewriteArgs* rewrite_args, ArgPa
...
@@ -4513,23 +4513,10 @@ Box* typeCallInternal(BoxedFunctionBase* f, CallRewriteArgs* rewrite_args, ArgPa
// Notably, "type" itself does not. For instance, assuming M is a subclass of
// Notably, "type" itself does not. For instance, assuming M is a subclass of
// type, type.__new__(M, 1) will return the int class, which is not an instance of M.
// type, type.__new__(M, 1) will return the int class, which is not an instance of M.
static
Box
*
object_new
=
NULL
;
static
Box
*
object_init
=
NULL
;
// this is ok with not using StlCompatAllocator since we will manually register these objects with the GC
// this is ok with not using StlCompatAllocator since we will manually register these objects with the GC
static
std
::
vector
<
Box
*>
allowable_news
;
static
std
::
vector
<
Box
*>
allowable_news
;
if
(
!
object_new
)
{
if
(
allowable_news
.
empty
())
{
object_new
=
typeLookup
(
object_cls
,
new_str
,
NULL
);
for
(
BoxedClass
*
allowed_cls
:
{
object_cls
,
enumerate_cls
,
xrange_cls
})
{
assert
(
object_new
);
// I think this is unnecessary, but good form:
gc
::
registerPermanentRoot
(
object_new
);
object_init
=
typeLookup
(
object_cls
,
init_str
,
NULL
);
assert
(
object_init
);
gc
::
registerPermanentRoot
(
object_init
);
allowable_news
.
push_back
(
object_new
);
for
(
BoxedClass
*
allowed_cls
:
{
enumerate_cls
,
xrange_cls
})
{
auto
new_obj
=
typeLookup
(
allowed_cls
,
new_str
,
NULL
);
auto
new_obj
=
typeLookup
(
allowed_cls
,
new_str
,
NULL
);
gc
::
registerPermanentRoot
(
new_obj
);
gc
::
registerPermanentRoot
(
new_obj
);
allowable_news
.
push_back
(
new_obj
);
allowable_news
.
push_back
(
new_obj
);
...
@@ -4585,16 +4572,9 @@ Box* typeCallInternal(BoxedFunctionBase* f, CallRewriteArgs* rewrite_args, ArgPa
...
@@ -4585,16 +4572,9 @@ Box* typeCallInternal(BoxedFunctionBase* f, CallRewriteArgs* rewrite_args, ArgPa
RewriterVar
*
r_made
=
NULL
;
RewriterVar
*
r_made
=
NULL
;
ArgPassSpec
new_argspec
=
argspec
;
ArgPassSpec
new_argspec
=
argspec
;
if
(
npassed_args
>
1
&&
new_attr
==
object_new
)
{
if
(
init_attr
==
object_init
)
{
raiseExcHelper
(
TypeError
,
objectNewParameterTypeErrorMsg
());
}
else
{
new_argspec
=
ArgPassSpec
(
1
);
}
}
if
(
rewrite_args
)
{
if
(
rewrite_args
)
{
if
(
new_attr
==
object_new
&&
init_attr
!=
object
_init
)
{
if
(
cls
->
tp_new
==
object_cls
->
tp_new
&&
cls
->
tp_init
!=
object_cls
->
tp
_init
)
{
// Fast case: if we are calling object_new, we normally doesn't look at the arguments at all.
// Fast case: if we are calling object_new, we normally doesn't look at the arguments at all.
// (Except in the case when init_attr != object_init, in which case object_new looks at the number
// (Except in the case when init_attr != object_init, in which case object_new looks at the number
// of arguments and throws an exception.)
// of arguments and throws an exception.)
...
@@ -4660,7 +4640,7 @@ Box* typeCallInternal(BoxedFunctionBase* f, CallRewriteArgs* rewrite_args, ArgPa
...
@@ -4660,7 +4640,7 @@ Box* typeCallInternal(BoxedFunctionBase* f, CallRewriteArgs* rewrite_args, ArgPa
}
}
}
}
if
(
init_attr
&&
init_attr
!=
object
_init
)
{
if
(
init_attr
&&
made
->
cls
->
tp_init
!=
object_cls
->
tp
_init
)
{
// TODO apply the same descriptor special-casing as in callattr?
// TODO apply the same descriptor special-casing as in callattr?
Box
*
initrtn
;
Box
*
initrtn
;
...
@@ -4722,8 +4702,10 @@ Box* typeCallInternal(BoxedFunctionBase* f, CallRewriteArgs* rewrite_args, ArgPa
...
@@ -4722,8 +4702,10 @@ Box* typeCallInternal(BoxedFunctionBase* f, CallRewriteArgs* rewrite_args, ArgPa
Box
*
typeCall
(
Box
*
obj
,
BoxedTuple
*
vararg
,
BoxedDict
*
kwargs
)
{
Box
*
typeCall
(
Box
*
obj
,
BoxedTuple
*
vararg
,
BoxedDict
*
kwargs
)
{
assert
(
vararg
->
cls
==
tuple_cls
);
assert
(
vararg
->
cls
==
tuple_cls
);
bool
pass_kwargs
=
(
kwargs
&&
kwargs
->
d
.
size
());
int
n
=
vararg
->
size
();
int
n
=
vararg
->
size
();
int
args_to_pass
=
n
+
2
;
// 1 for obj, 1 for kwargs
int
args_to_pass
=
n
+
1
+
(
pass_kwargs
?
1
:
0
)
;
// 1 for obj, 1 for kwargs
Box
**
args
=
NULL
;
Box
**
args
=
NULL
;
if
(
args_to_pass
>
3
)
if
(
args_to_pass
>
3
)
...
@@ -4734,9 +4716,11 @@ Box* typeCall(Box* obj, BoxedTuple* vararg, BoxedDict* kwargs) {
...
@@ -4734,9 +4716,11 @@ Box* typeCall(Box* obj, BoxedTuple* vararg, BoxedDict* kwargs) {
for
(
int
i
=
0
;
i
<
n
;
i
++
)
{
for
(
int
i
=
0
;
i
<
n
;
i
++
)
{
getArg
(
i
+
1
,
arg1
,
arg2
,
arg3
,
args
)
=
vararg
->
elts
[
i
];
getArg
(
i
+
1
,
arg1
,
arg2
,
arg3
,
args
)
=
vararg
->
elts
[
i
];
}
}
if
(
pass_kwargs
)
getArg
(
n
+
1
,
arg1
,
arg2
,
arg3
,
args
)
=
kwargs
;
getArg
(
n
+
1
,
arg1
,
arg2
,
arg3
,
args
)
=
kwargs
;
return
typeCallInternal
(
NULL
,
NULL
,
ArgPassSpec
(
n
+
1
,
0
,
false
,
true
),
arg1
,
arg2
,
arg3
,
args
,
NULL
);
return
typeCallInternal
(
NULL
,
NULL
,
ArgPassSpec
(
n
+
1
,
0
,
false
,
pass_kwargs
),
arg1
,
arg2
,
arg3
,
args
,
NULL
);
}
}
extern
"C"
void
delGlobal
(
Box
*
globals
,
const
std
::
string
*
name
)
{
extern
"C"
void
delGlobal
(
Box
*
globals
,
const
std
::
string
*
name
)
{
...
...
src/runtime/types.cpp
View file @
3e8f2520
...
@@ -1731,26 +1731,45 @@ Box* objectNewNoArgs(BoxedClass* cls) {
...
@@ -1731,26 +1731,45 @@ Box* objectNewNoArgs(BoxedClass* cls) {
return
new
(
cls
)
Box
();
return
new
(
cls
)
Box
();
}
}
Box
*
objectNew
(
BoxedClass
*
cls
,
BoxedTuple
*
args
,
BoxedDict
*
kwargs
)
{
static
int
excess_args
(
PyObject
*
args
,
PyObject
*
kwds
)
noexcept
{
assert
(
isSubclass
(
cls
->
cls
,
type_cls
));
return
PyTuple_GET_SIZE
(
args
)
||
(
kwds
&&
PyDict_Check
(
kwds
)
&&
PyDict_Size
(
kwds
));
assert
(
args
->
cls
==
tuple_cls
);
}
assert
(
kwargs
->
cls
==
dict_cls
);
// We use a different strategy from CPython: we let object.__new__ take extra
static
PyObject
*
object_new
(
PyTypeObject
*
type
,
PyObject
*
args
,
PyObject
*
kwds
)
noexcept
;
// arguments, but raise an error if they wouldn't be handled by the corresponding init.
// TODO switch to the CPython approach?
if
(
args
->
size
()
!=
0
||
kwargs
->
d
.
size
()
!=
0
)
{
// TODO slow (We already cache these in typeCall -- should use that here too?)
if
(
typeLookup
(
cls
,
"__new__"
,
NULL
)
!=
typeLookup
(
object_cls
,
"__new__"
,
NULL
)
||
typeLookup
(
cls
,
"__init__"
,
NULL
)
==
typeLookup
(
object_cls
,
"__init__"
,
NULL
))
raiseExcHelper
(
TypeError
,
objectNewParameterTypeErrorMsg
());
}
return
new
(
cls
)
Box
();
static
int
object_init
(
PyObject
*
self
,
PyObject
*
args
,
PyObject
*
kwds
)
noexcept
{
int
err
=
0
;
if
(
excess_args
(
args
,
kwds
))
{
PyTypeObject
*
type
=
Py_TYPE
(
self
);
if
(
type
->
tp_init
!=
object_init
&&
type
->
tp_new
!=
object_new
)
{
err
=
PyErr_WarnEx
(
PyExc_DeprecationWarning
,
"object.__init__() takes no parameters"
,
1
);
}
else
if
(
type
->
tp_init
!=
object_init
||
type
->
tp_new
==
object_new
)
{
PyErr_SetString
(
PyExc_TypeError
,
"object.__init__() takes no parameters"
);
err
=
-
1
;
}
}
return
err
;
}
}
Box
*
objectInit
(
Box
*
b
,
BoxedTuple
*
args
)
{
static
PyObject
*
object_new
(
PyTypeObject
*
type
,
PyObject
*
args
,
PyObject
*
kwds
)
noexcept
{
return
None
;
int
err
=
0
;
if
(
excess_args
(
args
,
kwds
))
{
if
(
type
->
tp_new
!=
object_new
&&
type
->
tp_init
!=
object_init
)
{
err
=
PyErr_WarnEx
(
PyExc_DeprecationWarning
,
"object() takes no parameters"
,
1
);
}
else
if
(
type
->
tp_new
!=
object_new
||
type
->
tp_init
==
object_init
)
{
PyErr_SetString
(
PyExc_TypeError
,
"object() takes no parameters"
);
err
=
-
1
;
}
}
if
(
err
<
0
)
return
NULL
;
if
(
type
->
tp_flags
&
Py_TPFLAGS_IS_ABSTRACT
)
{
// I don't know what this is or when it happens, but
// CPython does something special with it
Py_FatalError
(
"unimplemented"
);
}
return
type
->
tp_alloc
(
type
,
0
);
}
}
Box
*
objectRepr
(
Box
*
obj
)
{
Box
*
objectRepr
(
Box
*
obj
)
{
...
@@ -2430,6 +2449,8 @@ void setupRuntime() {
...
@@ -2430,6 +2449,8 @@ void setupRuntime() {
object_cls
->
tp_getattro
=
PyObject_GenericGetAttr
;
object_cls
->
tp_getattro
=
PyObject_GenericGetAttr
;
object_cls
->
tp_setattro
=
PyObject_GenericSetAttr
;
object_cls
->
tp_setattro
=
PyObject_GenericSetAttr
;
object_cls
->
tp_init
=
object_init
;
object_cls
->
tp_new
=
object_new
;
add_operators
(
object_cls
);
add_operators
(
object_cls
);
object_cls
->
finishInitialization
();
object_cls
->
finishInitialization
();
...
@@ -2494,8 +2515,6 @@ void setupRuntime() {
...
@@ -2494,8 +2515,6 @@ void setupRuntime() {
SET
=
typeFromClass
(
set_cls
);
SET
=
typeFromClass
(
set_cls
);
FROZENSET
=
typeFromClass
(
frozenset_cls
);
FROZENSET
=
typeFromClass
(
frozenset_cls
);
object_cls
->
giveAttr
(
"__new__"
,
new
BoxedFunction
(
boxRTFunction
((
void
*
)
objectNew
,
UNKNOWN
,
1
,
0
,
true
,
true
)));
object_cls
->
giveAttr
(
"__init__"
,
new
BoxedFunction
(
boxRTFunction
((
void
*
)
objectInit
,
UNKNOWN
,
1
,
0
,
true
,
false
)));
object_cls
->
giveAttr
(
"__repr__"
,
new
BoxedFunction
(
boxRTFunction
((
void
*
)
objectRepr
,
UNKNOWN
,
1
,
0
,
false
,
false
)));
object_cls
->
giveAttr
(
"__repr__"
,
new
BoxedFunction
(
boxRTFunction
((
void
*
)
objectRepr
,
UNKNOWN
,
1
,
0
,
false
,
false
)));
object_cls
->
giveAttr
(
"__str__"
,
new
BoxedFunction
(
boxRTFunction
((
void
*
)
objectStr
,
UNKNOWN
,
1
,
0
,
false
,
false
)));
object_cls
->
giveAttr
(
"__str__"
,
new
BoxedFunction
(
boxRTFunction
((
void
*
)
objectStr
,
UNKNOWN
,
1
,
0
,
false
,
false
)));
object_cls
->
giveAttr
(
"__hash__"
,
object_cls
->
giveAttr
(
"__hash__"
,
...
@@ -2548,6 +2567,8 @@ void setupRuntime() {
...
@@ -2548,6 +2567,8 @@ void setupRuntime() {
}
}
object_cls
->
giveAttr
(
"__class__"
,
new
(
pyston_getset_cls
)
BoxedGetsetDescriptor
(
objectClass
,
objectSetClass
,
NULL
));
object_cls
->
giveAttr
(
"__class__"
,
new
(
pyston_getset_cls
)
BoxedGetsetDescriptor
(
objectClass
,
objectSetClass
,
NULL
));
object_cls
->
freeze
();
object_cls
->
freeze
();
assert
(
object_cls
->
tp_init
==
object_init
);
assert
(
object_cls
->
tp_new
==
object_new
);
setupBool
();
setupBool
();
setupLong
();
setupLong
();
...
...
test/tests/class_noctor.py
View file @
3e8f2520
# should_error
# skip-if: sys.version_info < (2, 7, 4)
# - Error message changed in 2.7.4
# Regression test:
# Regression test:
# If the init function doesn't exist, shouldn't just silently ignore any args
# If the init function doesn't exist, shouldn't just silently ignore any args
# that got passed
# that got passed
...
@@ -16,5 +12,8 @@ print "This should have worked"
...
@@ -16,5 +12,8 @@ print "This should have worked"
class
D
(
object
):
class
D
(
object
):
pass
pass
d
=
D
(
1
)
try
:
print
"This should have failed"
d
=
D
(
1
)
print
"This should have failed"
except
TypeError
as
e
:
print
"expected exception"
# the message got changed in 2.7.4
test/tests/object_new_arguments.py
View file @
3e8f2520
# should_error
# skip-if: sys.version_info < (2, 7, 4)
# - Error message changed in 2.7.4
# object.__new__ doesn't complain if __init__ is overridden:
# object.__new__ doesn't complain if __init__ is overridden:
class
C1
(
object
):
class
C1
(
object
):
...
@@ -16,4 +12,12 @@ object.__new__(C1, 1)
...
@@ -16,4 +12,12 @@ object.__new__(C1, 1)
object
.
__new__
(
C1
,
a
=
1
)
object
.
__new__
(
C1
,
a
=
1
)
print
"Trying C2"
print
"Trying C2"
object
.
__new__
(
C2
,
1
)
try
:
object
.
__new__
(
C2
,
1
)
except
TypeError
as
e
:
print
"caught TypeError"
# These are some tricky cases, since they can potentially look like arguments
# are being passed, but really they are not.
type
.
__call__
(
*
[
C2
])
type
.
__call__
(
C2
,
**
{})
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