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
e6893159
Commit
e6893159
authored
Jul 22, 2015
by
Chris Toshok
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #536 from rudi-c/setslice
Handle the extensive edge cases related to sequence slicing
parents
6add43fe
09df9da7
Changes
8
Hide whitespace changes
Inline
Side-by-side
Showing
8 changed files
with
452 additions
and
93 deletions
+452
-93
src/codegen/patchpoints.cpp
src/codegen/patchpoints.cpp
+2
-2
src/runtime/list.cpp
src/runtime/list.cpp
+72
-66
src/runtime/objmodel.cpp
src/runtime/objmodel.cpp
+121
-20
src/runtime/str.cpp
src/runtime/str.cpp
+14
-0
src/runtime/util.cpp
src/runtime/util.cpp
+47
-1
src/runtime/util.h
src/runtime/util.h
+21
-0
test/extra/protobuf_test.py
test/extra/protobuf_test.py
+4
-4
test/tests/slice.py
test/tests/slice.py
+171
-0
No files found.
src/codegen/patchpoints.cpp
View file @
e6893159
...
...
@@ -302,11 +302,11 @@ ICSetupInfo* createGetitemIC(TypeRecorder* type_recorder) {
}
ICSetupInfo
*
createSetitemIC
(
TypeRecorder
*
type_recorder
)
{
return
ICSetupInfo
::
initialize
(
true
,
1
,
256
,
ICSetupInfo
::
Setitem
,
type_recorder
);
return
ICSetupInfo
::
initialize
(
true
,
1
,
512
,
ICSetupInfo
::
Setitem
,
type_recorder
);
}
ICSetupInfo
*
createDelitemIC
(
TypeRecorder
*
type_recorder
)
{
return
ICSetupInfo
::
initialize
(
false
,
1
,
256
,
ICSetupInfo
::
Delitem
,
type_recorder
);
return
ICSetupInfo
::
initialize
(
false
,
1
,
512
,
ICSetupInfo
::
Delitem
,
type_recorder
);
}
ICSetupInfo
*
createSetattrIC
(
TypeRecorder
*
type_recorder
)
{
...
...
src/runtime/list.cpp
View file @
e6893159
...
...
@@ -134,7 +134,6 @@ static Py_ssize_t list_length(Box* self) noexcept {
}
Box
*
_listSlice
(
BoxedList
*
self
,
i64
start
,
i64
stop
,
i64
step
,
i64
length
)
{
// printf("%ld %ld %ld\n", start, stop, step);
assert
(
step
!=
0
);
if
(
step
>
0
)
{
assert
(
0
<=
start
);
...
...
@@ -220,6 +219,16 @@ extern "C" Box* listGetitemSlice(BoxedList* self, BoxedSlice* slice) {
return
_listSlice
(
self
,
start
,
stop
,
step
,
length
);
}
extern
"C"
Box
*
listGetslice
(
BoxedList
*
self
,
Box
*
boxedStart
,
Box
*
boxedStop
)
{
assert
(
isSubclass
(
self
->
cls
,
list_cls
));
i64
start
,
stop
,
step
;
sliceIndex
(
boxedStart
,
&
start
);
sliceIndex
(
boxedStop
,
&
stop
);
boundSliceWithLength
(
&
start
,
&
stop
,
start
,
stop
,
self
->
size
);
return
_listSlice
(
self
,
start
,
stop
,
1
,
stop
-
start
);
}
extern
"C"
Box
*
listGetitem
(
BoxedList
*
self
,
Box
*
slice
)
{
assert
(
isSubclass
(
self
->
cls
,
list_cls
));
if
(
PyIndex_Check
(
slice
))
{
...
...
@@ -278,15 +287,6 @@ extern "C" int PyList_SetItem(PyObject* op, Py_ssize_t i, PyObject* newitem) noe
Box
*
listIAdd
(
BoxedList
*
self
,
Box
*
_rhs
);
// Analogue of _PyEval_SliceIndex
static
void
sliceIndex
(
Box
*
b
,
int64_t
*
out
)
{
if
(
b
->
cls
==
none_cls
)
return
;
RELEASE_ASSERT
(
b
->
cls
==
int_cls
,
""
);
*
out
=
static_cast
<
BoxedInt
*>
(
b
)
->
n
;
}
// Copied from CPython's list_ass_subscript
int
list_ass_ext_slice
(
BoxedList
*
self
,
PyObject
*
item
,
PyObject
*
value
)
{
Py_ssize_t
start
,
stop
,
step
,
slicelength
;
...
...
@@ -296,8 +296,6 @@ int list_ass_ext_slice(BoxedList* self, PyObject* item, PyObject* value) {
}
RELEASE_ASSERT
(
step
!=
1
,
"should have handled this elsewhere"
);
// if (step == 1)
// return list_ass_slice(self, start, stop, value);
/* Make sure s[5:2] = [..] inserts at the right place:
before 5, not before 2. */
...
...
@@ -419,45 +417,10 @@ int list_ass_ext_slice(BoxedList* self, PyObject* item, PyObject* value) {
}
}
extern
"C"
Box
*
listSetitemSlice
(
BoxedList
*
self
,
BoxedSlice
*
slice
,
Box
*
v
)
{
assert
(
isSubclass
(
self
->
cls
,
list_cls
));
assert
(
slice
->
cls
==
slice_cls
);
i64
start
=
0
,
stop
=
self
->
size
,
step
=
1
;
sliceIndex
(
slice
->
start
,
&
start
);
sliceIndex
(
slice
->
stop
,
&
stop
);
sliceIndex
(
slice
->
step
,
&
step
);
if
(
self
==
v
)
// handle self assignment by creating a copy
v
=
_listSlice
(
self
,
0
,
self
->
size
,
1
,
self
->
size
);
if
(
step
!=
1
)
{
int
r
=
list_ass_ext_slice
(
self
,
slice
,
v
);
if
(
r
)
throwCAPIException
();
return
None
;
}
RELEASE_ASSERT
(
step
==
1
,
"step sizes must be 1 for now"
);
// Logic from PySequence_GetSlice:
if
(
start
<
0
)
start
+=
self
->
size
;
if
(
stop
<
0
)
stop
+=
self
->
size
;
// Logic from list_ass_slice:
if
(
start
<
0
)
start
=
0
;
else
if
(
start
>
self
->
size
)
start
=
self
->
size
;
Box
*
listSetitemSliceInt64
(
BoxedList
*
self
,
i64
start
,
i64
stop
,
i64
step
,
Box
*
v
)
{
RELEASE_ASSERT
(
step
==
1
,
"step sizes must be 1 in this code path"
);
if
(
stop
<
start
)
stop
=
start
;
else
if
(
stop
>
self
->
size
)
stop
=
self
->
size
;
assert
(
0
<=
start
&&
start
<=
stop
&&
stop
<=
self
->
size
);
boundSliceWithLength
(
&
start
,
&
stop
,
start
,
stop
,
self
->
size
);
size_t
v_size
;
Box
**
v_elts
;
...
...
@@ -479,9 +442,8 @@ extern "C" Box* listSetitemSlice(BoxedList* self, BoxedSlice* slice, Box* v) {
v_elts
=
NULL
;
}
// If self->size is 0, self->elts->elts is garbage
RELEASE_ASSERT
(
self
->
size
==
0
||
!
v_elts
||
self
->
elts
->
elts
!=
v_elts
,
"Slice self-assignment currently unsupported"
);
if
(
self
==
v
)
// handle self assignment by creating a copy
v
=
_listSlice
(
self
,
0
,
self
->
size
,
1
,
self
->
size
);
int
delts
=
v_size
-
(
stop
-
start
);
int
remaining_elts
=
self
->
size
-
stop
;
...
...
@@ -498,6 +460,39 @@ extern "C" Box* listSetitemSlice(BoxedList* self, BoxedSlice* slice, Box* v) {
return
None
;
}
extern
"C"
Box
*
listSetitemSlice
(
BoxedList
*
self
,
BoxedSlice
*
slice
,
Box
*
v
)
{
assert
(
isSubclass
(
self
->
cls
,
list_cls
));
assert
(
slice
->
cls
==
slice_cls
);
i64
start
=
0
,
stop
=
self
->
size
,
step
=
1
;
sliceIndex
(
slice
->
start
,
&
start
);
sliceIndex
(
slice
->
stop
,
&
stop
);
sliceIndex
(
slice
->
step
,
&
step
);
adjustNegativeIndicesOnObject
(
self
,
&
start
,
&
stop
);
if
(
step
!=
1
)
{
int
r
=
list_ass_ext_slice
(
self
,
slice
,
v
);
if
(
r
)
throwCAPIException
();
return
None
;
}
return
listSetitemSliceInt64
(
self
,
start
,
stop
,
step
,
v
);
}
extern
"C"
Box
*
listSetslice
(
BoxedList
*
self
,
Box
*
boxedStart
,
Box
*
boxedStop
,
Box
**
args
)
{
Box
*
value
=
args
[
0
];
i64
start
=
0
,
stop
=
self
->
size
;
sliceIndex
(
boxedStart
,
&
start
);
sliceIndex
(
boxedStop
,
&
stop
);
return
listSetitemSliceInt64
(
self
,
start
,
stop
,
1
,
value
);
}
extern
"C"
Box
*
listSetitem
(
BoxedList
*
self
,
Box
*
slice
,
Box
*
v
)
{
assert
(
isSubclass
(
self
->
cls
,
list_cls
));
if
(
PyIndex_Check
(
slice
))
{
...
...
@@ -530,6 +525,11 @@ extern "C" Box* listDelitemSlice(BoxedList* self, BoxedSlice* slice) {
return
listSetitemSlice
(
self
,
slice
,
NULL
);
}
extern
"C"
Box
*
listDelslice
(
BoxedList
*
self
,
Box
*
start
,
Box
*
stop
)
{
Box
*
args
=
{
NULL
};
return
listSetslice
(
self
,
start
,
stop
,
&
args
);
}
extern
"C"
Box
*
listDelitem
(
BoxedList
*
self
,
Box
*
slice
)
{
Box
*
rtn
;
if
(
PyIndex_Check
(
slice
))
{
...
...
@@ -1077,12 +1077,30 @@ void setupList() {
list_cls
->
giveAttr
(
"__len__"
,
new
BoxedFunction
(
boxRTFunction
((
void
*
)
listLen
,
BOXED_INT
,
1
)));
CLFunction
*
getitem
=
createRTFunction
(
2
,
0
,
0
,
0
);
CLFunction
*
getitem
=
createRTFunction
(
2
,
0
,
false
,
false
);
addRTFunction
(
getitem
,
(
void
*
)
listGetitemInt
,
UNKNOWN
,
std
::
vector
<
ConcreteCompilerType
*>
{
LIST
,
BOXED_INT
});
addRTFunction
(
getitem
,
(
void
*
)
listGetitemSlice
,
LIST
,
std
::
vector
<
ConcreteCompilerType
*>
{
LIST
,
SLICE
});
addRTFunction
(
getitem
,
(
void
*
)
listGetitem
,
UNKNOWN
,
std
::
vector
<
ConcreteCompilerType
*>
{
UNKNOWN
,
UNKNOWN
});
list_cls
->
giveAttr
(
"__getitem__"
,
new
BoxedFunction
(
getitem
));
list_cls
->
giveAttr
(
"__getslice__"
,
new
BoxedFunction
(
boxRTFunction
((
void
*
)
listGetslice
,
LIST
,
3
)));
CLFunction
*
setitem
=
createRTFunction
(
3
,
0
,
false
,
false
);
addRTFunction
(
setitem
,
(
void
*
)
listSetitemInt
,
NONE
,
std
::
vector
<
ConcreteCompilerType
*>
{
LIST
,
BOXED_INT
,
UNKNOWN
});
addRTFunction
(
setitem
,
(
void
*
)
listSetitemSlice
,
NONE
,
std
::
vector
<
ConcreteCompilerType
*>
{
LIST
,
SLICE
,
UNKNOWN
});
addRTFunction
(
setitem
,
(
void
*
)
listSetitem
,
NONE
,
std
::
vector
<
ConcreteCompilerType
*>
{
UNKNOWN
,
UNKNOWN
,
UNKNOWN
});
list_cls
->
giveAttr
(
"__setitem__"
,
new
BoxedFunction
(
setitem
));
list_cls
->
giveAttr
(
"__setslice__"
,
new
BoxedFunction
(
boxRTFunction
((
void
*
)
listSetslice
,
NONE
,
4
)));
CLFunction
*
delitem
=
createRTFunction
(
2
,
0
,
false
,
false
);
addRTFunction
(
delitem
,
(
void
*
)
listDelitemInt
,
NONE
,
std
::
vector
<
ConcreteCompilerType
*>
{
LIST
,
BOXED_INT
});
addRTFunction
(
delitem
,
(
void
*
)
listDelitemSlice
,
NONE
,
std
::
vector
<
ConcreteCompilerType
*>
{
LIST
,
SLICE
});
addRTFunction
(
delitem
,
(
void
*
)
listDelitem
,
NONE
,
std
::
vector
<
ConcreteCompilerType
*>
{
UNKNOWN
,
UNKNOWN
});
list_cls
->
giveAttr
(
"__delitem__"
,
new
BoxedFunction
(
delitem
));
list_cls
->
giveAttr
(
"__delslice__"
,
new
BoxedFunction
(
boxRTFunction
((
void
*
)
listDelslice
,
NONE
,
3
)));
list_cls
->
giveAttr
(
"__iter__"
,
new
BoxedFunction
(
boxRTFunction
((
void
*
)
listIter
,
typeFromClass
(
list_iterator_cls
),
1
)));
...
...
@@ -1104,18 +1122,6 @@ void setupList() {
list_cls
->
giveAttr
(
"append"
,
new
BoxedFunction
(
boxRTFunction
((
void
*
)
listAppend
,
NONE
,
2
)));
list_cls
->
giveAttr
(
"extend"
,
new
BoxedFunction
(
boxRTFunction
((
void
*
)
listIAdd
,
UNKNOWN
,
2
)));
CLFunction
*
setitem
=
createRTFunction
(
3
,
0
,
false
,
false
);
addRTFunction
(
setitem
,
(
void
*
)
listSetitemInt
,
NONE
,
std
::
vector
<
ConcreteCompilerType
*>
{
LIST
,
BOXED_INT
,
UNKNOWN
});
addRTFunction
(
setitem
,
(
void
*
)
listSetitemSlice
,
NONE
,
std
::
vector
<
ConcreteCompilerType
*>
{
LIST
,
SLICE
,
UNKNOWN
});
addRTFunction
(
setitem
,
(
void
*
)
listSetitem
,
NONE
,
std
::
vector
<
ConcreteCompilerType
*>
{
UNKNOWN
,
UNKNOWN
,
UNKNOWN
});
list_cls
->
giveAttr
(
"__setitem__"
,
new
BoxedFunction
(
setitem
));
CLFunction
*
delitem
=
createRTFunction
(
2
,
0
,
false
,
false
);
addRTFunction
(
delitem
,
(
void
*
)
listDelitemInt
,
NONE
,
std
::
vector
<
ConcreteCompilerType
*>
{
LIST
,
BOXED_INT
});
addRTFunction
(
delitem
,
(
void
*
)
listDelitemSlice
,
NONE
,
std
::
vector
<
ConcreteCompilerType
*>
{
LIST
,
SLICE
});
addRTFunction
(
delitem
,
(
void
*
)
listDelitem
,
NONE
,
std
::
vector
<
ConcreteCompilerType
*>
{
UNKNOWN
,
UNKNOWN
});
list_cls
->
giveAttr
(
"__delitem__"
,
new
BoxedFunction
(
delitem
));
list_cls
->
giveAttr
(
"insert"
,
new
BoxedFunction
(
boxRTFunction
((
void
*
)
listInsert
,
NONE
,
3
)));
list_cls
->
giveAttr
(
"__mul__"
,
new
BoxedFunction
(
boxRTFunction
((
void
*
)
listMul
,
LIST
,
2
)));
list_cls
->
giveAttr
(
"__rmul__"
,
new
BoxedFunction
(
boxRTFunction
((
void
*
)
listMul
,
LIST
,
2
)));
...
...
src/runtime/objmodel.cpp
View file @
e6893159
...
...
@@ -2396,7 +2396,8 @@ extern "C" bool nonzero(Box* obj) {
||
isSubclass
(
obj
->
cls
,
Exception
)
||
obj
->
cls
==
file_cls
||
obj
->
cls
==
traceback_cls
||
obj
->
cls
==
instancemethod_cls
||
obj
->
cls
==
module_cls
||
obj
->
cls
==
capifunc_cls
||
obj
->
cls
==
builtin_function_or_method_cls
||
obj
->
cls
==
method_cls
||
obj
->
cls
==
frame_cls
||
obj
->
cls
==
capi_getset_cls
||
obj
->
cls
==
pyston_getset_cls
||
obj
->
cls
==
wrapperdescr_cls
,
||
obj
->
cls
==
generator_cls
||
obj
->
cls
==
capi_getset_cls
||
obj
->
cls
==
pyston_getset_cls
||
obj
->
cls
==
wrapperdescr_cls
,
"%s.__nonzero__"
,
getTypeName
(
obj
));
// TODO
// TODO should rewrite these?
...
...
@@ -4426,7 +4427,105 @@ extern "C" Box* unaryop(Box* operand, int op_type) {
return
rtn
;
}
extern
"C"
Box
*
getitem
(
Box
*
value
,
Box
*
slice
)
{
Box
*
callItemAttr
(
Box
*
target
,
BoxedString
*
item_str
,
Box
*
item
,
Box
*
value
,
CallRewriteArgs
*
rewrite_args
)
{
if
(
value
)
{
return
callattrInternal2
(
target
,
item_str
,
CLASS_ONLY
,
rewrite_args
,
ArgPassSpec
(
2
),
item
,
value
);
}
else
{
return
callattrInternal1
(
target
,
item_str
,
CLASS_ONLY
,
rewrite_args
,
ArgPassSpec
(
1
),
item
);
}
}
// This function decides whether to call the slice operator (e.g. __getslice__)
// or the item operator (__getitem__).
Box
*
callItemOrSliceAttr
(
Box
*
target
,
BoxedString
*
item_str
,
BoxedString
*
slice_str
,
Box
*
slice
,
Box
*
value
,
CallRewriteArgs
*
rewrite_args
)
{
// This function contains a lot of logic for deciding between whether to call
// the slice operator or the item operator, so we can match CPython's behavior
// on custom classes that define those operators. However, for builtin types,
// we know we can call either and the behavior will be the same. Adding all those
// guards are unnecessary and bad for performance.
//
// Also, for special slicing logic (e.g. open slice ranges [:]), the builtin types
// have C-implemented functions that already handle all the edge cases, so we don't
// need to have a slowpath for them here.
if
(
target
->
cls
==
list_cls
||
target
->
cls
==
str_cls
||
target
->
cls
==
unicode_cls
)
{
if
(
rewrite_args
)
{
rewrite_args
->
obj
->
addAttrGuard
(
offsetof
(
Box
,
cls
),
(
uint64_t
)
target
->
cls
);
}
return
callItemAttr
(
target
,
item_str
,
slice
,
value
,
rewrite_args
);
}
// Guard on the type of the object (need to have the slice operator attribute to call it).
Box
*
slice_attr
=
NULL
;
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
);
if
(
!
grewrite_args
.
out_success
)
{
rewrite_args
=
NULL
;
}
}
else
{
slice_attr
=
typeLookup
(
target
->
cls
,
slice_str
,
NULL
);
}
if
(
!
slice_attr
)
{
return
callItemAttr
(
target
,
item_str
,
slice
,
value
,
rewrite_args
);
}
// Need a slice object to use the slice operators.
if
(
rewrite_args
)
{
rewrite_args
->
arg1
->
addAttrGuard
(
offsetof
(
Box
,
cls
),
(
uint64_t
)
slice
->
cls
);
}
if
(
slice
->
cls
!=
slice_cls
)
{
return
callItemAttr
(
target
,
item_str
,
slice
,
value
,
rewrite_args
);
}
BoxedSlice
*
bslice
=
(
BoxedSlice
*
)
slice
;
// If we use slice notation with a step parameter (e.g. o[1:10:2]), the slice operator
// functions don't support that, so fallback to the item operator functions.
if
(
bslice
->
step
->
cls
!=
none_cls
)
{
if
(
rewrite_args
)
{
rewrite_args
->
arg1
->
getAttr
(
offsetof
(
BoxedSlice
,
step
))
->
addAttrGuard
(
offsetof
(
Box
,
cls
),
(
uint64_t
)
none_cls
,
/*negate=*/
true
);
}
return
callItemAttr
(
target
,
item_str
,
slice
,
value
,
rewrite_args
);
}
else
{
rewrite_args
=
NULL
;
REWRITE_ABORTED
(
""
);
// If the slice cannot be used as integer slices, also fall back to the get operator.
// We could optimize further here by having a version of isSliceIndex that
// creates guards, but it would only affect some rare edge cases.
if
(
!
isSliceIndex
(
bslice
->
start
)
||
!
isSliceIndex
(
bslice
->
stop
))
{
return
callItemAttr
(
target
,
item_str
,
slice
,
value
,
rewrite_args
);
}
// If we don't specify the start/stop (e.g. o[:]), the slice operator functions
// CPython seems to use 0 and sys.maxint as the default values.
int64_t
start
=
0
,
stop
=
PyInt_GetMax
();
sliceIndex
(
bslice
->
start
,
&
start
);
sliceIndex
(
bslice
->
stop
,
&
stop
);
adjustNegativeIndicesOnObject
(
target
,
&
start
,
&
stop
);
Box
*
boxedStart
=
boxInt
(
start
);
Box
*
boxedStop
=
boxInt
(
stop
);
if
(
value
)
{
return
callattrInternal3
(
target
,
slice_str
,
CLASS_ONLY
,
rewrite_args
,
ArgPassSpec
(
3
),
boxedStart
,
boxedStop
,
value
);
}
else
{
return
callattrInternal2
(
target
,
slice_str
,
CLASS_ONLY
,
rewrite_args
,
ArgPassSpec
(
2
),
boxedStart
,
boxedStop
);
}
}
}
// target[slice]
extern
"C"
Box
*
getitem
(
Box
*
target
,
Box
*
slice
)
{
STAT_TIMER
(
t0
,
"us_timer_slowpath_getitem"
,
10
);
// This possibly could just be represented as a single callattr; the only tricky part
...
...
@@ -4447,7 +4546,7 @@ extern "C" Box* getitem(Box* value, Box* slice) {
// For now, just use the first clause: call mp_subscript if it exists.
// And only if we think it's better than calling __getitem__, which should
// exist if mp_subscript exists.
PyMappingMethods
*
m
=
value
->
cls
->
tp_as_mapping
;
PyMappingMethods
*
m
=
target
->
cls
->
tp_as_mapping
;
if
(
m
&&
m
->
mp_subscript
&&
m
->
mp_subscript
!=
slot_mp_subscript
)
{
if
(
rewriter
.
get
())
{
RewriterVar
*
r_obj
=
rewriter
->
getArg
(
0
);
...
...
@@ -4466,38 +4565,41 @@ extern "C" Box* getitem(Box* value, Box* slice) {
rewriter
->
call
(
true
,
(
void
*
)
checkAndThrowCAPIException
);
rewriter
->
commitReturning
(
r_rtn
);
}
Box
*
r
=
m
->
mp_subscript
(
value
,
slice
);
Box
*
r
=
m
->
mp_subscript
(
target
,
slice
);
if
(
!
r
)
throwCAPIException
();
return
r
;
}
static
BoxedString
*
getitem_str
=
internStringImmortal
(
"__getitem__"
);
static
BoxedString
*
getslice_str
=
internStringImmortal
(
"__getslice__"
);
Box
*
rtn
;
if
(
rewriter
.
get
())
{
CallRewriteArgs
rewrite_args
(
rewriter
.
get
(),
rewriter
->
getArg
(
0
),
rewriter
->
getReturnDestination
());
rewrite_args
.
arg1
=
rewriter
->
getArg
(
1
);
rtn
=
call
attrInternal1
(
value
,
getitem_str
,
CLASS_ONLY
,
&
rewrite_args
,
ArgPassSpec
(
1
),
slice
);
rtn
=
call
ItemOrSliceAttr
(
target
,
getitem_str
,
getslice_str
,
slice
,
NULL
,
&
rewrite_args
);
if
(
!
rewrite_args
.
out_success
)
{
rewriter
.
reset
(
NULL
);
}
else
if
(
rtn
)
}
else
if
(
rtn
)
{
rewriter
->
commitReturning
(
rewrite_args
.
out_rtn
);
}
}
else
{
rtn
=
call
attrInternal1
(
value
,
getitem_str
,
CLASS_ONLY
,
NULL
,
ArgPassSpec
(
1
),
slice
);
rtn
=
call
ItemOrSliceAttr
(
target
,
getitem_str
,
getslice_str
,
slice
,
NULL
,
NULL
);
}
if
(
rtn
==
NULL
)
{
// different versions of python give different error messages for this:
if
(
PYTHON_VERSION_MAJOR
==
2
&&
PYTHON_VERSION_MINOR
<
7
)
{
raiseExcHelper
(
TypeError
,
"'%s' object is unsubscriptable"
,
getTypeName
(
value
));
// tested on 2.6.6
raiseExcHelper
(
TypeError
,
"'%s' object is unsubscriptable"
,
getTypeName
(
target
));
// tested on 2.6.6
}
else
if
(
PYTHON_VERSION_MAJOR
==
2
&&
PYTHON_VERSION_MINOR
==
7
&&
PYTHON_VERSION_MICRO
<
3
)
{
raiseExcHelper
(
TypeError
,
"'%s' object is not subscriptable"
,
getTypeName
(
value
));
// tested on 2.7.1
raiseExcHelper
(
TypeError
,
"'%s' object is not subscriptable"
,
getTypeName
(
target
));
// tested on 2.7.1
}
else
{
// Changed to this in 2.7.3:
raiseExcHelper
(
TypeError
,
"'%s' object has no attribute '__getitem__'"
,
getTypeName
(
value
));
// tested on 2.7.3
getTypeName
(
target
));
// tested on 2.7.3
}
}
...
...
@@ -4515,6 +4617,7 @@ extern "C" void setitem(Box* target, Box* slice, Box* value) {
Rewriter
::
createRewriter
(
__builtin_extract_return_addr
(
__builtin_return_address
(
0
)),
3
,
"setitem"
));
static
BoxedString
*
setitem_str
=
internStringImmortal
(
"__setitem__"
);
static
BoxedString
*
setslice_str
=
internStringImmortal
(
"__setslice__"
);
Box
*
rtn
;
if
(
rewriter
.
get
())
{
...
...
@@ -4522,25 +4625,24 @@ extern "C" void setitem(Box* target, Box* slice, Box* value) {
rewrite_args
.
arg1
=
rewriter
->
getArg
(
1
);
rewrite_args
.
arg2
=
rewriter
->
getArg
(
2
);
rtn
=
call
attrInternal2
(
target
,
setitem_str
,
CLASS_ONLY
,
&
rewrite_args
,
ArgPassSpec
(
2
),
slice
,
value
);
rtn
=
call
ItemOrSliceAttr
(
target
,
setitem_str
,
setslice_str
,
slice
,
value
,
&
rewrite_args
);
if
(
!
rewrite_args
.
out_success
)
{
rewriter
.
reset
(
NULL
);
}
}
else
{
rtn
=
call
attrInternal2
(
target
,
setitem_str
,
CLASS_ONLY
,
NULL
,
ArgPassSpec
(
2
),
slice
,
value
);
rtn
=
call
ItemOrSliceAttr
(
target
,
setitem_str
,
setslice_str
,
slice
,
value
,
NULL
);
}
if
(
rtn
==
NULL
)
{
raiseExcHelper
(
TypeError
,
"'%s' object does not support item assignment"
,
getTypeName
(
target
));
}
if
(
rewriter
.
get
())
{
if
(
rewriter
.
get
())
rewriter
->
commit
();
}
}
// del target[s
tart:end:step
]
// del target[s
lice
]
extern
"C"
void
delitem
(
Box
*
target
,
Box
*
slice
)
{
STAT_TIMER
(
t0
,
"us_timer_slowpath_delitem"
,
10
);
...
...
@@ -4551,29 +4653,28 @@ extern "C" void delitem(Box* target, Box* slice) {
Rewriter
::
createRewriter
(
__builtin_extract_return_addr
(
__builtin_return_address
(
0
)),
2
,
"delitem"
));
static
BoxedString
*
delitem_str
=
internStringImmortal
(
"__delitem__"
);
static
BoxedString
*
delslice_str
=
internStringImmortal
(
"__delslice__"
);
Box
*
rtn
;
if
(
rewriter
.
get
())
{
CallRewriteArgs
rewrite_args
(
rewriter
.
get
(),
rewriter
->
getArg
(
0
),
rewriter
->
getReturnDestination
());
rewrite_args
.
arg1
=
rewriter
->
getArg
(
1
);
rtn
=
call
attrInternal1
(
target
,
delitem_str
,
CLASS_ONLY
,
&
rewrite_args
,
ArgPassSpec
(
1
),
slice
);
rtn
=
call
ItemOrSliceAttr
(
target
,
delitem_str
,
delslice_str
,
slice
,
NULL
,
&
rewrite_args
);
if
(
!
rewrite_args
.
out_success
)
{
rewriter
.
reset
(
NULL
);
}
}
else
{
rtn
=
call
attrInternal1
(
target
,
delitem_str
,
CLASS_ONLY
,
NULL
,
ArgPassSpec
(
1
),
slice
);
rtn
=
call
ItemOrSliceAttr
(
target
,
delitem_str
,
delslice_str
,
slice
,
NULL
,
NULL
);
}
if
(
rtn
==
NULL
)
{
raiseExcHelper
(
TypeError
,
"'%s' object does not support item deletion"
,
getTypeName
(
target
));
}
if
(
rewriter
.
get
())
{
if
(
rewriter
.
get
())
rewriter
->
commit
();
}
}
void
Box
::
delattr
(
BoxedString
*
attr
,
DelattrRewriteArgs
*
rewrite_args
)
{
...
...
src/runtime/str.cpp
View file @
e6893159
...
...
@@ -2250,6 +2250,18 @@ extern "C" Box* strGetitem(BoxedString* self, Box* slice) {
}
}
extern
"C"
Box
*
strGetslice
(
BoxedString
*
self
,
Box
*
boxedStart
,
Box
*
boxedStop
)
{
assert
(
isSubclass
(
self
->
cls
,
str_cls
));
i64
start
,
stop
;
sliceIndex
(
boxedStart
,
&
start
);
sliceIndex
(
boxedStop
,
&
stop
);
boundSliceWithLength
(
&
start
,
&
stop
,
start
,
stop
,
self
->
s
().
size
());
return
_strSlice
(
self
,
start
,
stop
,
1
,
stop
-
start
);
}
// TODO it looks like strings don't have their own iterators, but instead
// rely on the sequence iteration protocol.
...
...
@@ -2756,6 +2768,8 @@ void setupStr() {
str_cls
->
giveAttr
(
"__getitem__"
,
new
BoxedFunction
(
boxRTFunction
((
void
*
)
strGetitem
,
STR
,
2
)));
str_cls
->
giveAttr
(
"__getslice__"
,
new
BoxedFunction
(
boxRTFunction
((
void
*
)
strGetslice
,
STR
,
3
)));
str_cls
->
giveAttr
(
"__iter__"
,
new
BoxedFunction
(
boxRTFunction
((
void
*
)
strIter
,
typeFromClass
(
str_iterator_cls
),
1
)));
str_cls
->
giveAttr
(
"replace"
,
...
...
src/runtime/util.cpp
View file @
e6893159
...
...
@@ -15,8 +15,8 @@
#include "runtime/util.h"
#include "core/options.h"
#include "core/types.h"
#include "runtime/objmodel.h"
#include "runtime/types.h"
namespace
pyston
{
...
...
@@ -25,4 +25,50 @@ void parseSlice(BoxedSlice* slice, int size, i64* out_start, i64* out_stop, i64*
if
(
ret
==
-
1
)
throwCAPIException
();
}
bool
isSliceIndex
(
Box
*
b
)
{
return
b
->
cls
==
none_cls
||
b
->
cls
==
int_cls
||
PyIndex_Check
(
b
);
}
void
adjustNegativeIndicesOnObject
(
Box
*
obj
,
i64
*
start_out
,
i64
*
stop_out
)
{
i64
start
=
*
start_out
;
i64
stop
=
*
stop_out
;
PySequenceMethods
*
m
;
// Logic from PySequence_GetSlice:
m
=
obj
->
cls
->
tp_as_sequence
;
if
(
m
&&
m
->
sq_slice
)
{
if
(
start
<
0
||
stop
<
0
)
{
if
(
m
->
sq_length
)
{
Py_ssize_t
l
=
(
*
m
->
sq_length
)(
obj
);
if
(
l
>=
0
)
{
if
(
start
<
0
)
start
+=
l
;
if
(
stop
<
0
)
stop
+=
l
;
}
}
}
}
*
start_out
=
start
;
*
stop_out
=
stop
;
}
void
boundSliceWithLength
(
i64
*
start_out
,
i64
*
stop_out
,
i64
start
,
i64
stop
,
i64
size
)
{
if
(
start
<
0
)
start
=
0
;
else
if
(
start
>
size
)
start
=
size
;
if
(
stop
<
start
)
stop
=
start
;
else
if
(
stop
>
size
)
stop
=
size
;
assert
(
0
<=
start
&&
start
<=
stop
&&
stop
<=
size
);
*
start_out
=
start
;
*
stop_out
=
stop
;
}
}
src/runtime/util.h
View file @
e6893159
...
...
@@ -16,6 +16,7 @@
#define PYSTON_RUNTIME_UTIL_H
#include "core/types.h"
#include "runtime/types.h"
namespace
pyston
{
...
...
@@ -23,6 +24,26 @@ class BoxedSlice;
void
parseSlice
(
BoxedSlice
*
slice
,
int
size
,
i64
*
out_start
,
i64
*
out_stop
,
i64
*
out_end
,
i64
*
out_length
=
nullptr
);
// Analogue of _PyEval_SliceIndex
inline
void
sliceIndex
(
Box
*
b
,
int64_t
*
out
)
{
if
(
b
->
cls
==
none_cls
)
{
// Leave default value in case of None (useful for slices like [2:])
return
;
}
int
ret
=
_PyEval_SliceIndex
(
b
,
out
);
if
(
ret
<=
0
)
throwCAPIException
();
}
bool
isSliceIndex
(
Box
*
b
);
void
adjustNegativeIndicesOnObject
(
Box
*
obj
,
i64
*
start
,
i64
*
stop
);
// Adjust the start and stop bounds of the sequence we are slicing to its size.
// Ensure stop >= start and remain within bounds.
void
boundSliceWithLength
(
i64
*
start_out
,
i64
*
stop_out
,
i64
start
,
i64
stop
,
i64
size
);
template
<
typename
T
>
void
copySlice
(
T
*
__restrict__
dst
,
const
T
*
__restrict__
src
,
i64
start
,
i64
step
,
i64
length
)
{
assert
(
dst
!=
src
);
if
(
step
==
1
)
{
...
...
test/extra/protobuf_test.py
View file @
e6893159
...
...
@@ -18,15 +18,15 @@ def install_and_test_protobuf():
subprocess
.
check_call
([
"./configure"
,
"--prefix="
+
INSTALL_DIR
],
cwd
=
PROTOBUF_DIR
)
subprocess
.
check_call
([
"make"
,
"-j4"
],
cwd
=
PROTOBUF_DIR
)
subprocess
.
check_call
([
"make"
,
"install"
],
cwd
=
PROTOBUF_DIR
)
PROTOBUF_PY_DIR
=
os
.
path
.
join
(
PROTOBUF_DIR
,
"python"
)
env
=
os
.
environ
env
[
"PATH"
]
=
env
[
"PATH"
]
+
":"
+
os
.
path
.
join
(
INSTALL_DIR
,
"bin"
)
env
[
"LD_LIBRARY_PATH"
]
=
os
.
path
.
join
(
INSTALL_DIR
,
"lib"
)
subprocess
.
check_call
([
PYTHON_EXE
,
"setup.py"
,
"build"
],
cwd
=
PROTOBUF_PY_DIR
,
env
=
env
)
expected
=
[{
"ran"
:
216
,
"failures"
:
0
,
"errors"
:
1
}]
expected
=
[{
"ran"
:
216
}]
run_test
([
PYTHON_EXE
,
"setup.py"
,
"test"
],
cwd
=
PROTOBUF_PY_DIR
,
expected
=
expected
,
env
=
env
)
create_virtenv
(
ENV_NAME
,
None
,
force_create
=
True
)
install_and_test_protobuf
()
test/tests/slice.py
View file @
e6893159
class
Indexable
(
object
):
def
__getitem__
(
self
,
idx
):
print
"called getitem on object"
,
idx
def
__delitem__
(
self
,
idx
):
print
"called delitem on object"
,
idx
def
__setitem__
(
self
,
idx
,
item
):
print
"called setitem on object"
,
idx
class
Sliceable
(
object
):
def
__getslice__
(
self
,
start
,
stop
):
print
"called getslice on object"
,
start
,
stop
def
__delslice__
(
self
,
start
,
stop
):
print
"called delslice on object"
,
start
,
stop
def
__setslice__
(
self
,
start
,
stop
,
item
):
print
"called setslice on object"
,
start
,
stop
class
Both
(
object
):
def
__getitem__
(
self
,
idx
):
print
"called getitem on object"
,
idx
def
__delitem__
(
self
,
idx
):
print
"called delitem on object"
,
idx
def
__setitem__
(
self
,
idx
,
item
):
print
"called setitem on object"
,
idx
def
__getslice__
(
self
,
start
,
stop
):
print
"called getslice on object"
,
start
,
stop
def
__delslice__
(
self
,
start
,
stop
):
print
"called delslice on object"
,
start
,
stop
def
__setslice__
(
self
,
start
,
stop
,
item
):
print
"called setslice on object"
,
start
,
stop
class
IndexZero
(
object
):
def
__index__
(
self
):
return
0
def
__repr__
(
self
):
return
"0"
class
FalseIndex
(
object
):
def
__index__
(
self
):
return
"troll"
indexable
=
Indexable
()
sliceable
=
Sliceable
()
index_zero
=
IndexZero
()
false_index
=
FalseIndex
()
both
=
Both
()
numbers
=
range
(
10
)
letters
=
"abcde"
unicodestr
=
unicode
(
"abcde"
)
# Can use index and slice notation for object with only getitem
indexable
[
0
]
indexable
[
index_zero
]
indexable
[:
10
]
indexable
[
11
:]
indexable
[:]
indexable
[
3
:
8
]
indexable
[
slice
(
1
,
2
)]
indexable
[
slice
(
1
,
12
,
2
)]
indexable
[
0
]
=
32
indexable
[:]
=
xrange
(
2
)
indexable
[
3
:
8
]
=
xrange
(
2
)
indexable
[
slice
(
1
,
12
,
2
)]
=
xrange
(
2
)
del
indexable
[
0
]
del
indexable
[:]
del
indexable
[
3
:
8
]
del
indexable
[
slice
(
1
,
12
,
2
)]
try
:
sliceable
[
0
]
except
TypeError
:
print
"can't use index notation or pass in a slice for objects with only getslice"
try
:
sliceable
[
'a'
:
'b'
]
except
TypeError
:
print
"can't pass in any type into a slice with only getslice"
try
:
sliceable
[
1
:
10
:
2
]
except
TypeError
:
print
"need getitem to support variable-sized steps"
sliceable
[
index_zero
:
index_zero
]
sliceable
[:
10
]
sliceable
[
11
:]
sliceable
[:]
sliceable
[
3
:
8
]
# Make sure the right function gets called when both are present
both
[
0
]
both
[:]
both
[
3
:
8
]
both
[::
2
]
# this should call __getitem__ since __getslice__ doesn't support steps
both
[
0
]
=
xrange
(
2
)
both
[:]
=
xrange
(
2
)
both
[
3
:
8
]
=
xrange
(
2
)
both
[::
2
]
=
xrange
(
2
)
# Should all call getitem as a fallback
both
[
'a'
]
both
[
'a'
:
'b'
]
both
[
1
:
'b'
]
both
[
'a'
:
2
]
both
[
1
:
2
:
'c'
]
del
both
[
0
]
del
both
[:]
del
both
[
3
:
8
]
del
both
[::
2
]
try
:
both
[
false_index
:
false_index
]
except
TypeError
:
print
"even if we have getitem, __index__ should not return a non-int"
# Number lists should have the set/get/del|item/slice functions
print
numbers
[
0
]
print
numbers
[:]
print
numbers
[
1
:
9
]
numbers
[
0
]
=
42
numbers
[
7
:
8
]
=
xrange
(
8
)
print
numbers
del
numbers
[
0
]
del
numbers
[
5
:
6
]
print
numbers
# Number lists should support negative indices
print
numbers
[
-
1
]
print
numbers
[
-
1
:
-
1
]
print
numbers
[:
-
2
]
print
numbers
[
-
2
:]
# String support slicing
print
letters
[
2
]
print
letters
[:
2
]
print
letters
[
2
:]
print
letters
[
1
:
3
]
print
letters
[:
-
2
]
print
letters
[
-
2
:]
# Unicode string support slicing
# Note that unicode strings are not the same type of object as strings,
# (but both have base class basestring)
print
unicodestr
[
2
]
print
unicodestr
[:
2
]
print
unicodestr
[
2
:]
print
unicodestr
[
1
:
3
]
print
unicodestr
[:
-
2
]
print
unicodestr
[
-
2
:]
# Calling the slice operator directly does not have the same behavior
# as using the slice notation []. Namely, it will not modify negative
# indices.
print
numbers
.
__getslice__
(
0
,
-
1
);
print
letters
.
__getslice__
(
0
,
-
1
);
print
unicodestr
.
__getslice__
(
0
,
-
1
);
# Other
class
C
(
object
):
def
__getitem__
(
self
,
idx
):
print
idx
...
...
@@ -17,3 +187,4 @@ print sl
C
()[:,:]
C
()[
1
:
2
,
3
:
4
]
C
()[
1
:
2
:
3
,
3
:
4
:
5
]
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