Commit 1c1a34e4 authored by Travis Hance's avatar Travis Hance Committed by Travis Hance

added extension module testing capabilities and the rest of the descriptor field types

parent d8a02b3d
......@@ -86,10 +86,6 @@ int PyDict_SetItemString(PyObject* mp, const char* key, PyObject* item);
PyObject* PyModule_GetDict(PyObject*);
PyObject* PyDict_New(void);
#define Py_XDECREF(op) (op)
#define Py_INCREF(op) (op)
#define Py_DECREF(op) (op)
#define PyDoc_VAR(name) static char name[]
#define PyDoc_STRVAR(name, str) PyDoc_VAR(name) = PyDoc_STR(str)
#define PyDoc_STR(str) str
......
......@@ -824,9 +824,14 @@ PyAPI_FUNC(void) _Py_AddToAllObjects(PyObject *, int force);
(*Py_TYPE(op)->tp_dealloc)((PyObject *)(op)))
#endif /* !Py_TRACE_REFS */
// Pyston change: made Py_INCREF and Py_DECREF into noops
#define Py_INCREF(op) (op)
#define Py_DECREF(op) (op)
// written in a way that won't give "value not used" warnings. Use this empty
// method instead:
static void _Py_do_nothing(PyObject *unused) { }
#define Py_INCREF(op) (_Py_do_nothing((PyObject*)(op)))
#define Py_DECREF(op) (_Py_do_nothing((PyObject*)(op)))
/* Safely decref `op` and set `op` to NULL, especially useful in tp_clear
* and tp_dealloc implementatons.
......@@ -873,8 +878,8 @@ PyAPI_FUNC(void) _Py_AddToAllObjects(PyObject *, int force);
/* Macros to use in case the object pointer may be NULL: */
// Pyston change: made these noops as well
#define Py_XINCREF(op) (op)
#define Py_XDECREF(op) (op)
#define Py_XINCREF(op) (_Py_do_nothing((PyObject*)(op)))
#define Py_XDECREF(op) (_Py_do_nothing((PyObject*)(op)))
/*
These are provided as conveniences to Python runtime embedders, so that
......
......@@ -360,7 +360,7 @@ cpplint:
check:
@# These are ordered roughly in decreasing order of (chance will expose issue) / (time to run test)
$(MAKE) lint
$(MAKE) ext pyston_dbg
$(MAKE) ext_python ext_pyston pyston_dbg
$(MAKE) check_dbg
......@@ -739,12 +739,12 @@ $(patsubst %, $$1: %/$$1 ;,$(EXTRA_SEARCH_DIRS))
)
endef
RUN_DEPS := ext
RUN_DEPS := ext_pyston
define make_target
$(eval \
.PHONY: test$1 check$1
check$1 test$1: pyston$1 ext
check$1 test$1: pyston$1 ext_pyston
python ../tools/tester.py -R pyston$1 -j$(TEST_THREADS) -k $(TESTS_DIR) $(ARGS)
python ../tools/tester.py -R pyston$1 -j$(TEST_THREADS) -a -n -k $(TESTS_DIR) $(ARGS)
python ../tools/tester.py -R pyston$1 -j$(TEST_THREADS) -a -O -k $(TESTS_DIR) $(ARGS)
......@@ -899,13 +899,19 @@ test_cpp_ll:
less test.ll
rm test.ll
.PHONY: ext
ext: ../test/test_extension/test.so
../test/test_extension/test.so: ../test/test_extension/test.o $(BUILD_SYSTEM_DEPS)
TEST_EXT_MODULE_NAMES := basic_test descr_test
.PHONY: ext_pyston
ext_pyston: $(TEST_EXT_MODULE_NAMES:%=../test/test_extension/%.pyston.so)
../test/test_extension/%.pyston.so: ../test/test_extension/%.o $(BUILD_SYSTEM_DEPS)
$(CLANG_EXE) -shared $< -o $@ -g
../test/test_extension/test.o: ../test/test_extension/test.c $(wildcard ../include/*.h) $(BUILD_SYSTEM_DEPS)
../test/test_extension/%.o: ../test/test_extension/%.c $(wildcard ../include/*.h) $(BUILD_SYSTEM_DEPS)
$(CLANG_EXE) -O2 -fPIC -Wimplicit -I../include -c $< -o $@ -g
.PHONY: ext_python
ext_python: $(TEST_EXT_MODULE_NAMES:%=../test/test_extension/*.c)
cd ../test/test_extension; python setup.py build; cd -
$(FROM_CPYTHON_SRCS:.c=.o): %.o: %.c $(BUILD_SYSTEM_DEPS)
$(ECHO) Compiling C file to $@
$(VERB) $(CC) $(EXT_CFLAGS) -c $< -o $@ -g -MMD -MP -MF $(patsubst %.o,%.d,$@) -O0
......
......@@ -122,9 +122,7 @@ void Assembler::emitInt(int64_t n, int bytes) {
}
void Assembler::emitRex(uint8_t rex) {
if (rex != 0) {
emitByte(rex | 0x40);
}
emitByte(rex | 0x40);
}
void Assembler::emitModRM(uint8_t mod, uint8_t reg, uint8_t rm) {
......@@ -141,8 +139,6 @@ void Assembler::emitSIB(uint8_t scalebits, uint8_t index, uint8_t base) {
emitByte((scalebits << 6) | (index << 3) | base);
}
void Assembler::mov(Immediate val, Register dest) {
int rex = REX_W;
......@@ -263,15 +259,63 @@ void Assembler::mov(Register src, Indirect dest) {
}
}
void Assembler::mov(Indirect src, Register dest, MovType type) {
void Assembler::mov(Indirect src, Register dest) {
mov_generic(src, dest, MovType::Q);
}
void Assembler::movq(Indirect src, Register dest) {
mov_generic(src, dest, MovType::Q);
}
void Assembler::movl(Indirect src, Register dest) {
mov_generic(src, dest, MovType::L);
}
void Assembler::movb(Indirect src, Register dest) {
mov_generic(src, dest, MovType::B);
}
void Assembler::movzbl(Indirect src, Register dest) {
mov_generic(src, dest, MovType::ZBL);
}
void Assembler::movsbl(Indirect src, Register dest) {
mov_generic(src, dest, MovType::SBL);
}
void Assembler::movzwl(Indirect src, Register dest) {
mov_generic(src, dest, MovType::ZBL);
}
void Assembler::movswl(Indirect src, Register dest) {
mov_generic(src, dest, MovType::SBL);
}
void Assembler::movzbq(Indirect src, Register dest) {
mov_generic(src, dest, MovType::ZBQ);
}
void Assembler::movsbq(Indirect src, Register dest) {
mov_generic(src, dest, MovType::SBQ);
}
void Assembler::movzwq(Indirect src, Register dest) {
mov_generic(src, dest, MovType::ZWQ);
}
void Assembler::movswq(Indirect src, Register dest) {
mov_generic(src, dest, MovType::SWQ);
}
void Assembler::movslq(Indirect src, Register dest) {
mov_generic(src, dest, MovType::SLQ);
}
void Assembler::mov_generic(Indirect src, Register dest, MovType type) {
int rex;
switch (type) {
case MovType::Q:
case MovType::ZBQ:
case MovType::SBQ:
case MovType::ZWQ:
case MovType::SWQ:
case MovType::SLQ:
rex = REX_W;
break;
case MovType::L:
case MovType::B:
case MovType::ZBL:
case MovType::SBL:
case MovType::ZWL:
case MovType::SWL:
rex = 0;
break;
default:
......@@ -302,10 +346,29 @@ void Assembler::mov(Indirect src, Register dest, MovType type) {
case MovType::B:
emitByte(0x8a);
break;
case MovType::ZBQ:
case MovType::ZBL:
emitByte(0x0f);
emitByte(0xb6);
break;
case MovType::SBQ:
case MovType::SBL:
emitByte(0x0f);
emitByte(0xbe);
break;
case MovType::ZWQ:
case MovType::ZWL:
emitByte(0x0f);
emitByte(0xb7);
break;
case MovType::SWQ:
case MovType::SWL:
emitByte(0x0f);
emitByte(0xbf);
break;
case MovType::SLQ:
emitByte(0x63);
break;
default:
RELEASE_ASSERT(false, "unrecognized MovType");
}
......@@ -444,6 +507,74 @@ void Assembler::movsd(Indirect src, XMMRegister dest) {
}
}
void Assembler::movss(Indirect src, XMMRegister dest) {
int rex = 0;
int src_idx = src.base.regnum;
int dest_idx = dest.regnum;
if (src_idx >= 8) {
trap();
rex |= REX_R;
src_idx -= 8;
}
if (dest_idx >= 8) {
trap();
rex |= REX_B;
dest_idx -= 8;
}
emitByte(0xf3);
if (rex)
emitRex(rex);
emitByte(0x0f);
emitByte(0x10);
bool needssib = (src_idx == 0b100);
int mode;
if (src.offset == 0)
mode = 0b00;
else if (-0x80 <= src.offset && src.offset < 0x80)
mode = 0b01;
else
mode = 0b10;
emitModRM(mode, dest_idx, src_idx);
if (needssib)
emitSIB(0b00, 0b100, src_idx);
if (mode == 0b01) {
emitByte(src.offset);
} else if (mode == 0b10) {
emitInt(src.offset, 4);
}
}
void Assembler::cvtss2sd(XMMRegister src, XMMRegister dest) {
int rex = 0;
int src_idx = src.regnum;
int dest_idx = dest.regnum;
if (src_idx >= 8) {
trap();
rex |= REX_R;
src_idx -= 8;
}
if (dest_idx >= 8) {
trap();
rex |= REX_B;
dest_idx -= 8;
}
emitByte(0xf3);
if (rex)
emitRex(rex);
emitByte(0x0f);
emitByte(0x5a);
emitModRM(0b11, src_idx, dest_idx);
}
void Assembler::push(Register reg) {
// assert(0 && "This breaks unwinding, please don't use.");
......@@ -744,7 +875,7 @@ void Assembler::emitBatchPop(int scratch_rbp_offset, int scratch_size, const std
if (r.type == GenericRegister::GP) {
Register gp = r.gp;
assert(gp.regnum >= 0 && gp.regnum < 16);
mov(next_slot, gp);
movq(next_slot, gp);
offset += 8;
} else if (r.type == GenericRegister::XMM) {
XMMRegister reg = r.xmm;
......
......@@ -53,6 +53,16 @@ enum class MovType {
L,
B,
ZBL,
SBL,
ZWL,
SWL,
ZBQ,
SBQ,
ZWQ,
SWQ,
SLQ,
ZLQ = L,
};
class Assembler {
......@@ -87,11 +97,29 @@ public:
void movq(Immediate imm, Indirect dest);
void mov(Register src, Register dest);
void mov(Register src, Indirect dest);
void mov(Indirect src, Register dest, MovType type = MovType::Q);
void movsd(XMMRegister src, XMMRegister dest);
void movsd(XMMRegister src, Indirect dest);
void movsd(Indirect src, XMMRegister dest);
void movss(Indirect src, XMMRegister dest);
void cvtss2sd(XMMRegister src, XMMRegister dest);
void mov(Indirect scr, Register dest);
void movq(Indirect scr, Register dest);
void movl(Indirect scr, Register dest);
void movb(Indirect scr, Register dest);
void movzbl(Indirect scr, Register dest);
void movsbl(Indirect scr, Register dest);
void movzwl(Indirect scr, Register dest);
void movswl(Indirect scr, Register dest);
void movzbq(Indirect scr, Register dest);
void movsbq(Indirect scr, Register dest);
void movzwq(Indirect scr, Register dest);
void movswq(Indirect scr, Register dest);
void movslq(Indirect scr, Register dest);
void mov_generic(Indirect src, Register dest, MovType type);
void push(Register reg);
void pop(Register reg);
......
......@@ -127,7 +127,7 @@ void Location::dump() const {
RELEASE_ASSERT(0, "%d", type);
}
static bool isLargeConstant(uint64_t val) {
static bool isLargeConstant(int64_t val) {
return (val < (-1L << 31) || val >= (1L << 31) - 1);
}
......@@ -147,6 +147,8 @@ void Rewriter::_addGuard(RewriterVar* var, uint64_t val) {
assembler->jne(assembler::JumpDestination::fromStart(rewrite->getSlotSize()));
var->bumpUse();
assertConsistent();
}
void RewriterVar::addGuardNotEq(uint64_t val) {
......@@ -165,6 +167,8 @@ void Rewriter::_addGuardNotEq(RewriterVar* var, uint64_t val) {
assembler->je(assembler::JumpDestination::fromStart(rewrite->getSlotSize()));
var->bumpUse();
assertConsistent();
}
void RewriterVar::addAttrGuard(int offset, uint64_t val, bool negate) {
......@@ -187,6 +191,8 @@ void Rewriter::_addAttrGuard(RewriterVar* var, int offset, uint64_t val, bool ne
assembler->jne(assembler::JumpDestination::fromStart(rewrite->getSlotSize()));
var->bumpUse();
assertConsistent();
}
RewriterVar* RewriterVar::getAttr(int offset, Location dest, assembler::MovType type) {
......@@ -202,13 +208,47 @@ void Rewriter::_getAttr(RewriterVar* result, RewriterVar* ptr, int offset, Locat
// in the same register as ptr
ptr->bumpUse();
if (dest.type == Location::XMMRegister) {
assembler::XMMRegister newvar_reg = result->initializeInXMMReg(dest);
assembler->movsd(assembler::Indirect(ptr_reg, offset), newvar_reg);
} else {
assembler::Register newvar_reg = result->initializeInReg(dest);
assembler->mov(assembler::Indirect(ptr_reg, offset), newvar_reg, type);
}
assembler::Register newvar_reg = result->initializeInReg(dest);
assembler->mov_generic(assembler::Indirect(ptr_reg, offset), newvar_reg, type);
assertConsistent();
}
RewriterVar* RewriterVar::getAttrDouble(int offset, Location dest) {
RewriterVar* result = rewriter->createNewVar();
rewriter->addAction([=]() { rewriter->_getAttrDouble(result, this, offset, dest); }, { this }, ActionType::NORMAL);
return result;
}
void Rewriter::_getAttrDouble(RewriterVar* result, RewriterVar* ptr, int offset, Location dest) {
assembler::Register ptr_reg = ptr->getInReg();
ptr->bumpUse();
assembler::XMMRegister newvar_reg = result->initializeInXMMReg(dest);
assembler->movsd(assembler::Indirect(ptr_reg, offset), newvar_reg);
assertConsistent();
}
RewriterVar* RewriterVar::getAttrFloat(int offset, Location dest) {
RewriterVar* result = rewriter->createNewVar();
rewriter->addAction([=]() { rewriter->_getAttrFloat(result, this, offset, dest); }, { this }, ActionType::NORMAL);
return result;
}
void Rewriter::_getAttrFloat(RewriterVar* result, RewriterVar* ptr, int offset, Location dest) {
assembler::Register ptr_reg = ptr->getInReg();
ptr->bumpUse();
assembler::XMMRegister newvar_reg = result->initializeInXMMReg(dest);
assembler->movss(assembler::Indirect(ptr_reg, offset), newvar_reg);
// cast to double
assembler->cvtss2sd(newvar_reg, newvar_reg);
assertConsistent();
}
RewriterVar* RewriterVar::cmp(AST_TYPE::AST_TYPE cmp_type, RewriterVar* other, Location dest) {
......@@ -239,6 +279,8 @@ void Rewriter::_cmp(RewriterVar* result, RewriterVar* v1, AST_TYPE::AST_TYPE cmp
default:
RELEASE_ASSERT(0, "%d", cmp_type);
}
assertConsistent();
}
RewriterVar* RewriterVar::toBool(Location dest) {
......@@ -257,6 +299,8 @@ void Rewriter::_toBool(RewriterVar* result, RewriterVar* var, Location dest) {
assembler->test(this_reg, this_reg);
assembler->setnz(result_reg);
assertConsistent();
}
void RewriterVar::setAttr(int offset, RewriterVar* val) {
......@@ -267,7 +311,7 @@ void Rewriter::_setAttr(RewriterVar* ptr, int offset, RewriterVar* val) {
assembler::Register ptr_reg = ptr->getInReg();
bool is_immediate;
assembler::Immediate imm = ptr->tryGetAsImmediate(&is_immediate);
assembler::Immediate imm = val->tryGetAsImmediate(&is_immediate);
if (is_immediate) {
assembler->movq(imm, assembler::Indirect(ptr_reg, offset));
......@@ -280,6 +324,8 @@ void Rewriter::_setAttr(RewriterVar* ptr, int offset, RewriterVar* val) {
ptr->bumpUse();
val->bumpUse();
assertConsistent();
}
void RewriterVar::dump() {
......@@ -450,6 +496,8 @@ void Rewriter::_loadConst(RewriterVar* result, int64_t val, Location dest) {
assembler::Register reg = allocReg(dest);
assembler->mov(assembler::Immediate(val), reg);
result->initializeInReg(reg);
assertConsistent();
}
RewriterVar* Rewriter::call(bool can_call_into_python, void* func_addr, RewriterVar* arg0) {
......@@ -494,6 +542,7 @@ void Rewriter::_call(RewriterVar* result, bool can_call_into_python, void* func_
// TODO figure out why this is here -- what needs to be done differently
// if can_call_into_python is true?
// assert(!can_call_into_python);
assert(done_guarding);
// RewriterVarUsage scratch = createNewVar(Location::any());
assembler::Register r = allocReg(assembler::R11);
......@@ -530,6 +579,8 @@ void Rewriter::_call(RewriterVar* result, bool can_call_into_python, void* func_
assert(var->isInLocation(Location::forArg(i)));
}
assertConsistent();
for (int i = 0; i < args_xmm.size(); i++) {
Location l((assembler::XMMRegister(i)));
assert(args_xmm[i]->isInLocation(l));
......@@ -552,6 +603,8 @@ void Rewriter::_call(RewriterVar* result, bool can_call_into_python, void* func_
arg_xmm->bumpUse();
}
assertConsistent();
// Spill caller-saved registers:
for (auto check_reg : caller_save_registers) {
// check_reg.dump();
......@@ -595,6 +648,8 @@ void Rewriter::_call(RewriterVar* result, bool can_call_into_python, void* func_
}
}
assertConsistent();
#ifndef NDEBUG
for (const auto& p : vars_by_location.getAsMap()) {
Location l = p.first;
......@@ -611,6 +666,8 @@ void Rewriter::_call(RewriterVar* result, bool can_call_into_python, void* func_
assert(vars_by_location.count(assembler::RAX) == 0);
result->initializeInReg(assembler::RAX);
assertConsistent();
}
void Rewriter::abort() {
......@@ -851,6 +908,33 @@ Location Rewriter::allocScratch() {
RELEASE_ASSERT(0, "Using all %d bytes of scratch!", scratch_bytes);
}
RewriterVar* Rewriter::add(RewriterVar* a, int64_t b, Location dest) {
RewriterVar* result = createNewVar();
addAction([=]() { this->_add(result, a, b, dest); }, { a }, ActionType::NORMAL);
return result;
}
void Rewriter::_add(RewriterVar* result, RewriterVar* a, int64_t b, Location dest) {
// TODO better reg alloc (e.g., mov `a` directly to the dest reg)
assembler::Register newvar_reg = allocReg(dest);
assembler::Register a_reg
= a->getInReg(Location::any(), /* allow_constant_in_reg */ true, /* otherThan */ newvar_reg);
assert(a_reg != newvar_reg);
result->initializeInReg(newvar_reg);
assembler->mov(a_reg, newvar_reg);
// TODO we can't rely on this being true, so we need to support the full version
assert(!isLargeConstant(b));
assembler->add(assembler::Immediate(b), newvar_reg);
a->bumpUse();
assertConsistent();
}
RewriterVar* Rewriter::allocate(int n) {
RewriterVar* result = createNewVar();
addAction([=]() { this->_allocate(result, n); }, {}, ActionType::NORMAL);
......@@ -884,6 +968,7 @@ int Rewriter::_allocate(RewriterVar* result, int n) {
vars_by_location[m] = LOCATION_PLACEHOLDER;
}
assertConsistent();
return a;
}
} else {
......@@ -914,6 +999,8 @@ void Rewriter::_allocateAndCopy(RewriterVar* result, RewriterVar* array_ptr, int
}
array_ptr->bumpUse();
assertConsistent();
}
RewriterVar* Rewriter::allocateAndCopyPlus1(RewriterVar* first_elem, RewriterVar* rest_ptr, int n_rest) {
......@@ -950,6 +1037,8 @@ void Rewriter::_allocateAndCopyPlus1(RewriterVar* result, RewriterVar* first_ele
}
first_elem->bumpUse();
assertConsistent();
}
assembler::Indirect Rewriter::indirectFor(Location l) {
......@@ -962,7 +1051,9 @@ assembler::Indirect Rewriter::indirectFor(Location l) {
return assembler::Indirect(assembler::RSP, l.stack_offset);
}
void Rewriter::spillRegister(assembler::Register reg) {
void Rewriter::spillRegister(assembler::Register reg, Location preserve) {
assert(preserve.type == Location::Register || preserve.type == Location::AnyReg);
if (!done_guarding) {
for (int i = 0; i < args.size(); i++) {
assert(args[i]->arg_loc != Location(reg));
......@@ -984,6 +1075,8 @@ void Rewriter::spillRegister(assembler::Register reg) {
continue;
if (vars_by_location.count(new_reg))
continue;
if (Location(new_reg) == preserve)
continue;
assembler->mov(reg, new_reg);
addLocationToVar(var, new_reg);
......@@ -1041,7 +1134,7 @@ assembler::Register Rewriter::allocReg(Location dest, Location otherThan) {
// Spill the register whose next use is farthest in the future
assert(found);
spillRegister(best_reg);
spillRegister(best_reg, /* preserve */ otherThan);
assert(vars_by_location.count(best_reg) == 0);
return best_reg;
} else if (dest.type == Location::Register) {
......@@ -1118,6 +1211,14 @@ RewriterVar* Rewriter::createNewVar() {
}
assembler::Register RewriterVar::initializeInReg(Location l) {
// TODO um should we check this in more places, or what?
// The thing is: if we aren't done guarding, and the register we want to use
// is taken by an arg, we can't spill it, so we shouldn't ask to alloc it.
if (l.type == Location::Register && !rewriter->done_guarding && rewriter->vars_by_location[l] != NULL
&& rewriter->vars_by_location[l]->is_arg) {
l = Location::any();
}
assembler::Register reg = rewriter->allocReg(l);
l = Location(reg);
......
......@@ -193,7 +193,9 @@ public:
}
}
for (std::pair<int32_t, RewriterVar*> p : map_const) {
m.emplace(Location(Location::Constant, p.first), p.second);
if (p.second != NULL) {
m.emplace(Location(Location::Constant, p.first), p.second);
}
}
return m;
}
......@@ -212,10 +214,15 @@ public:
void addGuardNotEq(uint64_t val);
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?)
RewriterVar* getAttrFloat(int offset, Location loc = Location::any());
RewriterVar* getAttrDouble(int offset, Location loc = Location::any());
void setAttr(int offset, RewriterVar* other);
RewriterVar* cmp(AST_TYPE::AST_TYPE cmp_type, RewriterVar* other, Location loc = Location::any());
RewriterVar* toBool(Location loc = Location::any());
template <typename Src, typename Dst> inline RewriterVar* getAttrCast(int offset, Location loc = Location::any());
private:
Rewriter* rewriter;
......@@ -331,7 +338,7 @@ private:
assembler::Indirect indirectFor(Location l);
// Spills a specified register.
// If there are open callee-save registers, takes one of those, otherwise goes on the stack
void spillRegister(assembler::Register reg);
void spillRegister(assembler::Register reg, Location preserve = Location::any());
// Similar, but for XMM registers (always go on the stack)
void spillRegister(assembler::XMMRegister reg);
......@@ -351,6 +358,7 @@ private:
void _loadConst(RewriterVar* result, int64_t val, Location loc);
void _call(RewriterVar* result, bool can_call_into_python, void* func_addr, const std::vector<RewriterVar*>& args,
const std::vector<RewriterVar*>& args_xmm);
void _add(RewriterVar* result, RewriterVar* a, int64_t b, Location dest);
int _allocate(RewriterVar* result, int n);
void _allocateAndCopy(RewriterVar* result, RewriterVar* array, int n);
void _allocateAndCopyPlus1(RewriterVar* result, RewriterVar* first_elem, RewriterVar* rest, int n_rest);
......@@ -361,6 +369,8 @@ private:
void _addAttrGuard(RewriterVar* var, int offset, uint64_t val, bool negate = false);
void _getAttr(RewriterVar* result, RewriterVar* var, int offset, Location loc = Location::any(),
assembler::MovType type = assembler::MovType::Q);
void _getAttrFloat(RewriterVar* result, RewriterVar* var, int offset, Location loc = Location::any());
void _getAttrDouble(RewriterVar* result, RewriterVar* var, int offset, Location loc = Location::any());
void _setAttr(RewriterVar* var, int offset, RewriterVar* other);
void _cmp(RewriterVar* result, RewriterVar* var1, AST_TYPE::AST_TYPE cmp_type, RewriterVar* var2,
Location loc = Location::any());
......@@ -411,6 +421,7 @@ public:
const std::vector<RewriterVar*>& args_xmm = std::vector<RewriterVar*>());
RewriterVar* call(bool can_call_into_python, void* func_addr, RewriterVar* arg0);
RewriterVar* call(bool can_call_into_python, void* func_addr, RewriterVar* arg0, RewriterVar* arg1);
RewriterVar* add(RewriterVar* a, int64_t b, Location dest);
RewriterVar* allocate(int n);
RewriterVar* allocateAndCopy(RewriterVar* array, int n);
RewriterVar* allocateAndCopyPlus1(RewriterVar* first_elem, RewriterVar* rest, int n_rest);
......@@ -452,6 +463,44 @@ bool spillFrameArgumentIfNecessary(StackMap::Record::Location& l, uint8_t*& inst
std::pair<uint8_t*, uint8_t*> initializePatchpoint3(void* slowpath_func, uint8_t* start_addr, uint8_t* end_addr,
int scratch_offset, int scratch_size,
const std::unordered_set<int>& live_outs, SpillMap& remapped);
template <> inline RewriterVar* RewriterVar::getAttrCast<bool, bool>(int offset, Location loc) {
return getAttr(offset, loc, assembler::MovType::ZBL);
}
template <> inline RewriterVar* RewriterVar::getAttrCast<char, char>(int offset, Location loc) {
return getAttr(offset, loc, assembler::MovType::SBL);
}
template <> inline RewriterVar* RewriterVar::getAttrCast<int8_t, int64_t>(int offset, Location loc) {
return getAttr(offset, loc, assembler::MovType::SBQ);
}
template <> inline RewriterVar* RewriterVar::getAttrCast<int16_t, int64_t>(int offset, Location loc) {
return getAttr(offset, loc, assembler::MovType::SWQ);
}
template <> inline RewriterVar* RewriterVar::getAttrCast<int32_t, int64_t>(int offset, Location loc) {
return getAttr(offset, loc, assembler::MovType::SLQ);
}
template <> inline RewriterVar* RewriterVar::getAttrCast<int64_t, int64_t>(int offset, Location loc) {
return getAttr(offset, loc, assembler::MovType::Q);
}
template <> inline RewriterVar* RewriterVar::getAttrCast<uint8_t, uint64_t>(int offset, Location loc) {
return getAttr(offset, loc, assembler::MovType::ZBQ);
}
template <> inline RewriterVar* RewriterVar::getAttrCast<uint16_t, uint64_t>(int offset, Location loc) {
return getAttr(offset, loc, assembler::MovType::ZWQ);
}
template <> inline RewriterVar* RewriterVar::getAttrCast<uint32_t, uint64_t>(int offset, Location loc) {
return getAttr(offset, loc, assembler::MovType::ZLQ);
}
template <> inline RewriterVar* RewriterVar::getAttrCast<uint64_t, uint64_t>(int offset, Location loc) {
return getAttr(offset, loc, assembler::MovType::Q);
}
template <> inline RewriterVar* RewriterVar::getAttrCast<long long, long long>(int offset, Location loc) {
return getAttr(offset, loc, assembler::MovType::Q);
}
template <>
inline RewriterVar* RewriterVar::getAttrCast<unsigned long long, unsigned long long>(int offset, Location loc) {
return getAttr(offset, loc, assembler::MovType::Q);
}
}
#endif
......@@ -934,8 +934,9 @@ extern "C" Py_ssize_t PyNumber_AsSsize_t(PyObject* o, PyObject* exc) {
Py_FatalError("unimplemented");
}
BoxedModule* importTestExtension() {
const char* pathname = "../test/test_extension/test.so";
BoxedModule* importTestExtension(const std::string& name) {
std::string pathname_name = "../test/test_extension/" + name + ".pyston.so";
const char* pathname = pathname_name.c_str();
void* handle = dlopen(pathname, RTLD_NOW);
if (!handle) {
fprintf(stderr, "%s\n", dlerror());
......@@ -943,7 +944,8 @@ BoxedModule* importTestExtension() {
}
assert(handle);
void (*init)() = (void (*)())dlsym(handle, "inittest");
std::string initname = "init" + name;
void (*init)() = (void (*)())dlsym(handle, initname.c_str());
char* error;
if ((error = dlerror()) != NULL) {
......@@ -955,7 +957,7 @@ BoxedModule* importTestExtension() {
(*init)();
BoxedDict* sys_modules = getSysModulesDict();
Box* s = boxStrConstant("test");
Box* s = boxStrConstant(name.c_str());
Box* _m = sys_modules->d[s];
RELEASE_ASSERT(_m, "module failed to initialize properly?");
assert(_m->cls == module_cls);
......
......@@ -15,10 +15,12 @@
#ifndef PYSTON_RUNTIME_CAPI_H
#define PYSTON_RUNTIME_CAPI_H
#include <cstring>
namespace pyston {
class BoxedModule;
BoxedModule* importTestExtension();
BoxedModule* importTestExtension(const std::string&);
}
#endif
......@@ -252,9 +252,9 @@ void setupComplex() {
complex_cls->giveAttr("__str__", new BoxedFunction(boxRTFunction((void*)complexStr, STR, 1)));
complex_cls->giveAttr("__repr__", new BoxedFunction(boxRTFunction((void*)complexRepr, STR, 1)));
complex_cls->giveAttr("real",
new BoxedMemberDescriptor(BoxedMemberDescriptor::FLOAT, offsetof(BoxedComplex, real)));
new BoxedMemberDescriptor(BoxedMemberDescriptor::DOUBLE, offsetof(BoxedComplex, real)));
complex_cls->giveAttr("imag",
new BoxedMemberDescriptor(BoxedMemberDescriptor::FLOAT, offsetof(BoxedComplex, imag)));
new BoxedMemberDescriptor(BoxedMemberDescriptor::DOUBLE, offsetof(BoxedComplex, imag)));
complex_cls->freeze();
}
......
......@@ -84,8 +84,11 @@ static Box* importSub(const std::string* name, Box* parent_module) {
return module;
}
if (*name == "test") {
return importTestExtension();
if (*name == "basic_test") {
return importTestExtension("basic_test");
}
if (*name == "descr_test") {
return importTestExtension("descr_test");
}
raiseExcHelper(ImportError, "No module named %s", name->c_str());
......
......@@ -132,6 +132,18 @@ extern "C" BoxedLong* boxLong(int64_t n) {
return rtn;
}
extern "C" PyObject* PyLong_FromLongLong(long long ival) {
BoxedLong* rtn = new BoxedLong(long_cls);
mpz_init_set_si(rtn->n, ival);
return rtn;
}
extern "C" PyObject* PyLong_FromUnsignedLongLong(unsigned long long ival) {
BoxedLong* rtn = new BoxedLong(long_cls);
mpz_init_set_ui(rtn->n, ival);
return rtn;
}
extern "C" Box* longNew(Box* _cls, Box* val, Box* _base) {
if (!isSubclass(_cls->cls, type_cls))
raiseExcHelper(TypeError, "long.__new__(X): X is not a type object (%s)", getTypeName(_cls)->c_str());
......
This diff is collapsed.
......@@ -364,7 +364,21 @@ public:
BYTE = T_BYTE,
INT = T_INT,
OBJECT = T_OBJECT,
OBJECT_EX = T_OBJECT_EX,
FLOAT = T_FLOAT,
SHORT = T_SHORT,
LONG = T_LONG,
DOUBLE = T_DOUBLE,
STRING = T_STRING,
STRING_INPLACE = T_STRING_INPLACE,
CHAR = T_CHAR,
UBYTE = T_UBYTE,
USHORT = T_USHORT,
UINT = T_UINT,
ULONG = T_ULONG,
LONGLONG = T_LONGLONG,
ULONGLONG = T_ULONGLONG,
PYSSIZET = T_PYSSIZET
} type;
int offset;
......
......@@ -21,3 +21,27 @@ int f() {
extern "C" C* c() {
return new C(f());
}
void moo(double);
float chrs[10];
void foo(int i) {
moo(chrs[i]);
}
void moo2(long long);
int chrs2[10];
void foo2(int i) {
moo2(chrs2[i]);
}
void moo3(long long);
short chrs3[10];
void foo3(int i) {
moo3(chrs3[i]);
}
void moo4(bool);
bool chrs4[10];
void foo4(int i) {
moo4(chrs4[i]);
}
......@@ -39,11 +39,11 @@ static PyMethodDef TestMethods[] = {
};
PyMODINIT_FUNC
inittest(void)
initbasic_test(void)
{
PyObject *m;
m = Py_InitModule("test", TestMethods);
m = Py_InitModule("basic_test", TestMethods);
if (m == NULL)
return;
}
#include <string.h>
#include <Python.h>
#include <structmember.h>
typedef struct {
PyObject_HEAD
short member_short;
int member_int;
long member_long;
float member_float;
double member_double;
char* member_string;
char member_string_inplace[80];
char member_char;
int8_t member_byte;
uint8_t member_ubyte;
unsigned short member_ushort;
unsigned int member_uint;
unsigned long member_ulong;
char member_bool;
PyObject* member_object;
PyObject* member_object_ex;
long long member_long_long;
unsigned long long member_ulong_long;
Py_ssize_t member_pyssizet;
} descr_tester_object;
char* string1 = "string1";
char* string2 = "string2";
char* string_empty = "";
static struct PyMemberDef descr_memberlist[] = {
{"member_short", T_SHORT, offsetof(descr_tester_object, member_short), READONLY},
{"member_int", T_INT, offsetof(descr_tester_object, member_int), READONLY},
{"member_long", T_LONG, offsetof(descr_tester_object, member_long), READONLY},
{"member_float", T_FLOAT, offsetof(descr_tester_object, member_float), READONLY},
{"member_double", T_DOUBLE, offsetof(descr_tester_object, member_double), READONLY},
{"member_string", T_STRING, offsetof(descr_tester_object, member_string), READONLY},
{"member_string_inplace", T_STRING_INPLACE, offsetof(descr_tester_object, member_string_inplace), READONLY},
{"member_char", T_CHAR, offsetof(descr_tester_object, member_char), READONLY},
{"member_byte", T_BYTE, offsetof(descr_tester_object, member_byte), READONLY},
{"member_ubyte", T_UBYTE, offsetof(descr_tester_object, member_ubyte), READONLY},
{"member_ushort", T_USHORT, offsetof(descr_tester_object, member_ushort), READONLY},
{"member_uint", T_UINT, offsetof(descr_tester_object, member_uint), READONLY},
{"member_ulong", T_ULONG, offsetof(descr_tester_object, member_ulong), READONLY},
{"member_bool", T_BOOL, offsetof(descr_tester_object, member_bool), READONLY},
{"member_object", T_OBJECT, offsetof(descr_tester_object, member_object), READONLY},
{"member_object_ex", T_OBJECT_EX, offsetof(descr_tester_object, member_object_ex), READONLY},
{"member_long_long", T_LONGLONG, offsetof(descr_tester_object, member_long_long), READONLY},
{"member_ulong_long", T_ULONGLONG, offsetof(descr_tester_object, member_ulong_long), READONLY},
{"member_pyssizet", T_PYSSIZET, offsetof(descr_tester_object, member_pyssizet), READONLY},
{NULL}
};
static void
descr_tester_dealloc(descr_tester_object *mc)
{
printf("dealloc");
if (mc->member_object)
Py_DECREF(mc->member_object);
if (mc->member_object_ex)
Py_DECREF(mc->member_object_ex);
PyObject_GC_UnTrack(mc);
PyObject_GC_Del(mc);
printf("done dealloc");
}
PyDoc_STRVAR(descr_tester_doc, "descr_tester doc");
static int
descr_tester_traverse(descr_tester_object *mc, visitproc visit, void *arg)
{
printf("traverse");
if (mc->member_object != NULL)
Py_VISIT(mc->member_object);
if (mc->member_object_ex != NULL)
Py_VISIT(mc->member_object_ex);
printf("done traverse");
return 0;
}
static PyTypeObject descr_tester;
static PyObject *
descr_tester_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
{
printf("shouldn't get here? (new)");
return NULL;
}
static PyObject *
descr_tester_call(descr_tester_object *mc, PyObject *args, PyObject *kw)
{
printf("shouldn't get here? (call)");
return NULL;
}
static PyTypeObject descr_tester = {
PyVarObject_HEAD_INIT(NULL, 0)
"descr_test.descr_tester", /* tp_name */
sizeof(descr_tester_object), /* tp_basicsize */
0, /* tp_itemsize */
/* methods */
(destructor)descr_tester_dealloc, /* tp_dealloc */
0, /* tp_print */
0, /* tp_getattr */
0, /* tp_setattr */
0, /* tp_compare */
0, /* tp_repr */
0, /* tp_as_number */
0, /* tp_as_sequence */
0, /* tp_as_mapping */
0, /* tp_hash */
(ternaryfunc)descr_tester_call, /* tp_call */
0, /* tp_str */
PyObject_GenericGetAttr, /* tp_getattro */
0, /* tp_setattro */
0, /* tp_as_buffer */
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,/* tp_flags */
descr_tester_doc, /* tp_doc */
(traverseproc)descr_tester_traverse, /* tp_traverse */
0, /* tp_clear */
0, /* tp_richcompare */
0, /* tp_weaklistoffset */
0, /* tp_iter */
0, /* tp_iternext */
0, /* tp_methods */
descr_memberlist, /* tp_members */
0, /* tp_getset */
0, /* tp_base */
0, /* tp_dict */
0, /* tp_descr_get */
0, /* tp_descr_set */
0, /* tp_dictoffset */
0, /* tp_init */
0, /* tp_alloc */
descr_tester_new, /* tp_new */
0, /* tp_free */
};
static PyMethodDef DescrTestMethods[] = {
{NULL, NULL, 0, NULL} /* Sentinel */
};
PyMODINIT_FUNC
initdescr_test(void)
{
int res = PyType_Ready(&descr_tester);
if (res < 0)
return;
Py_INCREF(&descr_tester);
descr_tester_object* o1 = PyObject_New(descr_tester_object, &descr_tester);
if (o1 == NULL)
return;
o1->member_short = SHRT_MAX;
o1->member_int = INT_MAX;
o1->member_long = LONG_MAX;
o1->member_float = 1.0f;
o1->member_double = 2.0;
o1->member_string = string1;
strcpy(o1->member_string_inplace, string2);
o1->member_char = 'A';
o1->member_byte = CHAR_MAX;
o1->member_ubyte = UCHAR_MAX;
o1->member_ushort = USHRT_MAX;
o1->member_uint = UINT_MAX;
o1->member_ulong = ULONG_MAX;
o1->member_bool = 1;
o1->member_object = PyInt_FromLong(15);
o1->member_object_ex = PyInt_FromLong(16);
o1->member_long_long = LLONG_MAX;
o1->member_ulong_long = ULLONG_MAX;
o1->member_pyssizet = (Py_ssize_t)((1ULL << (8 * sizeof(Py_ssize_t) - 1)) - 1); // max Py_ssize_t
Py_INCREF(o1);
Py_INCREF(o1->member_object);
Py_INCREF(o1->member_object_ex);
descr_tester_object* o2 = PyObject_GC_New(descr_tester_object, &descr_tester);
if (o2 == NULL)
return;
o2->member_short = SHRT_MIN;
o2->member_int = INT_MIN;
o2->member_long = LONG_MIN;
o2->member_float = 3.0f;
o2->member_double = 4.0;
o2->member_string = NULL; // let's see what happens!
strcpy(o2->member_string_inplace, string_empty);
o2->member_char = 'a';
o2->member_byte = CHAR_MIN;
o2->member_ubyte = 0;
o2->member_ushort = 0;
o2->member_uint = 0;
o2->member_ulong = 0;
o2->member_bool = 0;
o2->member_object = NULL; // None
o2->member_object_ex = NULL; // Exception
o2->member_long_long = LLONG_MIN;
o2->member_ulong_long = 0;
o2->member_pyssizet = o1->member_pyssizet + 1; // min Py_ssize_t
Py_INCREF(o2);
PyObject *m;
m = Py_InitModule("descr_test", DescrTestMethods);
if (m == NULL)
return;
PyModule_AddObject(m, "descr_tester", (PyObject *)&descr_tester);
PyModule_AddObject(m, "member_descr_object1", (PyObject *)o1);
PyModule_AddObject(m, "member_descr_object2", (PyObject *)o2);
}
from distutils.core import setup, Extension
test_module = Extension("test", sources = ["test.c"])
setup(name="test",
version="1.0",
description="test",
ext_modules=[test_module],
)
ext_modules=[
Extension("basic_test", sources = ["basic_test.c"]),
Extension("descr_test", sources = ["descr_test.c"]),
],
)
# skip-if: sys.version_info.micro >= 4
# - Error message changed in 2.7.4
# Regression test:
# If the init function doesn't exist, shouldn't just silently ignore any args
# that got passed
......
<module 'test' from '../test/test_extension/test.so'>
[]
This will break
[]
import test
# expected: fail
# This test case currently fails because it prints the relative path to the .so
# module rather than the absolute path.
print test
import basic_test
print basic_test
# TODO this should work even if we don't keep a reference to l;
# it doesn't currently always work, but it sometimes works, so it's hard
......@@ -8,8 +12,8 @@ print test
# Instead just weaken the test, and add this TODO to add the harder test back
# later.
l = []
test.store(l)
print test.load()
basic_test.store(l)
print basic_test.load()
class C(object):
def __init__(self):
......@@ -19,4 +23,4 @@ for i in xrange(100000):
C()
print "This will break"
print test.load()
print basic_test.load()
# run_args: -n
# statcheck: noninit_count('slowpath_member_descriptor_get') <= 50
# statcheck: noninit_count('slowpath_member_descriptor_get') <= 1500
f = open("/dev/null")
# Right now this will fail for the access with the try-block.
# All other accesses should be re-written.
def go():
# object
s = slice(i, 1.0, "abc")
print s.start
print s.stop
print s.step
import descr_test
# byte
# TODO
# using softspace works for this test as long as we implement softspace as
# a member descriptor but it should actually a getset_descriptor
# in addition to fixing that, we should replace it in this test with a legit
# member descriptor
print f.softspace
def f(o, expect_exc):
# print the repr so we make sure we get the types right (int or long)
# TODO figure out what uses BOOL and test that
# TODO figure out what uses INT and test that
# float
c = 1j + i
print c.real
print c.imag
print 'short', repr(o.member_short)
print 'int', repr(o.member_int)
print 'long', repr(o.member_long)
print 'float', repr(o.member_float)
print 'double', repr(o.member_double)
print 'string', repr(o.member_string)
print 'string_inplace', repr(o.member_string_inplace)
print 'char', repr(o.member_char)
print 'byte', repr(o.member_byte)
print 'ubyte', repr(o.member_ubyte)
print 'ushort', repr(o.member_ushort)
print 'uint', repr(o.member_uint)
print 'ulong', repr(o.member_ulong)
print 'bool', repr(o.member_bool)
print 'object', repr(o.member_object)
if expect_exc:
try:
o.member_object_ex
except AttributeError as e:
print 'object_ex got AttributeError', e.message
else:
print 'object_ex', repr(o.member_object_ex)
print 'long_long', repr(o.member_long_long)
print 'ulong_long', repr(o.member_ulong_long)
print 'pyssizet', repr(o.member_pyssizet)
for i in xrange(1000):
go();
print "1:"
f(descr_test.member_descr_object1, False)
print "2:"
f(descr_test.member_descr_object2, True)
# skip-if: sys.version_info.micro >= 4
# - Error message changed in 2.7.4
# object.__new__ doesn't complain if __init__ is overridden:
class C1(object):
......
......@@ -68,7 +68,9 @@ def get_expected_output(fn):
pass
# TODO don't suppress warnings globally:
p = subprocess.Popen(["python", "-Wignore", fn], stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=open("/dev/null"), preexec_fn=set_ulimits)
env = dict(os.environ)
env["PYTHONPATH"] = "../test/test_extension/build/lib.linux-x86_64-2.7/"
p = subprocess.Popen(["python", "-Wignore", fn], stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=open("/dev/null"), preexec_fn=set_ulimits, env=env)
out, err = p.communicate()
code = p.wait()
......
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