Commit 5415879c authored by Kevin Modzelewski's avatar Kevin Modzelewski

Merge pull request #480 from kmod/gflags

run gflags unittests
parents 610be9f5 6ec39445
...@@ -16,3 +16,6 @@ ...@@ -16,3 +16,6 @@
[submodule "test/integration/pycrypto"] [submodule "test/integration/pycrypto"]
path = test/integration/pycrypto path = test/integration/pycrypto
url = https://github.com/dlitz/pycrypto.git url = https://github.com/dlitz/pycrypto.git
[submodule "test/integration/gflags"]
path = test/integration/gflags
url = https://github.com/google/python-gflags
...@@ -356,6 +356,7 @@ STDMODULE_SRCS := \ ...@@ -356,6 +356,7 @@ STDMODULE_SRCS := \
_sqlite/row.c \ _sqlite/row.c \
_sqlite/statement.c \ _sqlite/statement.c \
_sqlite/util.c \ _sqlite/util.c \
stropmodule.c \
$(EXTRA_STDMODULE_SRCS) $(EXTRA_STDMODULE_SRCS)
STDOBJECT_SRCS := \ STDOBJECT_SRCS := \
...@@ -383,6 +384,7 @@ STDPYTHON_SRCS := \ ...@@ -383,6 +384,7 @@ STDPYTHON_SRCS := \
formatter_unicode.c \ formatter_unicode.c \
structmember.c \ structmember.c \
marshal.c \ marshal.c \
mystrtoul.c \
$(EXTRA_STDPYTHON_SRCS) $(EXTRA_STDPYTHON_SRCS)
STDPARSER_SRCS := \ STDPARSER_SRCS := \
...@@ -528,6 +530,7 @@ quick_check: ...@@ -528,6 +530,7 @@ quick_check:
$(MAKE) check_format $(MAKE) check_format
$(MAKE) unittests $(MAKE) unittests
$(PYTHON) $(TOOLS_DIR)/tester.py -R pyston_dbg -j$(TEST_THREADS) -a=-S -k --order-by-mtime $(TESTS_DIR) $(ARGS) $(PYTHON) $(TOOLS_DIR)/tester.py -R pyston_dbg -j$(TEST_THREADS) -a=-S -k --order-by-mtime $(TESTS_DIR) $(ARGS)
$(PYTHON) $(TOOLS_DIR)/tester.py -R pyston_dbg -j$(TEST_THREADS) -a=-S -k --exit-code-only --skip-failing $(TEST_DIR)/cpython $(ARGS)
Makefile.local: Makefile.local:
echo "Creating default Makefile.local" echo "Creating default Makefile.local"
......
...@@ -62,6 +62,7 @@ file(GLOB_RECURSE STDMODULE_SRCS Modules ...@@ -62,6 +62,7 @@ file(GLOB_RECURSE STDMODULE_SRCS Modules
socketmodule.c socketmodule.c
statement.c statement.c
stringio.c stringio.c
stropmodule.c
textio.c textio.c
timemodule.c timemodule.c
unicodedata.c unicodedata.c
...@@ -94,6 +95,7 @@ file(GLOB_RECURSE STDPYTHON_SRCS Python ...@@ -94,6 +95,7 @@ file(GLOB_RECURSE STDPYTHON_SRCS Python
formatter_unicode.c formatter_unicode.c
getargs.c getargs.c
marshal.c marshal.c
mystrtoul.c
pyctype.c pyctype.c
pystrtod.c pystrtod.c
structmember.c structmember.c
......
...@@ -636,9 +636,9 @@ xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx*/ ...@@ -636,9 +636,9 @@ xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx*/
is an iterator, this returns itself. */ is an iterator, this returns itself. */
#define PyIter_Check(obj) \ #define PyIter_Check(obj) \
(PyType_HasFeature((obj)->ob_type, Py_TPFLAGS_HAVE_ITER) && \ (PyType_HasFeature(Py_TYPE((obj)), Py_TPFLAGS_HAVE_ITER) && \
(obj)->ob_type->tp_iternext != NULL && \ Py_TYPE((obj))->tp_iternext != NULL && \
(obj)->ob_type->tp_iternext != &_PyObject_NextNotImplemented) Py_TYPE((obj))->tp_iternext != &_PyObject_NextNotImplemented)
PyAPI_FUNC(PyObject *) PyIter_Next(PyObject *) PYSTON_NOEXCEPT; PyAPI_FUNC(PyObject *) PyIter_Next(PyObject *) PYSTON_NOEXCEPT;
/* Takes an iterator object and calls its tp_iternext slot, /* Takes an iterator object and calls its tp_iternext slot,
......
...@@ -124,6 +124,7 @@ ...@@ -124,6 +124,7 @@
#define HAVE_UNISTD_H 1 #define HAVE_UNISTD_H 1
#define HAVE_UTIME_H 1 #define HAVE_UTIME_H 1
#define HAVE_WCHAR_H 1 #define HAVE_WCHAR_H 1
#define HAVE_PUTENV 1
// Added this for some Pyston modifications: // Added this for some Pyston modifications:
#define MAX_PYSTRING_SIZE (PY_SSIZE_T_MAX/2 - (1<<20)) #define MAX_PYSTRING_SIZE (PY_SSIZE_T_MAX/2 - (1<<20))
......
...@@ -9451,7 +9451,7 @@ INITFUNC(void) ...@@ -9451,7 +9451,7 @@ INITFUNC(void)
#ifdef HAVE_PUTENV #ifdef HAVE_PUTENV
if (posix_putenv_garbage == NULL) if (posix_putenv_garbage == NULL)
posix_putenv_garbage = PyDict_New(); posix_putenv_garbage = PyGC_AddRoot(PyDict_New());
#endif #endif
if (!initialized) { if (!initialized) {
......
#include "Python.h"
#if defined(__sgi) && defined(WITH_THREAD) && !defined(_SGI_MP_SOURCE)
#define _SGI_MP_SOURCE
#endif
/* strtol and strtoul, renamed to avoid conflicts */
#include <ctype.h>
#ifdef HAVE_ERRNO_H
#include <errno.h>
#endif
/* Static overflow check values for bases 2 through 36.
* smallmax[base] is the largest unsigned long i such that
* i * base doesn't overflow unsigned long.
*/
static unsigned long smallmax[] = {
0, /* bases 0 and 1 are invalid */
0,
ULONG_MAX / 2,
ULONG_MAX / 3,
ULONG_MAX / 4,
ULONG_MAX / 5,
ULONG_MAX / 6,
ULONG_MAX / 7,
ULONG_MAX / 8,
ULONG_MAX / 9,
ULONG_MAX / 10,
ULONG_MAX / 11,
ULONG_MAX / 12,
ULONG_MAX / 13,
ULONG_MAX / 14,
ULONG_MAX / 15,
ULONG_MAX / 16,
ULONG_MAX / 17,
ULONG_MAX / 18,
ULONG_MAX / 19,
ULONG_MAX / 20,
ULONG_MAX / 21,
ULONG_MAX / 22,
ULONG_MAX / 23,
ULONG_MAX / 24,
ULONG_MAX / 25,
ULONG_MAX / 26,
ULONG_MAX / 27,
ULONG_MAX / 28,
ULONG_MAX / 29,
ULONG_MAX / 30,
ULONG_MAX / 31,
ULONG_MAX / 32,
ULONG_MAX / 33,
ULONG_MAX / 34,
ULONG_MAX / 35,
ULONG_MAX / 36,
};
/* maximum digits that can't ever overflow for bases 2 through 36,
* calculated by [int(math.floor(math.log(2**32, i))) for i in range(2, 37)].
* Note that this is pessimistic if sizeof(long) > 4.
*/
#if SIZEOF_LONG == 4
static int digitlimit[] = {
0, 0, 32, 20, 16, 13, 12, 11, 10, 10, /* 0 - 9 */
9, 9, 8, 8, 8, 8, 8, 7, 7, 7, /* 10 - 19 */
7, 7, 7, 7, 6, 6, 6, 6, 6, 6, /* 20 - 29 */
6, 6, 6, 6, 6, 6, 6}; /* 30 - 36 */
#elif SIZEOF_LONG == 8
/* [int(math.floor(math.log(2**64, i))) for i in range(2, 37)] */
static int digitlimit[] = {
0, 0, 64, 40, 32, 27, 24, 22, 21, 20, /* 0 - 9 */
19, 18, 17, 17, 16, 16, 16, 15, 15, 15, /* 10 - 19 */
14, 14, 14, 14, 13, 13, 13, 13, 13, 13, /* 20 - 29 */
13, 12, 12, 12, 12, 12, 12}; /* 30 - 36 */
#else
#error "Need table for SIZEOF_LONG"
#endif
/*
** strtoul
** This is a general purpose routine for converting
** an ascii string to an integer in an arbitrary base.
** Leading white space is ignored. If 'base' is zero
** it looks for a leading 0, 0b, 0B, 0o, 0O, 0x or 0X
** to tell which base. If these are absent it defaults
** to 10. Base must be 0 or between 2 and 36 (inclusive).
** If 'ptr' is non-NULL it will contain a pointer to
** the end of the scan.
** Errors due to bad pointers will probably result in
** exceptions - we don't check for them.
*/
unsigned long
PyOS_strtoul(register char *str, char **ptr, int base)
{
register unsigned long result = 0; /* return value of the function */
register int c; /* current input character */
register int ovlimit; /* required digits to overflow */
/* skip leading white space */
while (*str && isspace(Py_CHARMASK(*str)))
++str;
/* check for leading 0 or 0x for auto-base or base 16 */
switch (base) {
case 0: /* look for leading 0, 0b, 0o or 0x */
if (*str == '0') {
++str;
if (*str == 'x' || *str == 'X') {
/* there must be at least one digit after 0x */
if (_PyLong_DigitValue[Py_CHARMASK(str[1])] >= 16) {
if (ptr)
*ptr = str;
return 0;
}
++str;
base = 16;
} else if (*str == 'o' || *str == 'O') {
/* there must be at least one digit after 0o */
if (_PyLong_DigitValue[Py_CHARMASK(str[1])] >= 8) {
if (ptr)
*ptr = str;
return 0;
}
++str;
base = 8;
} else if (*str == 'b' || *str == 'B') {
/* there must be at least one digit after 0b */
if (_PyLong_DigitValue[Py_CHARMASK(str[1])] >= 2) {
if (ptr)
*ptr = str;
return 0;
}
++str;
base = 2;
} else {
base = 8;
}
}
else
base = 10;
break;
case 2: /* skip leading 0b or 0B */
if (*str == '0') {
++str;
if (*str == 'b' || *str == 'B') {
/* there must be at least one digit after 0b */
if (_PyLong_DigitValue[Py_CHARMASK(str[1])] >= 2) {
if (ptr)
*ptr = str;
return 0;
}
++str;
}
}
break;
case 8: /* skip leading 0o or 0O */
if (*str == '0') {
++str;
if (*str == 'o' || *str == 'O') {
/* there must be at least one digit after 0o */
if (_PyLong_DigitValue[Py_CHARMASK(str[1])] >= 8) {
if (ptr)
*ptr = str;
return 0;
}
++str;
}
}
break;
case 16: /* skip leading 0x or 0X */
if (*str == '0') {
++str;
if (*str == 'x' || *str == 'X') {
/* there must be at least one digit after 0x */
if (_PyLong_DigitValue[Py_CHARMASK(str[1])] >= 16) {
if (ptr)
*ptr = str;
return 0;
}
++str;
}
}
break;
}
/* catch silly bases */
if (base < 2 || base > 36) {
if (ptr)
*ptr = str;
return 0;
}
/* skip leading zeroes */
while (*str == '0')
++str;
/* base is guaranteed to be in [2, 36] at this point */
ovlimit = digitlimit[base];
/* do the conversion until non-digit character encountered */
while ((c = _PyLong_DigitValue[Py_CHARMASK(*str)]) < base) {
if (ovlimit > 0) /* no overflow check required */
result = result * base + c;
else { /* requires overflow check */
register unsigned long temp_result;
if (ovlimit < 0) /* guaranteed overflow */
goto overflowed;
/* there could be an overflow */
/* check overflow just from shifting */
if (result > smallmax[base])
goto overflowed;
result *= base;
/* check overflow from the digit's value */
temp_result = result + c;
if (temp_result < result)
goto overflowed;
result = temp_result;
}
++str;
--ovlimit;
}
/* set pointer to point to the last character scanned */
if (ptr)
*ptr = str;
return result;
overflowed:
if (ptr) {
/* spool through remaining digit characters */
while (_PyLong_DigitValue[Py_CHARMASK(*str)] < base)
++str;
*ptr = str;
}
errno = ERANGE;
return (unsigned long)-1;
}
/* Checking for overflow in PyOS_strtol is a PITA; see comments
* about PY_ABS_LONG_MIN in longobject.c.
*/
#define PY_ABS_LONG_MIN (0-(unsigned long)LONG_MIN)
long
PyOS_strtol(char *str, char **ptr, int base)
{
long result;
unsigned long uresult;
char sign;
while (*str && isspace(Py_CHARMASK(*str)))
str++;
sign = *str;
if (sign == '+' || sign == '-')
str++;
uresult = PyOS_strtoul(str, ptr, base);
if (uresult <= (unsigned long)LONG_MAX) {
result = (long)uresult;
if (sign == '-')
result = -result;
}
else if (sign == '-' && uresult == PY_ABS_LONG_MIN) {
result = LONG_MIN;
}
else {
errno = ERANGE;
result = LONG_MAX;
}
return result;
}
...@@ -346,6 +346,16 @@ public: ...@@ -346,6 +346,16 @@ public:
abort(); abort();
} }
Box* getGlobalsDict() {
Box* globals = getGlobals();
if (!globals)
return NULL;
if (isSubclass(globals->cls, module_cls))
return globals->getAttrWrapper();
return globals;
}
FrameInfo* getFrameInfo() { FrameInfo* getFrameInfo() {
if (id.type == PythonFrameId::COMPILED) { if (id.type == PythonFrameId::COMPILED) {
CompiledFunction* cf = getCF(); CompiledFunction* cf = getCF();
...@@ -591,13 +601,7 @@ Box* getGlobals() { ...@@ -591,13 +601,7 @@ Box* getGlobals() {
} }
Box* getGlobalsDict() { Box* getGlobalsDict() {
Box* globals = getGlobals(); return getTopPythonFrame()->getGlobalsDict();
if (!globals)
return NULL;
if (isSubclass(globals->cls, module_cls))
return globals->getAttrWrapper();
return globals;
} }
BoxedModule* getCurrentModule() { BoxedModule* getCurrentModule() {
...@@ -890,6 +894,10 @@ CompiledFunction* PythonFrameIterator::getCF() { ...@@ -890,6 +894,10 @@ CompiledFunction* PythonFrameIterator::getCF() {
return impl->getCF(); return impl->getCF();
} }
Box* PythonFrameIterator::getGlobalsDict() {
return impl->getGlobalsDict();
}
FrameInfo* PythonFrameIterator::getFrameInfo() { FrameInfo* PythonFrameIterator::getFrameInfo() {
return impl->getFrameInfo(); return impl->getFrameInfo();
} }
...@@ -907,6 +915,29 @@ PythonFrameIterator PythonFrameIterator::getCurrentVersion() { ...@@ -907,6 +915,29 @@ PythonFrameIterator PythonFrameIterator::getCurrentVersion() {
return PythonFrameIterator(std::move(rtn)); return PythonFrameIterator(std::move(rtn));
} }
PythonFrameIterator PythonFrameIterator::back() {
// TODO this is ineffecient: the iterator is no longer valid for libunwind iteration, so
// we have to do a full stack crawl again.
// Hopefully examination of f_back is uncommon.
std::unique_ptr<PythonFrameIteratorImpl> rtn(nullptr);
auto& impl = this->impl;
bool found = false;
unwindPythonStack([&](std::unique_ptr<PythonFrameIteratorImpl> frame_iter) {
if (found) {
rtn = std::move(frame_iter);
return true;
}
if (frame_iter->pointsToTheSameAs(*impl.get()))
found = true;
return false;
});
RELEASE_ASSERT(found, "this wasn't a valid frame?");
return PythonFrameIterator(std::move(rtn));
}
llvm::JITEventListener* makeTracebacksListener() { llvm::JITEventListener* makeTracebacksListener() {
return new TracebacksEventListener(); return new TracebacksEventListener();
} }
......
...@@ -53,15 +53,20 @@ public: ...@@ -53,15 +53,20 @@ public:
bool exists() { return impl.get() != NULL; } bool exists() { return impl.get() != NULL; }
std::unique_ptr<ExecutionPoint> getExecutionPoint(); std::unique_ptr<ExecutionPoint> getExecutionPoint();
Box* fastLocalsToBoxedLocals(); Box* fastLocalsToBoxedLocals();
Box* getGlobalsDict();
// Gets the "current version" of this frame: if the frame has executed since // Gets the "current version" of this frame: if the frame has executed since
// the iterator was obtained, the methods may return old values. This returns // the iterator was obtained, the methods may return old values. This returns
// an updated copy that returns the updated values. // an updated copy that returns the updated values.
// The "current version" will live at the same stack location, but any other // The "current version" will live at the same stack location, but any other
// similarities need to be verified by the caller. // similarities need to be verified by the caller, ie it is up to the caller
// to determine that we didn't leave and reenter the stack frame.
// This function can only be called from the thread that created this object. // This function can only be called from the thread that created this object.
PythonFrameIterator getCurrentVersion(); PythonFrameIterator getCurrentVersion();
// Assuming this is a valid frame iterator, return the next frame back (ie older).
PythonFrameIterator back();
PythonFrameIterator(PythonFrameIterator&& rhs); PythonFrameIterator(PythonFrameIterator&& rhs);
void operator=(PythonFrameIterator&& rhs); void operator=(PythonFrameIterator&& rhs);
PythonFrameIterator(std::unique_ptr<PythonFrameIteratorImpl> impl); PythonFrameIterator(std::unique_ptr<PythonFrameIteratorImpl> impl);
......
...@@ -333,6 +333,34 @@ Box* instanceSetattr(Box* _inst, Box* _attr, Box* value) { ...@@ -333,6 +333,34 @@ Box* instanceSetattr(Box* _inst, Box* _attr, Box* value) {
return None; return None;
} }
Box* instanceDelattr(Box* _inst, Box* _attr) {
RELEASE_ASSERT(_inst->cls == instance_cls, "");
BoxedInstance* inst = static_cast<BoxedInstance*>(_inst);
RELEASE_ASSERT(_attr->cls == str_cls, "");
BoxedString* attr = static_cast<BoxedString*>(_attr);
// These are special cases in CPython as well:
if (attr->s[0] == '_' && attr->s[1] == '_') {
if (attr->s == "__dict__")
raiseExcHelper(TypeError, "__dict__ must be set to a dictionary");
if (attr->s == "__class__")
raiseExcHelper(TypeError, "__class__ must be set to a class");
}
static const std::string delattr_str("__delattr__");
Box* delattr = classLookup(inst->inst_cls, delattr_str);
if (delattr) {
delattr = processDescriptor(delattr, inst, inst->inst_cls);
return runtimeCall(delattr, ArgPassSpec(1), _attr, NULL, NULL, NULL, NULL);
}
_inst->delattr(attr->s, NULL);
return None;
}
static int instance_setattro(Box* cls, Box* attr, Box* value) noexcept { static int instance_setattro(Box* cls, Box* attr, Box* value) noexcept {
try { try {
if (value) { if (value) {
...@@ -488,6 +516,45 @@ static Box* instanceHash(BoxedInstance* inst) { ...@@ -488,6 +516,45 @@ static Box* instanceHash(BoxedInstance* inst) {
} }
} }
static Box* instanceIter(BoxedInstance* self) {
assert(self->cls == instance_cls);
PyObject* func;
if ((func = _instanceGetattribute(self, boxStrConstant("__iter__"), false)) != NULL) {
PyObject* res = PyEval_CallObject(func, (PyObject*)NULL);
if (!res)
throwCAPIException();
if (!PyIter_Check(res))
raiseExcHelper(TypeError, "__iter__ returned non-iterator of type '%.100s'", res->cls->tp_name);
return res;
}
if ((func = _instanceGetattribute(self, boxStrConstant("__getitem__"), false)) == NULL) {
raiseExcHelper(TypeError, "iteration over non-sequence");
}
Box* r = PySeqIter_New((PyObject*)self);
if (!r)
throwCAPIException();
return r;
}
static Box* instanceNext(BoxedInstance* inst) {
assert(inst->cls == instance_cls);
Box* next_func = _instanceGetattribute(inst, boxStrConstant("next"), false);
if (!next_func) {
// not 100% sure why this is a different error:
raiseExcHelper(TypeError, "instance has no next() method");
}
Box* r = runtimeCall(next_func, ArgPassSpec(0), NULL, NULL, NULL, NULL, NULL);
return r;
}
static PyObject* instance_index(PyObject* self) noexcept { static PyObject* instance_index(PyObject* self) noexcept {
PyObject* func, *res; PyObject* func, *res;
/* /*
...@@ -569,6 +636,7 @@ void setupClassobj() { ...@@ -569,6 +636,7 @@ void setupClassobj() {
instance_cls->giveAttr("__getattribute__", instance_cls->giveAttr("__getattribute__",
new BoxedFunction(boxRTFunction((void*)instanceGetattribute, UNKNOWN, 2))); new BoxedFunction(boxRTFunction((void*)instanceGetattribute, UNKNOWN, 2)));
instance_cls->giveAttr("__setattr__", new BoxedFunction(boxRTFunction((void*)instanceSetattr, UNKNOWN, 3))); instance_cls->giveAttr("__setattr__", new BoxedFunction(boxRTFunction((void*)instanceSetattr, UNKNOWN, 3)));
instance_cls->giveAttr("__delattr__", new BoxedFunction(boxRTFunction((void*)instanceDelattr, UNKNOWN, 2)));
instance_cls->giveAttr("__str__", new BoxedFunction(boxRTFunction((void*)instanceStr, UNKNOWN, 1))); instance_cls->giveAttr("__str__", new BoxedFunction(boxRTFunction((void*)instanceStr, UNKNOWN, 1)));
instance_cls->giveAttr("__repr__", new BoxedFunction(boxRTFunction((void*)instanceRepr, UNKNOWN, 1))); instance_cls->giveAttr("__repr__", new BoxedFunction(boxRTFunction((void*)instanceRepr, UNKNOWN, 1)));
instance_cls->giveAttr("__nonzero__", new BoxedFunction(boxRTFunction((void*)instanceNonzero, UNKNOWN, 1))); instance_cls->giveAttr("__nonzero__", new BoxedFunction(boxRTFunction((void*)instanceNonzero, UNKNOWN, 1)));
...@@ -578,6 +646,8 @@ void setupClassobj() { ...@@ -578,6 +646,8 @@ void setupClassobj() {
instance_cls->giveAttr("__delitem__", new BoxedFunction(boxRTFunction((void*)instanceDelitem, UNKNOWN, 2))); instance_cls->giveAttr("__delitem__", new BoxedFunction(boxRTFunction((void*)instanceDelitem, UNKNOWN, 2)));
instance_cls->giveAttr("__contains__", new BoxedFunction(boxRTFunction((void*)instanceContains, UNKNOWN, 2))); instance_cls->giveAttr("__contains__", new BoxedFunction(boxRTFunction((void*)instanceContains, UNKNOWN, 2)));
instance_cls->giveAttr("__hash__", new BoxedFunction(boxRTFunction((void*)instanceHash, UNKNOWN, 1))); instance_cls->giveAttr("__hash__", new BoxedFunction(boxRTFunction((void*)instanceHash, UNKNOWN, 1)));
instance_cls->giveAttr("__iter__", new BoxedFunction(boxRTFunction((void*)instanceIter, UNKNOWN, 1)));
instance_cls->giveAttr("next", new BoxedFunction(boxRTFunction((void*)instanceNext, UNKNOWN, 1)));
instance_cls->giveAttr("__call__", instance_cls->giveAttr("__call__",
new BoxedFunction(boxRTFunction((void*)instanceCall, UNKNOWN, 1, 0, true, true))); new BoxedFunction(boxRTFunction((void*)instanceCall, UNKNOWN, 1, 0, true, true)));
instance_cls->giveAttr("__eq__", new BoxedFunction(boxRTFunction((void*)instanceEq, UNKNOWN, 2))); instance_cls->giveAttr("__eq__", new BoxedFunction(boxRTFunction((void*)instanceEq, UNKNOWN, 2)));
......
...@@ -1647,6 +1647,8 @@ void setupFile() { ...@@ -1647,6 +1647,8 @@ void setupFile() {
file_cls->giveAttr("tell", new BoxedFunction(boxRTFunction((void*)fileTell, UNKNOWN, 1))); file_cls->giveAttr("tell", new BoxedFunction(boxRTFunction((void*)fileTell, UNKNOWN, 1)));
file_cls->giveAttr("softspace", file_cls->giveAttr("softspace",
new BoxedMemberDescriptor(BoxedMemberDescriptor::INT, offsetof(BoxedFile, f_softspace), false)); new BoxedMemberDescriptor(BoxedMemberDescriptor::INT, offsetof(BoxedFile, f_softspace), false));
file_cls->giveAttr("name",
new BoxedMemberDescriptor(BoxedMemberDescriptor::OBJECT, offsetof(BoxedFile, f_name), true));
file_cls->giveAttr("__new__", new BoxedFunction(boxRTFunction((void*)fileNew, UNKNOWN, 4, 2, false, false), file_cls->giveAttr("__new__", new BoxedFunction(boxRTFunction((void*)fileNew, UNKNOWN, 4, 2, false, false),
{ boxStrConstant("r"), boxInt(-1) })); { boxStrConstant("r"), boxInt(-1) }));
......
...@@ -27,10 +27,12 @@ BoxedClass* frame_cls; ...@@ -27,10 +27,12 @@ BoxedClass* frame_cls;
// - breaks c++ exceptions // - breaks c++ exceptions
// - we never free the trampolines // - we never free the trampolines
class BoxedFrame : public Box { class BoxedFrame : public Box {
public: private:
BoxedFrame(PythonFrameIterator&& it) __attribute__((visibility("default"))) // Call boxFrame to get a BoxedFrame object.
BoxedFrame(PythonFrameIterator it) __attribute__((visibility("default")))
: it(std::move(it)), thread_id(PyThread_get_thread_ident()) {} : it(std::move(it)), thread_id(PyThread_get_thread_ident()) {}
public:
PythonFrameIterator it; PythonFrameIterator it;
long thread_id; long thread_id;
...@@ -105,6 +107,16 @@ public: ...@@ -105,6 +107,16 @@ public:
return f->_globals; return f->_globals;
} }
static Box* back(Box* obj, void*) {
auto f = static_cast<BoxedFrame*>(obj);
f->update();
PythonFrameIterator it = f->it.back();
if (!it.exists())
return None;
return BoxedFrame::boxFrame(std::move(it));
}
static Box* lineno(Box* obj, void*) { static Box* lineno(Box* obj, void*) {
auto f = static_cast<BoxedFrame*>(obj); auto f = static_cast<BoxedFrame*>(obj);
f->update(); f->update();
...@@ -113,6 +125,19 @@ public: ...@@ -113,6 +125,19 @@ public:
} }
DEFAULT_CLASS(frame_cls); DEFAULT_CLASS(frame_cls);
static Box* boxFrame(PythonFrameIterator it) {
FrameInfo* fi = it.getFrameInfo();
if (fi->frame_obj == NULL) {
auto cf = it.getCF();
Box* globals = it.getGlobalsDict();
BoxedFrame* f = fi->frame_obj = new BoxedFrame(std::move(it));
f->_globals = globals;
f->_code = codeForCLFunction(cf->clfunc);
}
return fi->frame_obj;
}
}; };
Box* getFrame(int depth) { Box* getFrame(int depth) {
...@@ -120,19 +145,9 @@ Box* getFrame(int depth) { ...@@ -120,19 +145,9 @@ Box* getFrame(int depth) {
if (!it.exists()) if (!it.exists())
return NULL; return NULL;
FrameInfo* fi = it.getFrameInfo(); return BoxedFrame::boxFrame(std::move(it));
if (fi->frame_obj == NULL) {
auto cf = it.getCF();
BoxedFrame* f = fi->frame_obj = new BoxedFrame(std::move(it));
assert(cf->clfunc->source->scoping->areGlobalsFromModule());
f->_globals = cf->clfunc->source->parent_module->getAttrWrapper();
f->_code = codeForCLFunction(cf->clfunc);
}
return fi->frame_obj;
} }
void setupFrame() { void setupFrame() {
frame_cls = BoxedHeapClass::create(type_cls, object_cls, &BoxedFrame::gchandler, 0, 0, sizeof(BoxedFrame), false, frame_cls = BoxedHeapClass::create(type_cls, object_cls, &BoxedFrame::gchandler, 0, 0, sizeof(BoxedFrame), false,
"frame"); "frame");
...@@ -143,6 +158,7 @@ void setupFrame() { ...@@ -143,6 +158,7 @@ void setupFrame() {
frame_cls->giveAttr("f_lineno", new (pyston_getset_cls) BoxedGetsetDescriptor(BoxedFrame::lineno, NULL, NULL)); frame_cls->giveAttr("f_lineno", new (pyston_getset_cls) BoxedGetsetDescriptor(BoxedFrame::lineno, NULL, NULL));
frame_cls->giveAttr("f_globals", new (pyston_getset_cls) BoxedGetsetDescriptor(BoxedFrame::globals, NULL, NULL)); frame_cls->giveAttr("f_globals", new (pyston_getset_cls) BoxedGetsetDescriptor(BoxedFrame::globals, NULL, NULL));
frame_cls->giveAttr("f_back", new (pyston_getset_cls) BoxedGetsetDescriptor(BoxedFrame::back, NULL, NULL));
frame_cls->freeze(); frame_cls->freeze();
} }
......
...@@ -1103,6 +1103,8 @@ void setupList() { ...@@ -1103,6 +1103,8 @@ void setupList() {
"index", new BoxedFunction(boxRTFunction((void*)listIndex, BOXED_INT, 4, 2, false, false), { NULL, NULL })); "index", new BoxedFunction(boxRTFunction((void*)listIndex, BOXED_INT, 4, 2, false, false), { NULL, NULL }));
list_cls->giveAttr("remove", new BoxedFunction(boxRTFunction((void*)listRemove, NONE, 2))); list_cls->giveAttr("remove", new BoxedFunction(boxRTFunction((void*)listRemove, NONE, 2)));
list_cls->giveAttr("reverse", new BoxedFunction(boxRTFunction((void*)listReverse, NONE, 1))); list_cls->giveAttr("reverse", new BoxedFunction(boxRTFunction((void*)listReverse, NONE, 1)));
list_cls->giveAttr("__hash__", None);
list_cls->freeze(); list_cls->freeze();
CLFunction* hasnext = boxRTFunction((void*)listiterHasnextUnboxed, BOOL, 1); CLFunction* hasnext = boxRTFunction((void*)listiterHasnextUnboxed, BOOL, 1);
......
...@@ -35,6 +35,27 @@ namespace pyston { ...@@ -35,6 +35,27 @@ namespace pyston {
BoxedClass* long_cls; BoxedClass* long_cls;
/* Table of digit values for 8-bit string -> integer conversion.
* '0' maps to 0, ..., '9' maps to 9.
* 'a' and 'A' map to 10, ..., 'z' and 'Z' map to 35.
* All other indices map to 37.
* Note that when converting a base B string, a char c is a legitimate
* base B digit iff _PyLong_DigitValue[Py_CHARMASK(c)] < B.
*/
extern "C" {
int _PyLong_DigitValue[256] = {
37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37,
37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
37, 37, 37, 37, 37, 37, 37, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
32, 33, 34, 35, 37, 37, 37, 37, 37, 37, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28,
29, 30, 31, 32, 33, 34, 35, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37,
37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37,
37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37,
37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37,
37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37,
};
}
#define IS_LITTLE_ENDIAN (int)*(unsigned char*)&one #define IS_LITTLE_ENDIAN (int)*(unsigned char*)&one
#define PY_ABS_LLONG_MIN (0 - (unsigned PY_LONG_LONG)PY_LLONG_MIN) #define PY_ABS_LLONG_MIN (0 - (unsigned PY_LONG_LONG)PY_LLONG_MIN)
......
...@@ -320,13 +320,10 @@ BoxedClass::BoxedClass(BoxedClass* base, gcvisit_func gc_visit, int attrs_offset ...@@ -320,13 +320,10 @@ BoxedClass::BoxedClass(BoxedClass* base, gcvisit_func gc_visit, int attrs_offset
tp_basicsize = instance_size; tp_basicsize = instance_size;
tp_weaklistoffset = weaklist_offset; tp_weaklistoffset = weaklist_offset;
tp_flags |= Py_TPFLAGS_DEFAULT_EXTERNAL;
tp_flags |= Py_TPFLAGS_CHECKTYPES; tp_flags |= Py_TPFLAGS_CHECKTYPES;
tp_flags |= Py_TPFLAGS_BASETYPE; tp_flags |= Py_TPFLAGS_BASETYPE;
tp_flags |= Py_TPFLAGS_HAVE_CLASS;
tp_flags |= Py_TPFLAGS_HAVE_GC; tp_flags |= Py_TPFLAGS_HAVE_GC;
tp_flags |= Py_TPFLAGS_HAVE_WEAKREFS;
tp_flags |= Py_TPFLAGS_HAVE_RICHCOMPARE;
tp_flags |= Py_TPFLAGS_HAVE_INDEX;
if (base && (base->tp_flags & Py_TPFLAGS_HAVE_NEWBUFFER)) if (base && (base->tp_flags & Py_TPFLAGS_HAVE_NEWBUFFER))
tp_flags |= Py_TPFLAGS_HAVE_NEWBUFFER; tp_flags |= Py_TPFLAGS_HAVE_NEWBUFFER;
...@@ -2113,6 +2110,10 @@ extern "C" BoxedInt* hash(Box* obj) { ...@@ -2113,6 +2110,10 @@ extern "C" BoxedInt* hash(Box* obj) {
return static_cast<BoxedInt*>(boxInt((i64)obj)); return static_cast<BoxedInt*>(boxInt((i64)obj));
} }
if (hash == None) {
raiseExcHelper(TypeError, "unhashable type: '%s'", obj->cls->tp_name);
}
Box* rtn = runtimeCall0(hash, ArgPassSpec(0)); Box* rtn = runtimeCall0(hash, ArgPassSpec(0));
if (rtn->cls != int_cls) { if (rtn->cls != int_cls) {
raiseExcHelper(TypeError, "an integer is required"); raiseExcHelper(TypeError, "an integer is required");
......
...@@ -78,6 +78,7 @@ extern "C" void init_csv(); ...@@ -78,6 +78,7 @@ extern "C" void init_csv();
extern "C" void init_ssl(); extern "C" void init_ssl();
extern "C" void init_sqlite3(); extern "C" void init_sqlite3();
extern "C" void PyMarshal_Init(); extern "C" void PyMarshal_Init();
extern "C" void initstrop();
namespace pyston { namespace pyston {
...@@ -2401,6 +2402,7 @@ void setupRuntime() { ...@@ -2401,6 +2402,7 @@ void setupRuntime() {
init_ssl(); init_ssl();
init_sqlite3(); init_sqlite3();
PyMarshal_Init(); PyMarshal_Init();
initstrop();
// some additional setup to ensure weakrefs participate in our GC // some additional setup to ensure weakrefs participate in our GC
BoxedClass* weakref_ref_cls = &_PyWeakref_RefType; BoxedClass* weakref_ref_cls = &_PyWeakref_RefType;
......
Subproject commit 1569dd1f3855abd262ea3a7741527d4413b35bc9
import glob
import subprocess, sys, os
gflags_dir = os.path.dirname(os.path.abspath(__file__)) + "/gflags"
os.chdir(gflags_dir)
env = os.environ
env["PYTHONPATH"] = "."
TESTS_DIR = "tests"
for fn in glob.glob("%s/*.py" % TESTS_DIR):
# We don't support xml.dom.minidom yet
if "helpxml_test.py" in fn:
print "Skipping", fn
continue
print "Running", fn
subprocess.check_call([sys.executable, fn])
print "-- Tests finished"
...@@ -131,3 +131,21 @@ g = {} ...@@ -131,3 +131,21 @@ g = {}
l = {} l = {}
exec ("a=1; print a", g, l) exec ("a=1; print a", g, l)
print g.keys(), l.keys() print g.keys(), l.keys()
s = """
global a
a = 1
b = 2
def inner():
print sorted(globals().keys()), sorted(locals().keys())
print a
print b
print sorted(globals().keys()), sorted(locals().keys())
inner()
"""
exec s in {}
try:
exec s in {}, {}
raise Exception()
except NameError as e:
print e
...@@ -3,6 +3,7 @@ import tempfile ...@@ -3,6 +3,7 @@ import tempfile
f = open("/dev/null") f = open("/dev/null")
print repr(f.read()) print repr(f.read())
print repr(f.name)
f2 = file("/dev/null") f2 = file("/dev/null")
print repr(f2.read()) print repr(f2.read())
......
...@@ -195,3 +195,5 @@ l.sort(cmp=mycmp, key=str) ...@@ -195,3 +195,5 @@ l.sort(cmp=mycmp, key=str)
print types_seen print types_seen
print l print l
""" """
print repr(list.__hash__)
...@@ -147,9 +147,13 @@ class SetattrTest: ...@@ -147,9 +147,13 @@ class SetattrTest:
def __setattr__(self, attr, value): def __setattr__(self, attr, value):
print "setattr", attr, value print "setattr", attr, value
def __delattr__(self, attr):
print "delattr", attr
s = SetattrTest() s = SetattrTest()
s.b = 2 s.b = 2
print g.__dict__.items() print s.__dict__.items()
del s.b
class MappingTest: class MappingTest:
def __getitem__(self, key): def __getitem__(self, key):
...@@ -245,3 +249,29 @@ class E(C, object): ...@@ -245,3 +249,29 @@ class E(C, object):
print issubclass(D, C), isinstance(D(), C) print issubclass(D, C), isinstance(D(), C)
print issubclass(E, C), isinstance(E(), C) print issubclass(E, C), isinstance(E(), C)
print isinstance(E, object), isinstance(E(), object) print isinstance(E, object), isinstance(E(), object)
class SeqTest:
class Iterator:
def __init__(self):
self.n = 5
def next(self):
print "next"
if self.n <= 0:
raise StopIteration()
r = self.n
self.n -= 1
return r
def __iter__(self):
print "iter"
return SeqTest.Iterator()
m = SeqTest()
print list(m)
class OldSeqTest:
def __getitem__(self, n):
print "getitem", n
if n > 5:
raise IndexError()
return n ** 2
m = OldSeqTest()
print list(m)
...@@ -23,8 +23,13 @@ print e.strerror ...@@ -23,8 +23,13 @@ print e.strerror
print e.filename print e.filename
print OSError(1, 2).filename print OSError(1, 2).filename
# This part needs sys.exc_info() and the three-arg raise statement try:
# try: os.execvp("aoeuaoeu", ['aoeuaoeu'])
# os.execvp("aoeuaoeu", ['aoeuaoeu']) except OSError, e:
# except OSError, e: print e
# print e
# Changes to os.environ should show up in subprocesses:
import subprocess
env = os.environ
env["PYTHONPATH"] = "."
subprocess.check_call("echo PYTHONPATH is $PYTHONPATH", shell=1)
import strop
print repr(strop.whitespace)
import string
print repr(string.whitespace)
print repr(string.lowercase)
print repr(string.uppercase)
all_chars = ''.join(chr(i) for i in xrange(256))
print repr(strop.lower(all_chars))
...@@ -72,3 +72,30 @@ assert sys._getframe(0).f_globals is globals() ...@@ -72,3 +72,30 @@ assert sys._getframe(0).f_globals is globals()
def f5(): def f5():
assert sys._getframe(0).f_globals is globals() assert sys._getframe(0).f_globals is globals()
f5() f5()
# A number of libraries have functions like this:
def get_main_module():
f = sys._getframe(1)
while f.f_locals is not globals():
print f.f_code.co_filename, f.f_lineno, sorted(f.f_locals.items())
f = f.f_back
print "Main module currently at:", f.f_code.co_filename, f.f_lineno
print "f_back:", f.f_back
def f6(n):
if n:
f6(n - 1)
else:
get_main_module()
f6(10)
def custom_globals():
s = """
def inner():
import sys
return sys._getframe(1).f_globals
print sorted(inner().keys())
""".strip()
exec s
exec s in {'a':1}
exec s in {'b':2}, {'c':3}
custom_globals()
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