[pypy-commit] pypy default: merge a major refactoring of parts of cpyext to default

mattip pypy.commits at gmail.com
Wed Apr 27 11:17:12 EDT 2016


Author: Matti Picus <matti.picus at gmail.com>
Branch: 
Changeset: r83988:26e1999e0803
Date: 2016-04-27 18:16 +0300
http://bitbucket.org/pypy/pypy/changeset/26e1999e0803/

Log:	merge a major refactoring of parts of cpyext to default

diff too long, truncating to 2000 out of 8378 lines

diff --git a/TODO b/TODO
new file mode 100644
--- /dev/null
+++ b/TODO
@@ -0,0 +1,3 @@
+* python setup.py install in numpy does not somehow tell setuptools
+  it's installed (I bet it's about the py27 tag)
+* reduce size of generated c code from slot definitions in slotdefs.
diff --git a/pypy/doc/whatsnew-head.rst b/pypy/doc/whatsnew-head.rst
--- a/pypy/doc/whatsnew-head.rst
+++ b/pypy/doc/whatsnew-head.rst
@@ -22,3 +22,24 @@
 JIT: use bitstrings to compress the lists of read or written descrs
 that we attach to EffectInfo.  Fixes a problem we had in
 remove-objspace-options.
+
+.. branch: cpyext-for-merge
+Update cpyext C-API support:
+  - allow c-snippet tests to be run with -A so we can verify we are compatible
+  - fix many edge cases exposed by fixing tests to run with -A
+  - issequence() logic matches cpython
+  - make PyStringObject and PyUnicodeObject field names compatible with cpython
+  - add prelminary support for PyDateTime_*
+  - support PyComplexObject, PyFloatObject, PyDict_Merge, PyDictProxy,
+    PyMemoryView_*, _Py_HashDouble, PyFile_AsFile, PyFile_FromFile,
+  - PyAnySet_CheckExact, PyUnicode_Concat
+  - improve support for PyGILState_Ensure, PyGILState_Release, and thread
+    primitives, also find a case where CPython will allow thread creation
+    before PyEval_InitThreads is run, dissallow on PyPy 
+  - create a PyObject-specific list strategy
+  - rewrite slot assignment for typeobjects
+  - improve tracking of PyObject to rpython object mapping
+  - support tp_as_{number, sequence, mapping, buffer} slots
+After this branch, we are almost able to support upstream numpy via cpyext, so
+we created (yet another) fork of numpy at github.com/pypy/numpy with the needed
+changes
diff --git a/pypy/interpreter/baseobjspace.py b/pypy/interpreter/baseobjspace.py
--- a/pypy/interpreter/baseobjspace.py
+++ b/pypy/interpreter/baseobjspace.py
@@ -1176,7 +1176,27 @@
         return self.w_False
 
     def issequence_w(self, w_obj):
-        return (self.findattr(w_obj, self.wrap("__getitem__")) is not None)
+        if self.is_oldstyle_instance(w_obj):
+            return (self.findattr(w_obj, self.wrap('__getitem__')) is not None)
+        flag = self.type(w_obj).flag_map_or_seq
+        if flag == 'M':
+            return False
+        elif flag == 'S':
+            return True
+        else:
+            return (self.lookup(w_obj, '__getitem__') is not None)
+
+    def ismapping_w(self, w_obj):
+        if self.is_oldstyle_instance(w_obj):
+            return (self.findattr(w_obj, self.wrap('__getitem__')) is not None)
+        flag = self.type(w_obj).flag_map_or_seq
+        if flag == 'M':
+            return True
+        elif flag == 'S':
+            return False
+        else:
+            return (self.lookup(w_obj, '__getitem__') is not None and
+                    self.lookup(w_obj, '__getslice__') is None)
 
     # The code below only works
     # for the simple case (new-style instance).
diff --git a/pypy/module/cpyext/api.py b/pypy/module/cpyext/api.py
--- a/pypy/module/cpyext/api.py
+++ b/pypy/module/cpyext/api.py
@@ -37,6 +37,8 @@
 from rpython.tool.sourcetools import func_with_new_name
 from rpython.rtyper.lltypesystem.lloperation import llop
 from rpython.rlib import rawrefcount
+from rpython.rlib import rthread
+from rpython.rlib.debug import fatalerror_notb
 
 DEBUG_WRAPPER = True
 
@@ -85,11 +87,13 @@
 FILEP = rffi.COpaquePtr('FILE')
 
 if sys.platform == 'win32':
-    fileno = rffi.llexternal('_fileno', [FILEP], rffi.INT)
+    dash = '_'
 else:
-    fileno = rffi.llexternal('fileno', [FILEP], rffi.INT)
-
+    dash = ''
+fileno = rffi.llexternal(dash + 'fileno', [FILEP], rffi.INT)
 fopen = rffi.llexternal('fopen', [CONST_STRING, CONST_STRING], FILEP)
+fdopen = rffi.llexternal(dash + 'fdopen', [rffi.INT, CONST_STRING],
+                  FILEP, save_err=rffi.RFFI_SAVE_ERRNO)
 
 _fclose = rffi.llexternal('fclose', [FILEP], rffi.INT)
 def fclose(fp):
@@ -119,16 +123,18 @@
 def is_valid_fp(fp):
     return is_valid_fd(fileno(fp))
 
+pypy_decl = 'pypy_decl.h'
+
 constant_names = """
 Py_TPFLAGS_READY Py_TPFLAGS_READYING Py_TPFLAGS_HAVE_GETCHARBUFFER
-METH_COEXIST METH_STATIC METH_CLASS
+METH_COEXIST METH_STATIC METH_CLASS Py_TPFLAGS_BASETYPE
 METH_NOARGS METH_VARARGS METH_KEYWORDS METH_O
 Py_TPFLAGS_HEAPTYPE Py_TPFLAGS_HAVE_CLASS
 Py_LT Py_LE Py_EQ Py_NE Py_GT Py_GE Py_TPFLAGS_CHECKTYPES
 """.split()
 for name in constant_names:
     setattr(CConfig_constants, name, rffi_platform.ConstantInteger(name))
-udir.join('pypy_decl.h').write("/* Will be filled later */\n")
+udir.join(pypy_decl).write("/* Will be filled later */\n")
 udir.join('pypy_structmember_decl.h').write("/* Will be filled later */\n")
 udir.join('pypy_macros.h').write("/* Will be filled later */\n")
 globals().update(rffi_platform.configure(CConfig_constants))
@@ -144,7 +150,7 @@
         target.chmod(0444) # make the file read-only, to make sure that nobody
                            # edits it by mistake
 
-def copy_header_files(dstdir):
+def copy_header_files(dstdir, copy_numpy_headers):
     # XXX: 20 lines of code to recursively copy a directory, really??
     assert dstdir.check(dir=True)
     headers = include_dir.listdir('*.h') + include_dir.listdir('*.inl')
@@ -152,6 +158,18 @@
         headers.append(udir.join(name))
     _copy_header_files(headers, dstdir)
 
+    if copy_numpy_headers:
+        try:
+            dstdir.mkdir('numpy')
+        except py.error.EEXIST:
+            pass
+        numpy_dstdir = dstdir / 'numpy'
+
+        numpy_include_dir = include_dir / 'numpy'
+        numpy_headers = numpy_include_dir.listdir('*.h') + numpy_include_dir.listdir('*.inl')
+        _copy_header_files(numpy_headers, numpy_dstdir)
+
+
 class NotSpecified(object):
     pass
 _NOT_SPECIFIED = NotSpecified()
@@ -177,6 +195,61 @@
 # exceptions generate a OperationError(w_SystemError); and the funtion returns
 # the error value specifed in the API.
 #
+# Handling of the GIL
+# -------------------
+#
+# We add a global variable 'cpyext_glob_tid' that contains a thread
+# id.  Invariant: this variable always contain 0 when the PyPy GIL is
+# released.  It should also contain 0 when regular RPython code
+# executes.  In non-cpyext-related code, it will thus always be 0.
+# 
+# **make_generic_cpy_call():** RPython to C, with the GIL held.  Before
+# the call, must assert that the global variable is 0 and set the
+# current thread identifier into the global variable.  After the call,
+# assert that the global variable still contains the current thread id,
+# and reset it to 0.
+# 
+# **make_wrapper():** C to RPython; by default assume that the GIL is
+# held, but accepts gil="acquire", "release", "around",
+# "pygilstate_ensure", "pygilstate_release".
+# 
+# When a wrapper() is called:
+# 
+# * "acquire": assert that the GIL is not currently held, i.e. the
+#   global variable does not contain the current thread id (otherwise,
+#   deadlock!).  Acquire the PyPy GIL.  After we acquired it, assert
+#   that the global variable is 0 (it must be 0 according to the
+#   invariant that it was 0 immediately before we acquired the GIL,
+#   because the GIL was released at that point).
+# 
+# * gil=None: we hold the GIL already.  Assert that the current thread
+#   identifier is in the global variable, and replace it with 0.
+# 
+# * "pygilstate_ensure": if the global variable contains the current
+#   thread id, replace it with 0 and set the extra arg to 0.  Otherwise,
+#   do the "acquire" and set the extra arg to 1.  Then we'll call
+#   pystate.py:PyGILState_Ensure() with this extra arg, which will do
+#   the rest of the logic.
+# 
+# When a wrapper() returns, first assert that the global variable is
+# still 0, and then:
+# 
+# * "release": release the PyPy GIL.  The global variable was 0 up to
+#   and including at the point where we released the GIL, but afterwards
+#   it is possible that the GIL is acquired by a different thread very
+#   quickly.
+# 
+# * gil=None: we keep holding the GIL.  Set the current thread
+#   identifier into the global variable.
+# 
+# * "pygilstate_release": if the argument is PyGILState_UNLOCKED,
+#   release the PyPy GIL; otherwise, set the current thread identifier
+#   into the global variable.  The rest of the logic of
+#   PyGILState_Release() should be done before, in pystate.py.
+
+cpyext_glob_tid_ptr = lltype.malloc(rffi.CArray(lltype.Signed), 1,
+                                    flavor='raw', immortal=True, zero=True)
+
 
 cpyext_namespace = NameManager('cpyext_')
 
@@ -196,6 +269,9 @@
         argnames, varargname, kwargname = pycode.cpython_code_signature(callable.func_code)
 
         assert argnames[0] == 'space'
+        if gil == 'pygilstate_ensure':
+            assert argnames[-1] == 'previous_state'
+            del argnames[-1]
         self.argnames = argnames[1:]
         assert len(self.argnames) == len(self.argtypes)
         self.gil = gil
@@ -414,15 +490,14 @@
     'PyThread_acquire_lock', 'PyThread_release_lock',
     'PyThread_create_key', 'PyThread_delete_key', 'PyThread_set_key_value',
     'PyThread_get_key_value', 'PyThread_delete_key_value',
-    'PyThread_ReInitTLS',
+    'PyThread_ReInitTLS', 'PyThread_init_thread',
+    'PyThread_start_new_thread',
 
     'PyStructSequence_InitType', 'PyStructSequence_New',
     'PyStructSequence_UnnamedField',
 
     'PyFunction_Type', 'PyMethod_Type', 'PyRange_Type', 'PyTraceBack_Type',
 
-    'PyArray_Type', '_PyArray_FILLWBYTE', '_PyArray_ZEROS', '_PyArray_CopyInto',
-
     'Py_DebugFlag', 'Py_VerboseFlag', 'Py_InteractiveFlag', 'Py_InspectFlag',
     'Py_OptimizeFlag', 'Py_NoSiteFlag', 'Py_BytesWarningFlag', 'Py_UseClassExceptionsFlag',
     'Py_FrozenFlag', 'Py_TabcheckFlag', 'Py_UnicodeFlag', 'Py_IgnoreEnvironmentFlag',
@@ -431,11 +506,11 @@
 ]
 TYPES = {}
 GLOBALS = { # this needs to include all prebuilt pto, otherwise segfaults occur
-    '_Py_NoneStruct#': ('PyObject*', 'space.w_None'),
-    '_Py_TrueStruct#': ('PyIntObject*', 'space.w_True'),
-    '_Py_ZeroStruct#': ('PyIntObject*', 'space.w_False'),
-    '_Py_NotImplementedStruct#': ('PyObject*', 'space.w_NotImplemented'),
-    '_Py_EllipsisObject#': ('PyObject*', 'space.w_Ellipsis'),
+    '_Py_NoneStruct#%s' % pypy_decl: ('PyObject*', 'space.w_None'),
+    '_Py_TrueStruct#%s' % pypy_decl: ('PyIntObject*', 'space.w_True'),
+    '_Py_ZeroStruct#%s' % pypy_decl: ('PyIntObject*', 'space.w_False'),
+    '_Py_NotImplementedStruct#%s' % pypy_decl: ('PyObject*', 'space.w_NotImplemented'),
+    '_Py_EllipsisObject#%s' % pypy_decl: ('PyObject*', 'space.w_Ellipsis'),
     'PyDateTimeAPI': ('PyDateTime_CAPI*', 'None'),
     }
 FORWARD_DECLS = []
@@ -461,6 +536,7 @@
         "PyUnicode_Type": "space.w_unicode",
         "PyBaseString_Type": "space.w_basestring",
         "PyDict_Type": "space.w_dict",
+        "PyDictProxy_Type": "cpyext.dictobject.make_frozendict(space)",
         "PyTuple_Type": "space.w_tuple",
         "PyList_Type": "space.w_list",
         "PySet_Type": "space.w_set",
@@ -484,7 +560,7 @@
         'PyCFunction_Type': 'space.gettypeobject(cpyext.methodobject.W_PyCFunctionObject.typedef)',
         'PyWrapperDescr_Type': 'space.gettypeobject(cpyext.methodobject.W_PyCMethodObject.typedef)'
         }.items():
-        GLOBALS['%s#' % (cpyname, )] = ('PyTypeObject*', pypyexpr)
+        GLOBALS['%s#%s' % (cpyname, pypy_decl)] = ('PyTypeObject*', pypyexpr)
 
     for cpyname in '''PyMethodObject PyListObject PyLongObject
                       PyDictObject PyClassObject'''.split():
@@ -602,7 +678,14 @@
     fatal_value = callable.api_func.restype._defl()
     gil_acquire = (gil == "acquire" or gil == "around")
     gil_release = (gil == "release" or gil == "around")
-    assert gil is None or gil_acquire or gil_release
+    pygilstate_ensure = (gil == "pygilstate_ensure")
+    pygilstate_release = (gil == "pygilstate_release")
+    assert (gil is None or gil_acquire or gil_release
+            or pygilstate_ensure or pygilstate_release)
+    deadlock_error = ("GIL deadlock detected when a CPython C extension "
+                      "module calls %r" % (callable.__name__,))
+    no_gil_error = ("GIL not held when a CPython C extension "
+                    "module calls %r" % (callable.__name__,))
 
     @specialize.ll()
     def wrapper(*args):
@@ -610,8 +693,27 @@
         from pypy.module.cpyext.pyobject import as_pyobj
         # we hope that malloc removal removes the newtuple() that is
         # inserted exactly here by the varargs specializer
+
+        # see "Handling of the GIL" above (careful, we don't have the GIL here)
+        tid = rthread.get_or_make_ident()
         if gil_acquire:
+            if cpyext_glob_tid_ptr[0] == tid:
+                fatalerror_notb(deadlock_error)
             rgil.acquire()
+            assert cpyext_glob_tid_ptr[0] == 0
+        elif pygilstate_ensure:
+            from pypy.module.cpyext import pystate
+            if cpyext_glob_tid_ptr[0] == tid:
+                cpyext_glob_tid_ptr[0] = 0
+                args += (pystate.PyGILState_LOCKED,)
+            else:
+                rgil.acquire()
+                args += (pystate.PyGILState_UNLOCKED,)
+        else:
+            if cpyext_glob_tid_ptr[0] != tid:
+                fatalerror_notb(no_gil_error)
+            cpyext_glob_tid_ptr[0] = 0
+
         rffi.stackcounter.stacks_counter += 1
         llop.gc_stack_bottom(lltype.Void)   # marker for trackgcroot.py
         retval = fatal_value
@@ -620,7 +722,8 @@
         try:
             if not we_are_translated() and DEBUG_WRAPPER:
                 print >>sys.stderr, callable,
-            assert len(args) == len(callable.api_func.argtypes)
+            assert len(args) == (len(callable.api_func.argtypes) +
+                                 pygilstate_ensure)
             for i, (typ, is_wrapped) in argtypes_enum_ui:
                 arg = args[i]
                 if is_PyObject(typ) and is_wrapped:
@@ -629,6 +732,8 @@
                 else:
                     arg_conv = arg
                 boxed_args += (arg_conv, )
+            if pygilstate_ensure:
+                boxed_args += (args[-1], )
             state = space.fromcache(State)
             try:
                 result = callable(space, *boxed_args)
@@ -688,8 +793,20 @@
                 pypy_debug_catch_fatal_exception()
                 assert False
         rffi.stackcounter.stacks_counter -= 1
-        if gil_release:
+
+        # see "Handling of the GIL" above
+        assert cpyext_glob_tid_ptr[0] == 0
+        if pygilstate_release:
+            from pypy.module.cpyext import pystate
+            arg = rffi.cast(lltype.Signed, args[-1])
+            unlock = (arg == pystate.PyGILState_UNLOCKED)
+        else:
+            unlock = gil_release
+        if unlock:
             rgil.release()
+        else:
+            cpyext_glob_tid_ptr[0] = tid
+
         return retval
     callable._always_inline_ = 'try'
     wrapper.__name__ = "wrapper for %r" % (callable, )
@@ -782,6 +899,9 @@
     structindex = {}
     for header, header_functions in FUNCTIONS_BY_HEADER.iteritems():
         for name, func in header_functions.iteritems():
+            if not func: 
+                # added only for the macro, not the decl
+                continue
             restype, args = c_function_signature(db, func)
             members.append('%s (*%s)(%s);' % (restype, name, args))
             structindex[name] = len(structindex)
@@ -798,7 +918,7 @@
 
     global_objects = []
     for name, (typ, expr) in GLOBALS.iteritems():
-        if "#" in name:
+        if '#' in name:
             continue
         if typ == 'PyDateTime_CAPI*':
             continue
@@ -822,7 +942,7 @@
             '\n' +
             '\n'.join(functions))
 
-    eci = build_eci(True, export_symbols, code)
+    eci = build_eci(True, export_symbols, code, use_micronumpy)
     eci = eci.compile_shared_lib(
         outputfilename=str(udir / "module_cache" / "pypyapi"))
     modulename = py.path.local(eci.libraries[-1])
@@ -834,7 +954,7 @@
             ob = rawrefcount.next_dead(PyObject)
             if not ob:
                 break
-            print ob
+            print 'deallocating PyObject', ob
             decref(space, ob)
         print 'dealloc_trigger DONE'
         return "RETRY"
@@ -853,8 +973,8 @@
     for name, (typ, expr) in GLOBALS.iteritems():
         from pypy.module import cpyext    # for the eval() below
         w_obj = eval(expr)
-        if name.endswith('#'):
-            name = name[:-1]
+        if '#' in name:
+            name = name.split('#')[0]
             isptr = False
         else:
             isptr = True
@@ -899,7 +1019,7 @@
     #        ctypes.c_void_p)
     for header, header_functions in FUNCTIONS_BY_HEADER.iteritems():
         for name, func in header_functions.iteritems():
-            if name.startswith('cpyext_'): # XXX hack
+            if name.startswith('cpyext_') or func is None: # XXX hack
                 continue
             pypyAPI[structindex[name]] = ctypes.cast(
                 ll2ctypes.lltype2ctypes(func.get_llhelper(space)),
@@ -952,6 +1072,8 @@
         cpyext_type_init = self.cpyext_type_init
         self.cpyext_type_init = None
         for pto, w_type in cpyext_type_init:
+            if space.is_w(w_type, space.w_str):
+                pto.c_tp_itemsize = 1
             finish_type_1(space, pto)
             finish_type_2(space, pto, w_type)
 
@@ -969,10 +1091,14 @@
     pypy_macros = []
     renamed_symbols = []
     for name in export_symbols:
-        name = name.replace("#", "")
+        if '#' in name:
+            name,header = name.split('#')
+        else:
+            header = pypy_decl
         newname = mangle_name(prefix, name)
         assert newname, name
-        pypy_macros.append('#define %s %s' % (name, newname))
+        if header == pypy_decl:
+            pypy_macros.append('#define %s %s' % (name, newname))
         if name.startswith("PyExc_"):
             pypy_macros.append('#define _%s _%s' % (name, newname))
         renamed_symbols.append(newname)
@@ -1001,7 +1127,7 @@
     # implement function callbacks and generate function decls
     functions = []
     decls = {}
-    pypy_decls = decls['pypy_decl.h'] = []
+    pypy_decls = decls[pypy_decl] = []
     pypy_decls.append('#define Signed   long           /* xxx temporary fix */\n')
     pypy_decls.append('#define Unsigned unsigned long  /* xxx temporary fix */\n')
 
@@ -1017,6 +1143,8 @@
             header = decls[header_name]
 
         for name, func in sorted(header_functions.iteritems()):
+            if not func:
+                continue
             if header == DEFAULT_HEADER:
                 _name = name
             else:
@@ -1042,12 +1170,15 @@
         functions.append(header + '\n{return va_arg(*vp, %s);}\n' % name)
 
     for name, (typ, expr) in GLOBALS.iteritems():
-        if name.endswith('#'):
-            name = name.replace("#", "")
+        if '#' in name:
+            name, header = name.split("#")
             typ = typ.replace("*", "")
         elif name.startswith('PyExc_'):
             typ = 'PyObject*'
-        pypy_decls.append('PyAPI_DATA(%s) %s;' % (typ, name))
+            header = pypy_decl
+        if header != pypy_decl:
+            decls[header].append('#define %s %s' % (name, mangle_name(prefix, name)))
+        decls[header].append('PyAPI_DATA(%s) %s;' % (typ, name))
 
     for header_name in FUNCTIONS_BY_HEADER.keys():
         header = decls[header_name]
@@ -1075,9 +1206,10 @@
                          source_dir / "pysignals.c",
                          source_dir / "pythread.c",
                          source_dir / "missing.c",
+                         source_dir / "pymem.c",
                          ]
 
-def build_eci(building_bridge, export_symbols, code):
+def build_eci(building_bridge, export_symbols, code, use_micronumpy=False):
     "NOT_RPYTHON"
     # Build code and get pointer to the structure
     kwds = {}
@@ -1099,9 +1231,11 @@
 
     # Generate definitions for global structures
     structs = ["#include <Python.h>"]
+    if use_micronumpy:
+        structs.append('#include <pypy_numpy.h> /* api.py line 1223 */')
     for name, (typ, expr) in GLOBALS.iteritems():
-        if name.endswith('#'):
-            structs.append('%s %s;' % (typ[:-1], name[:-1]))
+        if '#' in name:
+            structs.append('%s %s;' % (typ[:-1], name.split('#')[0]))
         elif name.startswith('PyExc_'):
             structs.append('PyTypeObject _%s;' % (name,))
             structs.append('PyObject* %s = (PyObject*)&_%s;' % (name, name))
@@ -1142,11 +1276,12 @@
     use_micronumpy = space.config.objspace.usemodules.micronumpy
     if not use_micronumpy:
         return use_micronumpy
-    # import to register api functions by side-effect
-    import pypy.module.cpyext.ndarrayobject
-    global GLOBALS, SYMBOLS_C, separate_module_files
-    GLOBALS["PyArray_Type#"]= ('PyTypeObject*', "space.gettypeobject(W_NDimArray.typedef)")
-    SYMBOLS_C += ['PyArray_Type', '_PyArray_FILLWBYTE', '_PyArray_ZEROS']
+    # import registers api functions by side-effect, we also need HEADER
+    from pypy.module.cpyext.ndarrayobject import HEADER
+    global GLOBALS, FUNCTIONS_BY_HEADER, separate_module_files
+    for func_name in ['PyArray_Type', '_PyArray_FILLWBYTE', '_PyArray_ZEROS']:
+        FUNCTIONS_BY_HEADER.setdefault(HEADER, {})[func_name] = None
+    GLOBALS["PyArray_Type#%s" % HEADER] = ('PyTypeObject*', "space.gettypeobject(W_NDimArray.typedef)")
     separate_module_files.append(source_dir / "ndarrayobject.c")
     return use_micronumpy
 
@@ -1156,14 +1291,18 @@
     export_symbols = sorted(FUNCTIONS) + sorted(SYMBOLS_C) + sorted(GLOBALS)
     from rpython.translator.c.database import LowLevelDatabase
     db = LowLevelDatabase()
+    prefix = 'PyPy'
 
-    generate_macros(export_symbols, prefix='PyPy')
+    generate_macros(export_symbols, prefix=prefix)
 
     functions = generate_decls_and_callbacks(db, [], api_struct=False, 
-                                            prefix='PyPy')
-    code = "#include <Python.h>\n" + "\n".join(functions)
+                                            prefix=prefix)
+    code = "#include <Python.h>\n"
+    if use_micronumpy:
+        code += "#include <pypy_numpy.h> /* api.py line 1290 */"
+    code  += "\n".join(functions)
 
-    eci = build_eci(False, export_symbols, code)
+    eci = build_eci(False, export_symbols, code, use_micronumpy)
 
     space.fromcache(State).install_dll(eci)
 
@@ -1175,9 +1314,14 @@
     lines = ['PyObject *pypy_static_pyobjs[] = {\n']
     include_lines = ['RPY_EXTERN PyObject *pypy_static_pyobjs[];\n']
     for name, (typ, expr) in sorted(GLOBALS.items()):
-        if name.endswith('#'):
+        if '#' in name:
+            name, header = name.split('#')
             assert typ in ('PyObject*', 'PyTypeObject*', 'PyIntObject*')
-            typ, name = typ[:-1], name[:-1]
+            typ = typ[:-1]
+            if header != pypy_decl:
+                # since the #define is not in pypy_macros, do it here
+                mname = mangle_name(prefix, name)
+                include_lines.append('#define %s %s\n' % (name, mname))
         elif name.startswith('PyExc_'):
             typ = 'PyTypeObject'
             name = '_' + name
@@ -1204,6 +1348,8 @@
 
     for header, header_functions in FUNCTIONS_BY_HEADER.iteritems():
         for name, func in header_functions.iteritems():
+            if not func:
+                continue
             newname = mangle_name('PyPy', name) or name
             deco = entrypoint_lowlevel("cpyext", func.argtypes, newname, 
                                         relax=True)
@@ -1211,7 +1357,7 @@
 
     setup_init_functions(eci, translating=True)
     trunk_include = pypydir.dirpath() / 'include'
-    copy_header_files(trunk_include)
+    copy_header_files(trunk_include, use_micronumpy)
 
 def init_static_data_translated(space):
     builder = space.fromcache(StaticObjectBuilder)
@@ -1348,10 +1494,17 @@
                     arg = as_pyobj(space, arg)
             boxed_args += (arg,)
 
+        # see "Handling of the GIL" above
+        tid = rthread.get_ident()
+        assert cpyext_glob_tid_ptr[0] == 0
+        cpyext_glob_tid_ptr[0] = tid
+
         try:
             # Call the function
             result = call_external_function(func, *boxed_args)
         finally:
+            assert cpyext_glob_tid_ptr[0] == tid
+            cpyext_glob_tid_ptr[0] = 0
             keepalive_until_here(*keepalives)
 
         if is_PyObject(RESULT_TYPE):
diff --git a/pypy/module/cpyext/bytesobject.py b/pypy/module/cpyext/bytesobject.py
--- a/pypy/module/cpyext/bytesobject.py
+++ b/pypy/module/cpyext/bytesobject.py
@@ -2,11 +2,11 @@
 from rpython.rtyper.lltypesystem import rffi, lltype
 from pypy.module.cpyext.api import (
     cpython_api, cpython_struct, bootstrap_function, build_type_checkers,
-    PyObjectFields, Py_ssize_t, CONST_STRING, CANNOT_FAIL)
+    PyObjectFields, PyVarObjectFields, Py_ssize_t, CONST_STRING, CANNOT_FAIL)
 from pypy.module.cpyext.pyerrors import PyErr_BadArgument
 from pypy.module.cpyext.pyobject import (
     PyObject, PyObjectP, Py_DecRef, make_ref, from_ref, track_reference,
-    make_typedescr, get_typedescr)
+    make_typedescr, get_typedescr, as_pyobj, Py_IncRef)
 
 ##
 ## Implementation of PyStringObject
@@ -27,7 +27,7 @@
 ## Solution
 ## --------
 ##
-## PyStringObject contains two additional members: the size and a pointer to a
+## PyStringObject contains two additional members: the ob_size and a pointer to a
 ## char buffer; it may be NULL.
 ##
 ## - A string allocated by pypy will be converted into a PyStringObject with a
@@ -36,7 +36,7 @@
 ##
 ## - A string allocated with PyString_FromStringAndSize(NULL, size) will
 ##   allocate a PyStringObject structure, and a buffer with the specified
-##   size, but the reference won't be stored in the global map; there is no
+##   size+1, but the reference won't be stored in the global map; there is no
 ##   corresponding object in pypy.  When from_ref() or Py_INCREF() is called,
 ##   the pypy string is created, and added to the global map of tracked
 ##   objects.  The buffer is then supposed to be immutable.
@@ -52,8 +52,8 @@
 
 PyStringObjectStruct = lltype.ForwardReference()
 PyStringObject = lltype.Ptr(PyStringObjectStruct)
-PyStringObjectFields = PyObjectFields + \
-    (("buffer", rffi.CCHARP), ("size", Py_ssize_t))
+PyStringObjectFields = PyVarObjectFields + \
+    (("ob_shash", rffi.LONG), ("ob_sstate", rffi.INT), ("buffer", rffi.CCHARP))
 cpython_struct("PyStringObject", PyStringObjectFields, PyStringObjectStruct)
 
 @bootstrap_function
@@ -78,10 +78,11 @@
     py_str = rffi.cast(PyStringObject, py_obj)
 
     buflen = length + 1
-    py_str.c_size = length
+    py_str.c_ob_size = length
     py_str.c_buffer = lltype.malloc(rffi.CCHARP.TO, buflen,
                                     flavor='raw', zero=True,
                                     add_memory_pressure=True)
+    py_str.c_ob_sstate = rffi.cast(rffi.INT, 0) # SSTATE_NOT_INTERNED
     return py_str
 
 def string_attach(space, py_obj, w_obj):
@@ -90,8 +91,10 @@
     buffer must not be modified.
     """
     py_str = rffi.cast(PyStringObject, py_obj)
-    py_str.c_size = len(space.str_w(w_obj))
+    py_str.c_ob_size = len(space.str_w(w_obj))
     py_str.c_buffer = lltype.nullptr(rffi.CCHARP.TO)
+    py_str.c_ob_shash = space.hash_w(w_obj)
+    py_str.c_ob_sstate = rffi.cast(rffi.INT, 1) # SSTATE_INTERNED_MORTAL
 
 def string_realize(space, py_obj):
     """
@@ -99,8 +102,13 @@
     be modified after this call.
     """
     py_str = rffi.cast(PyStringObject, py_obj)
-    s = rffi.charpsize2str(py_str.c_buffer, py_str.c_size)
+    if not py_str.c_buffer:
+        py_str.c_buffer = lltype.malloc(rffi.CCHARP.TO, py_str.c_ob_size + 1,
+                                    flavor='raw', zero=True)
+    s = rffi.charpsize2str(py_str.c_buffer, py_str.c_ob_size)
     w_obj = space.wrap(s)
+    py_str.c_ob_shash = space.hash_w(w_obj)
+    py_str.c_ob_sstate = rffi.cast(rffi.INT, 1) # SSTATE_INTERNED_MORTAL
     track_reference(space, py_obj, w_obj)
     return w_obj
 
@@ -169,12 +177,12 @@
         ref_str.c_buffer = rffi.str2charp(s)
     buffer[0] = ref_str.c_buffer
     if length:
-        length[0] = ref_str.c_size
+        length[0] = ref_str.c_ob_size
     else:
         i = 0
         while ref_str.c_buffer[i] != '\0':
             i += 1
-        if i != ref_str.c_size:
+        if i != ref_str.c_ob_size:
             raise OperationError(space.w_TypeError, space.wrap(
                 "expected string without null bytes"))
     return 0
@@ -183,7 +191,7 @@
 def PyString_Size(space, ref):
     if from_ref(space, rffi.cast(PyObject, ref.c_ob_type)) is space.w_str:
         ref = rffi.cast(PyStringObject, ref)
-        return ref.c_size
+        return ref.c_ob_size
     else:
         w_obj = from_ref(space, ref)
         return space.len_w(w_obj)
@@ -212,7 +220,7 @@
         ref[0] = lltype.nullptr(PyObject.TO)
         raise
     to_cp = newsize
-    oldsize = py_str.c_size
+    oldsize = py_str.c_ob_size
     if oldsize < newsize:
         to_cp = oldsize
     for i in range(to_cp):
@@ -236,15 +244,16 @@
     if not ref[0]:
         return
 
-    if w_newpart is None or not PyString_Check(space, ref[0]) or \
-            not PyString_Check(space, w_newpart):
+    if w_newpart is None or not PyString_Check(space, ref[0]) or not \
+            (space.isinstance_w(w_newpart, space.w_str) or 
+             space.isinstance_w(w_newpart, space.w_unicode)):
         Py_DecRef(space, ref[0])
         ref[0] = lltype.nullptr(PyObject.TO)
         return
     w_str = from_ref(space, ref[0])
     w_newstr = space.add(w_str, w_newpart)
-    Py_DecRef(space, ref[0])
     ref[0] = make_ref(space, w_newstr)
+    Py_IncRef(space, ref[0])
 
 @cpython_api([PyObjectP, PyObject], lltype.Void)
 def PyString_ConcatAndDel(space, ref, newpart):
diff --git a/pypy/module/cpyext/cdatetime.py b/pypy/module/cpyext/cdatetime.py
--- a/pypy/module/cpyext/cdatetime.py
+++ b/pypy/module/cpyext/cdatetime.py
@@ -42,9 +42,15 @@
 
     return datetimeAPI
 
-PyDateTime_Date = PyObject
-PyDateTime_Time = PyObject
-PyDateTime_DateTime = PyObject
+PyDateTime_DateStruct = lltype.ForwardReference()
+PyDateTime_TimeStruct = lltype.ForwardReference()
+PyDateTime_DateTimeStruct = lltype.ForwardReference()
+cpython_struct("PyDateTime_Date", PyObjectFields, PyDateTime_DateStruct)
+PyDateTime_Date = lltype.Ptr(PyDateTime_DateStruct)
+cpython_struct("PyDateTime_Time", PyObjectFields, PyDateTime_TimeStruct)
+PyDateTime_Time = lltype.Ptr(PyDateTime_TimeStruct)
+cpython_struct("PyDateTime_DateTime", PyObjectFields, PyDateTime_DateTimeStruct)
+PyDateTime_DateTime = lltype.Ptr(PyDateTime_DateTimeStruct)
 
 PyDeltaObjectStruct = lltype.ForwardReference()
 cpython_struct("PyDateTime_Delta", PyObjectFields, PyDeltaObjectStruct)
diff --git a/pypy/module/cpyext/complexobject.py b/pypy/module/cpyext/complexobject.py
--- a/pypy/module/cpyext/complexobject.py
+++ b/pypy/module/cpyext/complexobject.py
@@ -1,16 +1,51 @@
 from rpython.rtyper.lltypesystem import lltype, rffi
-from pypy.module.cpyext.api import (
+from pypy.module.cpyext.api import (PyObjectFields, bootstrap_function,
     cpython_api, cpython_struct, PyObject, build_type_checkers)
+from pypy.module.cpyext.pyobject import (
+    make_typedescr, track_reference, from_ref)
 from pypy.module.cpyext.floatobject import PyFloat_AsDouble
 from pypy.objspace.std.complexobject import W_ComplexObject
 from pypy.interpreter.error import OperationError
 
 PyComplex_Check, PyComplex_CheckExact = build_type_checkers("Complex")
 
-Py_complex_t = lltype.ForwardReference()
+Py_complex_t = rffi.CStruct('Py_complex_t',
+                            ('real', rffi.DOUBLE),
+                            ('imag', rffi.DOUBLE),
+                            hints={'size': 2 * rffi.sizeof(rffi.DOUBLE)})
 Py_complex_ptr = lltype.Ptr(Py_complex_t)
-Py_complex_fields = (("real", rffi.DOUBLE), ("imag", rffi.DOUBLE))
-cpython_struct("Py_complex", Py_complex_fields, Py_complex_t)
+
+PyComplexObjectStruct = lltype.ForwardReference()
+PyComplexObject = lltype.Ptr(PyComplexObjectStruct)
+PyComplexObjectFields = PyObjectFields + \
+    (("cval", Py_complex_t),)
+cpython_struct("PyComplexObject", PyComplexObjectFields, PyComplexObjectStruct)
+
+ at bootstrap_function
+def init_complexobject(space):
+    "Type description of PyComplexObject"
+    make_typedescr(space.w_complex.layout.typedef,
+                   basestruct=PyComplexObject.TO,
+                   attach=complex_attach,
+                   realize=complex_realize)
+
+def complex_attach(space, py_obj, w_obj):
+    """
+    Fills a newly allocated PyComplexObject with the given complex object. The
+    value must not be modified.
+    """
+    assert isinstance(w_obj, W_ComplexObject)
+    py_obj = rffi.cast(PyComplexObject, py_obj)
+    py_obj.c_cval.c_real = w_obj.realval
+    py_obj.c_cval.c_imag = w_obj.imagval
+
+def complex_realize(space, obj):
+    py_obj = rffi.cast(PyComplexObject, obj)
+    w_type = from_ref(space, rffi.cast(PyObject, obj.c_ob_type))
+    w_obj = space.allocate_instance(W_ComplexObject, w_type)
+    w_obj.__init__(py_obj.c_cval.c_real, py_obj.c_cval.c_imag)
+    track_reference(space, obj, w_obj)
+    return w_obj
 
 
 @cpython_api([lltype.Float, lltype.Float], PyObject)
diff --git a/pypy/module/cpyext/dictobject.py b/pypy/module/cpyext/dictobject.py
--- a/pypy/module/cpyext/dictobject.py
+++ b/pypy/module/cpyext/dictobject.py
@@ -23,6 +23,7 @@
     # NOTE: this works so far because all our dict strategies store
     # *values* as full objects, which stay alive as long as the dict is
     # alive and not modified.  So we can return a borrowed ref.
+    # XXX this is wrong with IntMutableCell.  Hope it works...
     return w_res
 
 @cpython_api([PyObject, PyObject, PyObject], rffi.INT_real, error=-1)
@@ -62,6 +63,7 @@
     # NOTE: this works so far because all our dict strategies store
     # *values* as full objects, which stay alive as long as the dict is
     # alive and not modified.  So we can return a borrowed ref.
+    # XXX this is wrong with IntMutableCell.  Hope it works...
     return w_res
 
 @cpython_api([PyObject, CONST_STRING], rffi.INT_real, error=-1)
@@ -104,6 +106,32 @@
     """
     return space.call_method(space.w_dict, "copy", w_obj)
 
+def _has_val(space, w_dict, w_key):
+    try:
+        w_val = space.getitem(w_dict, w_key)
+    except OperationError as e:
+        if e.match(space, space.w_KeyError):
+            return False
+        else:
+            raise
+    return True
+
+ at cpython_api([PyObject, PyObject, rffi.INT_real], rffi.INT_real, error=-1)
+def PyDict_Merge(space, w_a, w_b, override):
+    """Iterate over mapping object b adding key-value pairs to dictionary a.
+    b may be a dictionary, or any object supporting PyMapping_Keys()
+    and PyObject_GetItem(). If override is true, existing pairs in a
+    will be replaced if a matching key is found in b, otherwise pairs will
+    only be added if there is not a matching key in a. Return 0 on
+    success or -1 if an exception was raised.
+    """
+    override = rffi.cast(lltype.Signed, override)
+    w_keys = space.call_method(w_b, "keys")
+    for w_key  in space.iteriterable(w_keys):
+        if not _has_val(space, w_a, w_key) or override != 0:
+            space.setitem(w_a, w_key, space.getitem(w_b, w_key))
+    return 0
+
 @cpython_api([PyObject, PyObject], rffi.INT_real, error=-1)
 def PyDict_Update(space, w_obj, w_other):
     """This is the same as PyDict_Merge(a, b, 1) in C, or a.update(b) in
@@ -204,6 +232,12 @@
 
 @specialize.memo()
 def make_frozendict(space):
+    if space not in _frozendict_cache:
+        _frozendict_cache[space] = _make_frozendict(space)
+    return _frozendict_cache[space]
+        
+_frozendict_cache = {}
+def _make_frozendict(space):
     return space.appexec([], '''():
     import _abcoll
     class FrozenDict(_abcoll.Mapping):
@@ -222,3 +256,15 @@
     w_frozendict = make_frozendict(space)
     return space.call_function(w_frozendict, w_dict)
 
+ at cpython_api([PyObject], rffi.INT_real, error=CANNOT_FAIL)
+def PyDictProxy_Check(space, w_obj):
+    w_typ = make_frozendict(space)
+    #print 'check', w_typ, space.type(w_obj)
+    return space.isinstance_w(w_obj, w_typ)
+
+ at cpython_api([PyObject], rffi.INT_real, error=CANNOT_FAIL)
+def PyDictProxy_CheckExact(space, w_obj):
+    w_typ = make_frozendict(space)
+    #print 'exact', w_typ, w_obj
+    return space.is_w(space.type(w_obj), w_typ)
+
diff --git a/pypy/module/cpyext/floatobject.py b/pypy/module/cpyext/floatobject.py
--- a/pypy/module/cpyext/floatobject.py
+++ b/pypy/module/cpyext/floatobject.py
@@ -1,8 +1,42 @@
 from rpython.rtyper.lltypesystem import rffi, lltype
-from pypy.module.cpyext.api import (
+from pypy.module.cpyext.api import (PyObjectFields, bootstrap_function,
+    cpython_struct,
     CANNOT_FAIL, cpython_api, PyObject, build_type_checkers, CONST_STRING)
+from pypy.module.cpyext.pyobject import (
+    make_typedescr, track_reference, from_ref)
 from pypy.interpreter.error import OperationError
 from rpython.rlib.rstruct import runpack
+from pypy.objspace.std.floatobject import W_FloatObject
+
+PyFloatObjectStruct = lltype.ForwardReference()
+PyFloatObject = lltype.Ptr(PyFloatObjectStruct)
+PyFloatObjectFields = PyObjectFields + \
+    (("ob_fval", rffi.DOUBLE),)
+cpython_struct("PyFloatObject", PyFloatObjectFields, PyFloatObjectStruct)
+
+ at bootstrap_function
+def init_floatobject(space):
+    "Type description of PyFloatObject"
+    make_typedescr(space.w_float.layout.typedef,
+                   basestruct=PyFloatObject.TO,
+                   attach=float_attach,
+                   realize=float_realize)
+
+def float_attach(space, py_obj, w_obj):
+    """
+    Fills a newly allocated PyFloatObject with the given float object. The
+    value must not be modified.
+    """
+    py_float = rffi.cast(PyFloatObject, py_obj)
+    py_float.c_ob_fval = space.float_w(w_obj)
+
+def float_realize(space, obj):
+    floatval = rffi.cast(lltype.Float, rffi.cast(PyFloatObject, obj).c_ob_fval)
+    w_type = from_ref(space, rffi.cast(PyObject, obj.c_ob_type))
+    w_obj = space.allocate_instance(W_FloatObject, w_type)
+    w_obj.__init__(floatval)
+    track_reference(space, obj, w_obj)
+    return w_obj
 
 PyFloat_Check, PyFloat_CheckExact = build_type_checkers("Float")
 
diff --git a/pypy/module/cpyext/include/Python.h b/pypy/module/cpyext/include/Python.h
--- a/pypy/module/cpyext/include/Python.h
+++ b/pypy/module/cpyext/include/Python.h
@@ -112,9 +112,11 @@
 #include "dictobject.h"
 #include "intobject.h"
 #include "listobject.h"
+#include "longobject.h"
 #include "unicodeobject.h"
 #include "compile.h"
 #include "frameobject.h"
+#include "memoryobject.h"
 #include "eval.h"
 #include "pymem.h"
 #include "pycobject.h"
diff --git a/pypy/module/cpyext/include/complexobject.h b/pypy/module/cpyext/include/complexobject.h
--- a/pypy/module/cpyext/include/complexobject.h
+++ b/pypy/module/cpyext/include/complexobject.h
@@ -6,14 +6,16 @@
 extern "C" {
 #endif
 
-/* fake PyComplexObject so that code that doesn't do direct field access works */
-#define PyComplexObject PyObject
-
 typedef struct Py_complex_t {
     double real;
     double imag;
 } Py_complex;
 
+typedef struct {
+    PyObject_HEAD
+    Py_complex cval;
+} PyComplexObject;
+
 /* generated function */
 PyAPI_FUNC(int) _PyComplex_AsCComplex(PyObject *, Py_complex *);
 PyAPI_FUNC(PyObject *) _PyComplex_FromCComplex(Py_complex *);
diff --git a/pypy/module/cpyext/include/datetime.h b/pypy/module/cpyext/include/datetime.h
--- a/pypy/module/cpyext/include/datetime.h
+++ b/pypy/module/cpyext/include/datetime.h
@@ -24,6 +24,18 @@
     PyObject_HEAD
 } PyDateTime_Delta;
 
+typedef struct {
+    PyObject_HEAD
+} PyDateTime_Date;
+
+typedef struct {
+    PyObject_HEAD
+} PyDateTime_Time;
+
+typedef struct {
+    PyObject_HEAD
+} PyDateTime_DateTime;
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/pypy/module/cpyext/include/descrobject.h b/pypy/module/cpyext/include/descrobject.h
--- a/pypy/module/cpyext/include/descrobject.h
+++ b/pypy/module/cpyext/include/descrobject.h
@@ -12,4 +12,34 @@
 } PyGetSetDef;
 
 
+#define PyDescr_COMMON \
+    PyObject_HEAD \
+    PyTypeObject *d_type; \
+    PyObject *d_name
+
+typedef struct {
+    PyDescr_COMMON;
+} PyDescrObject;
+
+typedef struct {
+    PyDescr_COMMON;
+    PyMethodDef *d_method;
+} PyMethodDescrObject;
+
+typedef struct {
+    PyDescr_COMMON;
+    struct PyMemberDef *d_member;
+} PyMemberDescrObject;
+
+typedef struct {
+    PyDescr_COMMON;
+    PyGetSetDef *d_getset;
+} PyGetSetDescrObject;
+
+typedef struct {
+    PyDescr_COMMON;
+    struct wrapperbase *d_base;
+    void *d_wrapped; /* This can be any function pointer */
+} PyWrapperDescrObject;
+
 #endif
diff --git a/pypy/module/cpyext/include/floatobject.h b/pypy/module/cpyext/include/floatobject.h
--- a/pypy/module/cpyext/include/floatobject.h
+++ b/pypy/module/cpyext/include/floatobject.h
@@ -3,10 +3,22 @@
 
 #ifndef Py_FLOATOBJECT_H
 #define Py_FLOATOBJECT_H
+
+#ifdef _MSC_VER
+#include <math.h>
+#include <float.h>
+#define copysign _copysign
+#endif
+
 #ifdef __cplusplus
 extern "C" {
 #endif
 
+typedef struct {
+    PyObject_HEAD
+    double ob_fval;
+} PyFloatObject;
+
 #define PyFloat_STR_PRECISION 12
 
 #ifdef Py_NAN
diff --git a/pypy/module/cpyext/include/longobject.h b/pypy/module/cpyext/include/longobject.h
new file mode 100644
--- /dev/null
+++ b/pypy/module/cpyext/include/longobject.h
@@ -0,0 +1,21 @@
+#ifndef Py_LONGOBJECT_H
+#define Py_LONGOBJECT_H
+
+#include <stdlib.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* why does cpython redefine these, and even supply an implementation in mystrtoul.c?
+PyAPI_FUNC(unsigned long) PyOS_strtoul(const char *, char **, int);
+PyAPI_FUNC(long) PyOS_strtol(const char *, char **, int);
+*/
+
+#define PyOS_strtoul strtoul
+#define PyOS_strtol strtoul
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* !Py_LONGOBJECT_H */
diff --git a/pypy/module/cpyext/include/memoryobject.h b/pypy/module/cpyext/include/memoryobject.h
new file mode 100644
--- /dev/null
+++ b/pypy/module/cpyext/include/memoryobject.h
@@ -0,0 +1,14 @@
+#ifndef Py_MEMORYOBJECT_H
+#define Py_MEMORYOBJECT_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* !Py_MEMORYOBJECT_H */
diff --git a/pypy/module/cpyext/include/numpy/README b/pypy/module/cpyext/include/numpy/README
new file mode 100644
--- /dev/null
+++ b/pypy/module/cpyext/include/numpy/README
@@ -0,0 +1,8 @@
+headers for the micronumpy multiarray and umath modules,
+as used by https://bitbucket.org/pypy/numpy. They are needed by
+downstream packages that depend on numpy, like matplotlib, but can
+be slightly non-compatible with traditional numpy C-API use cases.
+
+The trick to including these headers is in get_include, located in
+numpy/lib/utils.py. They will be ignored by an upstream build of numpy
+since the <site-packages>/numpy/core/include path will be used instead
diff --git a/pypy/module/cpyext/include/numpy/__multiarray_api.h b/pypy/module/cpyext/include/numpy/__multiarray_api.h
new file mode 100644
--- /dev/null
+++ b/pypy/module/cpyext/include/numpy/__multiarray_api.h
@@ -0,0 +1,11 @@
+
+
+typedef struct {
+        PyObject_HEAD
+        npy_bool obval;
+} PyBoolScalarObject;
+
+static int import_array(){return 0;};
+static int _import_array(){return 0;};
+static int _import_math(){return 0;};
+
diff --git a/pypy/module/cpyext/include/numpy/arrayobject.h b/pypy/module/cpyext/include/numpy/arrayobject.h
--- a/pypy/module/cpyext/include/numpy/arrayobject.h
+++ b/pypy/module/cpyext/include/numpy/arrayobject.h
@@ -1,6 +1,8 @@
 
-/* NDArray object interface - S. H. Muller, 2013/07/26 */
-/* For testing ndarrayobject only */
+/* NDArray object interface - S. H. Muller, 2013/07/26 
+ * It will be copied by numpy/core/setup.py by install_data to
+ * site-packages/numpy/core/includes/numpy  
+*/
 
 #ifndef Py_NDARRAYOBJECT_H
 #define Py_NDARRAYOBJECT_H
@@ -8,8 +10,14 @@
 extern "C" {
 #endif
 
+#include "pypy_numpy.h"
+#include "old_defines.h"
 #include "npy_common.h"
-#include "ndarraytypes.h"
+#include "__multiarray_api.h"
+
+#define NPY_UNUSED(x) x
+#define PyArray_MAX(a,b) (((a)>(b))?(a):(b))
+#define PyArray_MIN(a,b) (((a)<(b))?(a):(b))
 
 /* fake PyArrayObject so that code that doesn't do direct field access works */
 #define PyArrayObject PyObject
@@ -17,20 +25,206 @@
 
 PyAPI_DATA(PyTypeObject) PyArray_Type;
 
-#define PyArray_SimpleNew _PyArray_SimpleNew
-#define PyArray_ZEROS _PyArray_ZEROS
-#define PyArray_CopyInto _PyArray_CopyInto
-#define PyArray_FILLWBYTE _PyArray_FILLWBYTE
 
 #define NPY_MAXDIMS 32
 
-/* functions defined in ndarrayobject.c*/
+#ifndef NDARRAYTYPES_H
+typedef struct {
+    npy_intp *ptr;
+    int len;
+} PyArray_Dims;
+
+/* data types copied from numpy/ndarraytypes.h 
+ * keep numbers in sync with micronumpy.interp_dtype.DTypeCache
+ */
+enum NPY_TYPES {    NPY_BOOL=0,
+                    NPY_BYTE, NPY_UBYTE,
+                    NPY_SHORT, NPY_USHORT,
+                    NPY_INT, NPY_UINT,
+                    NPY_LONG, NPY_ULONG,
+                    NPY_LONGLONG, NPY_ULONGLONG,
+                    NPY_FLOAT, NPY_DOUBLE, NPY_LONGDOUBLE,
+                    NPY_CFLOAT, NPY_CDOUBLE, NPY_CLONGDOUBLE,
+                    NPY_OBJECT=17,
+                    NPY_STRING, NPY_UNICODE,
+                    NPY_VOID,
+                    /*
+                     * New 1.6 types appended, may be integrated
+                     * into the above in 2.0.
+                     */
+                    NPY_DATETIME, NPY_TIMEDELTA, NPY_HALF,
+
+                    NPY_NTYPES,
+                    NPY_NOTYPE,
+                    NPY_CHAR,      /* special flag */
+                    NPY_USERDEF=256,  /* leave room for characters */
+
+                    /* The number of types not including the new 1.6 types */
+                    NPY_NTYPES_ABI_COMPATIBLE=21
+};
+
+#define PyTypeNum_ISBOOL(type)      ((type) == NPY_BOOL)
+#define PyTypeNum_ISINTEGER(type)  (((type) >= NPY_BYTE) && \
+                                    ((type) <= NPY_ULONGLONG))
+#define PyTypeNum_ISFLOAT(type)   ((((type) >= NPY_FLOAT) && \
+                                    ((type) <= NPY_LONGDOUBLE)) || \
+                                    ((type) == NPY_HALF))
+#define PyTypeNum_ISCOMPLEX(type)  (((type) >= NPY_CFLOAT) && \
+                                    ((type) <= NPY_CLONGDOUBLE))
+
+#define PyArray_ISBOOL(arr)    (PyTypeNum_ISBOOL(PyArray_TYPE(arr)))
+#define PyArray_ISINTEGER(arr) (PyTypeNum_ISINTEGER(PyArray_TYPE(arr)))
+#define PyArray_ISFLOAT(arr)   (PyTypeNum_ISFLOAT(PyArray_TYPE(arr)))
+#define PyArray_ISCOMPLEX(arr) (PyTypeNum_ISCOMPLEX(PyArray_TYPE(arr)))
+
+
+/* flags */
+#define NPY_ARRAY_C_CONTIGUOUS    0x0001
+#define NPY_ARRAY_F_CONTIGUOUS    0x0002
+#define NPY_ARRAY_OWNDATA         0x0004
+#define NPY_ARRAY_FORCECAST       0x0010
+#define NPY_ARRAY_ENSURECOPY      0x0020
+#define NPY_ARRAY_ENSUREARRAY     0x0040
+#define NPY_ARRAY_ELEMENTSTRIDES  0x0080
+#define NPY_ARRAY_ALIGNED         0x0100
+#define NPY_ARRAY_NOTSWAPPED      0x0200
+#define NPY_ARRAY_WRITEABLE       0x0400
+#define NPY_ARRAY_UPDATEIFCOPY    0x1000
+
+#define NPY_ARRAY_BEHAVED      (NPY_ARRAY_ALIGNED | \
+                                NPY_ARRAY_WRITEABLE)
+#define NPY_ARRAY_BEHAVED_NS   (NPY_ARRAY_ALIGNED | \
+                                NPY_ARRAY_WRITEABLE | \
+                                NPY_ARRAY_NOTSWAPPED)
+#define NPY_ARRAY_CARRAY       (NPY_ARRAY_C_CONTIGUOUS | \
+                                NPY_ARRAY_BEHAVED)
+#define NPY_ARRAY_CARRAY_RO    (NPY_ARRAY_C_CONTIGUOUS | \
+                                NPY_ARRAY_ALIGNED)
+#define NPY_ARRAY_FARRAY       (NPY_ARRAY_F_CONTIGUOUS | \
+                                NPY_ARRAY_BEHAVED)
+#define NPY_ARRAY_FARRAY_RO    (NPY_ARRAY_F_CONTIGUOUS | \
+                                NPY_ARRAY_ALIGNED)
+#define NPY_ARRAY_DEFAULT      (NPY_ARRAY_CARRAY)
+#define NPY_ARRAY_IN_ARRAY     (NPY_ARRAY_CARRAY_RO)
+#define NPY_ARRAY_OUT_ARRAY    (NPY_ARRAY_CARRAY)
+#define NPY_ARRAY_INOUT_ARRAY  (NPY_ARRAY_CARRAY | \
+                                NPY_ARRAY_UPDATEIFCOPY)
+#define NPY_ARRAY_IN_FARRAY    (NPY_ARRAY_FARRAY_RO)
+#define NPY_ARRAY_OUT_FARRAY   (NPY_ARRAY_FARRAY)
+#define NPY_ARRAY_INOUT_FARRAY (NPY_ARRAY_FARRAY | \
+                                NPY_ARRAY_UPDATEIFCOPY)
+
+#define NPY_ARRAY_UPDATE_ALL   (NPY_ARRAY_C_CONTIGUOUS | \
+                                NPY_ARRAY_F_CONTIGUOUS | \
+                                NPY_ARRAY_ALIGNED)
+
+#define NPY_FARRAY NPY_ARRAY_FARRAY
+#define NPY_CARRAY NPY_ARRAY_CARRAY
+
+#define PyArray_CHKFLAGS(m, flags) (PyArray_FLAGS(m) & (flags))
+
+#define PyArray_ISCONTIGUOUS(m) PyArray_CHKFLAGS(m, NPY_ARRAY_C_CONTIGUOUS)
+#define PyArray_ISWRITEABLE(m) PyArray_CHKFLAGS(m, NPY_ARRAY_WRITEABLE)
+#define PyArray_ISALIGNED(m) PyArray_CHKFLAGS(m, NPY_ARRAY_ALIGNED)
+
+#define PyArray_IS_C_CONTIGUOUS(m) PyArray_CHKFLAGS(m, NPY_ARRAY_C_CONTIGUOUS)
+#define PyArray_IS_F_CONTIGUOUS(m) PyArray_CHKFLAGS(m, NPY_ARRAY_F_CONTIGUOUS)
+
+#define PyArray_FLAGSWAP(m, flags) (PyArray_CHKFLAGS(m, flags) &&       \
+                                    PyArray_ISNOTSWAPPED(m))
+
+#define PyArray_ISCARRAY(m) PyArray_FLAGSWAP(m, NPY_ARRAY_CARRAY)
+#define PyArray_ISCARRAY_RO(m) PyArray_FLAGSWAP(m, NPY_ARRAY_CARRAY_RO)
+#define PyArray_ISFARRAY(m) PyArray_FLAGSWAP(m, NPY_ARRAY_FARRAY)
+#define PyArray_ISFARRAY_RO(m) PyArray_FLAGSWAP(m, NPY_ARRAY_FARRAY_RO)
+#define PyArray_ISBEHAVED(m) PyArray_FLAGSWAP(m, NPY_ARRAY_BEHAVED)
+#define PyArray_ISBEHAVED_RO(m) PyArray_FLAGSWAP(m, NPY_ARRAY_ALIGNED)
+
+#define PyArray_ISONESEGMENT(arr)  (1)
+#define PyArray_ISNOTSWAPPED(arr)  (1)
+#define PyArray_ISBYTESWAPPED(arr) (0)
+
+#endif
+
+#define NPY_INT8      NPY_BYTE
+#define NPY_UINT8     NPY_UBYTE
+#define NPY_INT16     NPY_SHORT
+#define NPY_UINT16    NPY_USHORT
+#define NPY_INT32     NPY_INT
+#define NPY_UINT32    NPY_UINT
+#define NPY_INT64     NPY_LONG
+#define NPY_UINT64    NPY_ULONG
+#define NPY_FLOAT32   NPY_FLOAT
+#define NPY_FLOAT64   NPY_DOUBLE
+#define NPY_COMPLEX32 NPY_CFLOAT
+#define NPY_COMPLEX64 NPY_CDOUBLE
+
+
+/* functions */
+#ifndef PyArray_NDIM
+
+#define PyArray_Check      _PyArray_Check
+#define PyArray_CheckExact _PyArray_CheckExact
+#define PyArray_FLAGS      _PyArray_FLAGS
+
+#define PyArray_NDIM       _PyArray_NDIM
+#define PyArray_DIM        _PyArray_DIM
+#define PyArray_STRIDE     _PyArray_STRIDE
+#define PyArray_SIZE       _PyArray_SIZE
+#define PyArray_ITEMSIZE   _PyArray_ITEMSIZE
+#define PyArray_NBYTES     _PyArray_NBYTES
+#define PyArray_TYPE       _PyArray_TYPE
+#define PyArray_DATA       _PyArray_DATA
+
+#define PyArray_Size PyArray_SIZE
+#define PyArray_BYTES(arr) ((char *)PyArray_DATA(arr))
+
+#define PyArray_FromAny _PyArray_FromAny
+#define PyArray_FromObject _PyArray_FromObject
+#define PyArray_ContiguousFromObject PyArray_FromObject
+#define PyArray_ContiguousFromAny PyArray_FromObject
+
+#define PyArray_FROMANY(obj, typenum, min, max, requirements) (obj)
+#define PyArray_FROM_OTF(obj, typenum, requirements) \
+        PyArray_FromObject(obj, typenum, 0, 0)
+
+#define PyArray_New _PyArray_New
+#define PyArray_SimpleNew _PyArray_SimpleNew
+#define PyArray_SimpleNewFromData _PyArray_SimpleNewFromData
+#define PyArray_SimpleNewFromDataOwning _PyArray_SimpleNewFromDataOwning
+
+#define PyArray_EMPTY(nd, dims, type_num, fortran) \
+        PyArray_SimpleNew(nd, dims, type_num)
 
 PyAPI_FUNC(void) _PyArray_FILLWBYTE(PyObject* obj, int val);
 PyAPI_FUNC(PyObject *) _PyArray_ZEROS(int nd, npy_intp* dims, int type_num, int fortran);
-PyAPI_FUNC(int) _PyArray_CopyInto(PyArrayObject* dest, PyArrayObject* src);
 
+#define PyArray_FILLWBYTE _PyArray_FILLWBYTE
+#define PyArray_ZEROS _PyArray_ZEROS
 
+#define PyArray_Resize(self, newshape, refcheck, fortran) (NULL)
+
+/* Don't use these in loops! */
+
+#define PyArray_GETPTR1(obj, i) ((void *)(PyArray_BYTES(obj) + \
+                                         (i)*PyArray_STRIDE(obj,0)))
+
+#define PyArray_GETPTR2(obj, i, j) ((void *)(PyArray_BYTES(obj) + \
+                                            (i)*PyArray_STRIDE(obj,0) + \
+                                            (j)*PyArray_STRIDE(obj,1)))
+
+#define PyArray_GETPTR3(obj, i, j, k) ((void *)(PyArray_BYTES(obj) + \
+                                            (i)*PyArray_STRIDE(obj,0) + \
+                                            (j)*PyArray_STRIDE(obj,1) + \
+                                            (k)*PyArray_STRIDE(obj,2)))
+
+#define PyArray_GETPTR4(obj, i, j, k, l) ((void *)(PyArray_BYTES(obj) + \
+                                            (i)*PyArray_STRIDE(obj,0) + \
+                                            (j)*PyArray_STRIDE(obj,1) + \
+                                            (k)*PyArray_STRIDE(obj,2) + \
+                                            (l)*PyArray_STRIDE(obj,3)))
+
+#endif
 
 #ifdef __cplusplus
 }
diff --git a/pypy/module/cpyext/include/numpy/ndarraytypes.h b/pypy/module/cpyext/include/numpy/ndarraytypes.h
--- a/pypy/module/cpyext/include/numpy/ndarraytypes.h
+++ b/pypy/module/cpyext/include/numpy/ndarraytypes.h
@@ -1,9 +1,69 @@
 #ifndef NDARRAYTYPES_H
 #define NDARRAYTYPES_H
 
-/* For testing ndarrayobject only */
+#include "numpy/npy_common.h"
+//#include "npy_endian.h"
+//#include "npy_cpu.h"
+//#include "utils.h"
 
-#include "numpy/npy_common.h"
+//for pypy - numpy has lots of typedefs
+//for pypy - make life easier, less backward support
+#define NPY_1_8_API_VERSION 0x00000008
+#define NPY_NO_DEPRECATED_API NPY_1_8_API_VERSION
+#undef NPY_1_8_API_VERSION
+
+#define NPY_ENABLE_SEPARATE_COMPILATION 1
+#define NPY_VISIBILITY_HIDDEN 
+
+#ifdef NPY_ENABLE_SEPARATE_COMPILATION
+        #define NPY_NO_EXPORT NPY_VISIBILITY_HIDDEN
+#else
+        #define NPY_NO_EXPORT static
+#endif
+
+/* Only use thread if configured in config and python supports it */
+#if defined WITH_THREAD && !NPY_NO_SMP
+        #define NPY_ALLOW_THREADS 1
+#else
+        #define NPY_ALLOW_THREADS 0
+#endif
+
+
+
+/*
+ * There are several places in the code where an array of dimensions
+ * is allocated statically.  This is the size of that static
+ * allocation.
+ *
+ * The array creation itself could have arbitrary dimensions but all
+ * the places where static allocation is used would need to be changed
+ * to dynamic (including inside of several structures)
+ */
+
+#define NPY_MAXDIMS 32
+#define NPY_MAXARGS 32
+
+/* Used for Converter Functions "O&" code in ParseTuple */
+#define NPY_FAIL 0
+#define NPY_SUCCEED 1
+
+/*
+ * Binary compatibility version number.  This number is increased
+ * whenever the C-API is changed such that binary compatibility is
+ * broken, i.e. whenever a recompile of extension modules is needed.
+ */
+#define NPY_VERSION NPY_ABI_VERSION
+
+/*
+ * Minor API version.  This number is increased whenever a change is
+ * made to the C-API -- whether it breaks binary compatibility or not.
+ * Some changes, such as adding a function pointer to the end of the
+ * function table, can be made without breaking binary compatibility.
+ * In this case, only the NPY_FEATURE_VERSION (*not* NPY_VERSION)
+ * would be increased.  Whenever binary compatibility is broken, both
+ * NPY_VERSION and NPY_FEATURE_VERSION should be increased.
+ */
+#define NPY_FEATURE_VERSION NPY_API_VERSION
 
 enum NPY_TYPES {    NPY_BOOL=0,
                     NPY_BYTE, NPY_UBYTE,
@@ -31,6 +91,18 @@
                     NPY_NTYPES_ABI_COMPATIBLE=21
 };
 
+/* basetype array priority */
+#define NPY_PRIORITY 0.0
+
+/* default subtype priority */
+#define NPY_SUBTYPE_PRIORITY 1.0
+
+/* default scalar priority */
+#define NPY_SCALAR_PRIORITY -1000000.0
+
+/* How many floating point types are there (excluding half) */
+#define NPY_NUM_FLOATTYPE 3
+
 /*
  * These characters correspond to the array type and the struct
  * module
@@ -85,6 +157,27 @@
 };
 
 typedef enum {
+        NPY_QUICKSORT=0,
+        NPY_HEAPSORT=1,
+        NPY_MERGESORT=2
+} NPY_SORTKIND;
+#define NPY_NSORTS (NPY_MERGESORT + 1)
+
+
+typedef enum {
+        NPY_INTROSELECT=0,
+} NPY_SELECTKIND;
+#define NPY_NSELECTS (NPY_INTROSELECT + 1)
+
+
+typedef enum {
+        NPY_SEARCHLEFT=0,
+        NPY_SEARCHRIGHT=1
+} NPY_SEARCHSIDE;
+#define NPY_NSEARCHSIDES (NPY_SEARCHRIGHT + 1)
+
+
+typedef enum {
         NPY_NOSCALAR=-1,
         NPY_BOOL_SCALAR,
         NPY_INTPOS_SCALAR,
@@ -93,6 +186,7 @@
         NPY_COMPLEX_SCALAR,
         NPY_OBJECT_SCALAR
 } NPY_SCALARKIND;
+#define NPY_NSCALARKINDS (NPY_OBJECT_SCALAR + 1)
 
 /* For specifying array memory layout or iteration order */
 typedef enum {
@@ -106,6 +200,729 @@
         NPY_KEEPORDER=2
 } NPY_ORDER;
 
+/* For specifying allowed casting in operations which support it */
+typedef enum {
+        /* Only allow identical types */
+        NPY_NO_CASTING=0,
+        /* Allow identical and byte swapped types */
+        NPY_EQUIV_CASTING=1,
+        /* Only allow safe casts */
+        NPY_SAFE_CASTING=2,
+        /* Allow safe casts or casts within the same kind */
+        NPY_SAME_KIND_CASTING=3,
+        /* Allow any casts */
+        NPY_UNSAFE_CASTING=4,
+
+        /*
+         * Temporary internal definition only, will be removed in upcoming
+         * release, see below
+         * */
+        NPY_INTERNAL_UNSAFE_CASTING_BUT_WARN_UNLESS_SAME_KIND = 100,
+} NPY_CASTING;
+
+typedef enum {
+        NPY_CLIP=0,
+        NPY_WRAP=1,
+        NPY_RAISE=2
+} NPY_CLIPMODE;
+
+/* The special not-a-time (NaT) value */
+#define NPY_DATETIME_NAT NPY_MIN_INT64
+
+/*
+ * Upper bound on the length of a DATETIME ISO 8601 string
+ *   YEAR: 21 (64-bit year)
+ *   MONTH: 3
+ *   DAY: 3
+ *   HOURS: 3
+ *   MINUTES: 3
+ *   SECONDS: 3
+ *   ATTOSECONDS: 1 + 3*6
+ *   TIMEZONE: 5
+ *   NULL TERMINATOR: 1
+ */
+#define NPY_DATETIME_MAX_ISO8601_STRLEN (21+3*5+1+3*6+6+1)
+
+typedef enum {
+        NPY_FR_Y = 0,  /* Years */
+        NPY_FR_M = 1,  /* Months */
+        NPY_FR_W = 2,  /* Weeks */
+        /* Gap where 1.6 NPY_FR_B (value 3) was */
+        NPY_FR_D = 4,  /* Days */
+        NPY_FR_h = 5,  /* hours */
+        NPY_FR_m = 6,  /* minutes */
+        NPY_FR_s = 7,  /* seconds */
+        NPY_FR_ms = 8, /* milliseconds */
+        NPY_FR_us = 9, /* microseconds */
+        NPY_FR_ns = 10,/* nanoseconds */
+        NPY_FR_ps = 11,/* picoseconds */
+        NPY_FR_fs = 12,/* femtoseconds */
+        NPY_FR_as = 13,/* attoseconds */
+        NPY_FR_GENERIC = 14 /* Generic, unbound units, can convert to anything */
+} NPY_DATETIMEUNIT;
+
+/*
+ * NOTE: With the NPY_FR_B gap for 1.6 ABI compatibility, NPY_DATETIME_NUMUNITS
+ *       is technically one more than the actual number of units.
+ */
+#define NPY_DATETIME_NUMUNITS (NPY_FR_GENERIC + 1)
+#define NPY_DATETIME_DEFAULTUNIT NPY_FR_GENERIC
+
+/*
+ * Business day conventions for mapping invalid business
+ * days to valid business days.
+ */
+typedef enum {
+    /* Go forward in time to the following business day. */
+    NPY_BUSDAY_FORWARD,
+    NPY_BUSDAY_FOLLOWING = NPY_BUSDAY_FORWARD,
+    /* Go backward in time to the preceding business day. */
+    NPY_BUSDAY_BACKWARD,
+    NPY_BUSDAY_PRECEDING = NPY_BUSDAY_BACKWARD,
+    /*
+     * Go forward in time to the following business day, unless it
+     * crosses a month boundary, in which case go backward
+     */
+    NPY_BUSDAY_MODIFIEDFOLLOWING,
+    /*
+     * Go backward in time to the preceding business day, unless it
+     * crosses a month boundary, in which case go forward.
+     */
+    NPY_BUSDAY_MODIFIEDPRECEDING,
+    /* Produce a NaT for non-business days. */
+    NPY_BUSDAY_NAT,
+    /* Raise an exception for non-business days. */
+    NPY_BUSDAY_RAISE
+} NPY_BUSDAY_ROLL;
+
+/************************************************************
+ * NumPy Auxiliary Data for inner loops, sort functions, etc.
+ ************************************************************/
+
+/*
+ * When creating an auxiliary data struct, this should always appear
+ * as the first member, like this:
+ *
+ * typedef struct {
+ *     NpyAuxData base;
+ *     double constant;
+ * } constant_multiplier_aux_data;
+ */
+typedef struct NpyAuxData_tag NpyAuxData;
+
+/* Function pointers for freeing or cloning auxiliary data */
+typedef void (NpyAuxData_FreeFunc) (NpyAuxData *);
+typedef NpyAuxData *(NpyAuxData_CloneFunc) (NpyAuxData *);
+
+struct NpyAuxData_tag {
+    NpyAuxData_FreeFunc *free;
+    NpyAuxData_CloneFunc *clone;
+    /* To allow for a bit of expansion without breaking the ABI */
+    void *reserved[2];
+};
+
+/* Macros to use for freeing and cloning auxiliary data */
+#define NPY_AUXDATA_FREE(auxdata) \
+    do { \
+        if ((auxdata) != NULL) { \
+            (auxdata)->free(auxdata); \
+        } \
+    } while(0)
+#define NPY_AUXDATA_CLONE(auxdata) \
+    ((auxdata)->clone(auxdata))
+
+#define NPY_ERR(str) fprintf(stderr, #str); fflush(stderr);
+#define NPY_ERR2(str) fprintf(stderr, str); fflush(stderr);
+
+#define NPY_STRINGIFY(x) #x
+#define NPY_TOSTRING(x) NPY_STRINGIFY(x)
+
+  /*
+   * Macros to define how array, and dimension/strides data is
+   * allocated.
+   */
+
+  /* Data buffer - PyDataMem_NEW/FREE/RENEW are in multiarraymodule.c */
+
+#define NPY_USE_PYMEM 1
+
+#if NPY_USE_PYMEM == 1
+#define PyArray_malloc PyMem_Malloc
+#define PyArray_free PyMem_Free
+#define PyArray_realloc PyMem_Realloc
+#else
+#define PyArray_malloc malloc
+#define PyArray_free free
+#define PyArray_realloc realloc
+#endif
+
+/* Dimensions and strides */
+#define PyDimMem_NEW(size)                                         \
+    ((npy_intp *)PyArray_malloc(size*sizeof(npy_intp)))
+
+#define PyDimMem_FREE(ptr) PyArray_free(ptr)
+
+#define PyDimMem_RENEW(ptr,size)                                   \
+        ((npy_intp *)PyArray_realloc(ptr,size*sizeof(npy_intp)))
+
+/* forward declaration */
+struct _PyArray_Descr;
+
+/* These must deal with unaligned and swapped data if necessary */
+typedef PyObject * (PyArray_GetItemFunc) (void *, void *);
+typedef int (PyArray_SetItemFunc)(PyObject *, void *, void *);
+
+typedef void (PyArray_CopySwapNFunc)(void *, npy_intp, void *, npy_intp,
+                                     npy_intp, int, void *);
+
+typedef void (PyArray_CopySwapFunc)(void *, void *, int, void *);
+typedef npy_bool (PyArray_NonzeroFunc)(void *, void *);
+
+
+/*
+ * These assume aligned and notswapped data -- a buffer will be used
+ * before or contiguous data will be obtained
+ */
+
+typedef int (PyArray_CompareFunc)(const void *, const void *, void *);
+typedef int (PyArray_ArgFunc)(void*, npy_intp, npy_intp*, void *);
+
+typedef void (PyArray_DotFunc)(void *, npy_intp, void *, npy_intp, void *,
+                               npy_intp, void *);
+
+typedef void (PyArray_VectorUnaryFunc)(void *, void *, npy_intp, void *,
+                                       void *);
+
+/*
+ * XXX the ignore argument should be removed next time the API version
+ * is bumped. It used to be the separator.
+ */
+typedef int (PyArray_ScanFunc)(FILE *fp, void *dptr,
+                               char *ignore, struct _PyArray_Descr *);
+typedef int (PyArray_FromStrFunc)(char *s, void *dptr, char **endptr,
+                                  struct _PyArray_Descr *);
+
+typedef int (PyArray_FillFunc)(void *, npy_intp, void *);
+
+typedef int (PyArray_SortFunc)(void *, npy_intp, void *);
+typedef int (PyArray_ArgSortFunc)(void *, npy_intp *, npy_intp, void *);
+typedef int (PyArray_PartitionFunc)(void *, npy_intp, npy_intp,
+                                    npy_intp *, npy_intp *,
+                                    void *);
+typedef int (PyArray_ArgPartitionFunc)(void *, npy_intp *, npy_intp, npy_intp,
+                                       npy_intp *, npy_intp *,
+                                       void *);
+
+typedef int (PyArray_FillWithScalarFunc)(void *, npy_intp, void *, void *);
+
+typedef int (PyArray_ScalarKindFunc)(void *);
+
+typedef void (PyArray_FastClipFunc)(void *in, npy_intp n_in, void *min,
+                                    void *max, void *out);
+typedef void (PyArray_FastPutmaskFunc)(void *in, void *mask, npy_intp n_in,
+                                       void *values, npy_intp nv);
+typedef int  (PyArray_FastTakeFunc)(void *dest, void *src, npy_intp *indarray,
+                                       npy_intp nindarray, npy_intp n_outer,
+                                       npy_intp m_middle, npy_intp nelem,
+                                       NPY_CLIPMODE clipmode);
+
+typedef struct {
+        npy_intp *ptr;
+        int len;
+} PyArray_Dims;
+
+typedef struct {
+        /*
+         * Functions to cast to most other standard types
+         * Can have some NULL entries. The types
+         * DATETIME, TIMEDELTA, and HALF go into the castdict
+         * even though they are built-in.
+         */
+        PyArray_VectorUnaryFunc *cast[NPY_NTYPES_ABI_COMPATIBLE];
+
+        /* The next four functions *cannot* be NULL */
+
+        /*
+         * Functions to get and set items with standard Python types
+         * -- not array scalars
+         */
+        PyArray_GetItemFunc *getitem;
+        PyArray_SetItemFunc *setitem;
+
+        /*
+         * Copy and/or swap data.  Memory areas may not overlap
+         * Use memmove first if they might
+         */
+        PyArray_CopySwapNFunc *copyswapn;
+        PyArray_CopySwapFunc *copyswap;
+
+        /*
+         * Function to compare items
+         * Can be NULL
+         */
+        PyArray_CompareFunc *compare;
+
+        /*
+         * Function to select largest
+         * Can be NULL
+         */
+        PyArray_ArgFunc *argmax;
+
+        /*
+         * Function to compute dot product
+         * Can be NULL
+         */
+        PyArray_DotFunc *dotfunc;
+
+        /*
+         * Function to scan an ASCII file and
+         * place a single value plus possible separator
+         * Can be NULL
+         */
+        PyArray_ScanFunc *scanfunc;
+
+        /*
+         * Function to read a single value from a string
+         * and adjust the pointer; Can be NULL
+         */
+        PyArray_FromStrFunc *fromstr;
+
+        /*
+         * Function to determine if data is zero or not
+         * If NULL a default version is
+         * used at Registration time.
+         */
+        PyArray_NonzeroFunc *nonzero;
+
+        /*
+         * Used for arange.
+         * Can be NULL.
+         */
+        PyArray_FillFunc *fill;
+
+        /*
+         * Function to fill arrays with scalar values
+         * Can be NULL
+         */
+        PyArray_FillWithScalarFunc *fillwithscalar;
+
+        /*
+         * Sorting functions
+         * Can be NULL
+         */
+        PyArray_SortFunc *sort[NPY_NSORTS];
+        PyArray_ArgSortFunc *argsort[NPY_NSORTS];
+
+        /*
+         * Dictionary of additional casting functions
+         * PyArray_VectorUnaryFuncs
+         * which can be populated to support casting
+         * to other registered types. Can be NULL
+         */
+        PyObject *castdict;
+
+        /*
+         * Functions useful for generalizing
+         * the casting rules.
+         * Can be NULL;
+         */
+        PyArray_ScalarKindFunc *scalarkind;
+        int **cancastscalarkindto;
+        int *cancastto;
+
+        PyArray_FastClipFunc *fastclip;
+        PyArray_FastPutmaskFunc *fastputmask;
+        PyArray_FastTakeFunc *fasttake;
+
+        /*
+         * Function to select smallest
+         * Can be NULL
+         */
+        PyArray_ArgFunc *argmin;
+
+} PyArray_ArrFuncs;
+
+/* The item must be reference counted when it is inserted or extracted. */
+#define NPY_ITEM_REFCOUNT   0x01
+/* Same as needing REFCOUNT */
+#define NPY_ITEM_HASOBJECT  0x01
+/* Convert to list for pickling */
+#define NPY_LIST_PICKLE     0x02
+/* The item is a POINTER  */
+#define NPY_ITEM_IS_POINTER 0x04
+/* memory needs to be initialized for this data-type */
+#define NPY_NEEDS_INIT      0x08
+/* operations need Python C-API so don't give-up thread. */
+#define NPY_NEEDS_PYAPI     0x10
+/* Use f.getitem when extracting elements of this data-type */
+#define NPY_USE_GETITEM     0x20
+/* Use f.setitem when setting creating 0-d array from this data-type.*/
+#define NPY_USE_SETITEM     0x40
+/* A sticky flag specifically for structured arrays */
+#define NPY_ALIGNED_STRUCT  0x80
+
+/*
+ *These are inherited for global data-type if any data-types in the
+ * field have them
+ */
+#define NPY_FROM_FIELDS    (NPY_NEEDS_INIT | NPY_LIST_PICKLE | \
+                            NPY_ITEM_REFCOUNT | NPY_NEEDS_PYAPI)
+
+#define NPY_OBJECT_DTYPE_FLAGS (NPY_LIST_PICKLE | NPY_USE_GETITEM | \
+                                NPY_ITEM_IS_POINTER | NPY_ITEM_REFCOUNT | \
+                                NPY_NEEDS_INIT | NPY_NEEDS_PYAPI)
+
+#define PyDataType_FLAGCHK(dtype, flag) \
+        (((dtype)->flags & (flag)) == (flag))
+
+#define PyDataType_REFCHK(dtype) \
+        PyDataType_FLAGCHK(dtype, NPY_ITEM_REFCOUNT)
+
+typedef struct _PyArray_Descr {
+        PyObject_HEAD
+        /*
+         * the type object representing an
+         * instance of this type -- should not
+         * be two type_numbers with the same type
+         * object.
+         */
+        PyTypeObject *typeobj;
+        /* kind for this type */
+        char kind;
+        /* unique-character representing this type */
+        char type;
+        /*
+         * '>' (big), '<' (little), '|'
+         * (not-applicable), or '=' (native).
+         */
+        char byteorder;
+        /* flags describing data type */
+        char flags;
+        /* number representing this type */
+        int type_num;
+        /* element size (itemsize) for this type */
+        int elsize;
+        /* alignment needed for this type */
+        int alignment;
+        /*
+         * Non-NULL if this type is
+         * is an array (C-contiguous)
+         * of some other type
+         */
+        struct _arr_descr *subarray;
+        /*
+         * The fields dictionary for this type
+         * For statically defined descr this
+         * is always Py_None
+         */
+        PyObject *fields;
+        /*
+         * An ordered tuple of field names or NULL
+         * if no fields are defined
+         */
+        PyObject *names;
+        /*
+         * a table of functions specific for each
+         * basic data descriptor
+         */
+        PyArray_ArrFuncs *f;
+        /* Metadata about this dtype */
+        PyObject *metadata;
+        /*
+         * Metadata specific to the C implementation
+         * of the particular dtype. This was added
+         * for NumPy 1.7.0.
+         */
+        NpyAuxData *c_metadata;
+} PyArray_Descr;
+
+typedef struct _arr_descr {
+        PyArray_Descr *base;
+        PyObject *shape;       /* a tuple */
+} PyArray_ArrayDescr;
+
+/*
+ * The main array object structure.
+ *
+ * It has been recommended to use the inline functions defined below
+ * (PyArray_DATA and friends) to access fields here for a number of
+ * releases. Direct access to the members themselves is deprecated.
+ * To ensure that your code does not use deprecated access,
+ * #define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION
+ * (or NPY_1_8_API_VERSION or higher as required).
+ */
+/* This struct will be moved to a private header in a future release */
+typedef struct tagPyArrayObject_fields {
+    PyObject_HEAD
+    /* Pointer to the raw data buffer */
+    char *data;
+    /* The number of dimensions, also called 'ndim' */
+    int nd;
+    /* The size in each dimension, also called 'shape' */
+    npy_intp *dimensions;
+    /*
+     * Number of bytes to jump to get to the
+     * next element in each dimension
+     */
+    npy_intp *strides;
+    /*
+     * This object is decref'd upon
+     * deletion of array. Except in the
+     * case of UPDATEIFCOPY which has
+     * special handling.
+     *
+     * For views it points to the original
+     * array, collapsed so no chains of
+     * views occur.
+     *
+     * For creation from buffer object it
+     * points to an object that shold be
+     * decref'd on deletion
+     *
+     * For UPDATEIFCOPY flag this is an
+     * array to-be-updated upon deletion
+     * of this one


More information about the pypy-commit mailing list