Commit 3b40ed33 authored by Kevin Modzelewski's avatar Kevin Modzelewski

Match cpython's HEAPTYPE flag

It's supposed to mean "whether this type is heap allocated", but
it gets used as "is this a builtin/extension type".  We heap-allocate
our builtin types so we were setting HEAPTYPE, but this keeps on
causing issues.  I don't think anything actually uses HEAPTYPE to mean
it's on the stack or heap, so let's just set them all to be HEAPTYPE=0.

For better or worse, I ended up implementing this by changing the builtin
types from BoxedHeapClasses to BoxedClasses, which seems to make sense.
This had the effect of changing the existence of the tp_as_foo structs,
which get automatically created for HeapClasses but not for non-heap classes.
So most of the changes in this commit are trying to make sure that we
have those when CPython has them.
parent 28a969c2
......@@ -58,7 +58,9 @@ InstanceType = type(_x)
MethodType = type(_x._m)
BuiltinFunctionType = type(len)
BuiltinMethodType = type([].append) # Same as BuiltinFunctionType
# Pyston change:
# BuiltinMethodType = type([].append) # Same as BuiltinFunctionType
BuiltinMethodType = type((1.0).hex) # Same as BuiltinFunctionType
ModuleType = type(sys)
FileType = file
......@@ -85,8 +87,9 @@ NotImplementedType = type(NotImplemented)
AttrwrapperType = type(_C().__dict__)
# For Jython, the following two types are identical
# Pyston change: don't support these yet
# GetSetDescriptorType = type(FunctionType.func_code)
GetSetDescriptorType = type(FunctionType.func_code)
# Pyston change:
# MemberDescriptorType = type(FunctionType.func_globals)
MemberDescriptorType = type(file.softspace)
del sys, _f, _g, _C, _x # Not for export
......@@ -2615,7 +2615,9 @@ static void inherit_special(PyTypeObject* type, PyTypeObject* base) noexcept {
inherit tp_new; static extension types that specify some
other built-in type as the default are considered
new-style-aware so they also inherit object.__new__. */
if (base != object_cls || (type->tp_flags & Py_TPFLAGS_HEAPTYPE)) {
// Pyston change:
// if (base != object_cls || (type->tp_flags & Py_TPFLAGS_HEAPTYPE)) {
if (base != object_cls || !type->is_user_defined) {
if (type->tp_new == NULL)
type->tp_new = base->tp_new;
}
......
......@@ -1252,8 +1252,8 @@ llvm::JITEventListener* makeTracebacksListener() {
}
void setupUnwinding() {
unwind_session_cls = BoxedHeapClass::create(type_cls, object_cls, PythonUnwindSession::gcHandler, 0, 0,
sizeof(PythonUnwindSession), false, "unwind_session");
unwind_session_cls = BoxedClass::create(type_cls, object_cls, PythonUnwindSession::gcHandler, 0, 0,
sizeof(PythonUnwindSession), false, "unwind_session");
unwind_session_cls->freeze();
}
}
......@@ -87,6 +87,9 @@ extern "C" Box* boolXor(BoxedBool* lhs, BoxedBool* rhs) {
void setupBool() {
static PyNumberMethods bool_as_number;
bool_cls->tp_as_number = &bool_as_number;
bool_cls->giveAttr("__nonzero__", new BoxedFunction(boxRTFunction((void*)boolNonzero, BOXED_BOOL, 1)));
bool_cls->giveAttr("__repr__", new BoxedFunction(boxRTFunction((void*)boolRepr, STR, 1)));
bool_cls->giveAttr("__hash__", new BoxedFunction(boxRTFunction((void*)boolHash, BOXED_INT, 1)));
......
......@@ -71,15 +71,14 @@ void setupAST() {
// ::create takes care of registering the class as a GC root.
#define MAKE_CLS(name, base_cls) \
BoxedClass* name##_cls = BoxedHeapClass::create(type_cls, base_cls, /* gchandler = */ NULL, 0, 0, \
sizeof(BoxedAST), false, STRINGIFY(name)); \
BoxedClass* name##_cls = BoxedClass::create(type_cls, base_cls, /* gchandler = */ NULL, 0, 0, sizeof(BoxedAST), \
false, STRINGIFY(name)); \
ast_module->giveAttr(STRINGIFY(name), name##_cls); \
type_to_cls[AST_TYPE::name] = name##_cls; \
name##_cls->giveAttr("__module__", boxString("_ast")); \
name##_cls->freeze()
AST_cls
= BoxedHeapClass::create(type_cls, object_cls, /* gchandler = */ NULL, 0, 0, sizeof(BoxedAST), false, "AST");
AST_cls = BoxedClass::create(type_cls, object_cls, /* gchandler = */ NULL, 0, 0, sizeof(BoxedAST), false, "AST");
// ::create takes care of registering the class as a GC root.
AST_cls->giveAttr("__module__", boxString("_ast"));
AST_cls->freeze();
......
......@@ -1105,8 +1105,7 @@ static BoxedClass* makeBuiltinException(BoxedClass* base, const char* name, int
if (size == 0)
size = base->tp_basicsize;
BoxedClass* cls
= BoxedHeapClass::create(type_cls, base, NULL, offsetof(BoxedException, attrs), 0, size, false, name);
BoxedClass* cls = BoxedClass::create(type_cls, base, NULL, offsetof(BoxedException, attrs), 0, size, false, name);
cls->giveAttr("__module__", boxString("exceptions"));
if (base == object_cls) {
......@@ -1516,8 +1515,7 @@ void setupBuiltins() {
"Built-in functions, exceptions, and other objects.\n\nNoteworthy: None is "
"the `nil' object; Ellipsis represents `...' in slices.");
BoxedHeapClass* ellipsis_cls
= BoxedHeapClass::create(type_cls, object_cls, NULL, 0, 0, sizeof(Box), false, "ellipsis");
BoxedClass* ellipsis_cls = BoxedClass::create(type_cls, object_cls, NULL, 0, 0, sizeof(Box), false, "ellipsis");
Ellipsis = new (ellipsis_cls) Box();
assert(Ellipsis->cls);
gc::registerPermanentRoot(Ellipsis);
......@@ -1530,15 +1528,13 @@ void setupBuiltins() {
builtins_module->giveAttr(
"print", new BoxedBuiltinFunctionOrMethod(boxRTFunction((void*)print, NONE, 0, true, true), "print"));
notimplemented_cls
= BoxedHeapClass::create(type_cls, object_cls, NULL, 0, 0, sizeof(Box), false, "NotImplementedType");
notimplemented_cls = BoxedClass::create(type_cls, object_cls, NULL, 0, 0, sizeof(Box), false, "NotImplementedType");
notimplemented_cls->giveAttr("__repr__", new BoxedFunction(boxRTFunction((void*)notimplementedRepr, STR, 1)));
notimplemented_cls->freeze();
NotImplemented = new (notimplemented_cls) Box();
gc::registerPermanentRoot(NotImplemented);
builtins_module->giveAttr("NotImplemented", NotImplemented);
builtins_module->giveAttr("NotImplementedType", notimplemented_cls);
builtins_module->giveAttr("all", new BoxedBuiltinFunctionOrMethod(boxRTFunction((void*)all, BOXED_BOOL, 1), "all"));
builtins_module->giveAttr("any", new BoxedBuiltinFunctionOrMethod(boxRTFunction((void*)any, BOXED_BOOL, 1), "any"));
......@@ -1629,8 +1625,8 @@ void setupBuiltins() {
builtins_module->giveAttr("__import__", new BoxedBuiltinFunctionOrMethod(import_func, "__import__",
{ None, None, None, new BoxedInt(-1) }));
enumerate_cls = BoxedHeapClass::create(type_cls, object_cls, &BoxedEnumerate::gcHandler, 0, 0,
sizeof(BoxedEnumerate), false, "enumerate");
enumerate_cls = BoxedClass::create(type_cls, object_cls, &BoxedEnumerate::gcHandler, 0, 0, sizeof(BoxedEnumerate),
false, "enumerate");
enumerate_cls->giveAttr(
"__new__",
new BoxedFunction(boxRTFunction((void*)BoxedEnumerate::new_, UNKNOWN, 3, false, false), { boxInt(0) }));
......@@ -1724,7 +1720,6 @@ void setupBuiltins() {
builtins_module->giveAttr("set", set_cls);
builtins_module->giveAttr("frozenset", frozenset_cls);
builtins_module->giveAttr("tuple", tuple_cls);
builtins_module->giveAttr("instancemethod", instancemethod_cls);
builtins_module->giveAttr("complex", complex_cls);
builtins_module->giveAttr("super", super_cls);
builtins_module->giveAttr("property", property_cls);
......
......@@ -652,8 +652,8 @@ void setupSys() {
sys_module->giveAttr("maxint", boxInt(PYSTON_INT_MAX));
sys_module->giveAttr("maxsize", boxInt(PY_SSIZE_T_MAX));
sys_flags_cls = new (0) BoxedHeapClass(object_cls, BoxedSysFlags::gcHandler, 0, 0, sizeof(BoxedSysFlags), false,
static_cast<BoxedString*>(boxString("flags")));
sys_flags_cls = new (0)
BoxedClass(object_cls, BoxedSysFlags::gcHandler, 0, 0, sizeof(BoxedSysFlags), false, "flags");
sys_flags_cls->giveAttr("__new__",
new BoxedFunction(boxRTFunction((void*)BoxedSysFlags::__new__, UNKNOWN, 1, true, true)));
#define ADD(name) \
......
......@@ -210,7 +210,7 @@ void setupThread() {
thread_module->giveAttr(
"stack_size", new BoxedBuiltinFunctionOrMethod(boxRTFunction((void*)stackSize, BOXED_INT, 0), "stack_size"));
thread_lock_cls = BoxedHeapClass::create(type_cls, object_cls, NULL, 0, 0, sizeof(BoxedThreadLock), false, "lock");
thread_lock_cls = BoxedClass::create(type_cls, object_cls, NULL, 0, 0, sizeof(BoxedThreadLock), false, "lock");
thread_lock_cls->tp_dealloc = BoxedThreadLock::threadLockDestructor;
thread_lock_cls->has_safe_tp_dealloc = true;
......@@ -228,8 +228,8 @@ void setupThread() {
thread_lock_cls->giveAttr("locked_lock", thread_lock_cls->getattr(internStringMortal("locked")));
thread_lock_cls->freeze();
ThreadError = BoxedHeapClass::create(type_cls, Exception, NULL, Exception->attrs_offset,
Exception->tp_weaklistoffset, Exception->tp_basicsize, false, "error");
ThreadError = BoxedClass::create(type_cls, Exception, NULL, Exception->attrs_offset, Exception->tp_weaklistoffset,
Exception->tp_basicsize, false, "error");
ThreadError->giveAttr("__module__", boxString("thread"));
ThreadError->freeze();
......
......@@ -16,6 +16,7 @@
#include <sstream>
#include "capi/typeobject.h"
#include "capi/types.h"
#include "core/types.h"
#include "runtime/objmodel.h"
......@@ -213,7 +214,7 @@ static const char* set_bases(PyClassObject* c, PyObject* v) {
return "";
}
static Box* classobjSetattr(Box* _cls, Box* _attr, Box* _value) {
static void _classobjSetattr(Box* _cls, Box* _attr, Box* _value) {
RELEASE_ASSERT(_cls->cls == classobj_cls, "");
BoxedClassobj* cls = static_cast<BoxedClassobj*>(_cls);
......@@ -221,26 +222,30 @@ static Box* classobjSetattr(Box* _cls, Box* _attr, Box* _value) {
BoxedString* attr = static_cast<BoxedString*>(_attr);
if (attr->s() == "__bases__") {
RELEASE_ASSERT(_value, "can't delete __bases__");
const char* error_str = set_bases((PyClassObject*)cls, _value);
if (error_str && error_str[0] != '\0')
raiseExcHelper(TypeError, "%s", error_str);
static BoxedString* bases_str = internStringImmortal("__bases__");
cls->setattr(bases_str, _value, NULL);
return None;
return;
}
PyObject_GenericSetAttr(cls, _attr, _value);
checkAndThrowCAPIException();
}
static Box* classobjSetattr(Box* _cls, Box* _attr, Box* _value) {
assert(_value);
_classobjSetattr(_cls, _attr, _value);
return None;
}
static int classobj_setattro(Box* cls, Box* attr, Box* value) noexcept {
try {
if (value) {
classobjSetattr(cls, attr, value);
return 0;
} else {
RELEASE_ASSERT(0, "");
}
_classobjSetattr(cls, attr, value);
return 0;
} catch (ExcInfo e) {
setCAPIException(e);
return -1;
......@@ -1494,11 +1499,10 @@ extern "C" PyObject* PyMethod_Class(PyObject* im) noexcept {
}
void setupClassobj() {
classobj_cls = BoxedHeapClass::create(type_cls, object_cls, &BoxedClassobj::gcHandler,
offsetof(BoxedClassobj, attrs), 0, sizeof(BoxedClassobj), false, "classobj");
instance_cls
= BoxedHeapClass::create(type_cls, object_cls, &BoxedInstance::gcHandler, offsetof(BoxedInstance, attrs),
offsetof(BoxedInstance, weakreflist), sizeof(BoxedInstance), false, "instance");
classobj_cls = BoxedClass::create(type_cls, object_cls, &BoxedClassobj::gcHandler, offsetof(BoxedClassobj, attrs),
0, sizeof(BoxedClassobj), false, "classobj");
instance_cls = BoxedClass::create(type_cls, object_cls, &BoxedInstance::gcHandler, offsetof(BoxedInstance, attrs),
offsetof(BoxedInstance, weakreflist), sizeof(BoxedInstance), false, "instance");
classobj_cls->giveAttr("__new__", new BoxedFunction(boxRTFunction((void*)classobjNew, UNKNOWN, 4, false, false)));
......@@ -1513,7 +1517,14 @@ void setupClassobj() {
classobj_cls->freeze();
classobj_cls->tp_getattro = classobj_getattro;
classobj_cls->tp_setattro = classobj_setattro;
add_operators(classobj_cls);
static PyNumberMethods instance_as_number;
instance_cls->tp_as_number = &instance_as_number;
static PySequenceMethods instance_as_sequence;
instance_cls->tp_as_sequence = &instance_as_sequence;
static PyMappingMethods instance_as_mapping;
instance_cls->tp_as_mapping = &instance_as_mapping;
instance_cls->giveAttr("__getattribute__",
new BoxedFunction(boxRTFunction((void*)instanceGetattroInternal<CXX>, UNKNOWN, 2)));
......
......@@ -111,8 +111,7 @@ extern "C" PyCodeObject* PyCode_New(int, int, int, int, PyObject*, PyObject*, Py
}
void setupCode() {
code_cls
= BoxedHeapClass::create(type_cls, object_cls, &BoxedCode::gcHandler, 0, 0, sizeof(BoxedCode), false, "code");
code_cls = BoxedClass::create(type_cls, object_cls, &BoxedCode::gcHandler, 0, 0, sizeof(BoxedCode), false, "code");
code_cls->giveAttr("__new__", None); // Hacky way of preventing users from instantiating this
......
......@@ -14,6 +14,7 @@
#include "runtime/complex.h"
#include "capi/typeobject.h"
#include "core/types.h"
#include "runtime/float.h"
#include "runtime/inline/boxing.h"
......@@ -1224,6 +1225,9 @@ static PyMethodDef complex_methods[] = {
};
void setupComplex() {
static PyNumberMethods complex_as_number;
complex_cls->tp_as_number = &complex_as_number;
auto complex_new = boxRTFunction((void*)complexNew<CXX>, UNKNOWN, 3, false, false,
ParamNames({ "", "real", "imag" }, "", ""), CXX);
addRTFunction(complex_new, (void*)complexNew<CAPI>, UNKNOWN, CAPI);
......@@ -1278,6 +1282,8 @@ void setupComplex() {
complex_cls->giveAttr(md.ml_name, new BoxedMethodDescriptor(&md, complex_cls));
}
add_operators(complex_cls);
complex_cls->freeze();
complex_cls->tp_as_number->nb_negative = (unaryfunc)complex_neg;
complex_cls->tp_richcompare = complex_richcompare;
......
......@@ -775,15 +775,20 @@ void BoxedDict::dealloc(Box* b) noexcept {
}
void setupDict() {
dict_iterator_cls = BoxedHeapClass::create(type_cls, object_cls, &BoxedDictIterator::gcHandler, 0, 0,
sizeof(BoxedDictIterator), false, "dictionary-itemiterator");
dict_keys_cls = BoxedHeapClass::create(type_cls, object_cls, &BoxedDictView::gcHandler, 0, 0, sizeof(BoxedDictView),
false, "dict_keys");
dict_values_cls = BoxedHeapClass::create(type_cls, object_cls, &BoxedDictView::gcHandler, 0, 0,
sizeof(BoxedDictView), false, "dict_values");
dict_items_cls = BoxedHeapClass::create(type_cls, object_cls, &BoxedDictView::gcHandler, 0, 0,
sizeof(BoxedDictView), false, "dict_items");
static PyMappingMethods dict_as_mapping;
dict_cls->tp_as_mapping = &dict_as_mapping;
static PySequenceMethods dict_as_sequence;
dict_cls->tp_as_sequence = &dict_as_sequence;
dict_iterator_cls = BoxedClass::create(type_cls, object_cls, &BoxedDictIterator::gcHandler, 0, 0,
sizeof(BoxedDictIterator), false, "dictionary-itemiterator");
dict_keys_cls = BoxedClass::create(type_cls, object_cls, &BoxedDictView::gcHandler, 0, 0, sizeof(BoxedDictView),
false, "dict_keys");
dict_values_cls = BoxedClass::create(type_cls, object_cls, &BoxedDictView::gcHandler, 0, 0, sizeof(BoxedDictView),
false, "dict_values");
dict_items_cls = BoxedClass::create(type_cls, object_cls, &BoxedDictView::gcHandler, 0, 0, sizeof(BoxedDictView),
false, "dict_items");
dict_cls->tp_dealloc = &BoxedDict::dealloc;
dict_cls->has_safe_tp_dealloc = true;
......
......@@ -192,11 +192,13 @@ extern "C" void raise3_capi(Box* arg0, Box* arg1, Box* arg2) noexcept {
}
void raiseExcHelper(BoxedClass* cls, Box* arg) {
assert(!PyErr_Occurred());
Box* exc_obj = runtimeCall(cls, ArgPassSpec(1), arg, NULL, NULL, NULL, NULL);
raiseExc(exc_obj);
}
void raiseExcHelper(BoxedClass* cls, const char* msg, ...) {
assert(!PyErr_Occurred());
if (msg != NULL) {
va_list ap;
va_start(ap, msg);
......
......@@ -18,6 +18,7 @@
#include <cstring>
#include <gmp.h>
#include "capi/typeobject.h"
#include "capi/types.h"
#include "core/types.h"
#include "runtime/inline/boxing.h"
......@@ -1633,6 +1634,9 @@ static PyMethodDef float_methods[] = { { "hex", (PyCFunction)float_hex, METH_NOA
{ "__format__", (PyCFunction)float__format__, METH_VARARGS, NULL } };
void setupFloat() {
static PyNumberMethods float_as_number;
float_cls->tp_as_number = &float_as_number;
_addFunc("__add__", BOXED_FLOAT, (void*)floatAddFloat, (void*)floatAddInt, (void*)floatAdd);
float_cls->giveAttr("__radd__", float_cls->getattr(internStringMortal("__add__")));
......@@ -1687,6 +1691,7 @@ void setupFloat() {
float_cls->giveAttr(md.ml_name, new BoxedMethodDescriptor(&md, float_cls));
}
add_operators(float_cls);
float_cls->freeze();
floatFormatInit();
......
......@@ -150,8 +150,8 @@ Box* getFrame(int depth) {
}
void setupFrame() {
frame_cls = BoxedHeapClass::create(type_cls, object_cls, &BoxedFrame::gchandler, 0, 0, sizeof(BoxedFrame), false,
"frame");
frame_cls
= BoxedClass::create(type_cls, object_cls, &BoxedFrame::gchandler, 0, 0, sizeof(BoxedFrame), false, "frame");
frame_cls->tp_dealloc = BoxedFrame::simpleDestructor;
frame_cls->has_safe_tp_dealloc = true;
......
......@@ -478,8 +478,8 @@ void generatorDestructor(Box* b) {
void setupGenerator() {
generator_cls
= BoxedHeapClass::create(type_cls, object_cls, &BoxedGenerator::gcHandler, 0,
offsetof(BoxedGenerator, weakreflist), sizeof(BoxedGenerator), false, "generator");
= BoxedClass::create(type_cls, object_cls, &BoxedGenerator::gcHandler, 0, offsetof(BoxedGenerator, weakreflist),
sizeof(BoxedGenerator), false, "generator");
generator_cls->tp_dealloc = generatorDestructor;
generator_cls->has_safe_tp_dealloc = true;
generator_cls->giveAttr("__iter__",
......
......@@ -234,7 +234,7 @@ SearchResult findModule(const std::string& name, BoxedString* full_name, BoxedLi
PyObject* importer = get_path_importer(path_importer_cache, path_hooks, _p);
if (importer == NULL)
return SearchResult("", SearchResult::SEARCH_ERROR);
throwCAPIException();
if (importer != None) {
CallattrFlags callattr_flags{.cls_only = false, .null_on_nonexistent = false, .argspec = ArgPassSpec(1) };
......@@ -469,10 +469,8 @@ static bool loadNext(Box* mod, Box* altmod, std::string& name, std::string& buf,
buf = subname;
}
}
if (result == NULL) {
*rtn = NULL;
return false;
}
if (result == NULL)
throwCAPIException();
if (result == None)
raiseExcHelper(ImportError, "No module named %.200s", local_name.c_str());
......@@ -892,7 +890,7 @@ void setupImport() {
imp_module->giveAttr("C_BUILTIN", boxInt(SearchResult::C_BUILTIN));
imp_module->giveAttr("PY_FROZEN", boxInt(SearchResult::PY_FROZEN));
null_importer_cls = BoxedHeapClass::create(type_cls, object_cls, NULL, 0, 0, sizeof(Box), false, "NullImporter");
null_importer_cls = BoxedClass::create(type_cls, object_cls, NULL, 0, 0, sizeof(Box), false, "NullImporter");
null_importer_cls->giveAttr(
"__init__", new BoxedFunction(boxRTFunction((void*)nullImporterInit, NONE, 2, false, false), { None }));
null_importer_cls->giveAttr("find_module", new BoxedBuiltinFunctionOrMethod(
......
......@@ -206,9 +206,12 @@ Box* xrangeLen(Box* self) {
}
void setupXrange() {
xrange_cls = BoxedHeapClass::create(type_cls, object_cls, NULL, 0, 0, sizeof(BoxedXrange), false, "xrange");
xrange_iterator_cls = BoxedHeapClass::create(type_cls, object_cls, &BoxedXrangeIterator::gcHandler, 0, 0,
sizeof(BoxedXrangeIterator), false, "rangeiterator");
xrange_cls = BoxedClass::create(type_cls, object_cls, NULL, 0, 0, sizeof(BoxedXrange), false, "xrange");
xrange_iterator_cls = BoxedClass::create(type_cls, object_cls, &BoxedXrangeIterator::gcHandler, 0, 0,
sizeof(BoxedXrangeIterator), false, "rangeiterator");
static PySequenceMethods xrange_as_sequence;
xrange_cls->tp_as_sequence = &xrange_as_sequence;
xrange_cls->giveAttr(
"__new__",
......
......@@ -1207,6 +1207,9 @@ static PyObject* int_richcompare(PyObject* v, PyObject* w, int op) noexcept {
}
void setupInt() {
static PyNumberMethods int_as_number;
int_cls->tp_as_number = &int_as_number;
for (int i = 0; i < NUM_INTERNED_INTS; i++) {
interned_ints[i] = new BoxedInt(i);
gc::registerPermanentRoot(interned_ints[i]);
......
......@@ -181,8 +181,8 @@ bool calliter_hasnext(Box* b) {
void setupIter() {
seqiter_cls = BoxedHeapClass::create(type_cls, object_cls, &BoxedSeqIter::gcHandler, 0, 0, sizeof(BoxedSeqIter),
false, "iterator");
seqiter_cls = BoxedClass::create(type_cls, object_cls, &BoxedSeqIter::gcHandler, 0, 0, sizeof(BoxedSeqIter), false,
"iterator");
seqiter_cls->giveAttr("next", new BoxedFunction(boxRTFunction((void*)seqiterNext, UNKNOWN, 1)));
seqiter_cls->giveAttr("__hasnext__", new BoxedFunction(boxRTFunction((void*)seqiterHasnext, BOXED_BOOL, 1)));
......@@ -191,8 +191,8 @@ void setupIter() {
seqiter_cls->freeze();
seqiter_cls->tpp_hasnext = seqiterHasnextUnboxed;
seqreviter_cls = BoxedHeapClass::create(type_cls, object_cls, &BoxedSeqIter::gcHandler, 0, 0, sizeof(BoxedSeqIter),
false, "reversed");
seqreviter_cls = BoxedClass::create(type_cls, object_cls, &BoxedSeqIter::gcHandler, 0, 0, sizeof(BoxedSeqIter),
false, "reversed");
seqreviter_cls->giveAttr("next", new BoxedFunction(boxRTFunction((void*)seqiterNext, UNKNOWN, 1)));
seqreviter_cls->giveAttr("__hasnext__", new BoxedFunction(boxRTFunction((void*)seqreviterHasnext, BOXED_BOOL, 1)));
......@@ -200,8 +200,8 @@ void setupIter() {
seqreviter_cls->freeze();
iterwrapper_cls = BoxedHeapClass::create(type_cls, object_cls, &BoxedIterWrapper::gcHandler, 0, 0,
sizeof(BoxedIterWrapper), false, "iterwrapper");
iterwrapper_cls = BoxedClass::create(type_cls, object_cls, &BoxedIterWrapper::gcHandler, 0, 0,
sizeof(BoxedIterWrapper), false, "iterwrapper");
iterwrapper_cls->giveAttr("next", new BoxedFunction(boxRTFunction((void*)iterwrapperNext, UNKNOWN, 1)));
iterwrapper_cls->giveAttr("__hasnext__",
......
......@@ -148,6 +148,42 @@ static Py_ssize_t list_length(Box* self) noexcept {
return static_cast<BoxedList*>(self)->size;
}
static PyObject* list_concat(PyListObject* a, PyObject* bb) noexcept {
Py_ssize_t size;
Py_ssize_t i;
PyObject** src, **dest;
PyListObject* np;
if (!PyList_Check(bb)) {
PyErr_Format(PyExc_TypeError, "can only concatenate list (not \"%.200s\") to list", bb->cls->tp_name);
return NULL;
}
#define b ((PyListObject*)bb)
size = Py_SIZE(a) + Py_SIZE(b);
if (size < 0)
return PyErr_NoMemory();
np = (PyListObject*)PyList_New(size);
if (np == NULL) {
return NULL;
}
src = a->ob_item;
dest = np->ob_item;
for (i = 0; i < Py_SIZE(a); i++) {
PyObject* v = src[i];
Py_INCREF(v);
dest[i] = v;
}
src = b->ob_item;
dest = np->ob_item + Py_SIZE(a);
for (i = 0; i < Py_SIZE(b); i++) {
PyObject* v = src[i];
Py_INCREF(v);
dest[i] = v;
}
return (PyObject*)np;
#undef b
}
Box* _listSlice(BoxedList* self, i64 start, i64 stop, i64 step, i64 length) {
assert(step != 0);
if (step > 0) {
......@@ -921,10 +957,48 @@ static inline int list_contains_shared(BoxedList* self, Box* elt) {
return false;
}
static int list_contains(PyListObject* a, PyObject* el) {
static int list_contains(PyListObject* a, PyObject* el) noexcept {
return list_contains_shared((BoxedList*)a, el);
}
static PyObject* list_repeat(PyListObject* a, Py_ssize_t n) noexcept {
Py_ssize_t i, j;
Py_ssize_t size;
PyListObject* np;
PyObject** p, **items;
PyObject* elem;
if (n < 0)
n = 0;
if (n > 0 && Py_SIZE(a) > PY_SSIZE_T_MAX / n)
return PyErr_NoMemory();
size = Py_SIZE(a) * n;
if (size == 0)
return PyList_New(0);
np = (PyListObject*)PyList_New(size);
if (np == NULL)
return NULL;
items = np->ob_item;
if (Py_SIZE(a) == 1) {
elem = a->ob_item[0];
for (i = 0; i < n; i++) {
items[i] = elem;
Py_INCREF(elem);
}
return (PyObject*)np;
}
p = np->ob_item;
items = a->ob_item;
for (i = 0; i < n; i++) {
for (j = 0; j < Py_SIZE(a); j++) {
*p = items[j];
Py_INCREF(*p);
p++;
}
}
return (PyObject*)np;
}
Box* listContains(BoxedList* self, Box* elt) {
return boxBool(list_contains_shared(self, elt));
}
......@@ -1198,10 +1272,16 @@ void BoxedList::gcHandler(GCVisitor* v, Box* b) {
}
void setupList() {
list_iterator_cls = BoxedHeapClass::create(type_cls, object_cls, &BoxedListIterator::gcHandler, 0, 0,
sizeof(BoxedListIterator), false, "listiterator");
list_reverse_iterator_cls = BoxedHeapClass::create(type_cls, object_cls, &BoxedListIterator::gcHandler, 0, 0,
sizeof(BoxedListIterator), false, "listreverseiterator");
static PySequenceMethods list_as_sequence;
list_cls->tp_as_sequence = &list_as_sequence;
static PyMappingMethods list_as_mapping;
list_cls->tp_as_mapping = &list_as_mapping;
list_cls->tp_iter = listIter;
list_iterator_cls = BoxedClass::create(type_cls, object_cls, &BoxedListIterator::gcHandler, 0, 0,
sizeof(BoxedListIterator), false, "listiterator");
list_reverse_iterator_cls = BoxedClass::create(type_cls, object_cls, &BoxedListIterator::gcHandler, 0, 0,
sizeof(BoxedListIterator), false, "listreverseiterator");
list_cls->giveAttr("__len__", new BoxedFunction(boxRTFunction((void*)listLen, BOXED_INT, 1)));
......@@ -1281,13 +1361,14 @@ void setupList() {
list_cls->giveAttr("__hash__", None);
list_cls->freeze();
list_cls->tp_iter = listIter;
list_cls->tp_as_sequence->sq_length = list_length;
list_cls->tp_as_sequence->sq_concat = (binaryfunc)list_concat;
list_cls->tp_as_sequence->sq_item = (ssizeargfunc)list_item;
list_cls->tp_as_sequence->sq_slice = list_slice;
list_cls->tp_as_sequence->sq_ass_item = (ssizeobjargproc)list_ass_item;
list_cls->tp_as_sequence->sq_ass_slice = (ssizessizeobjargproc)list_ass_slice;
list_cls->tp_as_sequence->sq_contains = (objobjproc)list_contains;
list_cls->tp_as_sequence->sq_repeat = (ssizeargfunc)list_repeat;
CLFunction* hasnext = boxRTFunction((void*)listiterHasnextUnboxed, BOOL, 1);
addRTFunction(hasnext, (void*)listiterHasnext, BOXED_BOOL);
......
......@@ -1450,6 +1450,9 @@ static Box* long1(Box* b, void*) {
}
void setupLong() {
static PyNumberMethods long_as_number;
long_cls->tp_as_number = &long_as_number;
mp_set_memory_functions(customised_allocation, customised_realloc, customised_free);
_addFuncPow("__pow__", UNKNOWN, (void*)longPowFloat, (void*)longPow);
......
......@@ -420,7 +420,7 @@ void BoxedClass::freeze() {
}
BoxedClass::BoxedClass(BoxedClass* base, gcvisit_func gc_visit, int attrs_offset, int weaklist_offset,
int instance_size, bool is_user_defined)
int instance_size, bool is_user_defined, const char* name)
: attrs(HiddenClass::makeSingleton()),
gc_visit(gc_visit),
attrs_offset(attrs_offset),
......@@ -435,6 +435,7 @@ BoxedClass::BoxedClass(BoxedClass* base, gcvisit_func gc_visit, int attrs_offset
memset(&tp_name, 0, (char*)(&tp_version_tag + 1) - (char*)(&tp_name));
tp_basicsize = instance_size;
tp_weaklistoffset = weaklist_offset;
tp_name = name;
tp_flags |= Py_TPFLAGS_DEFAULT_EXTERNAL;
tp_flags |= Py_TPFLAGS_CHECKTYPES;
......@@ -515,6 +516,24 @@ BoxedClass::BoxedClass(BoxedClass* base, gcvisit_func gc_visit, int attrs_offset
gc::registerPermanentRoot(this);
}
BoxedClass* BoxedClass::create(BoxedClass* metaclass, BoxedClass* base, gcvisit_func gc_visit, int attrs_offset,
int weaklist_offset, int instance_size, bool is_user_defined, const char* name) {
assert(!is_user_defined);
BoxedClass* made = new (metaclass, 0)
BoxedClass(base, gc_visit, attrs_offset, weaklist_offset, instance_size, is_user_defined, name);
// While it might be ok if these were set, it'd indicate a difference in
// expectations as to who was going to calculate them:
assert(!made->tp_mro);
assert(!made->tp_bases);
made->tp_bases = NULL;
made->finishInitialization();
assert(made->tp_mro);
return made;
}
void BoxedClass::finishInitialization() {
assert(!tp_traverse);
assert(!tp_clear);
......@@ -531,19 +550,19 @@ void BoxedClass::finishInitialization() {
BoxedHeapClass::BoxedHeapClass(BoxedClass* base, gcvisit_func gc_visit, int attrs_offset, int weaklist_offset,
int instance_size, bool is_user_defined, BoxedString* name)
: BoxedClass(base, gc_visit, attrs_offset, weaklist_offset, instance_size, is_user_defined),
: BoxedClass(base, gc_visit, attrs_offset, weaklist_offset, instance_size, is_user_defined, name->data()),
ht_name(name),
ht_slots(NULL) {
assert(is_user_defined);
tp_as_number = &as_number;
tp_as_mapping = &as_mapping;
tp_as_sequence = &as_sequence;
tp_as_buffer = &as_buffer;
tp_flags |= Py_TPFLAGS_HEAPTYPE;
if (!ht_name)
assert(str_cls == NULL);
else
tp_name = ht_name->data();
memset(&as_number, 0, sizeof(as_number));
memset(&as_mapping, 0, sizeof(as_mapping));
......@@ -551,13 +570,6 @@ BoxedHeapClass::BoxedHeapClass(BoxedClass* base, gcvisit_func gc_visit, int attr
memset(&as_buffer, 0, sizeof(as_buffer));
}
BoxedHeapClass* BoxedHeapClass::create(BoxedClass* metaclass, BoxedClass* base, gcvisit_func gc_visit, int attrs_offset,
int weaklist_offset, int instance_size, bool is_user_defined,
llvm::StringRef name) {
return create(metaclass, base, gc_visit, attrs_offset, weaklist_offset, instance_size, is_user_defined,
boxString(name), NULL, 0);
}
BoxedHeapClass* BoxedHeapClass::create(BoxedClass* metaclass, BoxedClass* base, gcvisit_func gc_visit, int attrs_offset,
int weaklist_offset, int instance_size, bool is_user_defined, BoxedString* name,
BoxedTuple* bases, size_t nslots) {
......
......@@ -647,11 +647,20 @@ void BoxedSet::dealloc(Box* b) noexcept {
using namespace pyston::set;
void setupSet() {
static PySequenceMethods set_as_sequence;
set_cls->tp_as_sequence = &set_as_sequence;
static PyNumberMethods set_as_number;
set_cls->tp_as_number = &set_as_number;
static PySequenceMethods frozenset_as_sequence;
frozenset_cls->tp_as_sequence = &frozenset_as_sequence;
static PyNumberMethods frozenset_as_number;
frozenset_cls->tp_as_number = &frozenset_as_number;
set_cls->tp_dealloc = frozenset_cls->tp_dealloc = BoxedSet::dealloc;
set_cls->has_safe_tp_dealloc = frozenset_cls->has_safe_tp_dealloc = true;
set_iterator_cls = BoxedHeapClass::create(type_cls, object_cls, &BoxedSetIterator::gcHandler, 0, 0,
sizeof(BoxedSetIterator), false, "setiterator");
set_iterator_cls = BoxedClass::create(type_cls, object_cls, &BoxedSetIterator::gcHandler, 0, 0,
sizeof(BoxedSetIterator), false, "setiterator");
set_iterator_cls->giveAttr(
"__iter__", new BoxedFunction(boxRTFunction((void*)setiteratorIter, typeFromClass(set_iterator_cls), 1)));
set_iterator_cls->giveAttr("__hasnext__",
......
......@@ -2811,10 +2811,17 @@ static PyMethodDef string_methods[] = {
};
void setupStr() {
static PySequenceMethods string_as_sequence;
str_cls->tp_as_sequence = &string_as_sequence;
static PyNumberMethods str_as_number;
str_cls->tp_as_number = &str_as_number;
static PyMappingMethods str_as_mapping;
str_cls->tp_as_mapping = &str_as_mapping;
str_cls->tp_flags |= Py_TPFLAGS_HAVE_NEWBUFFER;
str_iterator_cls = BoxedHeapClass::create(type_cls, object_cls, &BoxedStringIterator::gcHandler, 0, 0,
sizeof(BoxedStringIterator), false, "striterator");
str_iterator_cls = BoxedClass::create(type_cls, object_cls, &BoxedStringIterator::gcHandler, 0, 0,
sizeof(BoxedStringIterator), false, "striterator");
str_iterator_cls->giveAttr("__hasnext__",
new BoxedFunction(boxRTFunction((void*)BoxedStringIterator::hasnext, BOXED_BOOL, 1)));
str_iterator_cls->giveAttr("__iter__",
......
......@@ -197,8 +197,8 @@ Box* superInit(Box* _self, Box* _type, Box* obj) {
}
void setupSuper() {
super_cls = BoxedHeapClass::create(type_cls, object_cls, &BoxedSuper::gcHandler, 0, 0, sizeof(BoxedSuper), false,
"super");
super_cls
= BoxedClass::create(type_cls, object_cls, &BoxedSuper::gcHandler, 0, 0, sizeof(BoxedSuper), false, "super");
// super_cls->giveAttr("__getattribute__", new BoxedFunction(boxRTFunction((void*)superGetattribute, UNKNOWN, 2)));
super_cls->giveAttr("__repr__", new BoxedFunction(boxRTFunction((void*)superRepr, STR, 1)));
......
......@@ -120,8 +120,8 @@ void BoxedTraceback::here(LineInfo lineInfo, Box** tb) {
}
void setupTraceback() {
traceback_cls = BoxedHeapClass::create(type_cls, object_cls, BoxedTraceback::gcHandler, 0, 0,
sizeof(BoxedTraceback), false, "traceback");
traceback_cls = BoxedClass::create(type_cls, object_cls, BoxedTraceback::gcHandler, 0, 0, sizeof(BoxedTraceback),
false, "traceback");
traceback_cls->giveAttr("getLines", new BoxedFunction(boxRTFunction((void*)BoxedTraceback::getLines, UNKNOWN, 1)));
......
......@@ -518,7 +518,7 @@ static PyObject* tuplerichcompare(PyObject* v, PyObject* w, int op) noexcept {
return PyObject_RichCompare(vt->elts[i], wt->elts[i], op);
}
static PyObject* tupleslice(PyTupleObject* a, Py_ssize_t ilow, Py_ssize_t ihigh) {
static PyObject* tupleslice(PyTupleObject* a, Py_ssize_t ilow, Py_ssize_t ihigh) noexcept {
PyTupleObject* np;
PyObject** src, **dest;
Py_ssize_t i;
......@@ -556,10 +556,80 @@ static PyObject* tupleitem(register PyTupleObject* a, register Py_ssize_t i) {
return a->ob_item[i];
}
static Py_ssize_t tuplelength(PyTupleObject* a) {
static Py_ssize_t tuplelength(PyTupleObject* a) noexcept {
return Py_SIZE(a);
}
static Box* tupleconcat(PyTupleObject* a, Box* bb) noexcept {
Py_ssize_t size;
Py_ssize_t i;
PyObject** src, **dest;
PyTupleObject* np;
if (!PyTuple_Check(bb)) {
PyErr_Format(PyExc_TypeError, "can only concatenate tuple (not \"%.200s\") to tuple", Py_TYPE(bb)->tp_name);
return NULL;
}
#define b ((PyTupleObject*)bb)
size = Py_SIZE(a) + Py_SIZE(b);
if (size < 0)
return PyErr_NoMemory();
np = (PyTupleObject*)PyTuple_New(size);
if (np == NULL) {
return NULL;
}
src = a->ob_item;
dest = np->ob_item;
for (i = 0; i < Py_SIZE(a); i++) {
PyObject* v = src[i];
Py_INCREF(v);
dest[i] = v;
}
src = b->ob_item;
dest = np->ob_item + Py_SIZE(a);
for (i = 0; i < Py_SIZE(b); i++) {
PyObject* v = src[i];
Py_INCREF(v);
dest[i] = v;
}
return (PyObject*)np;
#undef b
}
static PyObject* tuplerepeat(PyTupleObject* a, Py_ssize_t n) noexcept {
Py_ssize_t i, j;
Py_ssize_t size;
PyTupleObject* np;
PyObject** p, **items;
if (n < 0)
n = 0;
if (Py_SIZE(a) == 0 || n == 1) {
if (PyTuple_CheckExact((BoxedTuple*)a)) {
/* Since tuples are immutable, we can return a shared
* copy in this case */
Py_INCREF(a);
return (PyObject*)a;
}
if (Py_SIZE(a) == 0)
return PyTuple_New(0);
}
size = Py_SIZE(a) * n;
if (size / Py_SIZE(a) != n)
return PyErr_NoMemory();
np = (PyTupleObject*)PyTuple_New(size);
if (np == NULL)
return NULL;
p = np->ob_item;
items = a->ob_item;
for (i = 0; i < n; i++) {
for (j = 0; j < Py_SIZE(a); j++) {
*p = items[j];
Py_INCREF(*p);
p++;
}
}
return (PyObject*)np;
}
void BoxedTuple::gcHandler(GCVisitor* v, Box* b) {
Box::gcHandler(v, b);
......@@ -574,8 +644,13 @@ extern "C" void BoxedTupleIterator::gcHandler(GCVisitor* v, Box* b) {
}
void setupTuple() {
tuple_iterator_cls = BoxedHeapClass::create(type_cls, object_cls, &BoxedTupleIterator::gcHandler, 0, 0,
sizeof(BoxedTupleIterator), false, "tuple");
static PySequenceMethods tuple_as_sequence;
tuple_cls->tp_as_sequence = &tuple_as_sequence;
static PyMappingMethods tuple_as_mapping;
tuple_cls->tp_as_mapping = &tuple_as_mapping;
tuple_iterator_cls = BoxedClass::create(type_cls, object_cls, &BoxedTupleIterator::gcHandler, 0, 0,
sizeof(BoxedTupleIterator), false, "tuple");
tuple_cls->giveAttr("__new__", new BoxedFunction(boxRTFunction((void*)tupleNew, UNKNOWN, 1, true, true)));
CLFunction* getitem = createRTFunction(2, 0, 0);
......@@ -606,6 +681,7 @@ void setupTuple() {
tuple_cls->giveAttr("__mul__", new BoxedFunction(boxRTFunction((void*)tupleMul, BOXED_TUPLE, 2)));
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);
......@@ -614,6 +690,8 @@ void setupTuple() {
tuple_cls->tp_as_sequence->sq_item = (ssizeargfunc)tupleitem;
tuple_cls->tp_as_sequence->sq_length = (lenfunc)tuplelength;
tuple_cls->tp_as_sequence->sq_concat = (binaryfunc)tupleconcat;
tuple_cls->tp_as_sequence->sq_repeat = (ssizeargfunc)tuplerepeat;
tuple_cls->tp_iter = tupleIter;
CLFunction* hasnext = boxRTFunction((void*)tupleiterHasnextUnboxed, BOOL, 1);
......
This diff is collapsed.
......@@ -268,15 +268,27 @@ public:
void freeze();
static void gcHandler(GCVisitor* v, Box* b);
typedef size_t SlotOffset;
SlotOffset* slotOffsets() { return (BoxedClass::SlotOffset*)((char*)this + this->cls->tp_basicsize); }
// These should only be used for builtin types:
static BoxedClass* create(BoxedClass* metatype, BoxedClass* base, gcvisit_func gc_visit, int attrs_offset,
int weaklist_offset, int instance_size, bool is_user_defined, const char* name);
BoxedClass(BoxedClass* base, gcvisit_func gc_visit, int attrs_offset, int weaklist_offset, int instance_size,
bool is_user_defined, const char* name);
DEFAULT_CLASS_VAR(type_cls, sizeof(SlotOffset));
protected:
// These functions are not meant for external callers and will mostly just be called
// by BoxedHeapClass::create(), but setupRuntime() also needs to do some manual class
// creation due to bootstrapping issues.
void finishInitialization();
BoxedClass(BoxedClass* base, gcvisit_func gc_visit, int attrs_offset, int weaklist_offset, int instance_size,
bool is_user_defined);
friend void setupRuntime();
friend void setupSysEnd();
friend void setupThread();
......@@ -292,18 +304,12 @@ public:
BoxedString* ht_name;
PyObject* ht_slots;
typedef size_t SlotOffset;
SlotOffset* slotOffsets() { return (BoxedHeapClass::SlotOffset*)((char*)this + this->cls->tp_basicsize); }
size_t nslots() { return this->ob_size; }
// These functions are the preferred way to construct new types:
static BoxedHeapClass* create(BoxedClass* metatype, BoxedClass* base, gcvisit_func gc_visit, int attrs_offset,
int weaklist_offset, int instance_size, bool is_user_defined, BoxedString* name,
BoxedTuple* bases, size_t nslots);
static BoxedHeapClass* create(BoxedClass* metatype, BoxedClass* base, gcvisit_func gc_visit, int attrs_offset,
int weaklist_offset, int instance_size, bool is_user_defined, llvm::StringRef name);
static void gcHandler(GCVisitor* v, Box* b);
private:
// These functions are not meant for external callers and will mostly just be called
......@@ -315,8 +321,6 @@ private:
friend void setupRuntime();
friend void setupSys();
friend void setupThread();
DEFAULT_CLASS_VAR(type_cls, sizeof(SlotOffset));
};
static_assert(sizeof(pyston::Box) == sizeof(struct _object), "");
......
......@@ -806,8 +806,25 @@ call_funcs(PyObject* _module, PyObject* args) {
Py_RETURN_NONE;
}
static PyObject *
view_tp_as(PyObject* _module, PyObject* _type) {
assert(PyType_Check(_type));
PyTypeObject* type = (PyTypeObject*)_type;
printf("%s:", type->tp_name);
if (type->tp_as_number)
printf(" tp_as_number");
if (type->tp_as_sequence)
printf(" tp_as_sequence");
if (type->tp_as_mapping)
printf(" tp_as_mapping");
printf("\n");
Py_RETURN_NONE;
}
static PyMethodDef SlotsMethods[] = {
{"call_funcs", call_funcs, METH_VARARGS, "Call slotted functions."},
{"view_tp_as", view_tp_as, METH_O, "Check which tp_as_ slots are defined."},
{NULL, NULL, 0, NULL} /* Sentinel */
};
......
import slots_test
HEAPTYPE = 1<<9
def test(cls):
print cls
slots_test.view_tp_as(cls)
if HEAPTYPE & cls.__flags__:
print "heaptype"
def testall(module):
for n in sorted(dir((module))):
if n in ("reversed", "AttrwrapperType", "BuiltinMethodType", "BufferType", "DictProxyType"):
continue
cls = getattr(module, n)
if not isinstance(cls, type):
continue
print n
test(cls)
testall(__builtins__)
import types
testall(types)
class C(object):
pass
test(C)
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