Commit 6249512d authored by Kevin Modzelewski's avatar Kevin Modzelewski

Fix the last few issues with optparse_test.py behavior

- was missing comparison methods on 'long', and we were happily using the default comparison rules
- isinstance for oldstyle classes
- int * str (who does it that direction??)

Performance is abyssmal: 2s for us vs 30ms for CPython
parent b7a886b6
......@@ -45,26 +45,12 @@ extern "C" void gc_compat_free(void* ptr) {
gc_free(ptr);
}
bool recursive = false;
extern "C" void abort() {
static void (*libc_abort)() = (void (*)())dlsym(RTLD_NEXT, "abort");
// Py_FatalError is likely to call abort() itself...
static bool recursive = false;
if (!recursive) {
recursive = true;
Py_FatalError("someone called abort!\n");
}
libc_abort();
__builtin_unreachable();
}
// We may need to hook malloc as well. For now, these definitions serve
// as a reference on how to do that, and also can help with debugging malloc
// usage issues.
#if 0
bool recursive = false;
extern "C" void* malloc(size_t sz) {
static void *(*libc_malloc)(size_t) = (void* (*)(size_t))dlsym(RTLD_NEXT, "malloc");
void* r = libc_malloc(sz);
......
......@@ -272,7 +272,6 @@ extern "C" void PyBuffer_Release(Py_buffer* view) {
extern "C" void Py_FatalError(const char* msg) __attribute__((__noreturn__));
extern "C" void Py_FatalError(const char* msg) {
fprintf(stderr, "\nFatal Python error: %s\n", msg);
_printStacktrace();
abort();
}
......@@ -406,7 +405,7 @@ extern "C" int PyCallable_Check(PyObject* x) {
extern "C" void PyErr_Restore(PyObject* type, PyObject* value, PyObject* traceback) {
Py_FatalError("unimplemented");
Py_FatalError("setting exceptions from the C API is current unimplemented");
}
extern "C" void PyErr_Clear() {
......
......@@ -26,39 +26,20 @@ namespace pyston {
BoxedClass* classobj_cls, *instance_cls;
class BoxedClassobj : public Box {
public:
HCAttrs attrs;
bool classIssubclass(BoxedClassobj* child, BoxedClassobj* parent) {
if (child == parent)
return true;
BoxedTuple* bases;
BoxedString* name;
BoxedClassobj(BoxedClass* metaclass, BoxedString* name, BoxedTuple* bases)
: Box(metaclass), bases(bases), name(name) {}
static void gcHandler(GCVisitor* v, Box* _o) {
assert(_o->cls == classobj_cls);
BoxedClassobj* o = static_cast<BoxedClassobj*>(_o);
boxGCHandler(v, o);
for (auto e : child->bases->elts) {
if (e->cls == classobj_cls && classIssubclass(static_cast<BoxedClassobj*>(e), parent))
return true;
}
};
class BoxedInstance : public Box {
public:
HCAttrs attrs;
BoxedClassobj* inst_cls;
BoxedInstance(BoxedClassobj* inst_cls) : Box(instance_cls), inst_cls(inst_cls) {}
static void gcHandler(GCVisitor* v, Box* _o) {
assert(_o->cls == instance_cls);
BoxedInstance* o = static_cast<BoxedInstance*>(_o);
return false;
}
boxGCHandler(v, o);
}
};
bool instanceIsinstance(BoxedInstance* obj, BoxedClassobj* cls) {
return classIssubclass(obj->inst_cls, cls);
}
static Box* classLookup(BoxedClassobj* cls, const std::string& attr) {
Box* r = cls->getattr(attr);
......@@ -188,6 +169,24 @@ Box* instanceGetattribute(Box* _inst, Box* _attr) {
return _instanceGetattribute(_inst, _attr, true);
}
Box* instanceRepr(Box* _inst) {
RELEASE_ASSERT(_inst->cls == instance_cls, "");
BoxedInstance* inst = static_cast<BoxedInstance*>(_inst);
Box* repr_func = _instanceGetattribute(inst, boxStrConstant("__repr__"), false);
if (repr_func) {
return runtimeCall(repr_func, ArgPassSpec(0), NULL, NULL, NULL, NULL, NULL);
} else {
Box* class_str = classobjStr(inst->inst_cls);
assert(class_str->cls == str_cls);
char buf[80];
snprintf(buf, 80, "<%s instance at %p>", static_cast<BoxedString*>(class_str)->s.c_str(), inst);
return boxStrConstant(buf);
}
}
Box* instanceStr(Box* _inst) {
RELEASE_ASSERT(_inst->cls == instance_cls, "");
BoxedInstance* inst = static_cast<BoxedInstance*>(_inst);
......@@ -197,6 +196,7 @@ Box* instanceStr(Box* _inst) {
if (str_func) {
return runtimeCall(str_func, ArgPassSpec(0), NULL, NULL, NULL, NULL, NULL);
} else {
return instanceRepr(inst);
return objectStr(_inst);
}
}
......@@ -265,6 +265,7 @@ void setupClassobj() {
instance_cls->giveAttr("__getattribute__",
new BoxedFunction(boxRTFunction((void*)instanceGetattribute, UNKNOWN, 2)));
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("__nonzero__", new BoxedFunction(boxRTFunction((void*)instanceNonzero, UNKNOWN, 1)));
instance_cls->giveAttr("__len__", new BoxedFunction(boxRTFunction((void*)instanceLen, UNKNOWN, 1)));
instance_cls->giveAttr("__getitem__", new BoxedFunction(boxRTFunction((void*)instanceGetitem, UNKNOWN, 2)));
......
......@@ -15,12 +15,52 @@
#ifndef PYSTON_RUNTIME_CLASSOBJ_H
#define PYSTON_RUNTIME_CLASSOBJ_H
#include "runtime/types.h"
namespace pyston {
void setupClassobj();
class BoxedClass;
extern BoxedClass* classobj_cls;
class BoxedClassobj;
class BoxedInstance;
extern BoxedClass* classobj_cls, *instance_cls;
bool instanceIsinstance(BoxedInstance* obj, BoxedClassobj* cls);
class BoxedClassobj : public Box {
public:
HCAttrs attrs;
BoxedTuple* bases;
BoxedString* name;
BoxedClassobj(BoxedClass* metaclass, BoxedString* name, BoxedTuple* bases)
: Box(metaclass), bases(bases), name(name) {}
static void gcHandler(GCVisitor* v, Box* _o) {
assert(_o->cls == classobj_cls);
BoxedClassobj* o = static_cast<BoxedClassobj*>(_o);
boxGCHandler(v, o);
}
};
class BoxedInstance : public Box {
public:
HCAttrs attrs;
BoxedClassobj* inst_cls;
BoxedInstance(BoxedClassobj* inst_cls) : Box(instance_cls), inst_cls(inst_cls) {}
static void gcHandler(GCVisitor* v, Box* _o) {
assert(_o->cls == instance_cls);
BoxedInstance* o = static_cast<BoxedInstance*>(_o);
boxGCHandler(v, o);
}
};
}
#endif
......@@ -201,6 +201,115 @@ Box* longAdd(BoxedLong* v1, Box* _v2) {
}
}
// TODO reduce duplication between these 6 functions, and add double support
Box* longGt(BoxedLong* v1, Box* _v2) {
if (!isSubclass(v1->cls, long_cls))
raiseExcHelper(TypeError, "descriptor '__gt__' requires a 'long' object but received a '%s'",
getTypeName(v1)->c_str());
if (isSubclass(_v2->cls, long_cls)) {
BoxedLong* v2 = static_cast<BoxedLong*>(_v2);
return boxBool(mpz_cmp(v1->n, v2->n) > 0);
} else if (isSubclass(_v2->cls, int_cls)) {
BoxedInt* v2 = static_cast<BoxedInt*>(_v2);
return boxBool(mpz_cmp_si(v1->n, v2->n) > 0);
} else {
return NotImplemented;
}
}
Box* longGe(BoxedLong* v1, Box* _v2) {
if (!isSubclass(v1->cls, long_cls))
raiseExcHelper(TypeError, "descriptor '__ge__' requires a 'long' object but received a '%s'",
getTypeName(v1)->c_str());
if (isSubclass(_v2->cls, long_cls)) {
BoxedLong* v2 = static_cast<BoxedLong*>(_v2);
return boxBool(mpz_cmp(v1->n, v2->n) >= 0);
} else if (isSubclass(_v2->cls, int_cls)) {
BoxedInt* v2 = static_cast<BoxedInt*>(_v2);
return boxBool(mpz_cmp_si(v1->n, v2->n) >= 0);
} else {
return NotImplemented;
}
}
Box* longLt(BoxedLong* v1, Box* _v2) {
if (!isSubclass(v1->cls, long_cls))
raiseExcHelper(TypeError, "descriptor '__lt__' requires a 'long' object but received a '%s'",
getTypeName(v1)->c_str());
if (isSubclass(_v2->cls, long_cls)) {
BoxedLong* v2 = static_cast<BoxedLong*>(_v2);
return boxBool(mpz_cmp(v1->n, v2->n) < 0);
} else if (isSubclass(_v2->cls, int_cls)) {
BoxedInt* v2 = static_cast<BoxedInt*>(_v2);
return boxBool(mpz_cmp_si(v1->n, v2->n) < 0);
} else {
return NotImplemented;
}
}
Box* longLe(BoxedLong* v1, Box* _v2) {
if (!isSubclass(v1->cls, long_cls))
raiseExcHelper(TypeError, "descriptor '__le__' requires a 'long' object but received a '%s'",
getTypeName(v1)->c_str());
if (isSubclass(_v2->cls, long_cls)) {
BoxedLong* v2 = static_cast<BoxedLong*>(_v2);
return boxBool(mpz_cmp(v1->n, v2->n) <= 0);
} else if (isSubclass(_v2->cls, int_cls)) {
BoxedInt* v2 = static_cast<BoxedInt*>(_v2);
return boxBool(mpz_cmp_si(v1->n, v2->n) <= 0);
} else {
return NotImplemented;
}
}
Box* longEq(BoxedLong* v1, Box* _v2) {
if (!isSubclass(v1->cls, long_cls))
raiseExcHelper(TypeError, "descriptor '__eq__' requires a 'long' object but received a '%s'",
getTypeName(v1)->c_str());
if (isSubclass(_v2->cls, long_cls)) {
BoxedLong* v2 = static_cast<BoxedLong*>(_v2);
return boxBool(mpz_cmp(v1->n, v2->n) == 0);
} else if (isSubclass(_v2->cls, int_cls)) {
BoxedInt* v2 = static_cast<BoxedInt*>(_v2);
return boxBool(mpz_cmp_si(v1->n, v2->n) == 0);
} else {
return NotImplemented;
}
}
Box* longNe(BoxedLong* v1, Box* _v2) {
if (!isSubclass(v1->cls, long_cls))
raiseExcHelper(TypeError, "descriptor '__ne__' requires a 'long' object but received a '%s'",
getTypeName(v1)->c_str());
if (isSubclass(_v2->cls, long_cls)) {
BoxedLong* v2 = static_cast<BoxedLong*>(_v2);
return boxBool(mpz_cmp(v1->n, v2->n) != 0);
} else if (isSubclass(_v2->cls, int_cls)) {
BoxedInt* v2 = static_cast<BoxedInt*>(_v2);
return boxBool(mpz_cmp_si(v1->n, v2->n) != 0);
} else {
return NotImplemented;
}
}
Box* longLshift(BoxedLong* v1, Box* _v2) {
if (!isSubclass(v1->cls, long_cls))
raiseExcHelper(TypeError, "descriptor '__lshift__' requires a 'long' object but received a '%s'",
......@@ -431,6 +540,13 @@ void setupLong() {
long_cls->giveAttr("__add__", new BoxedFunction(boxRTFunction((void*)longAdd, UNKNOWN, 2)));
long_cls->giveAttr("__radd__", long_cls->getattr("__add__"));
long_cls->giveAttr("__gt__", new BoxedFunction(boxRTFunction((void*)longGt, UNKNOWN, 2)));
long_cls->giveAttr("__ge__", new BoxedFunction(boxRTFunction((void*)longGe, UNKNOWN, 2)));
long_cls->giveAttr("__lt__", new BoxedFunction(boxRTFunction((void*)longLt, UNKNOWN, 2)));
long_cls->giveAttr("__le__", new BoxedFunction(boxRTFunction((void*)longLe, UNKNOWN, 2)));
long_cls->giveAttr("__eq__", new BoxedFunction(boxRTFunction((void*)longEq, UNKNOWN, 2)));
long_cls->giveAttr("__ne__", new BoxedFunction(boxRTFunction((void*)longNe, UNKNOWN, 2)));
long_cls->giveAttr("__lshift__", new BoxedFunction(boxRTFunction((void*)longLshift, UNKNOWN, 2)));
long_cls->giveAttr("__repr__", new BoxedFunction(boxRTFunction((void*)longRepr, STR, 1)));
......
......@@ -1652,6 +1652,13 @@ extern "C" bool isinstance(Box* obj, Box* cls, int64_t flags) {
return false;
}
if (cls->cls == classobj_cls) {
if (!isSubclass(obj->cls, instance_cls))
return false;
return instanceIsinstance(static_cast<BoxedInstance*>(obj), static_cast<BoxedClassobj*>(cls));
}
if (!false_on_noncls) {
assert(cls->cls == type_cls);
} else {
......@@ -2954,6 +2961,13 @@ Box* compareInternal(Box* lhs, Box* rhs, int op_type, CompareRewriteArgs* rewrit
if (op_type == AST_TYPE::NotEq)
return boxBool(lhs != rhs);
#ifndef NDEBUG
if ((lhs->cls == int_cls || lhs->cls == float_cls || lhs->cls == long_cls)
&& (rhs->cls == int_cls || rhs->cls == float_cls || rhs->cls == long_cls)) {
Py_FatalError("missing comparison between these classes");
}
#endif
// TODO
// According to http://docs.python.org/2/library/stdtypes.html#comparisons
// CPython implementation detail: Objects of different types except numbers are ordered by their type names; objects
......
......@@ -14,6 +14,7 @@
#include <algorithm>
#include <cstdarg>
#include <dlfcn.h>
#include "llvm/DebugInfo/DIContext.h"
......@@ -178,6 +179,22 @@ void _printStacktrace() {
_printTraceback(getTracebackEntries());
}
// where should this go...
extern "C" void abort() {
static void (*libc_abort)() = (void (*)())dlsym(RTLD_NEXT, "abort");
// In case something calls abort down the line:
static bool recursive = false;
if (!recursive) {
recursive = true;
_printStacktrace();
}
libc_abort();
__builtin_unreachable();
}
static std::vector<const LineInfo*> getTracebackEntries() {
std::vector<const LineInfo*> entries;
......
......@@ -968,6 +968,8 @@ void setupStr() {
str_cls->giveAttr("__add__", new BoxedFunction(boxRTFunction((void*)strAdd, UNKNOWN, 2)));
str_cls->giveAttr("__mod__", new BoxedFunction(boxRTFunction((void*)strMod, STR, 2)));
str_cls->giveAttr("__mul__", new BoxedFunction(boxRTFunction((void*)strMul, UNKNOWN, 2)));
// TODO not sure if this is right in all cases:
str_cls->giveAttr("__rmul__", new BoxedFunction(boxRTFunction((void*)strMul, UNKNOWN, 2)));
str_cls->giveAttr("__lt__", new BoxedFunction(boxRTFunction((void*)strLt, UNKNOWN, 2)));
str_cls->giveAttr("__le__", new BoxedFunction(boxRTFunction((void*)strLe, UNKNOWN, 2)));
......
......@@ -111,6 +111,7 @@ extern "C" Box* createTuple(int64_t nelts, Box** elts);
extern "C" void printFloat(double d);
Box* objectStr(Box*);
Box* objectRepr(Box*);
template <class T> class StlCompatAllocator {
......
......@@ -13,6 +13,8 @@ def test(a, b):
print a - b, b - a, a.__sub__(b), b.__sub__(a)
print a * b, b * a, a.__mul__(b), b.__mul__(a)
print a / b, b / a, a.__div__(b), b.__div__(a)
print repr(a), repr(b), a < b, a > b, a <= b, a >= b, a == b, a != b
# print a ^ b, a | b, a & b
print 1L / 5L
......
......@@ -94,3 +94,11 @@ try:
f[1] = 2
except AttributeError, e:
print e
print isinstance(f, F)
print isinstance(e, F)
print isinstance(D(), D)
print isinstance(D(), C)
print str(f)[:26]
print repr(f)[:26]
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