// Copyright (c) 2014 Dropbox, Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #include <dlfcn.h> #include <stdarg.h> #include <string.h> #include "Python.h" #include "capi/types.h" #include "core/threading.h" #include "core/types.h" #include "runtime/import.h" #include "runtime/objmodel.h" #include "runtime/types.h" namespace pyston { BoxedClass* method_cls; #define MAKE_CHECK(NAME, cls_name) \ extern "C" bool Py##NAME##_Check(PyObject* op) { return isSubclass(op->cls, cls_name); } MAKE_CHECK(Int, int_cls) MAKE_CHECK(String, str_cls) MAKE_CHECK(Long, long_cls) MAKE_CHECK(List, list_cls) MAKE_CHECK(Tuple, tuple_cls) MAKE_CHECK(Dict, dict_cls) #ifdef Py_USING_UNICODE MAKE_CHECK(Unicode, unicode_cls) #endif #undef MAKE_CHECK extern "C" { int Py_Py3kWarningFlag; } BoxedClass* capifunc_cls; extern "C" PyObject* PyType_GenericAlloc(PyTypeObject* cls, Py_ssize_t nitems) { RELEASE_ASSERT(nitems == 0, "unimplemented"); RELEASE_ASSERT(cls->tp_itemsize == 0, "unimplemented"); auto rtn = (PyObject*)gc_alloc(cls->tp_basicsize, gc::GCKind::PYTHON); memset(rtn, 0, cls->tp_basicsize); PyObject_Init(rtn, cls); return rtn; } BoxedClass* wrapperdescr_cls, *wrapperobject_cls; Box* BoxedWrapperDescriptor::__get__(BoxedWrapperDescriptor* self, Box* inst, Box* owner) { RELEASE_ASSERT(self->cls == wrapperdescr_cls, ""); if (inst == None) return self; if (!isSubclass(inst->cls, self->type)) raiseExcHelper(TypeError, "Descriptor '' for '%s' objects doesn't apply to '%s' object", getFullNameOfClass(self->type).c_str(), getFullTypeName(inst).c_str()); return new BoxedWrapperObject(self, inst); } // copied from CPython's getargs.c: extern "C" int PyBuffer_FillInfo(Py_buffer* view, PyObject* obj, void* buf, Py_ssize_t len, int readonly, int flags) { if (view == NULL) return 0; if (((flags & PyBUF_WRITABLE) == PyBUF_WRITABLE) && (readonly == 1)) { // Don't support PyErr_SetString yet: assert(0); // PyErr_SetString(PyExc_BufferError, "Object is not writable."); // return -1; } view->obj = obj; if (obj) Py_INCREF(obj); view->buf = buf; view->len = len; view->readonly = readonly; view->itemsize = 1; view->format = NULL; if ((flags & PyBUF_FORMAT) == PyBUF_FORMAT) view->format = "B"; view->ndim = 1; view->shape = NULL; if ((flags & PyBUF_ND) == PyBUF_ND) view->shape = &(view->len); view->strides = NULL; if ((flags & PyBUF_STRIDES) == PyBUF_STRIDES) view->strides = &(view->itemsize); view->suboffsets = NULL; view->internal = NULL; return 0; } extern "C" void PyBuffer_Release(Py_buffer* view) { if (!view->buf) { assert(!view->obj); return; } PyObject* obj = view->obj; assert(obj); assert(obj->cls == str_cls); if (obj && Py_TYPE(obj)->tp_as_buffer && Py_TYPE(obj)->tp_as_buffer->bf_releasebuffer) Py_TYPE(obj)->tp_as_buffer->bf_releasebuffer(obj, view); Py_XDECREF(obj); view->obj = NULL; } // Not sure why we need another declaration here: 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); abort(); } extern "C" void _PyErr_BadInternalCall(const char* filename, int lineno) { Py_FatalError("unimplemented"); } extern "C" PyObject* PyObject_Init(PyObject* op, PyTypeObject* tp) { RELEASE_ASSERT(op, ""); RELEASE_ASSERT(tp, ""); assert(gc::isValidGCObject(op)); assert(gc::isValidGCObject(tp)); Py_TYPE(op) = tp; // I think CPython defers the dict creation (equivalent of our initUserAttrs) to the // first time that an attribute gets set. // Our HCAttrs object already includes this optimization of no-allocation-if-empty, // but it's nice to initialize the hcls here so we don't have to check it on every getattr/setattr. // TODO It does mean that anything not defering to this function will have to call // initUserAttrs themselves, though. initUserAttrs(op, tp); return op; } extern "C" PyVarObject* PyObject_InitVar(PyVarObject* op, PyTypeObject* tp, Py_ssize_t size) { assert(gc::isValidGCObject(op)); assert(gc::isValidGCObject(tp)); RELEASE_ASSERT(op, ""); RELEASE_ASSERT(tp, ""); Py_TYPE(op) = tp; op->ob_size = size; return op; } extern "C" PyObject* _PyObject_New(PyTypeObject* cls) { assert(cls->tp_itemsize == 0); auto rtn = (PyObject*)gc_alloc(cls->tp_basicsize, gc::GCKind::PYTHON); // no memset for this function PyObject_Init(rtn, cls); return rtn; } extern "C" void PyObject_Free(void* p) { gc::gc_free(p); ASSERT(0, "I think this is good enough but I'm not sure; should test"); } extern "C" PyObject* _PyObject_GC_Malloc(size_t) { Py_FatalError("unimplemented"); } extern "C" PyObject* _PyObject_GC_New(PyTypeObject* cls) { return _PyObject_New(cls); } extern "C" PyVarObject* _PyObject_GC_NewVar(PyTypeObject*, Py_ssize_t) { Py_FatalError("unimplemented"); } extern "C" void PyObject_GC_Track(void*) { // TODO do we have to do anything to support the C API GC protocol? } extern "C" void PyObject_GC_UnTrack(void*) { // TODO do we have to do anything to support the C API GC protocol? } extern "C" void PyObject_GC_Del(void*) { Py_FatalError("unimplemented"); } extern "C" PyObject* PyObject_CallObject(PyObject* obj, PyObject* args) { RELEASE_ASSERT(args, ""); // actually it looks like this is allowed to be NULL RELEASE_ASSERT(args->cls == tuple_cls, ""); // TODO do something like this? not sure if this is safe; will people expect that calling into a known function // won't end up doing a GIL check? // threading::GLDemoteRegion _gil_demote; try { Box* r = runtimeCall(obj, ArgPassSpec(0, 0, true, false), args, NULL, NULL, NULL, NULL); return r; } catch (Box* b) { Py_FatalError("unimplemented"); } } extern "C" PyObject* PyObject_CallMethod(PyObject* o, char* name, char* format, ...) { Py_FatalError("unimplemented"); } extern "C" PyObject* _PyObject_CallMethod_SizeT(PyObject* o, char* name, char* format, ...) { Py_FatalError("unimplemented"); } extern "C" PyObject* PyObject_GetAttrString(PyObject* o, const char* attr) { // TODO do something like this? not sure if this is safe; will people expect that calling into a known function // won't end up doing a GIL check? // threading::GLDemoteRegion _gil_demote; try { return getattr(o, attr); } catch (Box* b) { Py_FatalError("unimplemented"); } } extern "C" Py_ssize_t PyObject_Size(PyObject* o) { try { return len(o)->n; } catch (Box* b) { Py_FatalError("unimplemented"); } } extern "C" PyObject* PyObject_GetIter(PyObject*) { Py_FatalError("unimplemented"); } extern "C" PyObject* PyObject_Repr(PyObject* obj) { try { return repr(obj); } catch (Box* b) { Py_FatalError("unimplemented"); } } extern "C" PyObject* PyObject_GetAttr(PyObject* o, PyObject* attr_name) { if (!isSubclass(attr_name->cls, str_cls)) { PyErr_Format(PyExc_TypeError, "attribute name must be string, not '%.200s'", Py_TYPE(attr_name)->tp_name); return NULL; } try { return getattr(o, static_cast<BoxedString*>(attr_name)->s.c_str()); } catch (Box* b) { Py_FatalError("unimplemented"); } } extern "C" PyObject* PyObject_GenericGetAttr(PyObject* o, PyObject* name) { Py_FatalError("unimplemented"); } extern "C" PyObject* PyObject_GetItem(PyObject* o, PyObject* key) { try { return getitem(o, key); } catch (Box* b) { Py_FatalError("unimplemented"); } } extern "C" int PyObject_SetItem(PyObject* o, PyObject* key, PyObject* v) { Py_FatalError("unimplemented"); } extern "C" int PyObject_DelItem(PyObject* o, PyObject* key) { Py_FatalError("unimplemented"); } extern "C" PyObject* PyObject_RichCompare(PyObject* o1, PyObject* o2, int opid) { Py_FatalError("unimplemented"); } extern "C" long PyObject_Hash(PyObject* o) { try { return hash(o)->n; } catch (Box* b) { Py_FatalError("unimplemented"); } } extern "C" int PyObject_IsTrue(PyObject* o) { try { return nonzero(o); } catch (Box* b) { Py_FatalError("unimplemented"); } } extern "C" int PyObject_Not(PyObject* o) { Py_FatalError("unimplemented"); } extern "C" PyObject* PyObject_Call(PyObject* callable_object, PyObject* args, PyObject* kw) { try { return runtimeCall(callable_object, ArgPassSpec(0, 0, true, true), args, kw, NULL, NULL, NULL); } catch (Box* b) { Py_FatalError("unimplemented"); } } extern "C" void PyObject_ClearWeakRefs(PyObject* object) { Py_FatalError("unimplemented"); } extern "C" int PyObject_GetBuffer(PyObject* exporter, Py_buffer* view, int flags) { Py_FatalError("unimplemented"); } extern "C" int PyObject_Print(PyObject* obj, FILE* fp, int flags) { Py_FatalError("unimplemented"); }; extern "C" int PySequence_Check(PyObject*) { Py_FatalError("unimplemented"); } extern "C" Py_ssize_t PySequence_Size(PyObject* o) { Py_FatalError("unimplemented"); } extern "C" PyObject* PySequence_Concat(PyObject* o1, PyObject* o2) { Py_FatalError("unimplemented"); } extern "C" PyObject* PySequence_Repeat(PyObject* o, Py_ssize_t count) { Py_FatalError("unimplemented"); } extern "C" PyObject* PySequence_InPlaceConcat(PyObject* o1, PyObject* o2) { Py_FatalError("unimplemented"); } extern "C" PyObject* PySequence_InPlaceRepeat(PyObject* o, Py_ssize_t count) { Py_FatalError("unimplemented"); } extern "C" PyObject* PySequence_GetItem(PyObject* o, Py_ssize_t i) { try { // Not sure if this is really the same: return getitem(o, boxInt(i)); } catch (Box* b) { Py_FatalError("unimplemented"); } } extern "C" PyObject* PySequence_GetSlice(PyObject* o, Py_ssize_t i1, Py_ssize_t i2) { try { // Not sure if this is really the same: return getitem(o, new BoxedSlice(boxInt(i1), boxInt(i2), None)); } catch (Box* b) { Py_FatalError("unimplemented"); } } extern "C" int PySequence_SetItem(PyObject* o, Py_ssize_t i, PyObject* v) { Py_FatalError("unimplemented"); } extern "C" int PySequence_DelItem(PyObject* o, Py_ssize_t i) { Py_FatalError("unimplemented"); } extern "C" int PySequence_SetSlice(PyObject* o, Py_ssize_t i1, Py_ssize_t i2, PyObject* v) { Py_FatalError("unimplemented"); } extern "C" int PySequence_DelSlice(PyObject* o, Py_ssize_t i1, Py_ssize_t i2) { Py_FatalError("unimplemented"); } extern "C" Py_ssize_t PySequence_Count(PyObject* o, PyObject* value) { Py_FatalError("unimplemented"); } extern "C" int PySequence_Contains(PyObject* o, PyObject* value) { Py_FatalError("unimplemented"); } extern "C" Py_ssize_t PySequence_Index(PyObject* o, PyObject* value) { Py_FatalError("unimplemented"); } extern "C" PyObject* PySequence_List(PyObject* o) { Py_FatalError("unimplemented"); } extern "C" PyObject* PySequence_Tuple(PyObject* o) { Py_FatalError("unimplemented"); } extern "C" PyObject* PySequence_Fast(PyObject* o, const char* m) { Py_FatalError("unimplemented"); } extern "C" PyObject* PyIter_Next(PyObject*) { Py_FatalError("unimplemented"); } extern "C" int PyCallable_Check(PyObject* x) { if (x == NULL) return 0; static const std::string call_attr("__call__"); return typeLookup(x->cls, call_attr, NULL) != NULL; } extern "C" void PyErr_Restore(PyObject* type, PyObject* value, PyObject* traceback) { Py_FatalError("setting exceptions from the C API is current unimplemented"); } extern "C" void PyErr_Clear() { PyErr_Restore(NULL, NULL, NULL); } extern "C" void PyErr_SetString(PyObject* exception, const char* string) { PyErr_SetObject(exception, boxStrConstant(string)); } extern "C" void PyErr_SetObject(PyObject* exception, PyObject* value) { PyErr_Restore(exception, value, NULL); } extern "C" PyObject* PyErr_Format(PyObject* exception, const char* format, ...) { Py_FatalError("unimplemented"); } extern "C" PyObject* PyErr_NoMemory() { Py_FatalError("unimplemented"); } extern "C" int PyErr_CheckSignals() { Py_FatalError("unimplemented"); } extern "C" int PyErr_ExceptionMatches(PyObject* exc) { Py_FatalError("unimplemented"); } extern "C" PyObject* PyErr_Occurred() { // While there clearly needs to be more here, I think this is ok for now because all of the exception-setting // functions will abort() return NULL; } extern "C" int PyErr_WarnEx(PyObject* category, const char* text, Py_ssize_t stacklevel) { Py_FatalError("unimplemented"); } extern "C" PyObject* PyErr_SetFromErrno(PyObject* type) { Py_FatalError("unimplemented"); return NULL; } extern "C" PyObject* PyImport_Import(PyObject* module_name) { RELEASE_ASSERT(module_name, ""); RELEASE_ASSERT(module_name->cls == str_cls, ""); try { return import(-1, None, &static_cast<BoxedString*>(module_name)->s); } catch (Box* e) { Py_FatalError("unimplemented"); } } extern "C" PyObject* PyCallIter_New(PyObject* callable, PyObject* sentinel) { Py_FatalError("unimplemented"); } extern "C" void* PyMem_Malloc(size_t sz) { return gc_compat_malloc(sz); } extern "C" void* PyMem_Realloc(void* ptr, size_t sz) { return gc_compat_realloc(ptr, sz); } extern "C" void PyMem_Free(void* ptr) { gc_compat_free(ptr); } extern "C" int PyNumber_Check(PyObject*) { Py_FatalError("unimplemented"); } extern "C" PyObject* PyNumber_Add(PyObject* lhs, PyObject* rhs) { try { return binop(lhs, rhs, AST_TYPE::Add); } catch (Box* b) { Py_FatalError("unimplemented"); } } extern "C" PyObject* PyNumber_Subtract(PyObject* lhs, PyObject* rhs) { try { return binop(lhs, rhs, AST_TYPE::Sub); } catch (Box* b) { Py_FatalError("unimplemented"); } } extern "C" PyObject* PyNumber_Multiply(PyObject* lhs, PyObject* rhs) { try { return binop(lhs, rhs, AST_TYPE::Mult); } catch (Box* b) { Py_FatalError("unimplemented"); } } extern "C" PyObject* PyNumber_Divide(PyObject* lhs, PyObject* rhs) { try { return binop(lhs, rhs, AST_TYPE::Div); } catch (Box* b) { Py_FatalError("unimplemented"); } } extern "C" PyObject* PyNumber_FloorDivide(PyObject*, PyObject*) { Py_FatalError("unimplemented"); } extern "C" PyObject* PyNumber_TrueDivide(PyObject*, PyObject*) { Py_FatalError("unimplemented"); } extern "C" PyObject* PyNumber_Remainder(PyObject* lhs, PyObject* rhs) { try { return binop(lhs, rhs, AST_TYPE::Mod); } catch (Box* b) { Py_FatalError("unimplemented"); } } extern "C" PyObject* PyNumber_Divmod(PyObject*, PyObject*) { Py_FatalError("unimplemented"); } extern "C" PyObject* PyNumber_Power(PyObject*, PyObject*, PyObject* o3) { Py_FatalError("unimplemented"); } extern "C" PyObject* PyNumber_Negative(PyObject* o) { Py_FatalError("unimplemented"); } extern "C" PyObject* PyNumber_Positive(PyObject* o) { Py_FatalError("unimplemented"); } extern "C" PyObject* PyNumber_Absolute(PyObject* o) { try { return abs_(o); } catch (Box* b) { Py_FatalError("unimplemented"); } } extern "C" PyObject* PyNumber_Invert(PyObject* o) { Py_FatalError("unimplemented"); } extern "C" PyObject* PyNumber_Lshift(PyObject*, PyObject*) { Py_FatalError("unimplemented"); } extern "C" PyObject* PyNumber_Rshift(PyObject* lhs, PyObject* rhs) { try { return binop(lhs, rhs, AST_TYPE::RShift); } catch (Box* b) { Py_FatalError("unimplemented"); } } extern "C" PyObject* PyNumber_And(PyObject* lhs, PyObject* rhs) { try { return binop(lhs, rhs, AST_TYPE::BitAnd); } catch (Box* b) { Py_FatalError("unimplemented"); } } extern "C" PyObject* PyNumber_Xor(PyObject*, PyObject*) { Py_FatalError("unimplemented"); } extern "C" PyObject* PyNumber_Or(PyObject*, PyObject*) { Py_FatalError("unimplemented"); } extern "C" PyObject* PyNumber_InPlaceAdd(PyObject*, PyObject*) { Py_FatalError("unimplemented"); } extern "C" PyObject* PyNumber_InPlaceSubtract(PyObject*, PyObject*) { Py_FatalError("unimplemented"); } extern "C" PyObject* PyNumber_InPlaceMultiply(PyObject*, PyObject*) { Py_FatalError("unimplemented"); } extern "C" PyObject* PyNumber_InPlaceDivide(PyObject*, PyObject*) { Py_FatalError("unimplemented"); } extern "C" PyObject* PyNumber_InPlaceFloorDivide(PyObject*, PyObject*) { Py_FatalError("unimplemented"); } extern "C" PyObject* PyNumber_InPlaceTrueDivide(PyObject*, PyObject*) { Py_FatalError("unimplemented"); } extern "C" PyObject* PyNumber_InPlaceRemainder(PyObject*, PyObject*) { Py_FatalError("unimplemented"); } extern "C" PyObject* PyNumber_InPlacePower(PyObject*, PyObject*, PyObject* o3) { Py_FatalError("unimplemented"); } extern "C" PyObject* PyNumber_InPlaceLshift(PyObject*, PyObject*) { Py_FatalError("unimplemented"); } extern "C" PyObject* PyNumber_InPlaceRshift(PyObject*, PyObject*) { Py_FatalError("unimplemented"); } extern "C" PyObject* PyNumber_InPlaceAnd(PyObject*, PyObject*) { Py_FatalError("unimplemented"); } extern "C" PyObject* PyNumber_InPlaceXor(PyObject*, PyObject*) { Py_FatalError("unimplemented"); } extern "C" PyObject* PyNumber_InPlaceOr(PyObject*, PyObject*) { Py_FatalError("unimplemented"); } extern "C" int PyNumber_Coerce(PyObject**, PyObject**) { Py_FatalError("unimplemented"); } extern "C" int PyNumber_CoerceEx(PyObject**, PyObject**) { Py_FatalError("unimplemented"); } extern "C" PyObject* PyNumber_Int(PyObject* o) { Py_FatalError("unimplemented"); } extern "C" PyObject* PyNumber_Long(PyObject* o) { Py_FatalError("unimplemented"); } extern "C" PyObject* PyNumber_Float(PyObject* o) { Py_FatalError("unimplemented"); } extern "C" PyObject* PyNumber_Index(PyObject* o) { Py_FatalError("unimplemented"); } extern "C" PyObject* PyNumber_ToBase(PyObject* n, int base) { Py_FatalError("unimplemented"); } extern "C" Py_ssize_t PyNumber_AsSsize_t(PyObject* o, PyObject* exc) { Py_FatalError("unimplemented"); } extern "C" Py_ssize_t PyUnicode_GET_SIZE(PyObject*) { Py_FatalError("unimplemented"); } extern "C" Py_ssize_t PyUnicode_GET_DATA_SIZE(PyObject*) { Py_FatalError("unimplemented"); } extern "C" Py_UNICODE* PyUnicode_AS_UNICODE(PyObject*) { Py_FatalError("unimplemented"); } extern "C" const char* PyUnicode_AS_DATA(PyObject*) { Py_FatalError("unimplemented"); } BoxedModule* importTestExtension(const std::string& name) { std::string pathname_name = "test/test_extension/" + name + ".pyston.so"; const char* pathname = pathname_name.c_str(); void* handle = dlopen(pathname, RTLD_NOW); if (!handle) { fprintf(stderr, "%s\n", dlerror()); exit(1); } assert(handle); std::string initname = "init" + name; void (*init)() = (void (*)())dlsym(handle, initname.c_str()); char* error; if ((error = dlerror()) != NULL) { fprintf(stderr, "%s\n", error); exit(1); } assert(init); (*init)(); BoxedDict* sys_modules = getSysModulesDict(); Box* s = boxStrConstant(name.c_str()); Box* _m = sys_modules->d[s]; RELEASE_ASSERT(_m, "module failed to initialize properly?"); assert(_m->cls == module_cls); BoxedModule* m = static_cast<BoxedModule*>(_m); m->setattr("__file__", boxStrConstant(pathname), NULL); m->fn = pathname; return m; } void setupCAPI() { capifunc_cls = new BoxedClass(type_cls, object_cls, NULL, 0, sizeof(BoxedCApiFunction), false); capifunc_cls->giveAttr("__name__", boxStrConstant("capifunc")); capifunc_cls->giveAttr("__repr__", new BoxedFunction(boxRTFunction((void*)BoxedCApiFunction::__repr__, UNKNOWN, 1))); capifunc_cls->giveAttr("__str__", capifunc_cls->getattr("__repr__")); capifunc_cls->giveAttr( "__call__", new BoxedFunction(boxRTFunction((void*)BoxedCApiFunction::__call__, UNKNOWN, 1, 0, true, true))); capifunc_cls->freeze(); method_cls = new BoxedClass(type_cls, object_cls, NULL, 0, sizeof(BoxedMethodDescriptor), false); method_cls->giveAttr("__name__", boxStrConstant("method")); method_cls->giveAttr("__get__", new BoxedFunction(boxRTFunction((void*)BoxedMethodDescriptor::__get__, UNKNOWN, 3))); method_cls->giveAttr("__call__", new BoxedFunction(boxRTFunction((void*)BoxedMethodDescriptor::__call__, UNKNOWN, 2, 0, true, true))); method_cls->freeze(); wrapperdescr_cls = new BoxedClass(type_cls, object_cls, NULL, 0, sizeof(BoxedWrapperDescriptor), false); wrapperdescr_cls->giveAttr("__name__", boxStrConstant("wrapper_descriptor")); wrapperdescr_cls->giveAttr("__get__", new BoxedFunction(boxRTFunction((void*)BoxedWrapperDescriptor::__get__, UNKNOWN, 3))); wrapperdescr_cls->freeze(); wrapperobject_cls = new BoxedClass(type_cls, object_cls, NULL, 0, sizeof(BoxedWrapperObject), false); wrapperobject_cls->giveAttr("__name__", boxStrConstant("method-wrapper")); wrapperobject_cls->giveAttr( "__call__", new BoxedFunction(boxRTFunction((void*)BoxedWrapperObject::__call__, UNKNOWN, 1, 0, true, true))); wrapperobject_cls->freeze(); } void teardownCAPI() { } }