Commit e4938dd2 authored by Marius Wachtler's avatar Marius Wachtler

only lookup __[set/get/del]slice__ for slice AST nodes

before this change
C()[slice(1,2)] = "a"
would call into `__setslice__` because it got handled as
C()[1,2] = "a"

This commits adds cpythons assign_slice/apply_slice and add rewriter support for them.
parent 2edfc49b
...@@ -287,24 +287,29 @@ void RewriterVar::addGuard(uint64_t val) { ...@@ -287,24 +287,29 @@ void RewriterVar::addGuard(uint64_t val) {
rewriter->addAction([=]() { rewriter->_addGuard(this, val_var); }, { this, val_var }, ActionType::GUARD); 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. // 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 // 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. // 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. // 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; int last_jmp_offset = -1;
auto condition = condition_eq ? assembler::COND_EQUAL : assembler::COND_NOT_EQUAL; 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) { if (last_jmp_offset != -1 && assembler->bytesWritten() - last_jmp_offset < 0x80) {
assembler->jmp_cond(assembler::JumpDestination::fromStart(last_jmp_offset), condition); assembler->jmp_cond(assembler::JumpDestination::fromStart(last_jmp_offset), condition);
} else { } else {
last_jmp_offset = assembler->bytesWritten(); int last_jmp_offset = assembler->bytesWritten();
assembler->jmp_cond(assembler::JumpDestination::fromStart(rewrite->getSlotSize()), condition); assembler->jmp_cond(assembler::JumpDestination::fromStart(rewrite->getSlotSize()), condition);
next_slot_jmps.emplace_back(last_jmp_offset, assembler->bytesWritten(), 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) if (LOG_IC_ASSEMBLY)
assembler->comment("_addGuard"); assembler->comment("_addGuard");
...@@ -316,12 +321,15 @@ void Rewriter::_addGuard(RewriterVar* var, RewriterVar* val_constant) { ...@@ -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::Register reg = val_constant->getInReg(Location::any(), true, /* otherThan */ var_reg);
assembler->cmp(var_reg, reg); assembler->cmp(var_reg, reg);
} else { } 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 restoreArgs(); // can only do movs, doesn't affect flags, so it's safe
assertArgsInPlace(); assertArgsInPlace();
_nextSlotJump(false /*= not equal jmp */); _nextSlotJump(negate ? assembler::COND_EQUAL : assembler::COND_NOT_EQUAL);
var->bumpUse(); var->bumpUse();
val_constant->bumpUse(); val_constant->bumpUse();
...@@ -333,32 +341,24 @@ void RewriterVar::addGuardNotEq(uint64_t val) { ...@@ -333,32 +341,24 @@ void RewriterVar::addGuardNotEq(uint64_t val) {
STAT_TIMER(t0, "us_timer_rewriter", 10); STAT_TIMER(t0, "us_timer_rewriter", 10);
RewriterVar* val_var = rewriter->loadConst(val); 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) { void RewriterVar::addGuardNotLt0() {
if (LOG_IC_ASSEMBLY) rewriter->addAction([=]() {
assembler->comment("_addGuardNotEq"); assembler::Register var_reg = this->getInReg();
rewriter->assembler->test(var_reg, var_reg);
assert(val_constant->is_constant); rewriter->restoreArgs(); // can only do movs, doesn't affect flags, so it's safe
uint64_t val = val_constant->constant_value; rewriter->assertArgsInPlace();
assembler::Register var_reg = var->getInReg(); rewriter->_nextSlotJump(assembler::COND_SIGN);
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 */);
var->bumpUse(); bumpUse();
val_constant->bumpUse(); rewriter->assertConsistent();
assertConsistent(); }, { this }, ActionType::GUARD);
} }
void RewriterVar::addAttrGuard(int offset, uint64_t val, bool negate) { void RewriterVar::addAttrGuard(int offset, uint64_t val, bool negate) {
...@@ -405,7 +405,7 @@ void Rewriter::_addAttrGuard(RewriterVar* var, int offset, RewriterVar* val_cons ...@@ -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 restoreArgs(); // can only do movs, doesn't affect flags, so it's safe
assertArgsInPlace(); assertArgsInPlace();
_nextSlotJump(negate); _nextSlotJump(negate ? assembler::COND_EQUAL : assembler::COND_NOT_EQUAL);
var->bumpUse(); var->bumpUse();
val_constant->bumpUse(); val_constant->bumpUse();
...@@ -2220,8 +2220,6 @@ Rewriter::Rewriter(std::unique_ptr<ICSlotRewrite> rewrite, int num_args, const L ...@@ -2220,8 +2220,6 @@ Rewriter::Rewriter(std::unique_ptr<ICSlotRewrite> rewrite, int num_args, const L
marked_inside_ic(false), marked_inside_ic(false),
done_guarding(false), done_guarding(false),
last_guard_action(-1), last_guard_action(-1),
offset_eq_jmp_next_slot(-1),
offset_ne_jmp_next_slot(-1),
allocatable_regs(std_allocatable_regs) { allocatable_regs(std_allocatable_regs) {
initPhaseCollecting(); initPhaseCollecting();
......
...@@ -147,6 +147,7 @@ public: ...@@ -147,6 +147,7 @@ public:
void addGuard(uint64_t val); void addGuard(uint64_t val);
void addGuardNotEq(uint64_t val); void addGuardNotEq(uint64_t val);
void addGuardNotLt0();
void addAttrGuard(int offset, uint64_t val, bool negate = false); void addAttrGuard(int offset, uint64_t val, bool negate = false);
RewriterVar* getAttr(int offset, Location loc = Location::any(), assembler::MovType type = assembler::MovType::Q); RewriterVar* getAttr(int offset, Location loc = Location::any(), assembler::MovType type = assembler::MovType::Q);
// getAttrFloat casts to double (maybe I should make that separate?) // getAttrFloat casts to double (maybe I should make that separate?)
...@@ -502,8 +503,6 @@ protected: ...@@ -502,8 +503,6 @@ protected:
} }
int last_guard_action; 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 // 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; std::vector<NextSlotJumpInfo> next_slot_jmps;
...@@ -540,7 +539,7 @@ protected: ...@@ -540,7 +539,7 @@ protected:
bool finishAssembly(int continue_offset, bool& should_fill_with_nops, bool& variable_size_slots) override; 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 _trap();
void _loadConst(RewriterVar* result, int64_t val); void _loadConst(RewriterVar* result, int64_t val);
void _setupCall(bool has_side_effects, llvm::ArrayRef<RewriterVar*> args = {}, void _setupCall(bool has_side_effects, llvm::ArrayRef<RewriterVar*> args = {},
...@@ -557,8 +556,7 @@ protected: ...@@ -557,8 +556,7 @@ protected:
void _checkAndThrowCAPIException(RewriterVar* r, int64_t exc_val, assembler::MovType size); void _checkAndThrowCAPIException(RewriterVar* r, int64_t exc_val, assembler::MovType size);
// The public versions of these are in RewriterVar // The public versions of these are in RewriterVar
void _addGuard(RewriterVar* var, RewriterVar* val_constant); void _addGuard(RewriterVar* var, RewriterVar* val_constant, bool negate = false);
void _addGuardNotEq(RewriterVar* var, RewriterVar* val_constant);
void _addAttrGuard(RewriterVar* var, int offset, 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(), void _getAttr(RewriterVar* result, RewriterVar* var, int offset, Location loc = Location::any(),
assembler::MovType type = assembler::MovType::Q); assembler::MovType type = assembler::MovType::Q);
......
...@@ -1242,7 +1242,7 @@ static int slot_tp_descr_set(PyObject* self, PyObject* target, PyObject* value) ...@@ -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 { PyObject* slot_sq_item(PyObject* self, Py_ssize_t i) noexcept {
STAT_TIMER(t0, "us_timer_slot_sqitem", SLOT_AVOIDABILITY(self)); 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 { /* Pyston change: static */ Py_ssize_t slot_sq_length(PyObject* self) noexcept {
......
...@@ -554,12 +554,27 @@ void ASTInterpreter::doStore(AST_expr* node, STOLEN(Value) value) { ...@@ -554,12 +554,27 @@ void ASTInterpreter::doStore(AST_expr* node, STOLEN(Value) value) {
Value target = visit_expr(subscript->value); Value target = visit_expr(subscript->value);
AUTO_DECREF(target.o); AUTO_DECREF(target.o);
Value slice = visit_slice(subscript->slice); bool is_slice = (subscript->slice->type == AST_TYPE::Slice) && (((AST_Slice*)subscript->slice)->step == NULL);
AUTO_DECREF(slice.o); 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) if (jit)
jit->emitSetItem(target, slice, value); jit->emitAssignSlice(target, lower, upper, value);
setitem(target.o, slice.o, value.o); 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 { } else {
RELEASE_ASSERT(0, "not implemented"); RELEASE_ASSERT(0, "not implemented");
} }
...@@ -1321,11 +1336,26 @@ Value ASTInterpreter::visit_delete(AST_Delete* node) { ...@@ -1321,11 +1336,26 @@ Value ASTInterpreter::visit_delete(AST_Delete* node) {
AST_Subscript* sub = (AST_Subscript*)target_; AST_Subscript* sub = (AST_Subscript*)target_;
Value value = visit_expr(sub->value); Value value = visit_expr(sub->value);
AUTO_DECREF(value.o); AUTO_DECREF(value.o);
Value slice = visit_slice(sub->slice);
AUTO_DECREF(slice.o); bool is_slice = (sub->slice->type == AST_TYPE::Slice) && (((AST_Slice*)sub->slice)->step == NULL);
if (jit) if (is_slice) {
jit->emitDelItem(value, slice); AST_Slice* slice = (AST_Slice*)sub->slice;
delitem(value.o, slice.o); 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; break;
} }
case AST_TYPE::Attribute: { case AST_TYPE::Attribute: {
...@@ -1735,10 +1765,31 @@ Value ASTInterpreter::visit_name(AST_Name* node) { ...@@ -1735,10 +1765,31 @@ Value ASTInterpreter::visit_name(AST_Name* node) {
Value ASTInterpreter::visit_subscript(AST_Subscript* node) { Value ASTInterpreter::visit_subscript(AST_Subscript* node) {
Value value = visit_expr(node->value); Value value = visit_expr(node->value);
AUTO_DECREF(value.o); 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) { Value ASTInterpreter::visit_list(AST_List* node) {
......
...@@ -208,6 +208,14 @@ RewriterVar* JitFragmentWriter::emitAugbinop(AST_expr* node, RewriterVar* lhs, R ...@@ -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); 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) { 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); 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) { ...@@ -553,6 +561,15 @@ RewriterVar* JitFragmentWriter::emitYield(RewriterVar* v) {
return rtn; 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) { void JitFragmentWriter::emitDelAttr(RewriterVar* target, BoxedString* attr) {
emitPPCall((void*)delattr, { target, imm(attr) }, 144).first; emitPPCall((void*)delattr, { target, imm(attr) }, 144).first;
} }
......
...@@ -239,6 +239,7 @@ public: ...@@ -239,6 +239,7 @@ public:
RewriterVar* imm(void* val); RewriterVar* imm(void* val);
RewriterVar* emitAugbinop(AST_expr* node, RewriterVar* lhs, RewriterVar* rhs, int op_type); 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* emitBinop(AST_expr* node, RewriterVar* lhs, RewriterVar* rhs, int op_type);
RewriterVar* emitCallattr(AST_expr* node, RewriterVar* obj, BoxedString* attr, CallattrFlags flags, RewriterVar* emitCallattr(AST_expr* node, RewriterVar* obj, BoxedString* attr, CallattrFlags flags,
const llvm::ArrayRef<RewriterVar*> args, std::vector<BoxedString*>* keyword_names); const llvm::ArrayRef<RewriterVar*> args, std::vector<BoxedString*>* keyword_names);
...@@ -275,6 +276,7 @@ public: ...@@ -275,6 +276,7 @@ public:
std::vector<RewriterVar*> emitUnpackIntoArray(RewriterVar* v, uint64_t num); std::vector<RewriterVar*> emitUnpackIntoArray(RewriterVar* v, uint64_t num);
RewriterVar* emitYield(RewriterVar* v); RewriterVar* emitYield(RewriterVar* v);
void emitAssignSlice(RewriterVar* target, RewriterVar* lower, RewriterVar* upper, RewriterVar* value);
void emitDelAttr(RewriterVar* target, BoxedString* attr); void emitDelAttr(RewriterVar* target, BoxedString* attr);
void emitDelGlobal(BoxedString* name); void emitDelGlobal(BoxedString* name);
void emitDelItem(RewriterVar* target, RewriterVar* slice); void emitDelItem(RewriterVar* target, RewriterVar* slice);
......
...@@ -331,6 +331,9 @@ public: ...@@ -331,6 +331,9 @@ public:
CompilerVariable* getitem(IREmitter& emitter, const OpInfo& info, ConcreteCompilerVariable* var, CompilerVariable* getitem(IREmitter& emitter, const OpInfo& info, ConcreteCompilerVariable* var,
CompilerVariable* slice) override { CompilerVariable* slice) override {
ExceptionStyle target_exception_style = info.preferredExceptionStyle();
bool do_patchpoint = ENABLE_ICGETITEMS;
if (slice->getType() == UNBOXED_SLICE) { if (slice->getType() == UNBOXED_SLICE) {
UnboxedSlice slice_val = extractSlice(slice); UnboxedSlice slice_val = extractSlice(slice);
...@@ -340,31 +343,37 @@ public: ...@@ -340,31 +343,37 @@ public:
= var->getType()->getattrType(attr, true)->callType(ArgPassSpec(1), { SLICE }, NULL); = var->getType()->getattrType(attr, true)->callType(ArgPassSpec(1), { SLICE }, NULL);
assert(return_type->getConcreteType() == return_type); assert(return_type->getConcreteType() == return_type);
if (return_type != UNDEF) { llvm::Value* cstart, *cstop;
llvm::Value* cstart, *cstop; cstart = slice_val.start ? slice_val.start->makeConverted(emitter, UNKNOWN)->getValue()
cstart = slice_val.start ? slice_val.start->makeConverted(emitter, UNKNOWN)->getValue() : emitter.setType(getNullPtr(g.llvm_value_type_ptr), RefType::BORROWED);
: emitter.setType(getNullPtr(g.llvm_value_type_ptr), RefType::BORROWED); cstop = slice_val.stop ? slice_val.stop->makeConverted(emitter, UNKNOWN)->getValue()
cstop = slice_val.stop ? slice_val.stop->makeConverted(emitter, UNKNOWN)->getValue() : emitter.setType(getNullPtr(g.llvm_value_type_ptr), RefType::BORROWED);
: emitter.setType(getNullPtr(g.llvm_value_type_ptr), RefType::BORROWED); llvm::Value* r = NULL;
if (do_patchpoint) {
llvm::Value* r = emitter.createCall3(info.unw_info, g.funcs.apply_slice, var->getValue(), cstart, ICSetupInfo* pp = createGetitemIC(info.getTypeRecorder(), info.getBJitICInfo());
cstop, CAPI, getNullPtr(g.llvm_value_type_ptr)); llvm::Instruction* uncasted = emitter.createIC(
emitter.setType(r, RefType::OWNED); 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); emitter.setNullable(r, true);
if (return_type != UNDEF)
return new ConcreteCompilerVariable(static_cast<ConcreteCompilerType*>(return_type), r); return new ConcreteCompilerVariable(static_cast<ConcreteCompilerType*>(return_type), r);
} else { return new ConcreteCompilerVariable(UNKNOWN, r);
// 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
}
} }
} }
ConcreteCompilerVariable* converted_slice = slice->makeConverted(emitter, slice->getBoxType()); ConcreteCompilerVariable* converted_slice = slice->makeConverted(emitter, slice->getBoxType());
ExceptionStyle target_exception_style = info.preferredExceptionStyle();
bool do_patchpoint = ENABLE_ICGETITEMS;
llvm::Value* rtn; llvm::Value* rtn;
if (do_patchpoint) { if (do_patchpoint) {
ICSetupInfo* pp = createGetitemIC(info.getTypeRecorder(), info.getBJitICInfo()); ICSetupInfo* pp = createGetitemIC(info.getTypeRecorder(), info.getBJitICInfo());
......
...@@ -1508,7 +1508,6 @@ private: ...@@ -1508,7 +1508,6 @@ private:
CompilerVariable* evalSubscript(AST_Subscript* node, const UnwindInfo& unw_info) { CompilerVariable* evalSubscript(AST_Subscript* node, const UnwindInfo& unw_info) {
CompilerVariable* value = evalExpr(node->value, unw_info); CompilerVariable* value = evalExpr(node->value, unw_info);
CompilerVariable* slice = evalSlice(node->slice, unw_info); CompilerVariable* slice = evalSlice(node->slice, unw_info);
CompilerVariable* rtn = value->getitem(emitter, getOpInfoForNode(node, unw_info), slice); CompilerVariable* rtn = value->getitem(emitter, getOpInfoForNode(node, unw_info), slice);
return rtn; return rtn;
} }
...@@ -1992,31 +1991,59 @@ private: ...@@ -1992,31 +1991,59 @@ private:
t->setattr(emitter, getEmptyOpInfo(unw_info), target->attr.getBox(), val); t->setattr(emitter, getEmptyOpInfo(unw_info), target->attr.getBox(), val);
} }
void _doSetitem(AST_Subscript* target, CompilerVariable* val, const UnwindInfo& unw_info) { void _assignSlice(llvm::Value* target, llvm::Value* value, const UnboxedSlice& slice_val,
CompilerVariable* tget = evalExpr(target->value, unw_info); const UnwindInfo& unw_info) {
CompilerVariable* slice = evalSlice(target->slice, unw_info); llvm::Value* cstart, *cstop;
cstart = slice_val.start ? slice_val.start->makeConverted(emitter, UNKNOWN)->getValue()
ConcreteCompilerVariable* converted_target = tget->makeConverted(emitter, tget->getBoxType()); : emitter.setType(getNullPtr(g.llvm_value_type_ptr), RefType::BORROWED);
ConcreteCompilerVariable* converted_slice = slice->makeConverted(emitter, slice->getBoxType()); cstop = slice_val.stop ? slice_val.stop->makeConverted(emitter, UNKNOWN)->getValue()
: emitter.setType(getNullPtr(g.llvm_value_type_ptr), RefType::BORROWED);
ConcreteCompilerVariable* converted_val = val->makeConverted(emitter, val->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; bool do_patchpoint = ENABLE_ICSETITEMS;
if (do_patchpoint) { if (do_patchpoint) {
ICSetupInfo* pp = createSetitemIC(getEmptyOpInfo(unw_info).getTypeRecorder()); ICSetupInfo* pp = createSetitemIC(getEmptyOpInfo(unw_info).getTypeRecorder());
std::vector<llvm::Value*> llvm_args; std::vector<llvm::Value*> llvm_args;
llvm_args.push_back(converted_target->getValue()); llvm_args.push_back(target);
llvm_args.push_back(converted_slice->getValue()); llvm_args.push_back(cstart);
llvm_args.push_back(converted_val->getValue()); 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 { } else {
emitter.createCall3(unw_info, g.funcs.setitem, converted_target->getValue(), converted_slice->getValue(), emitter.createCall(unw_info, g.funcs.assignSlice, { target, cstart, cstop, value });
converted_val->getValue()); }
}
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());
}
} }
} }
...@@ -2125,19 +2152,27 @@ private: ...@@ -2125,19 +2152,27 @@ private:
CompilerVariable* slice = evalSlice(target->slice, unw_info); CompilerVariable* slice = evalSlice(target->slice, unw_info);
ConcreteCompilerVariable* converted_target = tget->makeConverted(emitter, tget->getBoxType()); ConcreteCompilerVariable* converted_target = tget->makeConverted(emitter, tget->getBoxType());
ConcreteCompilerVariable* converted_slice = slice->makeConverted(emitter, slice->getBoxType());
bool do_patchpoint = ENABLE_ICDELITEMS; if (slice->getType() == UNBOXED_SLICE && !extractSlice(slice).step) {
if (do_patchpoint) { _assignSlice(converted_target->getValue(),
ICSetupInfo* pp = createDelitemIC(getEmptyOpInfo(unw_info).getTypeRecorder()); 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; bool do_patchpoint = ENABLE_ICDELITEMS;
llvm_args.push_back(converted_target->getValue()); if (do_patchpoint) {
llvm_args.push_back(converted_slice->getValue()); ICSetupInfo* pp = createDelitemIC(getEmptyOpInfo(unw_info).getTypeRecorder());
emitter.createIC(pp, (void*)pyston::delitem, llvm_args, unw_info); std::vector<llvm::Value*> llvm_args;
} else { llvm_args.push_back(converted_target->getValue());
emitter.createCall2(unw_info, g.funcs.delitem, converted_target->getValue(), converted_slice->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());
}
} }
} }
......
...@@ -229,6 +229,8 @@ void initGlobalFuncs(GlobalState& g) { ...@@ -229,6 +229,8 @@ void initGlobalFuncs(GlobalState& g) {
GET(getiterHelper); GET(getiterHelper);
GET(hasnext); GET(hasnext);
GET(apply_slice); GET(apply_slice);
GET(applySlice);
GET(assignSlice);
GET(unpackIntoArray); GET(unpackIntoArray);
GET(raiseAttributeError); GET(raiseAttributeError);
......
...@@ -39,7 +39,7 @@ struct GlobalFuncs { ...@@ -39,7 +39,7 @@ struct GlobalFuncs {
llvm::Value* getattr, *getattr_capi, *setattr, *delattr, *delitem, *delGlobal, *nonzero, *binop, *compare, llvm::Value* getattr, *getattr_capi, *setattr, *delattr, *delitem, *delGlobal, *nonzero, *binop, *compare,
*augbinop, *unboxedLen, *getitem, *getitem_capi, *getclsattr, *getGlobal, *setitem, *unaryop, *import, *augbinop, *unboxedLen, *getitem, *getitem_capi, *getclsattr, *getGlobal, *setitem, *unaryop, *import,
*importFrom, *importStar, *repr, *exceptionMatches, *yield_capi, *getiterHelper, *hasnext, *setGlobal, *importFrom, *importStar, *repr, *exceptionMatches, *yield_capi, *getiterHelper, *hasnext, *setGlobal,
*apply_slice; *apply_slice, *applySlice, *assignSlice;
llvm::Value* unpackIntoArray, *raiseAttributeError, *raiseAttributeErrorStr, *raiseAttributeErrorCapi, llvm::Value* unpackIntoArray, *raiseAttributeError, *raiseAttributeErrorStr, *raiseAttributeErrorCapi,
*raiseAttributeErrorStrCapi, *raiseNotIterableError, *raiseIndexErrorStr, *raiseIndexErrorStrCapi, *raiseAttributeErrorStrCapi, *raiseNotIterableError, *raiseIndexErrorStr, *raiseIndexErrorStrCapi,
......
...@@ -777,6 +777,15 @@ Box* instanceGetslice(Box* _inst, Box* i, Box* j) { ...@@ -777,6 +777,15 @@ Box* instanceGetslice(Box* _inst, Box* i, Box* j) {
return runtimeCall(getslice_func, ArgPassSpec(2), i, j, NULL, NULL, NULL); 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) { Box* instanceSetslice(Box* _inst, Box* i, Box* j, Box** sequence) {
RELEASE_ASSERT(_inst->cls == instance_cls, ""); RELEASE_ASSERT(_inst->cls == instance_cls, "");
BoxedInstance* inst = static_cast<BoxedInstance*>(_inst); BoxedInstance* inst = static_cast<BoxedInstance*>(_inst);
...@@ -2005,5 +2014,6 @@ void setupClassobj() { ...@@ -2005,5 +2014,6 @@ void setupClassobj() {
instance_cls->tp_as_number->nb_index = instance_index; instance_cls->tp_as_number->nb_index = instance_index;
instance_cls->tp_as_number->nb_power = instance_pow; instance_cls->tp_as_number->nb_power = instance_pow;
instance_cls->tp_as_number->nb_inplace_power = instance_ipow; instance_cls->tp_as_number->nb_inplace_power = instance_ipow;
instance_cls->tp_as_sequence->sq_slice = instance_slice;
} }
} }
...@@ -377,13 +377,13 @@ extern "C" BORROWED(PyObject*) PyDict_GetItem(PyObject* dict, PyObject* key) noe ...@@ -377,13 +377,13 @@ extern "C" BORROWED(PyObject*) PyDict_GetItem(PyObject* dict, PyObject* key) noe
/* preserve the existing exception */ /* preserve the existing exception */
PyObject* err_type, *err_value, *err_tb; PyObject* err_type, *err_value, *err_tb;
PyErr_Fetch(&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 */ /* ignore errors */
PyErr_Restore(err_type, err_value, err_tb); PyErr_Restore(err_type, err_value, err_tb);
Py_XDECREF(b); Py_XDECREF(b);
return b; return b;
} else { } else {
Box* b = getitemInternal<CAPI>(dict, key); Box* b = PyObject_GetItem(dict, key);
if (b == NULL) if (b == NULL)
PyErr_Clear(); PyErr_Clear();
else else
...@@ -514,13 +514,7 @@ extern "C" int PyDict_DelItem(PyObject* op, PyObject* key) noexcept { ...@@ -514,13 +514,7 @@ extern "C" int PyDict_DelItem(PyObject* op, PyObject* key) noexcept {
} }
ASSERT(op->cls == attrwrapper_cls, "%s", getTypeName(op)); ASSERT(op->cls == attrwrapper_cls, "%s", getTypeName(op));
try { return PyObject_DelItem(op, key);
delitem(op, key);
return 0;
} catch (ExcInfo e) {
setCAPIException(e);
return -1;
}
} }
extern "C" int PyDict_DelItemString(PyObject* v, const char* key) noexcept { extern "C" int PyDict_DelItemString(PyObject* v, const char* key) noexcept {
......
...@@ -105,6 +105,8 @@ void force() { ...@@ -105,6 +105,8 @@ void force() {
FORCE(getiterHelper); FORCE(getiterHelper);
FORCE(hasnext); FORCE(hasnext);
FORCE(apply_slice); FORCE(apply_slice);
FORCE(applySlice);
FORCE(assignSlice);
FORCE(unpackIntoArray); FORCE(unpackIntoArray);
FORCE(raiseAttributeError); FORCE(raiseAttributeError);
......
This diff is collapsed.
...@@ -88,6 +88,9 @@ extern "C" Box* getitem_capi(Box* value, Box* slice) noexcept __attribute__((noi ...@@ -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 setitem(Box* target, Box* slice, Box* value) __attribute__((noinline));
extern "C" void delitem(Box* target, Box* slice) __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* 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* getclsattr(Box* obj, BoxedString* attr) __attribute__((noinline));
extern "C" Box* getclsattrMaybeNonstring(Box* obj, Box* attr) __attribute__((noinline)); extern "C" Box* getclsattrMaybeNonstring(Box* obj, Box* attr) __attribute__((noinline));
extern "C" Box* unaryop(Box* operand, int op_type) __attribute__((noinline)); extern "C" Box* unaryop(Box* operand, int op_type) __attribute__((noinline));
......
...@@ -326,7 +326,7 @@ static PyTypeObject slots_tester_map= { ...@@ -326,7 +326,7 @@ static PyTypeObject slots_tester_map= {
0, /* tp_getattro */ 0, /* tp_getattro */
0, /* tp_setattro */ 0, /* tp_setattro */
0, /* tp_as_buffer */ 0, /* tp_as_buffer */
Py_TPFLAGS_DEFAULT, /* tp_flags */ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
0, /* tp_doc */ 0, /* tp_doc */
0, /* tp_traverse */ 0, /* tp_traverse */
0, /* tp_clear */ 0, /* tp_clear */
......
...@@ -242,3 +242,12 @@ class C(object): ...@@ -242,3 +242,12 @@ class C(object):
c = C() c = C()
proxy = weakref.proxy(c) proxy = weakref.proxy(c)
print isinstance(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
...@@ -101,11 +101,13 @@ sliceable[3:8] ...@@ -101,11 +101,13 @@ sliceable[3:8]
both[0] both[0]
both[:] both[:]
both[3:8] both[3:8]
both[slice(3, 8)]
both[::2] # this should call __getitem__ since __getslice__ doesn't support steps both[::2] # this should call __getitem__ since __getslice__ doesn't support steps
both[0] = xrange(2) both[0] = xrange(2)
both[:] = xrange(2) both[:] = xrange(2)
both[3:8] = xrange(2) both[3:8] = xrange(2)
both[slice(3, 8)] = xrange(2)
both[::2] = xrange(2) both[::2] = xrange(2)
# Should all call getitem as a fallback # Should all call getitem as a fallback
...@@ -118,6 +120,7 @@ both[1:2:'c'] ...@@ -118,6 +120,7 @@ both[1:2:'c']
del both[0] del both[0]
del both[:] del both[:]
del both[3:8] del both[3:8]
del both[slice(3, 8)]
del both [::2] del both [::2]
try: try:
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment