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
c8bb686f
Commit
c8bb686f
authored
Apr 07, 2015
by
Travis Hance
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
slots
parent
ea1c4746
Changes
9
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
9 changed files
with
442 additions
and
69 deletions
+442
-69
from_cpython/Include/object.h
from_cpython/Include/object.h
+1
-0
src/analysis/scoping_analysis.cpp
src/analysis/scoping_analysis.cpp
+25
-0
src/analysis/scoping_analysis.h
src/analysis/scoping_analysis.h
+3
-0
src/core/types.h
src/core/types.h
+11
-2
src/runtime/objmodel.cpp
src/runtime/objmodel.cpp
+275
-52
src/runtime/types.cpp
src/runtime/types.cpp
+30
-3
src/runtime/types.h
src/runtime/types.h
+24
-12
test/tests/python_slots_test.py
test/tests/python_slots_test.py
+68
-0
test/tests/str_subclassing_gc.py
test/tests/str_subclassing_gc.py
+5
-0
No files found.
from_cpython/Include/object.h
View file @
c8bb686f
...
...
@@ -479,6 +479,7 @@ typedef struct _heaptypeobject {
see add_operators() in typeobject.c . */
PyBufferProcs
as_buffer
;
PyObject
*
ht_name
,
*
ht_slots
;
Py_ssize_t
nslots
;
/* here are optional user slots, followed by the members. */
}
PyHeapTypeObject
;
...
...
src/analysis/scoping_analysis.cpp
View file @
c8bb686f
...
...
@@ -20,6 +20,7 @@
#include "core/common.h"
#include "core/types.h"
#include "core/util.h"
#include "runtime/types.h"
namespace
pyston
{
...
...
@@ -52,6 +53,30 @@ bool containsYield(AST* ast) {
return
visitor
.
containsYield
;
}
// TODO
// Combine this with the below? Basically the same logic with different string types...
// Also should this go in this file?
BoxedString
*
mangleNameBoxedString
(
BoxedString
*
id
,
BoxedString
*
private_name
)
{
assert
(
id
);
assert
(
private_name
);
int
len
=
id
->
s
.
size
();
if
(
len
<
2
||
id
->
s
[
0
]
!=
'_'
||
id
->
s
[
1
]
!=
'_'
)
return
id
;
if
((
id
->
s
[
len
-
2
]
==
'_'
&&
id
->
s
[
len
-
1
]
==
'_'
)
||
id
->
s
.
find
(
'.'
)
!=
llvm
::
StringRef
::
npos
)
return
id
;
const
char
*
p
=
private_name
->
s
.
data
();
while
(
*
p
==
'_'
)
{
p
++
;
len
--
;
}
if
(
*
p
==
'\0'
)
return
id
;
return
static_cast
<
BoxedString
*>
(
boxStringTwine
(
"_"
+
(
p
+
id
->
s
)));
}
static
void
mangleNameInPlace
(
InternedString
&
id
,
const
std
::
string
*
private_name
,
InternedStringPool
&
interned_strings
)
{
if
(
!
private_name
)
...
...
src/analysis/scoping_analysis.h
View file @
c8bb686f
...
...
@@ -178,6 +178,9 @@ public:
};
bool
containsYield
(
AST
*
ast
);
class
BoxedString
;
BoxedString
*
mangleNameBoxedString
(
BoxedString
*
id
,
BoxedString
*
private_name
);
}
#endif
src/core/types.h
View file @
c8bb686f
...
...
@@ -440,6 +440,7 @@ public:
// Add a no-op constructor to make sure that we don't zero-initialize cls
Box
()
{}
void
*
operator
new
(
size_t
size
,
BoxedClass
*
cls
,
size_t
nitems
)
__attribute__
((
visibility
(
"default"
)));
void
*
operator
new
(
size_t
size
,
BoxedClass
*
cls
)
__attribute__
((
visibility
(
"default"
)));
void
operator
delete
(
void
*
ptr
)
__attribute__
((
visibility
(
"default"
)))
{
abort
();
}
...
...
@@ -448,10 +449,12 @@ public:
llvm
::
iterator_range
<
BoxIterator
>
pyElements
();
size_t
getHCAttrsOffset
();
HCAttrs
*
getHCAttrsPtr
();
void
setDict
(
BoxedDict
*
d
);
BoxedDict
*
getDict
();
void
setattr
(
const
std
::
string
&
attr
,
Box
*
val
,
SetattrRewriteArgs
*
rewrite_args
);
void
giveAttr
(
const
std
::
string
&
attr
,
Box
*
val
)
{
assert
(
!
this
->
hasattr
(
attr
));
...
...
@@ -481,10 +484,15 @@ extern "C" PyObject* PystonType_GenericAlloc(BoxedClass* cls, Py_ssize_t nitems)
#define DEFAULT_CLASS(default_cls) \
void* operator new(size_t size, BoxedClass * cls) __attribute__((visibility("default"))) { \
return Box::operator new(size, cls
);
\
return Box::operator new(size, cls
, 0);
\
} \
void* operator new(size_t size) __attribute__((visibility("default"))) { \
return Box::operator new(size, default_cls); \
return Box::operator new(size, default_cls, 0); \
}
#define ALLOCATABLE_WITH_ITEMS \
void* operator new(size_t size, BoxedClass * cls, size_t nitems) __attribute__((visibility("default"))) { \
return Box::operator new(size, cls, nitems); \
}
// The restrictions on when you can use the SIMPLE (ie fast) variant are encoded as
...
...
@@ -522,6 +530,7 @@ class BoxVar : public Box {
public:
Py_ssize_t
ob_size
;
BoxVar
()
{}
BoxVar
(
Py_ssize_t
ob_size
)
:
ob_size
(
ob_size
)
{}
};
static_assert
(
offsetof
(
BoxVar
,
ob_size
)
==
offsetof
(
struct
_varobject
,
ob_size
),
""
);
...
...
src/runtime/objmodel.cpp
View file @
c8bb686f
This diff is collapsed.
Click to expand it.
src/runtime/types.cpp
View file @
c8bb686f
...
...
@@ -132,7 +132,10 @@ extern "C" PyObject* PystonType_GenericAlloc(BoxedClass* cls, Py_ssize_t nitems)
Box
*
rtn
=
static_cast
<
Box
*>
(
mem
);
PyObject_Init
(
rtn
,
cls
);
if
(
cls
->
tp_itemsize
!=
0
)
static_cast
<
BoxVar
*>
(
rtn
)
->
ob_size
=
nitems
+
1
;
PyObject_INIT
(
rtn
,
cls
);
assert
(
rtn
->
cls
);
return
rtn
;
...
...
@@ -175,16 +178,20 @@ extern "C" PyObject* _PyObject_New(PyTypeObject* tp) noexcept {
}
// Analogue of PyType_GenericNew
void
*
Box
::
operator
new
(
size_t
size
,
BoxedClass
*
cls
)
{
void
*
Box
::
operator
new
(
size_t
size
,
BoxedClass
*
cls
,
size_t
nitems
)
{
assert
(
cls
);
ASSERT
(
cls
->
tp_basicsize
>=
size
,
"%s"
,
cls
->
tp_name
);
assert
(
cls
->
tp_alloc
);
void
*
mem
=
cls
->
tp_alloc
(
cls
,
0
);
void
*
mem
=
cls
->
tp_alloc
(
cls
,
nitems
);
RELEASE_ASSERT
(
mem
,
""
);
return
mem
;
}
void
*
Box
::
operator
new
(
size_t
size
,
BoxedClass
*
cls
)
{
return
Box
::
operator
new
(
size
,
cls
,
0
);
}
Box
*
BoxedClass
::
callHasnextIC
(
Box
*
obj
,
bool
null_on_nonexistent
)
{
assert
(
obj
->
cls
==
this
);
...
...
@@ -448,6 +455,14 @@ extern "C" void boxGCHandler(GCVisitor* v, Box* b) {
if
(
b
->
cls
->
instancesHaveDictAttrs
())
{
RELEASE_ASSERT
(
0
,
"Shouldn't all of these objects be conservatively scanned?"
);
}
if
(
b
->
cls
->
tp_flags
&
Py_TPFLAGS_HEAPTYPE
)
{
BoxedHeapClass
*
heap_cls
=
static_cast
<
BoxedHeapClass
*>
(
b
->
cls
);
BoxedHeapClass
::
SlotOffset
*
slotOffsets
=
heap_cls
->
slotOffsets
();
for
(
int
i
=
0
;
i
<
heap_cls
->
nslots
;
i
++
)
{
v
->
visit
(
*
((
Box
**
)((
char
*
)
b
+
slotOffsets
[
i
])));
}
}
}
else
{
assert
(
type_cls
==
NULL
||
b
==
type_cls
);
}
...
...
@@ -1958,6 +1973,17 @@ extern "C" PyObject* PyObject_Init(PyObject* op, PyTypeObject* tp) noexcept {
// initUserAttrs themselves, though.
initUserAttrs
(
op
,
tp
);
// Initialize the variables declared in __slots__ to NULL.
if
(
tp
->
tp_flags
&
Py_TPFLAGS_HEAPTYPE
)
{
BoxedHeapClass
*
heap_cls
=
static_cast
<
BoxedHeapClass
*>
(
tp
);
if
(
heap_cls
->
nslots
>
0
)
{
BoxedHeapClass
::
SlotOffset
*
slotOffsets
=
heap_cls
->
slotOffsets
();
for
(
int
i
=
0
;
i
<
heap_cls
->
nslots
;
i
++
)
{
*
(
Box
**
)((
char
*
)
op
+
slotOffsets
[
i
])
=
NULL
;
}
}
}
return
op
;
}
...
...
@@ -1987,6 +2013,7 @@ void setupRuntime() {
type_cls
=
::
new
(
mem
)
BoxedHeapClass
(
object_cls
,
&
typeGCHandler
,
offsetof
(
BoxedClass
,
attrs
),
offsetof
(
BoxedClass
,
tp_weaklist
),
sizeof
(
BoxedHeapClass
),
false
,
NULL
);
type_cls
->
tp_flags
|=
Py_TPFLAGS_TYPE_SUBCLASS
;
type_cls
->
tp_itemsize
=
sizeof
(
BoxedHeapClass
::
SlotOffset
);
PyObject_Init
(
object_cls
,
type_cls
);
PyObject_Init
(
type_cls
,
type_cls
);
...
...
src/runtime/types.h
View file @
c8bb686f
...
...
@@ -177,7 +177,10 @@ public:
void
(
*
simple_destructor
)(
Box
*
);
// Offset of the HCAttrs object or 0 if there are no hcattrs.
// Negative offset is from the end of the class (useful for variable-size objects with the attrs at the end)
// Analogous to tp_dictoffset
// A class should have at most of one attrs_offset and tp_dictoffset be nonzero.
// (But having nonzero attrs_offset here would map to having nonzero tp_dictoffset in CPython)
const
int
attrs_offset
;
bool
instancesHaveHCAttrs
()
{
return
attrs_offset
!=
0
;
}
...
...
@@ -231,12 +234,16 @@ public:
PyBufferProcs
as_buffer
;
BoxedString
*
ht_name
;
PyObject
**
ht_slots
;
PyObject
*
ht_slots
;
size_t
nslots
;
typedef
size_t
SlotOffset
;
SlotOffset
*
slotOffsets
()
{
return
(
BoxedHeapClass
::
SlotOffset
*
)((
char
*
)
this
+
this
->
cls
->
tp_basicsize
);
}
// These functions are the preferred way to construct new types:
static
BoxedHeapClass
*
create
(
BoxedClass
*
metatype
,
BoxedClass
*
base
,
gcvisit_func
gc_visit
,
int
attrs_offset
,
int
weaklist_offset
,
int
instance_size
,
bool
is_user_defined
,
BoxedString
*
name
,
BoxedTuple
*
bases
);
BoxedTuple
*
bases
,
size_t
nslots
);
static
BoxedHeapClass
*
create
(
BoxedClass
*
metatype
,
BoxedClass
*
base
,
gcvisit_func
gc_visit
,
int
attrs_offset
,
int
weaklist_offset
,
int
instance_size
,
bool
is_user_defined
,
const
std
::
string
&
name
);
...
...
@@ -246,12 +253,13 @@ private:
// by BoxedHeapClass::create(), but setupRuntime() also needs to do some manual class
// creation due to bootstrapping issues.
BoxedHeapClass
(
BoxedClass
*
base
,
gcvisit_func
gc_visit
,
int
attrs_offset
,
int
weaklist_offset
,
int
instance_size
,
bool
is_user_defined
,
BoxedString
*
name
);
bool
is_user_defined
,
BoxedString
*
name
,
size_t
nslots
=
0
);
friend
void
setupRuntime
();
friend
void
setupSys
();
DEFAULT_CLASS
(
type_cls
);
ALLOCATABLE_WITH_ITEMS
;
};
static_assert
(
sizeof
(
pyston
::
Box
)
==
sizeof
(
struct
_object
),
""
);
...
...
@@ -402,7 +410,7 @@ public:
DEFAULT_CLASS_SIMPLE
(
bool_cls
);
};
class
BoxedString
:
public
Box
{
class
BoxedString
:
public
Box
Var
{
public:
llvm
::
StringRef
s
;
...
...
@@ -410,13 +418,15 @@ public:
size_t
size
()
{
return
s
.
size
();
}
void
*
operator
new
(
size_t
size
,
size_t
ssize
)
__attribute__
((
visibility
(
"default"
)))
{
Box
*
rtn
=
static_cast
<
Box
*>
(
gc_alloc
(
str_cls
->
tp_basicsize
+
ssize
+
1
,
gc
::
GCKind
::
PYTHON
));
BoxVar
*
rtn
=
static_cast
<
BoxVar
*>
(
gc_alloc
(
str_cls
->
tp_basicsize
+
ssize
+
1
,
gc
::
GCKind
::
PYTHON
));
// TODO need to initialize ob_size for other objects as well
rtn
->
ob_size
=
ssize
+
1
;
rtn
->
cls
=
str_cls
;
return
rtn
;
}
void
*
operator
new
(
size_t
size
,
BoxedClass
*
cls
,
size_t
ssize
)
__attribute__
((
visibility
(
"default"
)))
{
Box
*
rtn
=
static_cast
<
Box
*>
(
cls
->
tp_alloc
(
cls
,
ssize
+
1
));
Box
Var
*
rtn
=
static_cast
<
BoxVar
*>
(
cls
->
tp_alloc
(
cls
,
ssize
+
1
));
rtn
->
cls
=
cls
;
return
rtn
;
}
...
...
@@ -429,7 +439,7 @@ public:
private:
// used only in ctors to give our llvm::StringRef the proper pointer
char
*
storage
()
{
return
(
char
*
)
this
+
cls
->
tp_basicsize
;
}
char
*
storage
()
{
return
(
char
*
)
this
+
sizeof
(
BoxedString
)
;
}
void
*
operator
new
(
size_t
size
)
=
delete
;
};
...
...
@@ -514,20 +524,21 @@ public:
DEFAULT_CLASS_SIMPLE
(
list_cls
);
};
class
BoxedTuple
:
public
Box
{
class
BoxedTuple
:
public
Box
Var
{
public:
typedef
std
::
vector
<
Box
*
,
StlCompatAllocator
<
Box
*>>
GCVector
;
Box
**
elts
;
void
*
operator
new
(
size_t
size
,
size_t
nelts
)
__attribute__
((
visibility
(
"default"
)))
{
Box
*
rtn
=
static_cast
<
Box
*>
(
gc_alloc
(
_PyObject_VAR_SIZE
(
tuple_cls
,
nelts
+
1
),
gc
::
GCKind
::
PYTHON
));
BoxVar
*
rtn
=
static_cast
<
BoxVar
*>
(
gc_alloc
(
_PyObject_VAR_SIZE
(
tuple_cls
,
nelts
+
1
),
gc
::
GCKind
::
PYTHON
));
rtn
->
ob_size
=
nelts
;
rtn
->
cls
=
tuple_cls
;
return
rtn
;
}
void
*
operator
new
(
size_t
size
,
BoxedClass
*
cls
,
size_t
nelts
)
__attribute__
((
visibility
(
"default"
)))
{
Box
*
rtn
=
static_cast
<
Box
*>
(
cls
->
tp_alloc
(
cls
,
nelts
));
Box
Var
*
rtn
=
static_cast
<
BoxVar
*>
(
cls
->
tp_alloc
(
cls
,
nelts
));
rtn
->
cls
=
cls
;
return
rtn
;
}
...
...
@@ -572,18 +583,19 @@ public:
Box
**
begin
()
const
{
return
&
elts
[
0
];
}
Box
**
end
()
const
{
return
&
elts
[
nelts
];
}
Box
*&
operator
[](
size_t
index
)
{
return
elts
[
index
];
}
size_t
size
()
const
{
return
nelts
;
}
private:
size_t
nelts
;
BoxedTuple
(
size_t
size
)
:
elts
(
reinterpret_cast
<
Box
**>
((
char
*
)
this
+
t
his
->
cls
->
tp_basicsize
)),
nelts
(
size
)
{
BoxedTuple
(
size_t
size
)
:
elts
(
reinterpret_cast
<
Box
**>
((
char
*
)
this
+
t
uple_
cls
->
tp_basicsize
)),
nelts
(
size
)
{
memset
(
elts
,
0
,
sizeof
(
Box
*
)
*
size
);
}
BoxedTuple
(
std
::
initializer_list
<
Box
*>&
members
)
:
elts
(
reinterpret_cast
<
Box
**>
((
char
*
)
this
+
t
his
->
cls
->
tp_basicsize
)),
nelts
(
members
.
size
())
{
:
elts
(
reinterpret_cast
<
Box
**>
((
char
*
)
this
+
t
uple_
cls
->
tp_basicsize
)),
nelts
(
members
.
size
())
{
// by the time we make it here elts[] is big enough to contain members
Box
**
p
=
&
elts
[
0
];
for
(
auto
b
:
members
)
{
...
...
test/tests/python_slots_test.py
0 → 100644
View file @
c8bb686f
print
'basic test'
class
C
(
object
):
__slots__
=
[
'a'
,
'b'
,
'__private_var'
]
c
=
C
()
try
:
print
c
.
a
except
AttributeError
as
e
:
print
e
.
message
c
.
a
=
5
print
c
.
a
print
c
.
__slots__
c
.
_C__private_var
=
6
print
c
.
_C__private_var
try
:
c
.
x
=
12
except
AttributeError
as
e
:
print
e
.
message
print
'testing __dict__'
class
C
(
object
):
__slots__
=
[
'd'
,
'e'
,
'__dict__'
]
c
=
C
()
c
.
d
=
5
print
c
.
d
c
.
r
=
6
print
c
.
r
print
c
.
__dict__
.
items
()
# dict should contain only r (not d)
print
'testing inheritance'
class
C
(
object
):
__slots__
=
[
'a'
,
'b'
]
class
D
(
object
):
__slots__
=
[
'c'
,
'd'
]
class
E
(
object
):
pass
class
G
(
C
):
__slots__
=
[
'k'
,
'l'
]
g
=
G
()
g
.
a
=
5
print
g
.
a
g
.
k
=
12
print
g
.
k
class
G
(
C
,
E
):
__slots__
=
[
'k'
,
'l'
]
g
=
G
()
g
.
a
=
5
print
g
.
a
g
.
k
=
12
print
g
.
k
class
G
(
E
,
C
):
__slots__
=
[
'k'
,
'l'
]
g
=
G
()
g
.
a
=
5
print
g
.
a
g
.
k
=
12
print
g
.
k
try
:
class
G
(
C
,
D
):
pass
except
TypeError
as
e
:
print
e
.
message
test/tests/str_subclassing_gc.py
View file @
c8bb686f
...
...
@@ -8,3 +8,8 @@ def f():
for
i
in
xrange
(
100
):
s
=
S
(
base
)
f
()
# make sure it has attrs
s
=
S
(
"blah"
)
s
.
blah
=
2
print
s
.
blah
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