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
4d4d78ae
Commit
4d4d78ae
authored
Jul 08, 2016
by
Marius Wachtler
Committed by
GitHub
Jul 08, 2016
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #1280 from undingen/slice_lookup
only lookup __[set/get/del]slice__ for slice AST nodes
parents
1923d116
e4938dd2
Changes
18
Hide whitespace changes
Inline
Side-by-side
Showing
18 changed files
with
507 additions
and
297 deletions
+507
-297
src/asm_writing/rewriter.cpp
src/asm_writing/rewriter.cpp
+28
-30
src/asm_writing/rewriter.h
src/asm_writing/rewriter.h
+3
-5
src/capi/typeobject.cpp
src/capi/typeobject.cpp
+1
-1
src/codegen/ast_interpreter.cpp
src/codegen/ast_interpreter.cpp
+64
-13
src/codegen/baseline_jit.cpp
src/codegen/baseline_jit.cpp
+17
-0
src/codegen/baseline_jit.h
src/codegen/baseline_jit.h
+2
-0
src/codegen/compvars.cpp
src/codegen/compvars.cpp
+25
-16
src/codegen/irgen/irgenerator.cpp
src/codegen/irgen/irgenerator.cpp
+63
-28
src/codegen/runtime_hooks.cpp
src/codegen/runtime_hooks.cpp
+2
-0
src/codegen/runtime_hooks.h
src/codegen/runtime_hooks.h
+1
-1
src/runtime/classobj.cpp
src/runtime/classobj.cpp
+10
-0
src/runtime/dict.cpp
src/runtime/dict.cpp
+3
-9
src/runtime/inline/link_forcer.cpp
src/runtime/inline/link_forcer.cpp
+2
-0
src/runtime/objmodel.cpp
src/runtime/objmodel.cpp
+270
-193
src/runtime/objmodel.h
src/runtime/objmodel.h
+3
-0
test/test_extension/slots_test.c
test/test_extension/slots_test.c
+1
-1
test/tests/capi_slots.py
test/tests/capi_slots.py
+9
-0
test/tests/slice.py
test/tests/slice.py
+3
-0
No files found.
src/asm_writing/rewriter.cpp
View file @
4d4d78ae
...
...
@@ -287,24 +287,29 @@ void RewriterVar::addGuard(uint64_t val) {
rewriter
->
addAction
([
=
]()
{
rewriter
->
_addGuard
(
this
,
val_var
);
},
{
this
,
val_var
},
ActionType
::
GUARD
);
}
void
Rewriter
::
_nextSlotJump
(
bool
condition_eq
)
{
void
Rewriter
::
_nextSlotJump
(
assembler
::
ConditionCode
condition
)
{
// If a jump offset is larger then 0x80 the instruction encoding requires 6bytes instead of 2bytes.
// This adds up quickly, thats why we will try to find another jump to the slowpath with the same condition with a
// smaller offset and jump to it / use it as a trampoline.
// The benchmark show that this increases the performance slightly even though it introduces additional jumps.
int
&
last_jmp_offset
=
condition_eq
?
offset_eq_jmp_next_slot
:
offset_ne_jmp_next_slot
;
auto
condition
=
condition_eq
?
assembler
::
COND_EQUAL
:
assembler
::
COND_NOT_EQUAL
;
int
last_jmp_offset
=
-
1
;
for
(
auto
it
=
next_slot_jmps
.
rbegin
(),
it_end
=
next_slot_jmps
.
rend
();
it
!=
it_end
;
++
it
)
{
if
(
std
::
get
<
2
>
(
*
it
)
==
condition
)
{
last_jmp_offset
=
std
::
get
<
0
>
(
*
it
);
break
;
}
}
if
(
last_jmp_offset
!=
-
1
&&
assembler
->
bytesWritten
()
-
last_jmp_offset
<
0x80
)
{
assembler
->
jmp_cond
(
assembler
::
JumpDestination
::
fromStart
(
last_jmp_offset
),
condition
);
}
else
{
last_jmp_offset
=
assembler
->
bytesWritten
();
int
last_jmp_offset
=
assembler
->
bytesWritten
();
assembler
->
jmp_cond
(
assembler
::
JumpDestination
::
fromStart
(
rewrite
->
getSlotSize
()),
condition
);
next_slot_jmps
.
emplace_back
(
last_jmp_offset
,
assembler
->
bytesWritten
(),
condition
);
}
}
void
Rewriter
::
_addGuard
(
RewriterVar
*
var
,
RewriterVar
*
val_constant
)
{
void
Rewriter
::
_addGuard
(
RewriterVar
*
var
,
RewriterVar
*
val_constant
,
bool
negate
)
{
if
(
LOG_IC_ASSEMBLY
)
assembler
->
comment
(
"_addGuard"
);
...
...
@@ -316,12 +321,15 @@ void Rewriter::_addGuard(RewriterVar* var, RewriterVar* val_constant) {
assembler
::
Register
reg
=
val_constant
->
getInReg
(
Location
::
any
(),
true
,
/* otherThan */
var_reg
);
assembler
->
cmp
(
var_reg
,
reg
);
}
else
{
assembler
->
cmp
(
var_reg
,
assembler
::
Immediate
(
val
));
if
(
val
==
0
)
assembler
->
test
(
var_reg
,
var_reg
);
else
assembler
->
cmp
(
var_reg
,
assembler
::
Immediate
(
val
));
}
restoreArgs
();
// can only do movs, doesn't affect flags, so it's safe
assertArgsInPlace
();
_nextSlotJump
(
false
/*= not equal jmp */
);
_nextSlotJump
(
negate
?
assembler
::
COND_EQUAL
:
assembler
::
COND_NOT_EQUAL
);
var
->
bumpUse
();
val_constant
->
bumpUse
();
...
...
@@ -333,32 +341,24 @@ void RewriterVar::addGuardNotEq(uint64_t val) {
STAT_TIMER
(
t0
,
"us_timer_rewriter"
,
10
);
RewriterVar
*
val_var
=
rewriter
->
loadConst
(
val
);
rewriter
->
addAction
([
=
]()
{
rewriter
->
_addGuardNotEq
(
this
,
val_var
);
},
{
this
,
val_var
},
ActionType
::
GUARD
);
rewriter
->
addAction
([
=
]()
{
rewriter
->
_addGuard
(
this
,
val_var
,
true
/* negate */
);
},
{
this
,
val_var
},
ActionType
::
GUARD
);
}
void
Rewriter
::
_addGuardNotEq
(
RewriterVar
*
var
,
RewriterVar
*
val_constant
)
{
if
(
LOG_IC_ASSEMBLY
)
assembler
->
comment
(
"_addGuardNotEq"
);
void
RewriterVar
::
addGuardNotLt0
()
{
rewriter
->
addAction
([
=
]()
{
assembler
::
Register
var_reg
=
this
->
getInReg
();
rewriter
->
assembler
->
test
(
var_reg
,
var_reg
);
assert
(
val_constant
->
is_constant
);
uint64_t
val
=
val_constant
->
constant_value
;
rewriter
->
restoreArgs
();
// can only do movs, doesn't affect flags, so it's safe
rewriter
->
assertArgsInPlace
()
;
assembler
::
Register
var_reg
=
var
->
getInReg
();
if
(
isLargeConstant
(
val
))
{
assembler
::
Register
reg
=
val_constant
->
getInReg
(
Location
::
any
(),
true
,
/* otherThan */
var_reg
);
assembler
->
cmp
(
var_reg
,
reg
);
}
else
{
assembler
->
cmp
(
var_reg
,
assembler
::
Immediate
(
val
));
}
restoreArgs
();
// can only do movs, doesn't affect flags, so it's safe
assertArgsInPlace
();
_nextSlotJump
(
true
/*= equal jmp */
);
rewriter
->
_nextSlotJump
(
assembler
::
COND_SIGN
);
var
->
bumpUse
();
val_constant
->
bumpUse
();
bumpUse
();
rewriter
->
assertConsistent
();
assertConsistent
(
);
},
{
this
},
ActionType
::
GUARD
);
}
void
RewriterVar
::
addAttrGuard
(
int
offset
,
uint64_t
val
,
bool
negate
)
{
...
...
@@ -405,7 +405,7 @@ void Rewriter::_addAttrGuard(RewriterVar* var, int offset, RewriterVar* val_cons
restoreArgs
();
// can only do movs, doesn't affect flags, so it's safe
assertArgsInPlace
();
_nextSlotJump
(
negate
);
_nextSlotJump
(
negate
?
assembler
::
COND_EQUAL
:
assembler
::
COND_NOT_EQUAL
);
var
->
bumpUse
();
val_constant
->
bumpUse
();
...
...
@@ -2220,8 +2220,6 @@ Rewriter::Rewriter(std::unique_ptr<ICSlotRewrite> rewrite, int num_args, const L
marked_inside_ic
(
false
),
done_guarding
(
false
),
last_guard_action
(
-
1
),
offset_eq_jmp_next_slot
(
-
1
),
offset_ne_jmp_next_slot
(
-
1
),
allocatable_regs
(
std_allocatable_regs
)
{
initPhaseCollecting
();
...
...
src/asm_writing/rewriter.h
View file @
4d4d78ae
...
...
@@ -147,6 +147,7 @@ public:
void
addGuard
(
uint64_t
val
);
void
addGuardNotEq
(
uint64_t
val
);
void
addGuardNotLt0
();
void
addAttrGuard
(
int
offset
,
uint64_t
val
,
bool
negate
=
false
);
RewriterVar
*
getAttr
(
int
offset
,
Location
loc
=
Location
::
any
(),
assembler
::
MovType
type
=
assembler
::
MovType
::
Q
);
// getAttrFloat casts to double (maybe I should make that separate?)
...
...
@@ -502,8 +503,6 @@ protected:
}
int
last_guard_action
;
int
offset_eq_jmp_next_slot
;
int
offset_ne_jmp_next_slot
;
// keeps track of all jumps to the next slot so we can patch them if the size of the current slot changes
std
::
vector
<
NextSlotJumpInfo
>
next_slot_jmps
;
...
...
@@ -540,7 +539,7 @@ protected:
bool
finishAssembly
(
int
continue_offset
,
bool
&
should_fill_with_nops
,
bool
&
variable_size_slots
)
override
;
void
_nextSlotJump
(
bool
condition_eq
);
void
_nextSlotJump
(
assembler
::
ConditionCode
condition
);
void
_trap
();
void
_loadConst
(
RewriterVar
*
result
,
int64_t
val
);
void
_setupCall
(
bool
has_side_effects
,
llvm
::
ArrayRef
<
RewriterVar
*>
args
=
{},
...
...
@@ -557,8 +556,7 @@ protected:
void
_checkAndThrowCAPIException
(
RewriterVar
*
r
,
int64_t
exc_val
,
assembler
::
MovType
size
);
// The public versions of these are in RewriterVar
void
_addGuard
(
RewriterVar
*
var
,
RewriterVar
*
val_constant
);
void
_addGuardNotEq
(
RewriterVar
*
var
,
RewriterVar
*
val_constant
);
void
_addGuard
(
RewriterVar
*
var
,
RewriterVar
*
val_constant
,
bool
negate
=
false
);
void
_addAttrGuard
(
RewriterVar
*
var
,
int
offset
,
RewriterVar
*
val_constant
,
bool
negate
=
false
);
void
_getAttr
(
RewriterVar
*
result
,
RewriterVar
*
var
,
int
offset
,
Location
loc
=
Location
::
any
(),
assembler
::
MovType
type
=
assembler
::
MovType
::
Q
);
...
...
src/capi/typeobject.cpp
View file @
4d4d78ae
...
...
@@ -1242,7 +1242,7 @@ static int slot_tp_descr_set(PyObject* self, PyObject* target, PyObject* value)
PyObject
*
slot_sq_item
(
PyObject
*
self
,
Py_ssize_t
i
)
noexcept
{
STAT_TIMER
(
t0
,
"us_timer_slot_sqitem"
,
SLOT_AVOIDABILITY
(
self
));
return
getitemInternal
<
CAPI
>
(
self
,
autoDecref
(
boxInt
(
i
)));
return
PyObject_GetItem
(
self
,
autoDecref
(
boxInt
(
i
)));
}
/* Pyston change: static */
Py_ssize_t
slot_sq_length
(
PyObject
*
self
)
noexcept
{
...
...
src/codegen/ast_interpreter.cpp
View file @
4d4d78ae
...
...
@@ -554,12 +554,27 @@ void ASTInterpreter::doStore(AST_expr* node, STOLEN(Value) value) {
Value
target
=
visit_expr
(
subscript
->
value
);
AUTO_DECREF
(
target
.
o
);
Value
slice
=
visit_slice
(
subscript
->
slice
);
AUTO_DECREF
(
slice
.
o
);
bool
is_slice
=
(
subscript
->
slice
->
type
==
AST_TYPE
::
Slice
)
&&
(((
AST_Slice
*
)
subscript
->
slice
)
->
step
==
NULL
);
if
(
is_slice
)
{
AST_Slice
*
slice
=
(
AST_Slice
*
)
subscript
->
slice
;
Value
lower
=
slice
->
lower
?
visit_expr
(
slice
->
lower
)
:
Value
();
AUTO_XDECREF
(
lower
.
o
);
Value
upper
=
slice
->
upper
?
visit_expr
(
slice
->
upper
)
:
Value
();
AUTO_XDECREF
(
upper
.
o
);
assert
(
slice
->
step
==
NULL
);
if
(
jit
)
jit
->
emitSetItem
(
target
,
slice
,
value
);
setitem
(
target
.
o
,
slice
.
o
,
value
.
o
);
if
(
jit
)
jit
->
emitAssignSlice
(
target
,
lower
,
upper
,
value
);
assignSlice
(
target
.
o
,
lower
.
o
,
upper
.
o
,
value
.
o
);
}
else
{
Value
slice
=
visit_slice
(
subscript
->
slice
);
AUTO_DECREF
(
slice
.
o
);
if
(
jit
)
jit
->
emitSetItem
(
target
,
slice
,
value
);
setitem
(
target
.
o
,
slice
.
o
,
value
.
o
);
}
}
else
{
RELEASE_ASSERT
(
0
,
"not implemented"
);
}
...
...
@@ -1306,11 +1321,26 @@ Value ASTInterpreter::visit_delete(AST_Delete* node) {
AST_Subscript
*
sub
=
(
AST_Subscript
*
)
target_
;
Value
value
=
visit_expr
(
sub
->
value
);
AUTO_DECREF
(
value
.
o
);
Value
slice
=
visit_slice
(
sub
->
slice
);
AUTO_DECREF
(
slice
.
o
);
if
(
jit
)
jit
->
emitDelItem
(
value
,
slice
);
delitem
(
value
.
o
,
slice
.
o
);
bool
is_slice
=
(
sub
->
slice
->
type
==
AST_TYPE
::
Slice
)
&&
(((
AST_Slice
*
)
sub
->
slice
)
->
step
==
NULL
);
if
(
is_slice
)
{
AST_Slice
*
slice
=
(
AST_Slice
*
)
sub
->
slice
;
Value
lower
=
slice
->
lower
?
visit_expr
(
slice
->
lower
)
:
Value
();
AUTO_XDECREF
(
lower
.
o
);
Value
upper
=
slice
->
upper
?
visit_expr
(
slice
->
upper
)
:
Value
();
AUTO_XDECREF
(
upper
.
o
);
assert
(
slice
->
step
==
NULL
);
if
(
jit
)
jit
->
emitAssignSlice
(
value
,
lower
,
upper
,
jit
->
imm
(
0ul
));
assignSlice
(
value
.
o
,
lower
.
o
,
upper
.
o
,
NULL
);
}
else
{
Value
slice
=
visit_slice
(
sub
->
slice
);
AUTO_DECREF
(
slice
.
o
);
if
(
jit
)
jit
->
emitDelItem
(
value
,
slice
);
delitem
(
value
.
o
,
slice
.
o
);
}
break
;
}
case
AST_TYPE
:
:
Attribute
:
{
...
...
@@ -1722,10 +1752,31 @@ Value ASTInterpreter::visit_name(AST_Name* node) {
Value
ASTInterpreter
::
visit_subscript
(
AST_Subscript
*
node
)
{
Value
value
=
visit_expr
(
node
->
value
);
AUTO_DECREF
(
value
.
o
);
Value
slice
=
visit_slice
(
node
->
slice
);
AUTO_DECREF
(
slice
.
o
);
return
Value
(
getitem
(
value
.
o
,
slice
.
o
),
jit
?
jit
->
emitGetItem
(
node
,
value
,
slice
)
:
NULL
);
bool
is_slice
=
(
node
->
slice
->
type
==
AST_TYPE
::
Slice
)
&&
(((
AST_Slice
*
)
node
->
slice
)
->
step
==
NULL
);
if
(
is_slice
)
{
AST_Slice
*
slice
=
(
AST_Slice
*
)
node
->
slice
;
Value
lower
=
slice
->
lower
?
visit_expr
(
slice
->
lower
)
:
Value
();
AUTO_XDECREF
(
lower
.
o
);
Value
upper
=
slice
->
upper
?
visit_expr
(
slice
->
upper
)
:
Value
();
AUTO_XDECREF
(
upper
.
o
);
assert
(
slice
->
step
==
NULL
);
Value
v
;
if
(
jit
)
v
.
var
=
jit
->
emitApplySlice
(
value
,
lower
,
upper
);
v
.
o
=
applySlice
(
value
.
o
,
lower
.
o
,
upper
.
o
);
return
v
;
}
else
{
Value
slice
=
visit_slice
(
node
->
slice
);
AUTO_DECREF
(
slice
.
o
);
Value
v
;
if
(
jit
)
v
.
var
=
jit
->
emitGetItem
(
node
,
value
,
slice
);
v
.
o
=
getitem
(
value
.
o
,
slice
.
o
);
return
v
;
}
}
Value
ASTInterpreter
::
visit_list
(
AST_List
*
node
)
{
...
...
src/codegen/baseline_jit.cpp
View file @
4d4d78ae
...
...
@@ -208,6 +208,14 @@ RewriterVar* JitFragmentWriter::emitAugbinop(AST_expr* node, RewriterVar* lhs, R
return
emitPPCall
((
void
*
)
augbinop
,
{
lhs
,
rhs
,
imm
(
op_type
)
},
2
*
320
,
node
).
first
->
setType
(
RefType
::
OWNED
);
}
RewriterVar
*
JitFragmentWriter
::
emitApplySlice
(
RewriterVar
*
target
,
RewriterVar
*
lower
,
RewriterVar
*
upper
)
{
if
(
!
lower
)
lower
=
imm
(
0ul
);
if
(
!
upper
)
upper
=
imm
(
0ul
);
return
emitPPCall
((
void
*
)
applySlice
,
{
target
,
lower
,
upper
},
256
).
first
->
setType
(
RefType
::
OWNED
);
}
RewriterVar
*
JitFragmentWriter
::
emitBinop
(
AST_expr
*
node
,
RewriterVar
*
lhs
,
RewriterVar
*
rhs
,
int
op_type
)
{
return
emitPPCall
((
void
*
)
binop
,
{
lhs
,
rhs
,
imm
(
op_type
)
},
2
*
240
,
node
).
first
->
setType
(
RefType
::
OWNED
);
}
...
...
@@ -553,6 +561,15 @@ RewriterVar* JitFragmentWriter::emitYield(RewriterVar* v) {
return
rtn
;
}
void
JitFragmentWriter
::
emitAssignSlice
(
RewriterVar
*
target
,
RewriterVar
*
lower
,
RewriterVar
*
upper
,
RewriterVar
*
value
)
{
if
(
!
lower
)
lower
=
imm
(
0ul
);
if
(
!
upper
)
upper
=
imm
(
0ul
);
emitPPCall
((
void
*
)
assignSlice
,
{
target
,
lower
,
upper
,
value
},
256
).
first
;
}
void
JitFragmentWriter
::
emitDelAttr
(
RewriterVar
*
target
,
BoxedString
*
attr
)
{
emitPPCall
((
void
*
)
delattr
,
{
target
,
imm
(
attr
)
},
144
).
first
;
}
...
...
src/codegen/baseline_jit.h
View file @
4d4d78ae
...
...
@@ -239,6 +239,7 @@ public:
RewriterVar
*
imm
(
void
*
val
);
RewriterVar
*
emitAugbinop
(
AST_expr
*
node
,
RewriterVar
*
lhs
,
RewriterVar
*
rhs
,
int
op_type
);
RewriterVar
*
emitApplySlice
(
RewriterVar
*
target
,
RewriterVar
*
lower
,
RewriterVar
*
upper
);
RewriterVar
*
emitBinop
(
AST_expr
*
node
,
RewriterVar
*
lhs
,
RewriterVar
*
rhs
,
int
op_type
);
RewriterVar
*
emitCallattr
(
AST_expr
*
node
,
RewriterVar
*
obj
,
BoxedString
*
attr
,
CallattrFlags
flags
,
const
llvm
::
ArrayRef
<
RewriterVar
*>
args
,
std
::
vector
<
BoxedString
*>*
keyword_names
);
...
...
@@ -275,6 +276,7 @@ public:
std
::
vector
<
RewriterVar
*>
emitUnpackIntoArray
(
RewriterVar
*
v
,
uint64_t
num
);
RewriterVar
*
emitYield
(
RewriterVar
*
v
);
void
emitAssignSlice
(
RewriterVar
*
target
,
RewriterVar
*
lower
,
RewriterVar
*
upper
,
RewriterVar
*
value
);
void
emitDelAttr
(
RewriterVar
*
target
,
BoxedString
*
attr
);
void
emitDelGlobal
(
BoxedString
*
name
);
void
emitDelItem
(
RewriterVar
*
target
,
RewriterVar
*
slice
);
...
...
src/codegen/compvars.cpp
View file @
4d4d78ae
...
...
@@ -331,6 +331,9 @@ public:
CompilerVariable
*
getitem
(
IREmitter
&
emitter
,
const
OpInfo
&
info
,
ConcreteCompilerVariable
*
var
,
CompilerVariable
*
slice
)
override
{
ExceptionStyle
target_exception_style
=
info
.
preferredExceptionStyle
();
bool
do_patchpoint
=
ENABLE_ICGETITEMS
;
if
(
slice
->
getType
()
==
UNBOXED_SLICE
)
{
UnboxedSlice
slice_val
=
extractSlice
(
slice
);
...
...
@@ -340,31 +343,37 @@ public:
=
var
->
getType
()
->
getattrType
(
attr
,
true
)
->
callType
(
ArgPassSpec
(
1
),
{
SLICE
},
NULL
);
assert
(
return_type
->
getConcreteType
()
==
return_type
);
if
(
return_type
!=
UNDEF
)
{
llvm
::
Value
*
cstart
,
*
cstop
;
cstart
=
slice_val
.
start
?
slice_val
.
start
->
makeConverted
(
emitter
,
UNKNOWN
)
->
getValue
()
:
emitter
.
setType
(
getNullPtr
(
g
.
llvm_value_type_ptr
),
RefType
::
BORROWED
);
cstop
=
slice_val
.
stop
?
slice_val
.
stop
->
makeConverted
(
emitter
,
UNKNOWN
)
->
getValue
()
:
emitter
.
setType
(
getNullPtr
(
g
.
llvm_value_type_ptr
),
RefType
::
BORROWED
);
llvm
::
Value
*
r
=
emitter
.
createCall3
(
info
.
unw_info
,
g
.
funcs
.
apply_slice
,
var
->
getValue
(),
cstart
,
cstop
,
CAPI
,
getNullPtr
(
g
.
llvm_value_type_ptr
));
emitter
.
setType
(
r
,
RefType
::
OWNED
);
llvm
::
Value
*
cstart
,
*
cstop
;
cstart
=
slice_val
.
start
?
slice_val
.
start
->
makeConverted
(
emitter
,
UNKNOWN
)
->
getValue
()
:
emitter
.
setType
(
getNullPtr
(
g
.
llvm_value_type_ptr
),
RefType
::
BORROWED
);
cstop
=
slice_val
.
stop
?
slice_val
.
stop
->
makeConverted
(
emitter
,
UNKNOWN
)
->
getValue
()
:
emitter
.
setType
(
getNullPtr
(
g
.
llvm_value_type_ptr
),
RefType
::
BORROWED
);
llvm
::
Value
*
r
=
NULL
;
if
(
do_patchpoint
)
{
ICSetupInfo
*
pp
=
createGetitemIC
(
info
.
getTypeRecorder
(),
info
.
getBJitICInfo
());
llvm
::
Instruction
*
uncasted
=
emitter
.
createIC
(
pp
,
(
void
*
)(
target_exception_style
==
CAPI
?
pyston
::
apply_slice
:
pyston
::
applySlice
),
{
var
->
getValue
(),
cstart
,
cstop
},
info
.
unw_info
,
target_exception_style
,
getNullPtr
(
g
.
llvm_value_type_ptr
));
r
=
createAfter
<
llvm
::
IntToPtrInst
>
(
uncasted
,
uncasted
,
g
.
llvm_value_type_ptr
,
""
);
}
else
{
r
=
emitter
.
createCall3
(
info
.
unw_info
,
target_exception_style
==
CAPI
?
g
.
funcs
.
apply_slice
:
g
.
funcs
.
applySlice
,
var
->
getValue
(),
cstart
,
cstop
,
target_exception_style
,
getNullPtr
(
g
.
llvm_value_type_ptr
));
}
emitter
.
setType
(
r
,
RefType
::
OWNED
);
if
(
target_exception_style
==
CAPI
)
emitter
.
setNullable
(
r
,
true
);
if
(
return_type
!=
UNDEF
)
return
new
ConcreteCompilerVariable
(
static_cast
<
ConcreteCompilerType
*>
(
return_type
),
r
);
}
else
{
// TODO: we could directly emit an exception if we know getitem is undefined but for now let it just
// call the normal getitem which will raise the exception
}
return
new
ConcreteCompilerVariable
(
UNKNOWN
,
r
);
}
}
ConcreteCompilerVariable
*
converted_slice
=
slice
->
makeConverted
(
emitter
,
slice
->
getBoxType
());
ExceptionStyle
target_exception_style
=
info
.
preferredExceptionStyle
();
bool
do_patchpoint
=
ENABLE_ICGETITEMS
;
llvm
::
Value
*
rtn
;
if
(
do_patchpoint
)
{
ICSetupInfo
*
pp
=
createGetitemIC
(
info
.
getTypeRecorder
(),
info
.
getBJitICInfo
());
...
...
src/codegen/irgen/irgenerator.cpp
View file @
4d4d78ae
...
...
@@ -1547,7 +1547,6 @@ private:
CompilerVariable
*
evalSubscript
(
AST_Subscript
*
node
,
const
UnwindInfo
&
unw_info
)
{
CompilerVariable
*
value
=
evalExpr
(
node
->
value
,
unw_info
);
CompilerVariable
*
slice
=
evalSlice
(
node
->
slice
,
unw_info
);
CompilerVariable
*
rtn
=
value
->
getitem
(
emitter
,
getOpInfoForNode
(
node
,
unw_info
),
slice
);
return
rtn
;
}
...
...
@@ -2015,31 +2014,59 @@ private:
t
->
setattr
(
emitter
,
getEmptyOpInfo
(
unw_info
),
target
->
attr
.
getBox
(),
val
);
}
void
_doSetitem
(
AST_Subscript
*
target
,
CompilerVariable
*
val
,
const
UnwindInfo
&
unw_info
)
{
CompilerVariable
*
tget
=
evalExpr
(
target
->
value
,
unw_info
);
CompilerVariable
*
slice
=
evalSlice
(
target
->
slice
,
unw_info
);
ConcreteCompilerVariable
*
converted_target
=
tget
->
makeConverted
(
emitter
,
tget
->
getBoxType
());
ConcreteCompilerVariable
*
converted_slice
=
slice
->
makeConverted
(
emitter
,
slice
->
getBoxType
());
ConcreteCompilerVariable
*
converted_val
=
val
->
makeConverted
(
emitter
,
val
->
getBoxType
());
void
_assignSlice
(
llvm
::
Value
*
target
,
llvm
::
Value
*
value
,
const
UnboxedSlice
&
slice_val
,
const
UnwindInfo
&
unw_info
)
{
llvm
::
Value
*
cstart
,
*
cstop
;
cstart
=
slice_val
.
start
?
slice_val
.
start
->
makeConverted
(
emitter
,
UNKNOWN
)
->
getValue
()
:
emitter
.
setType
(
getNullPtr
(
g
.
llvm_value_type_ptr
),
RefType
::
BORROWED
);
cstop
=
slice_val
.
stop
?
slice_val
.
stop
->
makeConverted
(
emitter
,
UNKNOWN
)
->
getValue
()
:
emitter
.
setType
(
getNullPtr
(
g
.
llvm_value_type_ptr
),
RefType
::
BORROWED
);
// TODO add a CompilerVariable::setattr, which can (similar to getitem)
// statically-resolve the function if possible, and only fall back to
// patchpoints if it couldn't.
bool
do_patchpoint
=
ENABLE_ICSETITEMS
;
if
(
do_patchpoint
)
{
ICSetupInfo
*
pp
=
createSetitemIC
(
getEmptyOpInfo
(
unw_info
).
getTypeRecorder
());
std
::
vector
<
llvm
::
Value
*>
llvm_args
;
llvm_args
.
push_back
(
converted_target
->
getValue
());
llvm_args
.
push_back
(
converted_slice
->
getValue
());
llvm_args
.
push_back
(
converted_val
->
getValue
());
llvm_args
.
push_back
(
target
);
llvm_args
.
push_back
(
cstart
);
llvm_args
.
push_back
(
cstop
);
llvm_args
.
push_back
(
value
);
emitter
.
createIC
(
pp
,
(
void
*
)
pyston
::
setitem
,
llvm_args
,
unw_info
);
emitter
.
createIC
(
pp
,
(
void
*
)
pyston
::
assignSlice
,
llvm_args
,
unw_info
);
}
else
{
emitter
.
createCall3
(
unw_info
,
g
.
funcs
.
setitem
,
converted_target
->
getValue
(),
converted_slice
->
getValue
(),
converted_val
->
getValue
());
emitter
.
createCall
(
unw_info
,
g
.
funcs
.
assignSlice
,
{
target
,
cstart
,
cstop
,
value
});
}
}
void
_doSetitem
(
AST_Subscript
*
target
,
CompilerVariable
*
val
,
const
UnwindInfo
&
unw_info
)
{
CompilerVariable
*
tget
=
evalExpr
(
target
->
value
,
unw_info
);
CompilerVariable
*
slice
=
evalSlice
(
target
->
slice
,
unw_info
);
ConcreteCompilerVariable
*
converted_target
=
tget
->
makeConverted
(
emitter
,
tget
->
getBoxType
());
ConcreteCompilerVariable
*
converted_val
=
val
->
makeConverted
(
emitter
,
val
->
getBoxType
());
if
(
slice
->
getType
()
==
UNBOXED_SLICE
&&
!
extractSlice
(
slice
).
step
)
{
_assignSlice
(
converted_target
->
getValue
(),
converted_val
->
getValue
(),
extractSlice
(
slice
),
unw_info
);
}
else
{
ConcreteCompilerVariable
*
converted_slice
=
slice
->
makeConverted
(
emitter
,
slice
->
getBoxType
());
// TODO add a CompilerVariable::setattr, which can (similar to getitem)
// statically-resolve the function if possible, and only fall back to
// patchpoints if it couldn't.
bool
do_patchpoint
=
ENABLE_ICSETITEMS
;
if
(
do_patchpoint
)
{
ICSetupInfo
*
pp
=
createSetitemIC
(
getEmptyOpInfo
(
unw_info
).
getTypeRecorder
());
std
::
vector
<
llvm
::
Value
*>
llvm_args
;
llvm_args
.
push_back
(
converted_target
->
getValue
());
llvm_args
.
push_back
(
converted_slice
->
getValue
());
llvm_args
.
push_back
(
converted_val
->
getValue
());
emitter
.
createIC
(
pp
,
(
void
*
)
pyston
::
setitem
,
llvm_args
,
unw_info
);
}
else
{
emitter
.
createCall3
(
unw_info
,
g
.
funcs
.
setitem
,
converted_target
->
getValue
(),
converted_slice
->
getValue
(),
converted_val
->
getValue
());
}
}
}
...
...
@@ -2148,19 +2175,27 @@ private:
CompilerVariable
*
slice
=
evalSlice
(
target
->
slice
,
unw_info
);
ConcreteCompilerVariable
*
converted_target
=
tget
->
makeConverted
(
emitter
,
tget
->
getBoxType
());
ConcreteCompilerVariable
*
converted_slice
=
slice
->
makeConverted
(
emitter
,
slice
->
getBoxType
());
bool
do_patchpoint
=
ENABLE_ICDELITEMS
;
if
(
do_patchpoint
)
{
ICSetupInfo
*
pp
=
createDelitemIC
(
getEmptyOpInfo
(
unw_info
).
getTypeRecorder
());
if
(
slice
->
getType
()
==
UNBOXED_SLICE
&&
!
extractSlice
(
slice
).
step
)
{
_assignSlice
(
converted_target
->
getValue
(),
emitter
.
setType
(
getNullPtr
(
g
.
llvm_value_type_ptr
),
RefType
::
BORROWED
),
extractSlice
(
slice
),
unw_info
);
}
else
{
ConcreteCompilerVariable
*
converted_slice
=
slice
->
makeConverted
(
emitter
,
slice
->
getBoxType
());
std
::
vector
<
llvm
::
Value
*>
llvm_args
;
llvm_args
.
push_back
(
converted_target
->
getValue
());
llvm_args
.
push_back
(
converted_slice
->
getValue
());
bool
do_patchpoint
=
ENABLE_ICDELITEMS
;
if
(
do_patchpoint
)
{
ICSetupInfo
*
pp
=
createDelitemIC
(
getEmptyOpInfo
(
unw_info
).
getTypeRecorder
());
emitter
.
createIC
(
pp
,
(
void
*
)
pyston
::
delitem
,
llvm_args
,
unw_info
);
}
else
{
emitter
.
createCall2
(
unw_info
,
g
.
funcs
.
delitem
,
converted_target
->
getValue
(),
converted_slice
->
getValue
());
std
::
vector
<
llvm
::
Value
*>
llvm_args
;
llvm_args
.
push_back
(
converted_target
->
getValue
());
llvm_args
.
push_back
(
converted_slice
->
getValue
());
emitter
.
createIC
(
pp
,
(
void
*
)
pyston
::
delitem
,
llvm_args
,
unw_info
);
}
else
{
emitter
.
createCall2
(
unw_info
,
g
.
funcs
.
delitem
,
converted_target
->
getValue
(),
converted_slice
->
getValue
());
}
}
}
...
...
src/codegen/runtime_hooks.cpp
View file @
4d4d78ae
...
...
@@ -229,6 +229,8 @@ void initGlobalFuncs(GlobalState& g) {
GET
(
getiterHelper
);
GET
(
hasnext
);
GET
(
apply_slice
);
GET
(
applySlice
);
GET
(
assignSlice
);
GET
(
unpackIntoArray
);
GET
(
raiseAttributeError
);
...
...
src/codegen/runtime_hooks.h
View file @
4d4d78ae
...
...
@@ -39,7 +39,7 @@ struct GlobalFuncs {
llvm
::
Value
*
getattr
,
*
getattr_capi
,
*
setattr
,
*
delattr
,
*
delitem
,
*
delGlobal
,
*
nonzero
,
*
binop
,
*
compare
,
*
augbinop
,
*
unboxedLen
,
*
getitem
,
*
getitem_capi
,
*
getclsattr
,
*
getGlobal
,
*
setitem
,
*
unaryop
,
*
import
,
*
importFrom
,
*
importStar
,
*
repr
,
*
exceptionMatches
,
*
yield_capi
,
*
getiterHelper
,
*
hasnext
,
*
setGlobal
,
*
apply_slice
;
*
apply_slice
,
*
applySlice
,
*
assignSlice
;
llvm
::
Value
*
unpackIntoArray
,
*
raiseAttributeError
,
*
raiseAttributeErrorStr
,
*
raiseAttributeErrorCapi
,
*
raiseAttributeErrorStrCapi
,
*
raiseNotIterableError
,
*
raiseIndexErrorStr
,
*
raiseIndexErrorStrCapi
,
...
...
src/runtime/classobj.cpp
View file @
4d4d78ae
...
...
@@ -777,6 +777,15 @@ Box* instanceGetslice(Box* _inst, Box* i, Box* j) {
return
runtimeCall
(
getslice_func
,
ArgPassSpec
(
2
),
i
,
j
,
NULL
,
NULL
,
NULL
);
}
Box
*
instance_slice
(
PyObject
*
self
,
Py_ssize_t
i
,
Py_ssize_t
j
)
noexcept
{
try
{
return
instanceGetslice
(
self
,
autoDecref
(
boxInt
(
i
)),
autoDecref
((
boxInt
(
j
))));
}
catch
(
ExcInfo
e
)
{
setCAPIException
(
e
);
return
0
;
}
}
Box
*
instanceSetslice
(
Box
*
_inst
,
Box
*
i
,
Box
*
j
,
Box
**
sequence
)
{
RELEASE_ASSERT
(
_inst
->
cls
==
instance_cls
,
""
);
BoxedInstance
*
inst
=
static_cast
<
BoxedInstance
*>
(
_inst
);
...
...
@@ -2005,5 +2014,6 @@ void setupClassobj() {
instance_cls
->
tp_as_number
->
nb_index
=
instance_index
;
instance_cls
->
tp_as_number
->
nb_power
=
instance_pow
;
instance_cls
->
tp_as_number
->
nb_inplace_power
=
instance_ipow
;
instance_cls
->
tp_as_sequence
->
sq_slice
=
instance_slice
;
}
}
src/runtime/dict.cpp
View file @
4d4d78ae
...
...
@@ -377,13 +377,13 @@ extern "C" BORROWED(PyObject*) PyDict_GetItem(PyObject* dict, PyObject* key) noe
/* preserve the existing exception */
PyObject
*
err_type
,
*
err_value
,
*
err_tb
;
PyErr_Fetch
(
&
err_type
,
&
err_value
,
&
err_tb
);
Box
*
b
=
getitemInternal
<
CAPI
>
(
dict
,
key
);
Box
*
b
=
PyObject_GetItem
(
dict
,
key
);
/* ignore errors */
PyErr_Restore
(
err_type
,
err_value
,
err_tb
);
Py_XDECREF
(
b
);
return
b
;
}
else
{
Box
*
b
=
getitemInternal
<
CAPI
>
(
dict
,
key
);
Box
*
b
=
PyObject_GetItem
(
dict
,
key
);
if
(
b
==
NULL
)
PyErr_Clear
();
else
...
...
@@ -514,13 +514,7 @@ extern "C" int PyDict_DelItem(PyObject* op, PyObject* key) noexcept {
}
ASSERT
(
op
->
cls
==
attrwrapper_cls
,
"%s"
,
getTypeName
(
op
));
try
{
delitem
(
op
,
key
);
return
0
;
}
catch
(
ExcInfo
e
)
{
setCAPIException
(
e
);
return
-
1
;
}
return
PyObject_DelItem
(
op
,
key
);
}
extern
"C"
int
PyDict_DelItemString
(
PyObject
*
v
,
const
char
*
key
)
noexcept
{
...
...
src/runtime/inline/link_forcer.cpp
View file @
4d4d78ae
...
...
@@ -105,6 +105,8 @@ void force() {
FORCE
(
getiterHelper
);
FORCE
(
hasnext
);
FORCE
(
apply_slice
);
FORCE
(
applySlice
);
FORCE
(
assignSlice
);
FORCE
(
unpackIntoArray
);
FORCE
(
raiseAttributeError
);
...
...
src/runtime/objmodel.cpp
View file @
4d4d78ae
...
...
@@ -6075,13 +6075,8 @@ static Box* callItemAttr(Box* target, BoxedString* item_str, Box* item, Box* val
if
(
rewrite_args
)
{
CallattrRewriteArgs
crewrite_args
(
rewrite_args
);
Box
*
r
;
if
(
value
)
r
=
callattrInternal2
<
S
,
REWRITABLE
>
(
target
,
item_str
,
CLASS_ONLY
,
&
crewrite_args
,
ArgPassSpec
(
2
),
item
,
value
);
else
r
=
callattrInternal1
<
S
,
REWRITABLE
>
(
target
,
item_str
,
CLASS_ONLY
,
&
crewrite_args
,
ArgPassSpec
(
1
),
item
);
Box
*
r
=
callattrInternal2
<
S
,
REWRITABLE
>
(
target
,
item_str
,
CLASS_ONLY
,
&
crewrite_args
,
ArgPassSpec
(
value
?
2
:
1
),
item
,
value
);
if
(
crewrite_args
.
isSuccessful
())
{
rewrite_args
->
out_success
=
true
;
if
(
r
||
PyErr_Occurred
())
...
...
@@ -6092,173 +6087,288 @@ static Box* callItemAttr(Box* target, BoxedString* item_str, Box* item, Box* val
}
return
r
;
}
else
{
if
(
value
)
return
callattrInternal2
<
S
,
NOT_REWRITABLE
>
(
target
,
item_str
,
CLASS_ONLY
,
NULL
,
ArgPassSpec
(
2
),
item
,
value
);
else
return
callattrInternal1
<
S
,
NOT_REWRITABLE
>
(
target
,
item_str
,
CLASS_ONLY
,
NULL
,
ArgPassSpec
(
1
),
item
);
return
callattrInternal2
<
S
,
NOT_REWRITABLE
>
(
target
,
item_str
,
CLASS_ONLY
,
NULL
,
ArgPassSpec
(
value
?
2
:
1
),
item
,
value
);
}
}
#define ISINDEX(x) ((x) == NULL || PyInt_Check(x) || PyLong_Check(x) || PyIndex_Check(x))
extern
"C"
PyObject
*
apply_slice
(
PyObject
*
u
,
PyObject
*
v
,
PyObject
*
w
)
noexcept
/* return u[v:w] */
{
// TODO: add rewriting here
static
int64_t
isSliceIndexHelper
(
Box
*
a
,
Box
*
b
)
{
return
ISINDEX
(
a
)
&&
ISINDEX
(
b
);
}
PyTypeObject
*
tp
=
u
->
cls
;
PySequenceMethods
*
sq
=
tp
->
tp_as_sequence
;
template
<
ExceptionStyle
S
>
static
Box
*
applySliceHelper
(
Box
*
u
,
Box
*
a
,
Box
*
b
)
noexcept
(
S
==
CAPI
)
{
Py_ssize_t
ilow
=
0
,
ihigh
=
PY_SSIZE_T_MAX
;
if
(
!
_PyEval_SliceIndex
(
a
,
&
ilow
))
{
if
(
S
==
CXX
)
throwCAPIException
();
return
NULL
;
}
if
(
!
_PyEval_SliceIndex
(
b
,
&
ihigh
))
{
if
(
S
==
CXX
)
throwCAPIException
();
return
NULL
;
}
if
(
sq
&&
sq
->
sq_slice
&&
ISINDEX
(
v
)
&&
ISINDEX
(
w
))
{
Py_ssize_t
ilow
=
0
,
ihigh
=
PY_SSIZE_T_MAX
;
if
(
!
_PyEval_SliceIndex
(
v
,
&
ilow
))
return
NULL
;
if
(
!
_PyEval_SliceIndex
(
w
,
&
ihigh
))
return
NULL
;
return
PySequence_GetSlice
(
u
,
ilow
,
ihigh
);
}
else
{
PyObject
*
slice
=
PySlice_New
(
v
,
w
,
NULL
);
if
(
slice
!=
NULL
)
{
PyObject
*
res
=
PyObject_GetItem
(
u
,
slice
);
Py_DECREF
(
slice
);
return
res
;
}
else
return
NULL
;
PySequenceMethods
*
sq
=
u
->
cls
->
tp_as_sequence
;
if
(
ilow
<
0
||
ihigh
<
0
)
{
if
(
sq
->
sq_length
)
{
Py_ssize_t
l
=
(
*
sq
->
sq_length
)(
u
);
if
(
l
<
0
)
{
if
(
S
==
CXX
)
throwCAPIException
();
return
NULL
;
}
if
(
ilow
<
0
)
ilow
+=
l
;
if
(
ihigh
<
0
)
ihigh
+=
l
;
}
}
Box
*
rtn
=
sq
->
sq_slice
(
u
,
ilow
,
ihigh
);
if
(
S
==
CXX
&&
!
rtn
)
throwCAPIException
();
return
rtn
;
}
// This function decides whether to call the slice operator (e.g. __getslice__)
// or the item operator (__getitem__).
template
<
ExceptionStyle
S
,
Rewritable
rewritable
>
static
Box
*
callItemOrSliceAttr
(
Box
*
target
,
BoxedString
*
item_str
,
BoxedString
*
slice_str
,
Box
*
slice
,
Box
*
value
,
CallRewriteArgs
*
rewrite_args
)
noexcept
(
S
==
CAPI
)
{
if
(
rewritable
==
NOT_REWRITABLE
)
{
assert
(
!
rewrite_args
);
rewrite_args
=
NULL
;
template
<
ExceptionStyle
S
>
static
int
assignSliceHelper
(
Box
*
u
,
Box
*
a
,
Box
*
b
,
Box
*
x
)
noexcept
(
S
==
CAPI
)
{
Py_ssize_t
ilow
=
0
,
ihigh
=
PY_SSIZE_T_MAX
;
if
(
!
_PyEval_SliceIndex
(
a
,
&
ilow
))
{
if
(
S
==
CXX
)
throwCAPIException
();
return
-
1
;
}
if
(
!
_PyEval_SliceIndex
(
b
,
&
ihigh
))
{
if
(
S
==
CXX
)
throwCAPIException
();
return
-
1
;
}
// 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
);
PySequenceMethods
*
sq
=
u
->
cls
->
tp_as_sequence
;
if
(
ilow
<
0
||
ihigh
<
0
)
{
if
(
sq
->
sq_length
)
{
Py_ssize_t
l
=
(
*
sq
->
sq_length
)(
u
);
if
(
l
<
0
)
{
if
(
S
==
CXX
)
throwCAPIException
();
return
-
1
;
}
if
(
ilow
<
0
)
ilow
+=
l
;
if
(
ihigh
<
0
)
ihigh
+=
l
;
}
return
callItemAttr
<
S
,
rewritable
>
(
target
,
item_str
,
slice
,
value
,
rewrite_args
);
}
// Guard on the type of the object (need to have the slice operator attribute to call it).
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
());
has_slice_attr
=
(
bool
)
typeLookup
(
target
->
cls
,
slice_str
,
&
grewrite_args
);
if
(
!
grewrite_args
.
isSuccessful
())
{
rewrite_args
=
NULL
;
}
else
{
RewriterVar
*
rtn
;
ReturnConvention
return_convention
;
std
::
tie
(
rtn
,
return_convention
)
=
grewrite_args
.
getReturn
();
if
(
return_convention
!=
ReturnConvention
::
HAS_RETURN
&&
return_convention
!=
ReturnConvention
::
NO_RETURN
)
rewrite_args
=
NULL
;
int
rtn
=
sq
->
sq_ass_slice
(
u
,
ilow
,
ihigh
,
x
);
if
(
S
==
CXX
&&
rtn
==
-
1
)
throwCAPIException
();
return
rtn
;
}
if
(
rewrite_args
)
assert
(
has_slice_attr
==
(
return_convention
==
ReturnConvention
::
HAS_RETURN
));
}
static
std
::
pair
<
RewriterVar
*
,
RewriterVar
*>
extractIntSliceStartStop
(
std
::
unique_ptr
<
Rewriter
>&
rewriter
,
PyObject
*
start
,
PyObject
*
stop
,
RewriterVar
*
r_start
,
RewriterVar
*
r_stop
)
{
RewriterVar
*
r_start_int
=
NULL
;
RewriterVar
*
r_stop_int
=
NULL
;
if
(
start
)
{
r_start
->
addGuardNotEq
(
0
);
r_start
->
addAttrGuard
(
offsetof
(
Box
,
cls
),
(
uint64_t
)
int_cls
);
r_start_int
=
r_start
->
getAttr
(
offsetof
(
BoxedInt
,
n
));
r_start_int
->
addGuardNotLt0
();
}
else
{
r_start
->
addGuard
(
0
);
r_start_int
=
rewriter
->
loadConst
(
0
);
}
if
(
stop
)
{
r_stop
->
addGuardNotEq
(
0
);
r_stop
->
addAttrGuard
(
offsetof
(
Box
,
cls
),
(
uint64_t
)
int_cls
);
r_stop_int
=
r_stop
->
getAttr
(
offsetof
(
BoxedInt
,
n
));
r_stop_int
->
addGuardNotLt0
();
}
else
{
has_slice_attr
=
(
bool
)
typeLookup
(
target
->
cls
,
slice_str
);
r_stop
->
addGuard
(
0
);
r_stop_int
=
rewriter
->
loadConst
(
PY_SSIZE_T_MAX
);
}
return
std
::
make_pair
(
r_start_int
,
r_stop_int
);
}
if
(
!
has_slice_attr
)
{
return
callItemAttr
<
S
,
rewritable
>
(
target
,
item_str
,
slice
,
value
,
rewrite_args
);
}
/* return u[v:w] */
template
<
ExceptionStyle
S
>
PyObject
*
applySliceIntern
(
PyObject
*
u
,
PyObject
*
v
,
PyObject
*
w
,
std
::
unique_ptr
<
Rewriter
>&
rewriter
)
noexcept
(
S
==
CAPI
)
{
RewriterVar
*
r_obj
=
NULL
,
*
r_start
=
NULL
,
*
r_stop
=
NULL
,
*
r_cls
=
NULL
,
*
r_sq
=
NULL
;
if
(
rewriter
)
{
r_obj
=
rewriter
->
getArg
(
0
);
r_start
=
rewriter
->
getArg
(
1
);
r_stop
=
rewriter
->
getArg
(
2
);
r_cls
=
r_obj
->
getAttr
(
offsetof
(
Box
,
cls
));
r_sq
=
r_cls
->
getAttr
(
offsetof
(
BoxedClass
,
tp_as_sequence
));
}
PySequenceMethods
*
sq
=
u
->
cls
->
tp_as_sequence
;
if
(
sq
&&
sq
->
sq_slice
&&
isSliceIndexHelper
(
v
,
w
))
{
// call __getslice__
if
(
rewriter
)
{
r_sq
->
addGuardNotEq
(
0
);
r_sq
->
addAttrGuard
(
offsetof
(
PySequenceMethods
,
sq_slice
),
(
intptr_t
)
sq
->
sq_slice
);
// handle int >= 0 and null because it is so frequent
if
((
!
v
||
(
v
->
cls
==
int_cls
&&
(
PyInt_AS_LONG
(
v
)
>=
0
)))
&&
(
!
w
||
(
w
->
cls
==
int_cls
&&
(
PyInt_AS_LONG
(
w
)
>=
0
))))
{
RewriterVar
*
r_start_int
=
NULL
;
RewriterVar
*
r_stop_int
=
NULL
;
std
::
tie
(
r_start_int
,
r_stop_int
)
=
extractIntSliceStartStop
(
rewriter
,
v
,
w
,
r_start
,
r_stop
);
RewriterVar
*
r_rtn
=
rewriter
->
call
(
true
,
(
void
*
)
sq
->
sq_slice
,
r_obj
,
r_start_int
,
r_stop_int
)
->
setType
(
RefType
::
OWNED
);
if
(
S
==
CXX
)
rewriter
->
checkAndThrowCAPIException
(
r_rtn
);
rewriter
->
commitReturning
(
r_rtn
);
}
else
{
RewriterVar
*
r_guard
=
rewriter
->
call
(
false
,
(
void
*
)
isSliceIndexHelper
,
r_start
,
r_stop
);
r_guard
->
addGuardNotEq
(
0
);
// 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
<
S
,
rewritable
>
(
target
,
item_str
,
slice
,
value
,
rewrite_args
);
RewriterVar
*
r_rtn
=
rewriter
->
call
(
true
,
(
void
*
)
&
applySliceHelper
<
S
>
,
r_obj
,
r_start
,
r_stop
)
->
setType
(
RefType
::
OWNED
);
rewriter
->
commitReturning
(
r_rtn
);
}
}
return
applySliceHelper
<
S
>
(
u
,
v
,
w
);
}
BoxedSlice
*
bslice
=
(
BoxedSlice
*
)
slice
;
// call __getitem__
if
(
rewriter
&&
(
!
sq
||
!
sq
->
sq_slice
))
{
// rewrite getitem
if
(
sq
)
{
r_sq
->
addGuardNotEq
(
0
);
r_sq
->
addAttrGuard
(
offsetof
(
PySequenceMethods
,
sq_slice
),
0
);
}
else
r_sq
->
addGuard
(
0
);
// 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
);
}
RewriterVar
*
r_slice
=
rewriter
->
call
(
false
,
(
void
*
)
PySlice_New
,
r_start
,
r_stop
,
rewriter
->
loadConst
(
0ul
))
->
setType
(
RefType
::
OWNED
);
Box
*
slice
=
PySlice_New
(
v
,
w
,
NULL
);
AUTO_DECREF
(
slice
);
return
callItemAttr
<
S
,
rewritable
>
(
target
,
item_str
,
slice
,
value
,
rewrite_args
);
}
else
{
rewrite_args
=
NULL
;
REWRITE_ABORTED
(
""
);
GetitemRewriteArgs
rewrite_args
(
rewriter
.
get
(),
r_obj
,
r_slice
,
rewriter
->
getReturnDestination
());
Box
*
rtn
=
getitemInternal
<
S
>
(
u
,
slice
,
&
rewrite_args
);
// 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
<
S
,
NOT_REWRITABLE
>
(
target
,
item_str
,
slice
,
value
,
rewrite_args
);
if
(
!
rewrite_args
.
out_success
)
{
rewriter
.
reset
(
NULL
);
}
else
if
(
rtn
)
{
rewriter
->
commitReturning
(
rewrite_args
.
out_rtn
);
}
// 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
();
if
(
S
==
CAPI
)
{
if
(
bslice
->
start
!=
None
)
if
(
!
_PyEval_SliceIndex
(
bslice
->
start
,
&
start
))
return
NULL
;
if
(
bslice
->
stop
!=
None
)
if
(
!
_PyEval_SliceIndex
(
bslice
->
stop
,
&
stop
))
return
NULL
;
return
rtn
;
}
else
{
PyObject
*
slice
=
PySlice_New
(
v
,
w
,
NULL
);
if
(
slice
!=
NULL
)
{
PyObject
*
res
=
PyObject_GetItem
(
u
,
slice
);
Py_DECREF
(
slice
);
if
(
S
==
CXX
&&
!
res
)
throwCAPIException
();
return
res
;
}
else
{
sliceIndex
(
bslice
->
start
,
&
start
);
sliceIndex
(
bslice
->
stop
,
&
stop
);
if
(
S
==
CXX
)
throwCAPIException
();
return
NULL
;
}
}
}
adjustNegativeIndicesOnObject
(
target
,
&
start
,
&
stop
);
if
(
PyErr_Occurred
())
throwCAPIException
(
);
extern
"C"
PyObject
*
apply_slice
(
PyObject
*
u
,
PyObject
*
v
,
PyObject
*
w
)
noexcept
{
std
::
unique_ptr
<
Rewriter
>
rewriter
(
Rewriter
::
createRewriter
(
__builtin_extract_return_addr
(
__builtin_return_address
(
0
)),
3
,
"apply_slice"
)
);
Box
*
boxedStart
=
boxInt
(
start
);
Box
*
boxedStop
=
boxInt
(
stop
);
AUTO_DECREF
(
boxedStart
);
AUTO_DECREF
(
boxedStop
);
return
applySliceIntern
<
CAPI
>
(
u
,
v
,
w
,
rewriter
);
}
if
(
rewrite_args
)
{
CallattrRewriteArgs
crewrite_args
(
rewrite_args
);
Box
*
r
;
if
(
value
)
r
=
callattrInternal3
<
S
,
REWRITABLE
>
(
target
,
slice_str
,
CLASS_ONLY
,
&
crewrite_args
,
ArgPassSpec
(
3
),
boxedStart
,
boxedStop
,
value
);
else
r
=
callattrInternal2
<
S
,
REWRITABLE
>
(
target
,
slice_str
,
CLASS_ONLY
,
&
crewrite_args
,
ArgPassSpec
(
2
),
boxedStart
,
boxedStop
);
extern
"C"
PyObject
*
applySlice
(
PyObject
*
u
,
PyObject
*
v
,
PyObject
*
w
)
{
std
::
unique_ptr
<
Rewriter
>
rewriter
(
Rewriter
::
createRewriter
(
__builtin_extract_return_addr
(
__builtin_return_address
(
0
)),
3
,
"apply_slice"
));
if
(
crewrite_args
.
isSuccessful
())
{
rewrite_args
->
out_success
=
true
;
rewrite_args
->
out_rtn
=
crewrite_args
.
getReturn
(
ReturnConvention
::
HAS_RETURN
);
return
applySliceIntern
<
CXX
>
(
u
,
v
,
w
,
rewriter
);
}
/* u[v:w] = x */
template
<
ExceptionStyle
S
>
int
assignSliceInternal
(
PyObject
*
u
,
PyObject
*
v
,
PyObject
*
w
,
PyObject
*
x
,
std
::
unique_ptr
<
Rewriter
>&
rewriter
)
noexcept
(
S
==
CAPI
)
{
PySequenceMethods
*
sq
=
u
->
cls
->
tp_as_sequence
;
if
(
sq
&&
sq
->
sq_ass_slice
&&
isSliceIndexHelper
(
v
,
w
))
{
// call __setslice__ / __delslice__
if
(
rewriter
)
{
RewriterVar
*
r_obj
=
rewriter
->
getArg
(
0
);
RewriterVar
*
r_start
=
rewriter
->
getArg
(
1
);
RewriterVar
*
r_stop
=
rewriter
->
getArg
(
2
);
RewriterVar
*
r_value
=
rewriter
->
getArg
(
3
);
RewriterVar
*
r_cls
=
r_obj
->
getAttr
(
offsetof
(
Box
,
cls
));
RewriterVar
*
r_sq
=
r_cls
->
getAttr
(
offsetof
(
BoxedClass
,
tp_as_sequence
));
r_sq
->
addGuardNotEq
(
0
);
r_sq
->
addAttrGuard
(
offsetof
(
PySequenceMethods
,
sq_ass_slice
),
(
intptr_t
)
sq
->
sq_ass_slice
);
// handle int >= 0 and null because it is so frequent
if
((
!
v
||
(
v
->
cls
==
int_cls
&&
(
PyInt_AS_LONG
(
v
)
>=
0
)))
&&
(
!
w
||
(
w
->
cls
==
int_cls
&&
(
PyInt_AS_LONG
(
w
)
>=
0
))))
{
RewriterVar
*
r_start_int
=
NULL
;
RewriterVar
*
r_stop_int
=
NULL
;
std
::
tie
(
r_start_int
,
r_stop_int
)
=
extractIntSliceStartStop
(
rewriter
,
v
,
w
,
r_start
,
r_stop
);
RewriterVar
*
r_rtn
=
rewriter
->
call
(
true
,
(
void
*
)
sq
->
sq_ass_slice
,
r_obj
,
r_start_int
,
r_stop_int
,
r_value
);
if
(
S
==
CXX
)
{
rewriter
->
checkAndThrowCAPIException
(
r_rtn
,
-
1
,
assembler
::
MovType
::
L
);
rewriter
->
commit
();
}
else
rewriter
->
commitReturningNonPython
(
r_rtn
);
}
else
{
RewriterVar
*
r_guard
=
rewriter
->
call
(
false
,
(
void
*
)
isSliceIndexHelper
,
r_start
,
r_stop
);
r_guard
->
addGuardNotEq
(
0
);
RewriterVar
*
r_rtn
=
rewriter
->
call
(
true
,
(
void
*
)
&
assignSliceHelper
<
S
>
,
r_obj
,
r_start
,
r_stop
,
r_value
);
if
(
S
==
CAPI
)
rewriter
->
commitReturningNonPython
(
r_rtn
);
else
rewriter
->
commit
();
}
return
r
;
}
else
{
if
(
value
)
return
callattrInternal3
<
S
,
NOT_REWRITABLE
>
(
target
,
slice_str
,
CLASS_ONLY
,
NULL
,
ArgPassSpec
(
3
),
boxedStart
,
boxedStop
,
value
);
else
return
callattrInternal2
<
S
,
NOT_REWRITABLE
>
(
target
,
slice_str
,
CLASS_ONLY
,
NULL
,
ArgPassSpec
(
2
),
boxedStart
,
boxedStop
);
}
return
assignSliceHelper
<
S
>
(
u
,
v
,
w
,
x
);
}
// call __setitem__ / __delitem__
PyObject
*
slice
=
PySlice_New
(
v
,
w
,
NULL
);
if
(
slice
!=
NULL
)
{
int
res
;
if
(
x
!=
NULL
)
res
=
PyObject_SetItem
(
u
,
slice
,
x
);
else
res
=
PyObject_DelItem
(
u
,
slice
);
Py_DECREF
(
slice
);
if
(
S
==
CXX
&&
res
==
-
1
)
throwCAPIException
();
return
res
;
}
else
{
if
(
S
==
CXX
)
throwCAPIException
();
return
-
1
;
}
}
extern
"C"
int
assign_slice
(
PyObject
*
u
,
PyObject
*
v
,
PyObject
*
w
,
PyObject
*
x
)
noexcept
{
std
::
unique_ptr
<
Rewriter
>
rewriter
(
Rewriter
::
createRewriter
(
__builtin_extract_return_addr
(
__builtin_return_address
(
0
)),
4
,
"assign_slice"
));
return
assignSliceInternal
<
CAPI
>
(
u
,
v
,
w
,
x
,
rewriter
);
}
extern
"C"
void
assignSlice
(
PyObject
*
u
,
PyObject
*
v
,
PyObject
*
w
,
PyObject
*
x
)
{
std
::
unique_ptr
<
Rewriter
>
rewriter
(
Rewriter
::
createRewriter
(
__builtin_extract_return_addr
(
__builtin_return_address
(
0
)),
4
,
"assign_slice"
));
assignSliceInternal
<
CXX
>
(
u
,
v
,
w
,
x
,
rewriter
);
}
template
<
ExceptionStyle
S
,
Rewritable
rewritable
>
Box
*
getitemInternal
(
Box
*
target
,
Box
*
slice
,
GetitemRewriteArgs
*
rewrite_args
)
noexcept
(
S
==
CAPI
)
{
if
(
rewritable
==
NOT_REWRITABLE
)
{
...
...
@@ -6303,7 +6413,6 @@ Box* getitemInternal(Box* target, Box* slice, GetitemRewriteArgs* rewrite_args)
}
static
BoxedString
*
getitem_str
=
getStaticString
(
"__getitem__"
);
static
BoxedString
*
getslice_str
=
getStaticString
(
"__getslice__"
);
Box
*
rtn
;
try
{
...
...
@@ -6311,7 +6420,7 @@ Box* getitemInternal(Box* target, Box* slice, GetitemRewriteArgs* rewrite_args)
CallRewriteArgs
crewrite_args
(
rewrite_args
->
rewriter
,
rewrite_args
->
target
,
rewrite_args
->
destination
);
crewrite_args
.
arg1
=
rewrite_args
->
slice
;
rtn
=
callItem
OrSliceAttr
<
S
,
REWRITABLE
>
(
target
,
getitem_str
,
getslice
_str
,
slice
,
NULL
,
&
crewrite_args
);
rtn
=
callItem
Attr
<
S
,
REWRITABLE
>
(
target
,
getitem
_str
,
slice
,
NULL
,
&
crewrite_args
);
if
(
!
crewrite_args
.
out_success
)
{
rewrite_args
=
NULL
;
...
...
@@ -6319,7 +6428,7 @@ Box* getitemInternal(Box* target, Box* slice, GetitemRewriteArgs* rewrite_args)
rewrite_args
->
out_rtn
=
crewrite_args
.
out_rtn
;
}
}
else
{
rtn
=
callItem
OrSliceAttr
<
S
,
NOT_REWRITABLE
>
(
target
,
getitem_str
,
getslice
_str
,
slice
,
NULL
,
NULL
);
rtn
=
callItem
Attr
<
S
,
NOT_REWRITABLE
>
(
target
,
getitem
_str
,
slice
,
NULL
,
NULL
);
}
}
catch
(
ExcInfo
e
)
{
if
(
S
==
CAPI
)
{
...
...
@@ -6358,13 +6467,13 @@ Box* getitemInternal(Box* target, Box* slice, GetitemRewriteArgs* rewrite_args)
return
rtn
;
}
// Force instantiation of the template
template
Box
*
getitemInternal
<
CAPI
,
REWRITABLE
>(
Box
*
,
Box
*
,
GetitemRewriteArgs
*
);
template
Box
*
getitemInternal
<
CAPI
,
REWRITABLE
>(
Box
*
,
Box
*
,
GetitemRewriteArgs
*
)
noexcept
;
template
Box
*
getitemInternal
<
CXX
,
REWRITABLE
>(
Box
*
,
Box
*
,
GetitemRewriteArgs
*
);
template
Box
*
getitemInternal
<
CAPI
,
NOT_REWRITABLE
>(
Box
*
,
Box
*
,
GetitemRewriteArgs
*
);
template
Box
*
getitemInternal
<
CAPI
,
NOT_REWRITABLE
>(
Box
*
,
Box
*
,
GetitemRewriteArgs
*
)
noexcept
;
template
Box
*
getitemInternal
<
CXX
,
NOT_REWRITABLE
>(
Box
*
,
Box
*
,
GetitemRewriteArgs
*
);
// target[slice]
extern
"C"
Box
*
getitem
(
Box
*
target
,
Box
*
slice
)
{
template
<
ExceptionStyle
S
>
static
Box
*
getitemEntry
(
Box
*
target
,
Box
*
slice
,
void
*
return_addr
)
noexcept
(
S
==
CAPI
)
{
STAT_TIMER
(
t0
,
"us_timer_slowpath_getitem"
,
10
);
// This possibly could just be represented as a single callattr; the only tricky part
...
...
@@ -6374,66 +6483,33 @@ extern "C" Box* getitem(Box* target, Box* slice) {
static
StatCounter
slowpath_getitem
(
"slowpath_getitem"
);
slowpath_getitem
.
log
();
std
::
unique_ptr
<
Rewriter
>
rewriter
(
Rewriter
::
createRewriter
(
__builtin_extract_return_addr
(
__builtin_return_address
(
0
)),
2
,
"getitem"
));
std
::
unique_ptr
<
Rewriter
>
rewriter
(
Rewriter
::
createRewriter
(
return_addr
,
2
,
"getitem"
));
Box
*
rtn
;
if
(
rewriter
.
get
())
{
GetitemRewriteArgs
rewrite_args
(
rewriter
.
get
(),
rewriter
->
getArg
(
0
),
rewriter
->
getArg
(
1
),
rewriter
->
getReturnDestination
());
rtn
=
getitemInternal
<
CXX
>
(
target
,
slice
,
&
rewrite_args
);
rtn
=
getitemInternal
<
S
,
REWRITABLE
>
(
target
,
slice
,
&
rewrite_args
);
if
(
!
rewrite_args
.
out_success
)
{
rewriter
.
reset
(
NULL
);
}
else
{
}
else
if
(
rtn
)
{
rewriter
->
commitReturning
(
rewrite_args
.
out_rtn
);
}
}
else
{
rtn
=
getitemInternal
<
CXX
>
(
target
,
slice
);
rtn
=
getitemInternal
<
S
>
(
target
,
slice
);
}
assert
(
rtn
);
return
rtn
;
}
// target[slice]
extern
"C"
Box
*
getitem_capi
(
Box
*
target
,
Box
*
slice
)
noexcept
{
STAT_TIMER
(
t0
,
"us_timer_slowpath_getitem"
,
10
);
// This possibly could just be represented as a single callattr; the only tricky part
// are the error messages.
// Ex "(1)[1]" and "(1).__getitem__(1)" give different error messages.
static
StatCounter
slowpath_getitem
(
"slowpath_getitem"
);
slowpath_getitem
.
log
();
std
::
unique_ptr
<
Rewriter
>
rewriter
(
Rewriter
::
createRewriter
(
__builtin_extract_return_addr
(
__builtin_return_address
(
0
)),
2
,
"getitem"
));
Box
*
rtn
;
if
(
rewriter
.
get
())
{
GetitemRewriteArgs
rewrite_args
(
rewriter
.
get
(),
rewriter
->
getArg
(
0
),
rewriter
->
getArg
(
1
),
rewriter
->
getReturnDestination
());
rtn
=
getitemInternal
<
CAPI
>
(
target
,
slice
,
&
rewrite_args
);
if
(
!
rewrite_args
.
out_success
)
{
rewriter
.
reset
(
NULL
);
}
else
if
(
rtn
)
{
rewriter
->
commitReturning
(
rewrite_args
.
out_rtn
);
}
}
else
{
rtn
=
getitemInternal
<
CAPI
>
(
target
,
slice
);
}
return
rtn
;
extern
"C"
Box
*
getitem
(
Box
*
target
,
Box
*
slice
)
{
return
getitemEntry
<
CXX
>
(
target
,
slice
,
__builtin_extract_return_addr
(
__builtin_return_address
(
0
)));
}
static
void
setitemHelper
(
Box
*
target
,
Box
*
slice
,
Box
*
value
)
{
int
ret
=
target
->
cls
->
tp_as_mapping
->
mp_ass_subscript
(
target
,
slice
,
value
);
if
(
ret
==
-
1
)
throwCAPIException
();
extern
"C"
Box
*
getitem_capi
(
Box
*
target
,
Box
*
slice
)
noexcept
{
return
getitemEntry
<
CAPI
>
(
target
,
slice
,
__builtin_extract_return_addr
(
__builtin_return_address
(
0
)));
}
// target[slice] = value
...
...
@@ -6447,7 +6523,6 @@ 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
=
getStaticString
(
"__setitem__"
);
static
BoxedString
*
setslice_str
=
getStaticString
(
"__setslice__"
);
auto
&&
m
=
target
->
cls
->
tp_as_mapping
;
if
(
m
&&
m
->
mp_ass_subscript
&&
m
->
mp_ass_subscript
!=
slot_mp_ass_subscript
)
{
...
...
@@ -6458,11 +6533,15 @@ extern "C" void setitem(Box* target, Box* slice, Box* value) {
RewriterVar
*
r_cls
=
r_obj
->
getAttr
(
offsetof
(
Box
,
cls
));
RewriterVar
*
r_m
=
r_cls
->
getAttr
(
offsetof
(
BoxedClass
,
tp_as_mapping
));
r_m
->
addGuardNotEq
(
0
);
rewriter
->
call
(
true
,
(
void
*
)
setitemHelper
,
r_obj
,
r_slice
,
r_value
);
r_m
->
addAttrGuard
(
offsetof
(
PyMappingMethods
,
mp_ass_subscript
),
(
intptr_t
)
m
->
mp_ass_subscript
);
RewriterVar
*
r_ret
=
rewriter
->
call
(
true
,
(
void
*
)
m
->
mp_ass_subscript
,
r_obj
,
r_slice
,
r_value
);
rewriter
->
checkAndThrowCAPIException
(
r_ret
,
-
1
,
assembler
::
MovType
::
L
);
rewriter
->
commit
();
}
setitemHelper
(
target
,
slice
,
value
);
int
ret
=
m
->
mp_ass_subscript
(
target
,
slice
,
value
);
if
(
ret
==
-
1
)
throwCAPIException
();
return
;
}
...
...
@@ -6472,13 +6551,13 @@ extern "C" void setitem(Box* target, Box* slice, Box* value) {
rewrite_args
.
arg1
=
rewriter
->
getArg
(
1
);
rewrite_args
.
arg2
=
rewriter
->
getArg
(
2
);
rtn
=
callItem
OrSliceAttr
<
CXX
,
REWRITABLE
>
(
target
,
setitem_str
,
setslice
_str
,
slice
,
value
,
&
rewrite_args
);
rtn
=
callItem
Attr
<
CXX
,
REWRITABLE
>
(
target
,
setitem
_str
,
slice
,
value
,
&
rewrite_args
);
if
(
!
rewrite_args
.
out_success
)
{
rewriter
.
reset
(
NULL
);
}
}
else
{
rtn
=
callItem
OrSliceAttr
<
CXX
,
NOT_REWRITABLE
>
(
target
,
setitem_str
,
setslice
_str
,
slice
,
value
,
NULL
);
rtn
=
callItem
Attr
<
CXX
,
NOT_REWRITABLE
>
(
target
,
setitem
_str
,
slice
,
value
,
NULL
);
}
if
(
rtn
==
NULL
)
{
...
...
@@ -6501,20 +6580,18 @@ extern "C" void delitem(Box* target, Box* slice) {
Rewriter
::
createRewriter
(
__builtin_extract_return_addr
(
__builtin_return_address
(
0
)),
2
,
"delitem"
));
static
BoxedString
*
delitem_str
=
getStaticString
(
"__delitem__"
);
static
BoxedString
*
delslice_str
=
getStaticString
(
"__delslice__"
);
Box
*
rtn
;
if
(
rewriter
.
get
())
{
CallRewriteArgs
rewrite_args
(
rewriter
.
get
(),
rewriter
->
getArg
(
0
),
rewriter
->
getReturnDestination
());
rewrite_args
.
arg1
=
rewriter
->
getArg
(
1
);
rtn
=
callItem
OrSliceAttr
<
CXX
,
REWRITABLE
>
(
target
,
delitem_str
,
delslice
_str
,
slice
,
NULL
,
&
rewrite_args
);
rtn
=
callItem
Attr
<
CXX
,
REWRITABLE
>
(
target
,
delitem
_str
,
slice
,
NULL
,
&
rewrite_args
);
if
(
!
rewrite_args
.
out_success
)
{
rewriter
.
reset
(
NULL
);
}
}
else
{
rtn
=
callItem
OrSliceAttr
<
CXX
,
NOT_REWRITABLE
>
(
target
,
delitem_str
,
delslice
_str
,
slice
,
NULL
,
NULL
);
rtn
=
callItem
Attr
<
CXX
,
NOT_REWRITABLE
>
(
target
,
delitem
_str
,
slice
,
NULL
,
NULL
);
}
if
(
rtn
==
NULL
)
{
...
...
src/runtime/objmodel.h
View file @
4d4d78ae
...
...
@@ -88,6 +88,9 @@ extern "C" Box* getitem_capi(Box* value, Box* slice) noexcept __attribute__((noi
extern
"C"
void
setitem
(
Box
*
target
,
Box
*
slice
,
Box
*
value
)
__attribute__
((
noinline
));
extern
"C"
void
delitem
(
Box
*
target
,
Box
*
slice
)
__attribute__
((
noinline
));
extern
"C"
PyObject
*
apply_slice
(
PyObject
*
u
,
PyObject
*
v
,
PyObject
*
w
)
noexcept
;
extern
"C"
PyObject
*
applySlice
(
PyObject
*
u
,
PyObject
*
v
,
PyObject
*
w
);
extern
"C"
int
assign_slice
(
PyObject
*
u
,
PyObject
*
v
,
PyObject
*
w
,
PyObject
*
x
)
noexcept
;
extern
"C"
void
assignSlice
(
PyObject
*
u
,
PyObject
*
v
,
PyObject
*
w
,
PyObject
*
x
);
extern
"C"
Box
*
getclsattr
(
Box
*
obj
,
BoxedString
*
attr
)
__attribute__
((
noinline
));
extern
"C"
Box
*
getclsattrMaybeNonstring
(
Box
*
obj
,
Box
*
attr
)
__attribute__
((
noinline
));
extern
"C"
Box
*
unaryop
(
Box
*
operand
,
int
op_type
)
__attribute__
((
noinline
));
...
...
test/test_extension/slots_test.c
View file @
4d4d78ae
...
...
@@ -326,7 +326,7 @@ static PyTypeObject slots_tester_map= {
0
,
/* tp_getattro */
0
,
/* tp_setattro */
0
,
/* tp_as_buffer */
Py_TPFLAGS_DEFAULT
,
/* tp_flags */
Py_TPFLAGS_DEFAULT
|
Py_TPFLAGS_BASETYPE
,
/* tp_flags */
0
,
/* tp_doc */
0
,
/* tp_traverse */
0
,
/* tp_clear */
...
...
test/tests/capi_slots.py
View file @
4d4d78ae
...
...
@@ -242,3 +242,12 @@ class C(object):
c
=
C
()
proxy
=
weakref
.
proxy
(
c
)
print
isinstance
(
proxy
,
C
)
# test if __setslice__ is prioritised over mp_ass_subscript
class
D
(
slots_test
.
SlotsTesterMap
):
def
__setslice__
(
self
,
*
args
):
print
"setslice"
,
args
d
=
D
(
1
)
for
i
in
xrange
(
10
):
print
i
d
[
1
:
2
]
=
1
test/tests/slice.py
View file @
4d4d78ae
...
...
@@ -101,11 +101,13 @@ sliceable[3:8]
both
[
0
]
both
[:]
both
[
3
:
8
]
both
[
slice
(
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
[
slice
(
3
,
8
)]
=
xrange
(
2
)
both
[::
2
]
=
xrange
(
2
)
# Should all call getitem as a fallback
...
...
@@ -118,6 +120,7 @@ both[1:2:'c']
del
both
[
0
]
del
both
[:]
del
both
[
3
:
8
]
del
both
[
slice
(
3
,
8
)]
del
both
[::
2
]
try
:
...
...
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