Commit 63ec21c9 authored by Kevin Modzelewski's avatar Kevin Modzelewski

Speed up a number of runtime functions

callable(), str(), repr(), PySequence_GetItem(),
and PyObject_HasAttrString()

Mostly by bringing in the CPython versions.
parent a6a326e5
......@@ -749,15 +749,6 @@ extern "C" PyObject* PyObject_GetIter(PyObject* o) noexcept {
}
}
extern "C" PyObject* PyObject_Repr(PyObject* obj) noexcept {
try {
return repr(obj);
} catch (ExcInfo e) {
setCAPIException(e);
return NULL;
}
}
static int recursive_issubclass(PyObject* derived, PyObject* cls) noexcept {
int retval;
......@@ -1454,14 +1445,26 @@ extern "C" PyObject* PySequence_InPlaceRepeat(PyObject* o, Py_ssize_t count) noe
return nullptr;
}
extern "C" PyObject* PySequence_GetItem(PyObject* o, Py_ssize_t i) noexcept {
try {
// Not sure if this is really the same:
return getitem(o, boxInt(i));
} catch (ExcInfo e) {
setCAPIException(e);
return NULL;
extern "C" PyObject* PySequence_GetItem(PyObject* s, Py_ssize_t i) noexcept {
PySequenceMethods* m;
if (s == NULL)
return null_error();
m = s->cls->tp_as_sequence;
if (m && m->sq_item) {
if (i < 0) {
if (m->sq_length) {
Py_ssize_t l = (*m->sq_length)(s);
if (l < 0)
return NULL;
i += l;
}
}
return m->sq_item(s, i);
}
return type_error("'%.200s' object does not support indexing", s);
}
PyObject* _PySlice_FromIndices(Py_ssize_t istart, Py_ssize_t istop) {
......
......@@ -379,19 +379,80 @@ extern "C" PyObject* PyObject_Unicode(PyObject* v) noexcept {
return res;
}
extern "C" PyObject* _PyObject_Str(PyObject* v) noexcept {
extern "C" PyObject* PyObject_Repr(PyObject* v) noexcept {
if (PyErr_CheckSignals())
return NULL;
#ifdef USE_STACKCHECK
if (PyOS_CheckStack()) {
PyErr_SetString(PyExc_MemoryError, "stack overflow");
return NULL;
}
#endif
if (v == NULL)
return boxString("<NULL>");
return PyString_FromString("<NULL>");
else if (Py_TYPE(v)->tp_repr == NULL)
return PyString_FromFormat("<%s object at %p>", Py_TYPE(v)->tp_name, v);
else {
PyObject* res;
res = (*Py_TYPE(v)->tp_repr)(v);
if (res == NULL)
return NULL;
#ifdef Py_USING_UNICODE
if (PyUnicode_Check(res)) {
PyObject* str;
str = PyUnicode_AsEncodedString(res, NULL, NULL);
Py_DECREF(res);
if (str)
res = str;
else
return NULL;
}
#endif
if (!PyString_Check(res)) {
PyErr_Format(PyExc_TypeError, "__repr__ returned non-string (type %.200s)", Py_TYPE(res)->tp_name);
Py_DECREF(res);
return NULL;
}
return res;
}
}
if (v->cls == str_cls)
extern "C" PyObject* _PyObject_Str(PyObject* v) noexcept {
PyObject* res;
int type_ok;
if (v == NULL)
return PyString_FromString("<NULL>");
if (PyString_CheckExact(v)) {
Py_INCREF(v);
return v;
}
#ifdef Py_USING_UNICODE
if (PyUnicode_CheckExact(v)) {
Py_INCREF(v);
return v;
}
#endif
if (Py_TYPE(v)->tp_str == NULL)
return PyObject_Repr(v);
try {
return str(v);
} catch (ExcInfo e) {
setCAPIException(e);
/* It is possible for a type to have a tp_str representation that loops
infinitely. */
if (Py_EnterRecursiveCall(" while getting the str of an object"))
return NULL;
res = (*Py_TYPE(v)->tp_str)(v);
Py_LeaveRecursiveCall();
if (res == NULL)
return NULL;
type_ok = PyString_Check(res);
#ifdef Py_USING_UNICODE
type_ok = type_ok || PyUnicode_Check(res);
#endif
if (!type_ok) {
PyErr_Format(PyExc_TypeError, "__str__ returned non-string (type %.200s)", Py_TYPE(res)->tp_name);
Py_DECREF(res);
return NULL;
}
return res;
}
extern "C" PyObject* PyObject_Str(PyObject* v) noexcept {
......@@ -473,7 +534,10 @@ extern "C" int PyObject_SetAttrString(PyObject* v, const char* name, PyObject* w
extern "C" PyObject* PyObject_GetAttrString(PyObject* o, const char* attr) noexcept {
try {
return getattr(o, internStringMortal(attr));
Box* r = getattrInternal(o, internStringMortal(attr), NULL);
if (!r)
PyErr_Format(PyExc_AttributeError, "'%.50s' object has no attribute '%.400s'", o->cls->tp_name, attr);
return r;
} catch (ExcInfo e) {
setCAPIException(e);
return NULL;
......
......@@ -854,9 +854,7 @@ Box* zip(BoxedTuple* containers) {
}
static Box* callable(Box* obj) {
Box* r = PyBool_FromLong((long)PyCallable_Check(obj));
checkAndThrowCAPIException();
return r;
return PyBool_FromLong((long)PyCallable_Check(obj));
}
BoxedClass* notimplemented_cls;
......
......@@ -638,9 +638,19 @@ extern "C" int PyObject_Print(PyObject* obj, FILE* fp, int flags) noexcept {
extern "C" int PyCallable_Check(PyObject* x) noexcept {
if (x == NULL)
return 0;
static BoxedString* call_attr = internStringImmortal("__call__");
return typeLookup(x->cls, call_attr, NULL) != NULL;
if (PyInstance_Check(x)) {
PyObject* call = PyObject_GetAttrString(x, "__call__");
if (call == NULL) {
PyErr_Clear();
return 0;
}
/* Could test recursively but don't, for fear of endless
recursion if some joker sets self.__call__ = self */
Py_DECREF(call);
return 1;
} else {
return x->cls->tp_call != NULL;
}
}
extern "C" int Py_FlushLine(void) noexcept {
......
......@@ -1142,6 +1142,8 @@ void setupInt() {
add_operators(int_cls);
int_cls->freeze();
int_cls->tp_repr = (reprfunc)int_to_decimal_string;
}
void teardownInt() {
......
......@@ -1557,15 +1557,19 @@ extern "C" Box* strNonzero(BoxedString* self) {
extern "C" Box* strNew(BoxedClass* cls, Box* obj) {
assert(isSubclass(cls, str_cls));
Box* rtn = str(obj);
assert(PyString_Check(rtn));
if (cls != str_cls) {
Box* tmp = strNew(str_cls, obj);
assert(isSubclass(tmp->cls, str_cls));
BoxedString* tmp_s = static_cast<BoxedString*>(tmp);
if (cls == str_cls)
return rtn;
BoxedString* _rtn = static_cast<BoxedString*>(rtn);
return new (cls, tmp_s->size()) BoxedString(tmp_s->s());
}
return new (cls, _rtn->size()) BoxedString(_rtn->s());
Box* r = PyObject_Str(obj);
if (!r)
throwCAPIException();
assert(PyString_Check(r));
return r;
}
extern "C" Box* basestringNew(BoxedClass* cls, Box* args, Box* kwargs) {
......
......@@ -517,6 +517,19 @@ static PyObject* tupleslice(PyTupleObject* a, Py_ssize_t ilow, Py_ssize_t ihigh)
return (PyObject*)np;
}
static PyObject* tupleitem(register PyTupleObject* a, register Py_ssize_t i) {
if (i < 0 || i >= Py_SIZE(a)) {
PyErr_SetString(PyExc_IndexError, "tuple index out of range");
return NULL;
}
Py_INCREF(a->ob_item[i]);
return a->ob_item[i];
}
static Py_ssize_t tuplelength(PyTupleObject* a) {
return Py_SIZE(a);
}
void setupTuple() {
tuple_iterator_cls = BoxedHeapClass::create(type_cls, object_cls, &tupleIteratorGCHandler, 0, 0,
sizeof(BoxedTupleIterator), false, "tuple");
......@@ -528,8 +541,6 @@ void setupTuple() {
addRTFunction(getitem, (void*)tupleGetitem, UNKNOWN, std::vector<ConcreteCompilerType*>{ UNKNOWN, UNKNOWN });
tuple_cls->giveAttr("__getitem__", new BoxedFunction(getitem));
tuple_cls->tp_as_sequence->sq_slice = (ssizessizeargfunc)&tupleslice;
tuple_cls->giveAttr("__contains__", new BoxedFunction(boxRTFunction((void*)tupleContains, BOXED_BOOL, 2)));
tuple_cls->giveAttr("index", new BoxedFunction(boxRTFunction((void*)tupleIndex, BOXED_INT, 4, 2, false, false),
{ boxInt(0), boxInt(std::numeric_limits<Py_ssize_t>::max()) }));
......@@ -550,10 +561,14 @@ void setupTuple() {
tuple_cls->giveAttr("__rmul__", new BoxedFunction(boxRTFunction((void*)tupleMul, BOXED_TUPLE, 2)));
tuple_cls->tp_hash = (hashfunc)tuple_hash;
tuple_cls->tp_as_sequence->sq_slice = (ssizessizeargfunc)&tupleslice;
add_operators(tuple_cls);
tuple_cls->freeze();
tuple_cls->tp_as_sequence->sq_item = (ssizeargfunc)tupleitem;
tuple_cls->tp_as_sequence->sq_length = (lenfunc)tuplelength;
CLFunction* hasnext = boxRTFunction((void*)tupleiterHasnextUnboxed, BOOL, 1);
addRTFunction(hasnext, (void*)tupleiterHasnext, BOXED_BOOL);
tuple_iterator_cls->giveAttr("__hasnext__", new BoxedFunction(hasnext));
......
......@@ -20,3 +20,5 @@ class C(object):
return MyStr("hello world")
print type(str(C()))
m = MyStr(C())
print type(m), repr(m)
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