Commit b04977a2 authored by Kevin Modzelewski's avatar Kevin Modzelewski

Merge pull request #767 from rudi-c/ctypes

Import the ctypes module.
parents 2f60cce3 15655a6d
......@@ -118,6 +118,7 @@ add_custom_command(OUTPUT
${CMAKE_BINARY_DIR}/lib_pyston/pyexpat.pyston.so
${CMAKE_BINARY_DIR}/lib_pyston/_elementtree.pyston.so
${CMAKE_BINARY_DIR}/lib_pyston/bz2.pyston.so
${CMAKE_BINARY_DIR}/lib_pyston/_ctypes.pyston.so
${CMAKE_BINARY_DIR}/lib_pyston/grp.pyston.so
${CMAKE_BINARY_DIR}/lib_pyston/termios.pyston.so
${CMAKE_BINARY_DIR}/lib_pyston/_curses.pyston.so
......@@ -129,6 +130,11 @@ add_custom_command(OUTPUT
Modules/_multiprocessing/multiprocessing.c
Modules/_multiprocessing/semaphore.c
Modules/_multiprocessing/socket_connection.c
Modules/_ctypes/_ctypes.c
Modules/_ctypes/callbacks.c
Modules/_ctypes/callproc.c
Modules/_ctypes/stgdict.c
Modules/_ctypes/cfield.c
Modules/expat/xmlparse.c
Modules/expat/xmlrole.c
Modules/expat/xmltok.c
......
#ifndef Py_COMPILE_H
#define Py_COMPILE_H
#include "code.h"
#ifdef __cplusplus
extern "C" {
#endif
/* Public interface */
struct _node; /* Declare the existence of this type */
PyAPI_FUNC(PyCodeObject *) PyNode_Compile(struct _node *, const char *);
/* Future feature support */
typedef struct {
int ff_features; /* flags set by future statements */
int ff_lineno; /* line number of last future statement */
} PyFutureFeatures;
#define FUTURE_NESTED_SCOPES "nested_scopes"
#define FUTURE_GENERATORS "generators"
#define FUTURE_DIVISION "division"
#define FUTURE_ABSOLUTE_IMPORT "absolute_import"
#define FUTURE_WITH_STATEMENT "with_statement"
#define FUTURE_PRINT_FUNCTION "print_function"
#define FUTURE_UNICODE_LITERALS "unicode_literals"
struct _mod; /* Declare the existence of this type */
PyAPI_FUNC(PyCodeObject *) PyAST_Compile(struct _mod *, const char *,
PyCompilerFlags *, PyArena *);
PyAPI_FUNC(PyFutureFeatures *) PyFuture_FromAST(struct _mod *, const char *);
#ifdef __cplusplus
}
#endif
#endif /* !Py_COMPILE_H */
......@@ -20,6 +20,7 @@
#define _GNU_SOURCE 1
#define PY_LONG_LONG long long
#define SIZEOF__BOOL 1
#define SIZEOF_VOID_P 8
#define SIZEOF_SIZE_T 8
#define SIZEOF_INT 4
......
......@@ -2044,13 +2044,21 @@ PyCSimpleType_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
break;
}
if (ml) {
// TODO: Pyston change:
// For now, don't run this code path because we don't support some of
// the descriptor CAPI functions.
// We do this to be able to run `import ctypes`, but this will need to be
// enabled again once we want CType to actually work.
// if (ml) {
if (false) {
#if (PYTHON_API_VERSION >= 1012)
PyObject *meth;
int x;
/*
meth = PyDescr_NewClassMethod(result, ml);
if (!meth)
return NULL;
*/
#else
#error
PyObject *meth, *func;
......
......@@ -4,7 +4,10 @@
#include "Python.h"
#include "compile.h" /* required only for 2.3, as it seems */
#include "frameobject.h"
// Pyston change: We don't have this file and commented out the function that needs it, but
// we may want to support that function in the future.
//#include "frameobject.h"
#include <ffi.h>
#ifdef MS_WIN32
......@@ -149,6 +152,9 @@ failed:
/* after code that pyrex generates */
void _ctypes_add_traceback(char *funcname, char *filename, int lineno)
{
// TODO: Pyston change:
// Supporting this will require frameobject.h
#if 0
PyObject *py_globals = 0;
PyCodeObject *py_code = 0;
PyFrameObject *py_frame = 0;
......@@ -170,6 +176,9 @@ void _ctypes_add_traceback(char *funcname, char *filename, int lineno)
Py_XDECREF(py_globals);
Py_XDECREF(py_code);
Py_XDECREF(py_frame);
#else
assert(false);
#endif
}
#ifdef MS_WIN32
......
......@@ -1291,7 +1291,9 @@ s_get(void *ptr, Py_ssize_t size)
*/
slen = strlen(PyString_AS_STRING(result));
size = min(size, (Py_ssize_t)slen);
if (result->ob_refcnt == 1) {
// Pyston change: no ob_refcnt
if (false /*result->ob_refcnt == 1*/) {
/* shorten the result */
_PyString_Resize(&result, size);
return result;
......
......@@ -2,11 +2,22 @@
from distutils.core import setup, Extension
import os
import sysconfig
def relpath(fn):
r = os.path.join(os.path.dirname(__file__), fn)
return r
def unique(f):
# Use an array otherwise Python 2 gets confused about scoping.
cache = []
def wrapper(*args):
if len(cache) == 0:
cache.append(f(*args))
return cache[0]
return wrapper
@unique
def multiprocessing_ext():
return Extension("_multiprocessing", sources = map(relpath, [
"Modules/_multiprocessing/multiprocessing.c",
......@@ -14,26 +25,58 @@ def multiprocessing_ext():
"Modules/_multiprocessing/semaphore.c",
]))
@unique
def bz2_ext():
return Extension("bz2", sources = map(relpath, [
"Modules/bz2module.c",
]), libraries = ['bz2'])
@unique
def ctypes_ext():
ext = Extension("_ctypes", sources = map(relpath, [
"Modules/_ctypes/_ctypes.c",
"Modules/_ctypes/callbacks.c",
"Modules/_ctypes/callproc.c",
"Modules/_ctypes/stgdict.c",
"Modules/_ctypes/cfield.c"
]))
# Hack: Just copy the values of ffi_inc and ffi_lib from CPython's setup.py
# May want something more robust later.
ffi_inc = ['/usr/include/x86_64-linux-gnu']
ffi_lib = "ffi_pic"
ext.include_dirs.extend(ffi_inc)
ext.libraries.append(ffi_lib)
return ext
@unique
def ctypes_test_ext():
# TODO: I'm not sure how to use the ctypes tests, I just copied it over
# from CPython's setup.py. For now we're only importing ctypes, not passing
# all its tests.
return Extension('_ctypes_test',
sources= map(relpath, ['Modules/_ctypes/_ctypes_test.c']))
@unique
def grp_ext():
return Extension("grp", sources = map(relpath, [
"Modules/grpmodule.c",
]))
@unique
def curses_ext():
return Extension("_curses", sources = map(relpath, [
"Modules/_cursesmodule.c",
]), libraries = ['curses'])
@unique
def termios_ext():
return Extension("termios", sources = map(relpath, [
"Modules/termios.c",
]))
@unique
def pyexpat_ext():
define_macros = [('HAVE_EXPAT_CONFIG_H', '1'),]
expat_sources = map(relpath, ['Modules/expat/xmlparse.c',
......@@ -60,6 +103,7 @@ def pyexpat_ext():
depends = expat_depends,
)
@unique
def elementtree_ext():
# elementtree depends on expat
pyexpat = pyexpat_ext()
......@@ -71,10 +115,15 @@ def elementtree_ext():
sources = [relpath('Modules/_elementtree.c')],
depends = pyexpat.depends,
)
ext_modules = [multiprocessing_ext(),
pyexpat_ext(),
elementtree_ext(),
bz2_ext(),
ctypes_ext(),
ctypes_test_ext(),
grp_ext(),
curses_ext(),
termios_ext()]
setup(name="Pyston",
version="1.0",
description="Pyston shared modules",
ext_modules=[multiprocessing_ext(), pyexpat_ext(), elementtree_ext(), bz2_ext(), grp_ext(), curses_ext(), termios_ext()]
)
setup(name="Pyston", version="1.0", description="Pyston shared modules", ext_modules=ext_modules)
......@@ -3235,11 +3235,7 @@ extern "C" int PyType_Ready(PyTypeObject* cls) noexcept {
| Py_TPFLAGS_TUPLE_SUBCLASS | Py_TPFLAGS_STRING_SUBCLASS | Py_TPFLAGS_UNICODE_SUBCLASS
| Py_TPFLAGS_DICT_SUBCLASS | Py_TPFLAGS_BASE_EXC_SUBCLASS | Py_TPFLAGS_TYPE_SUBCLASS;
RELEASE_ASSERT((cls->tp_flags & ~ALLOWABLE_FLAGS) == 0, "");
if (cls->tp_as_number) {
RELEASE_ASSERT(cls->tp_flags & Py_TPFLAGS_CHECKTYPES, "Pyston doesn't yet support non-checktypes behavior");
}
RELEASE_ASSERT(cls->tp_descr_set == NULL, "");
RELEASE_ASSERT(cls->tp_free == NULL || cls->tp_free == PyObject_Del || cls->tp_free == PyObject_GC_Del, "");
RELEASE_ASSERT(cls->tp_is_gc == NULL, "");
RELEASE_ASSERT(cls->tp_mro == NULL, "");
......@@ -3317,8 +3313,24 @@ extern "C" int PyType_Ready(PyTypeObject* cls) noexcept {
cls->gc_visit = &conservativeGCHandler;
cls->is_user_defined = true;
if (!cls->instancesHaveHCAttrs() && cls->tp_base) {
// These doesn't get copied in inherit_slots like other slots do.
if (cls->tp_base->instancesHaveHCAttrs()) {
cls->attrs_offset = cls->tp_base->attrs_offset;
}
// Example of when this code path could be reached and needs to be:
// If this class is a metaclass defined in a C extension, chances are that some of its
// instances may be hardcoded in the C extension as well. Those instances will call
// PyType_Ready and expect their class (this metaclass) to have a place to put attributes.
// e.g. CTypes does this.
bool is_metaclass = PyType_IsSubtype(cls, type_cls);
assert(!is_metaclass || cls->instancesHaveHCAttrs() || cls->instancesHaveDictAttrs());
} else {
// this should get automatically initialized to 0 on this path:
assert(cls->attrs_offset == 0);
}
if (Py_TPFLAGS_BASE_EXC_SUBCLASS & cls->tp_flags) {
exception_types.push_back(cls);
......
......@@ -184,6 +184,16 @@ extern "C" int _PyInt_AsInt(PyObject* obj) noexcept {
return (int)result;
}
#ifdef HAVE_LONG_LONG
extern "C" unsigned PY_LONG_LONG PyInt_AsUnsignedLongLongMask(register PyObject* op) noexcept {
Py_FatalError("unimplemented");
unsigned PY_LONG_LONG val = 0;
return val;
}
#endif
extern "C" PyObject* PyInt_FromString(const char* s, char** pend, int base) noexcept {
char* end;
long x;
......
......@@ -442,6 +442,13 @@ BoxedClass::BoxedClass(BoxedClass* base, gcvisit_func gc_visit, int attrs_offset
if (base && (base->tp_flags & Py_TPFLAGS_HAVE_NEWBUFFER))
tp_flags |= Py_TPFLAGS_HAVE_NEWBUFFER;
// From CPython: It's a new-style number unless it specifically inherits any
// old-style numeric behavior.
if (base) {
if ((base->tp_flags & Py_TPFLAGS_CHECKTYPES) || (base->tp_as_number == NULL))
tp_flags |= Py_TPFLAGS_CHECKTYPES;
}
tp_base = base;
if (tp_base) {
......@@ -4882,34 +4889,7 @@ void assertValidSlotIdentifier(Box* s) {
}
}
Box* typeNew(Box* _cls, Box* arg1, Box* arg2, Box** _args) {
STAT_TIMER(t0, "us_timer_typeNew", 10);
Box* arg3 = _args[0];
if (!isSubclass(_cls->cls, type_cls))
raiseExcHelper(TypeError, "type.__new__(X): X is not a type object (%s)", getTypeName(_cls));
BoxedClass* metatype = static_cast<BoxedClass*>(_cls);
if (!isSubclass(metatype, type_cls))
raiseExcHelper(TypeError, "type.__new__(%s): %s is not a subtype of type", getNameOfClass(metatype),
getNameOfClass(metatype));
if (arg2 == NULL) {
assert(arg3 == NULL);
BoxedClass* rtn = arg1->cls;
return rtn;
}
RELEASE_ASSERT(PyDict_Check(arg3), "%s", getTypeName(arg3));
BoxedDict* attr_dict = static_cast<BoxedDict*>(arg3);
RELEASE_ASSERT(arg2->cls == tuple_cls, "");
BoxedTuple* bases = static_cast<BoxedTuple*>(arg2);
RELEASE_ASSERT(arg1->cls == str_cls, "");
BoxedString* name = static_cast<BoxedString*>(arg1);
Box* _typeNew(BoxedClass* metatype, BoxedString* name, BoxedTuple* bases, BoxedDict* attr_dict) {
if (bases->size() == 0) {
bases = BoxedTuple::create({ object_cls });
}
......@@ -4939,7 +4919,8 @@ Box* typeNew(Box* _cls, Box* arg1, Box* arg2, Box** _args) {
if (getattr(winner, new_box) != getattr(type_cls, new_box)) {
CallattrFlags callattr_flags
= {.cls_only = false, .null_on_nonexistent = false, .argspec = ArgPassSpec(4) };
return callattr(winner, new_box, callattr_flags, winner, arg1, arg2, _args, NULL);
Box* args[1] = { (Box*)attr_dict };
return callattr(winner, new_box, callattr_flags, winner, name, bases, args, NULL);
}
metatype = winner;
}
......@@ -5173,6 +5154,100 @@ Box* typeNew(Box* _cls, Box* arg1, Box* arg2, Box** _args) {
return made;
}
// Analogous to CPython's type_new.
// This is assigned directly to type_cls's (PyType_Type's) tp_new slot and skips
// doing an attribute lookup for __new__.
//
// We need this to support some edge cases. For example, in ctypes, we have a function:
// PyCSimpleType_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
// {
// ...
// result = (PyTypeObject *)PyType_Type.tp_new(type, args, kwds);
// ...
// }
//
// Assigned to the tp_new of PyCSimpleType, a metaclass. By calling PyType_Type.tp_new,
// we don't want to do an attribute lookup for __new__, because that would end up calling
// the tp_new of the subclass PyCSimpleType (PyCSimpleType_new again) and end up in a loop.
Box* type_new(BoxedClass* metatype, Box* args, Box* kwds) noexcept {
PyObject* name, *bases, *dict;
static const char* kwlist[] = { "name", "bases", "dict", 0 };
// Copied from CPython.
assert(args != NULL && PyTuple_Check(args));
assert(kwds == NULL || PyDict_Check(kwds));
/* Special case: type(x) should return x->ob_type */
{
const Py_ssize_t nargs = PyTuple_GET_SIZE(args);
const Py_ssize_t nkwds = kwds == NULL ? 0 : PyDict_Size(kwds);
if (PyType_CheckExact(metatype) && nargs == 1 && nkwds == 0) {
PyObject* x = PyTuple_GET_ITEM(args, 0);
Py_INCREF(Py_TYPE(x));
return (PyObject*)Py_TYPE(x);
}
/* SF bug 475327 -- if that didn't trigger, we need 3
arguments. but PyArg_ParseTupleAndKeywords below may give
a msg saying type() needs exactly 3. */
if (nargs + nkwds != 3) {
PyErr_SetString(PyExc_TypeError, "type() takes 1 or 3 arguments");
return NULL;
}
}
// Check arguments: (name, bases, dict)
if (!PyArg_ParseTupleAndKeywords(args, kwds, "SO!O!:type", const_cast<char**>(kwlist), &name, &PyTuple_Type, &bases,
&PyDict_Type, &dict))
return NULL;
try {
RELEASE_ASSERT(name->cls == str_cls, "");
RELEASE_ASSERT(bases->cls == tuple_cls, "");
RELEASE_ASSERT(dict->cls == dict_cls, "");
return _typeNew(metatype, static_cast<BoxedString*>(name), static_cast<BoxedTuple*>(bases),
static_cast<BoxedDict*>(dict));
} catch (ExcInfo e) {
setCAPIException(e);
return NULL;
}
}
// This is the function we want uses of __new__ to call.
Box* typeNewGeneric(Box* _cls, Box* arg1, Box* arg2, Box** _args) {
STAT_TIMER(t0, "us_timer_typeNew", 10);
Box* arg3 = _args[0];
if (!isSubclass(_cls->cls, type_cls))
raiseExcHelper(TypeError, "type.__new__(X): X is not a type object (%s)", getTypeName(_cls));
BoxedClass* metatype = static_cast<BoxedClass*>(_cls);
if (!isSubclass(metatype, type_cls))
raiseExcHelper(TypeError, "type.__new__(%s): %s is not a subtype of type", getNameOfClass(metatype),
getNameOfClass(metatype));
if (arg2 == NULL) {
assert(arg3 == NULL);
BoxedClass* rtn = arg1->cls;
return rtn;
}
RELEASE_ASSERT(PyDict_Check(arg3), "%s", getTypeName(arg3));
BoxedDict* attr_dict = static_cast<BoxedDict*>(arg3);
RELEASE_ASSERT(arg2->cls == tuple_cls, "");
BoxedTuple* bases = static_cast<BoxedTuple*>(arg2);
RELEASE_ASSERT(arg1->cls == str_cls, "");
BoxedString* name = static_cast<BoxedString*>(arg1);
return _typeNew(metatype, name, bases, attr_dict);
}
extern "C" void delGlobal(Box* globals, BoxedString* name) {
if (globals->cls == module_cls) {
BoxedModule* m = static_cast<BoxedModule*>(globals);
......
......@@ -160,7 +160,8 @@ extern "C" void raiseNotIterableError(const char* typeName) __attribute__((__nor
extern "C" void raiseIndexErrorStr(const char* typeName) __attribute__((__noreturn__));
Box* typeCall(Box*, BoxedTuple*, BoxedDict*);
Box* typeNew(Box* cls, Box* arg1, Box* arg2, Box** _args);
Box* type_new(BoxedClass* metatype, Box* args, Box* kwds) noexcept;
Box* typeNewGeneric(Box* cls, Box* arg1, Box* arg2, Box** _args);
// These process a potential descriptor, differing in their behavior if the object was not a descriptor.
// the OrNull variant returns NULL to signify it wasn't a descriptor, and the processDescriptor version
......
......@@ -3424,8 +3424,8 @@ void setupRuntime() {
type_cls->giveAttr("__bases__", new (pyston_getset_cls) BoxedGetsetDescriptor(typeBases, typeSetBases, NULL));
type_cls->giveAttr("__call__", new BoxedFunction(typeCallObj));
type_cls->giveAttr("__new__",
new BoxedFunction(boxRTFunction((void*)typeNew, UNKNOWN, 4, 2, false, false), { NULL, NULL }));
type_cls->giveAttr("__new__", new BoxedFunction(boxRTFunction((void*)typeNewGeneric, UNKNOWN, 4, 2, false, false),
{ NULL, NULL }));
type_cls->giveAttr("__repr__", new BoxedFunction(boxRTFunction((void*)typeRepr, STR, 1)));
type_cls->tp_hash = (hashfunc)_Py_HashPointer;
type_cls->giveAttr("__module__", new (pyston_getset_cls) BoxedGetsetDescriptor(typeModule, typeSetModule, NULL));
......@@ -3436,6 +3436,7 @@ void setupRuntime() {
type_cls->tp_richcompare = type_richcompare;
add_operators(type_cls);
type_cls->freeze();
type_cls->tp_new = type_new;
type_cls->tpp_call = &typeTppCall;
none_cls->giveAttr("__repr__", new BoxedFunction(boxRTFunction((void*)noneRepr, STR, 1)));
......
......@@ -197,7 +197,7 @@ public:
// Analogous to tp_dictoffset
// A class should have at most of one attrs_offset and tp_dictoffset be nonzero.
// (But having nonzero attrs_offset here would map to having nonzero tp_dictoffset in CPython)
const int attrs_offset;
int attrs_offset;
bool instancesHaveHCAttrs() { return attrs_offset != 0; }
bool instancesHaveDictAttrs() { return tp_dictoffset != 0; }
......
......@@ -19,6 +19,20 @@
#include "core/types.h"
#include "runtime/objmodel.h"
// Temp hack to get CType sort of importing
PyObject* PyDescr_NewMember(PyTypeObject* x, struct PyMemberDef* y) PYSTON_NOEXCEPT {
Py_FatalError("unimplemented");
return NULL;
}
PyObject* PyDescr_NewGetSet(PyTypeObject* x, struct PyGetSetDef* y) PYSTON_NOEXCEPT {
Py_FatalError("unimplemented");
return NULL;
}
PyObject* PyDescr_NewClassMethod(PyTypeObject* x, PyMethodDef* y) PYSTON_NOEXCEPT {
Py_FatalError("unimplemented");
return NULL;
}
namespace pyston {
void parseSlice(BoxedSlice* slice, int size, i64* out_start, i64* out_stop, i64* out_step, i64* out_length) {
......
# We can only import ctypes for now - it would be nice to have tests later,
# which will probably involve running the existing test suite for ctype rather
# than add our own here (unless there's special Pyston-related edge cases).
import ctypes
import uuid
print len(str(uuid.uuid1()))
# Hack to get the test passing until we support CTypes.
# The problem is that we currently support import CTypes but it doesn't run
# correctly, so uuid fails without a fallback to using non-CTypes functions.
# This makes the uuid module think CTypes is not present.
uuid._uuid_generate_random = None
print len(str(uuid.uuid4()))
print uuid.uuid3(uuid.NAMESPACE_DNS, 'python.org')
print uuid.uuid5(uuid.NAMESPACE_DNS, 'python.org')
......
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