[pypy-commit] pypy default: merge heads

arigo noreply at buildbot.pypy.org
Wed Aug 31 10:23:03 CEST 2011


Author: Armin Rigo <arigo at tunes.org>
Branch: 
Changeset: r46939:a21048ef07ee
Date: 2011-08-31 10:22 +0200
http://bitbucket.org/pypy/pypy/changeset/a21048ef07ee/

Log:	merge heads

diff --git a/lib-python/modified-2.7/ctypes/util.py b/lib-python/modified-2.7/ctypes/util.py
--- a/lib-python/modified-2.7/ctypes/util.py
+++ b/lib-python/modified-2.7/ctypes/util.py
@@ -72,8 +72,8 @@
         return name
 
 if os.name == "posix" and sys.platform == "darwin":
-    from ctypes.macholib.dyld import dyld_find as _dyld_find
     def find_library(name):
+        from ctypes.macholib.dyld import dyld_find as _dyld_find
         possible = ['lib%s.dylib' % name,
                     '%s.dylib' % name,
                     '%s.framework/%s' % (name, name)]
diff --git a/lib-python/modified-2.7/gzip.py b/lib-python/modified-2.7/gzip.py
new file mode 100644
--- /dev/null
+++ b/lib-python/modified-2.7/gzip.py
@@ -0,0 +1,514 @@
+"""Functions that read and write gzipped files.
+
+The user of the file doesn't have to worry about the compression,
+but random access is not allowed."""
+
+# based on Andrew Kuchling's minigzip.py distributed with the zlib module
+
+import struct, sys, time, os
+import zlib
+import io
+import __builtin__
+
+__all__ = ["GzipFile","open"]
+
+FTEXT, FHCRC, FEXTRA, FNAME, FCOMMENT = 1, 2, 4, 8, 16
+
+READ, WRITE = 1, 2
+
+def write32u(output, value):
+    # The L format writes the bit pattern correctly whether signed
+    # or unsigned.
+    output.write(struct.pack("<L", value))
+
+def read32(input):
+    return struct.unpack("<I", input.read(4))[0]
+
+def open(filename, mode="rb", compresslevel=9):
+    """Shorthand for GzipFile(filename, mode, compresslevel).
+
+    The filename argument is required; mode defaults to 'rb'
+    and compresslevel defaults to 9.
+
+    """
+    return GzipFile(filename, mode, compresslevel)
+
+class GzipFile(io.BufferedIOBase):
+    """The GzipFile class simulates most of the methods of a file object with
+    the exception of the readinto() and truncate() methods.
+
+    """
+
+    myfileobj = None
+    max_read_chunk = 10 * 1024 * 1024   # 10Mb
+
+    def __init__(self, filename=None, mode=None,
+                 compresslevel=9, fileobj=None, mtime=None):
+        """Constructor for the GzipFile class.
+
+        At least one of fileobj and filename must be given a
+        non-trivial value.
+
+        The new class instance is based on fileobj, which can be a regular
+        file, a StringIO object, or any other object which simulates a file.
+        It defaults to None, in which case filename is opened to provide
+        a file object.
+
+        When fileobj is not None, the filename argument is only used to be
+        included in the gzip file header, which may includes the original
+        filename of the uncompressed file.  It defaults to the filename of
+        fileobj, if discernible; otherwise, it defaults to the empty string,
+        and in this case the original filename is not included in the header.
+
+        The mode argument can be any of 'r', 'rb', 'a', 'ab', 'w', or 'wb',
+        depending on whether the file will be read or written.  The default
+        is the mode of fileobj if discernible; otherwise, the default is 'rb'.
+        Be aware that only the 'rb', 'ab', and 'wb' values should be used
+        for cross-platform portability.
+
+        The compresslevel argument is an integer from 1 to 9 controlling the
+        level of compression; 1 is fastest and produces the least compression,
+        and 9 is slowest and produces the most compression.  The default is 9.
+
+        The mtime argument is an optional numeric timestamp to be written
+        to the stream when compressing.  All gzip compressed streams
+        are required to contain a timestamp.  If omitted or None, the
+        current time is used.  This module ignores the timestamp when
+        decompressing; however, some programs, such as gunzip, make use
+        of it.  The format of the timestamp is the same as that of the
+        return value of time.time() and of the st_mtime member of the
+        object returned by os.stat().
+
+        """
+
+        # guarantee the file is opened in binary mode on platforms
+        # that care about that sort of thing
+        if mode and 'b' not in mode:
+            mode += 'b'
+        if fileobj is None:
+            fileobj = self.myfileobj = __builtin__.open(filename, mode or 'rb')
+        if filename is None:
+            if hasattr(fileobj, 'name'): filename = fileobj.name
+            else: filename = ''
+        if mode is None:
+            if hasattr(fileobj, 'mode'): mode = fileobj.mode
+            else: mode = 'rb'
+
+        if mode[0:1] == 'r':
+            self.mode = READ
+            # Set flag indicating start of a new member
+            self._new_member = True
+            # Buffer data read from gzip file. extrastart is offset in
+            # stream where buffer starts. extrasize is number of
+            # bytes remaining in buffer from current stream position.
+            self.extrabuf = ""
+            self.extrasize = 0
+            self.extrastart = 0
+            self.name = filename
+            # Starts small, scales exponentially
+            self.min_readsize = 100
+
+        elif mode[0:1] == 'w' or mode[0:1] == 'a':
+            self.mode = WRITE
+            self._init_write(filename)
+            self.compress = zlib.compressobj(compresslevel,
+                                             zlib.DEFLATED,
+                                             -zlib.MAX_WBITS,
+                                             zlib.DEF_MEM_LEVEL,
+                                             0)
+        else:
+            raise IOError, "Mode " + mode + " not supported"
+
+        self.fileobj = fileobj
+        self.offset = 0
+        self.mtime = mtime
+
+        if self.mode == WRITE:
+            self._write_gzip_header()
+
+    @property
+    def filename(self):
+        import warnings
+        warnings.warn("use the name attribute", DeprecationWarning, 2)
+        if self.mode == WRITE and self.name[-3:] != ".gz":
+            return self.name + ".gz"
+        return self.name
+
+    def __repr__(self):
+        s = repr(self.fileobj)
+        return '<gzip ' + s[1:-1] + ' ' + hex(id(self)) + '>'
+
+    def _check_closed(self):
+        """Raises a ValueError if the underlying file object has been closed.
+
+        """
+        if self.closed:
+            raise ValueError('I/O operation on closed file.')
+
+    def _init_write(self, filename):
+        self.name = filename
+        self.crc = zlib.crc32("") & 0xffffffffL
+        self.size = 0
+        self.writebuf = []
+        self.bufsize = 0
+
+    def _write_gzip_header(self):
+        self.fileobj.write('\037\213')             # magic header
+        self.fileobj.write('\010')                 # compression method
+        fname = os.path.basename(self.name)
+        if fname.endswith(".gz"):
+            fname = fname[:-3]
+        flags = 0
+        if fname:
+            flags = FNAME
+        self.fileobj.write(chr(flags))
+        mtime = self.mtime
+        if mtime is None:
+            mtime = time.time()
+        write32u(self.fileobj, long(mtime))
+        self.fileobj.write('\002')
+        self.fileobj.write('\377')
+        if fname:
+            self.fileobj.write(fname + '\000')
+
+    def _init_read(self):
+        self.crc = zlib.crc32("") & 0xffffffffL
+        self.size = 0
+
+    def _read_gzip_header(self):
+        magic = self.fileobj.read(2)
+        if magic != '\037\213':
+            raise IOError, 'Not a gzipped file'
+        method = ord( self.fileobj.read(1) )
+        if method != 8:
+            raise IOError, 'Unknown compression method'
+        flag = ord( self.fileobj.read(1) )
+        self.mtime = read32(self.fileobj)
+        # extraflag = self.fileobj.read(1)
+        # os = self.fileobj.read(1)
+        self.fileobj.read(2)
+
+        if flag & FEXTRA:
+            # Read & discard the extra field, if present
+            xlen = ord(self.fileobj.read(1))
+            xlen = xlen + 256*ord(self.fileobj.read(1))
+            self.fileobj.read(xlen)
+        if flag & FNAME:
+            # Read and discard a null-terminated string containing the filename
+            while True:
+                s = self.fileobj.read(1)
+                if not s or s=='\000':
+                    break
+        if flag & FCOMMENT:
+            # Read and discard a null-terminated string containing a comment
+            while True:
+                s = self.fileobj.read(1)
+                if not s or s=='\000':
+                    break
+        if flag & FHCRC:
+            self.fileobj.read(2)     # Read & discard the 16-bit header CRC
+
+    def write(self,data):
+        self._check_closed()
+        if self.mode != WRITE:
+            import errno
+            raise IOError(errno.EBADF, "write() on read-only GzipFile object")
+
+        if self.fileobj is None:
+            raise ValueError, "write() on closed GzipFile object"
+
+        # Convert data type if called by io.BufferedWriter.
+        if isinstance(data, memoryview):
+            data = data.tobytes()
+
+        if len(data) > 0:
+            self.size = self.size + len(data)
+            self.crc = zlib.crc32(data, self.crc) & 0xffffffffL
+            self.fileobj.write( self.compress.compress(data) )
+            self.offset += len(data)
+
+        return len(data)
+
+    def read(self, size=-1):
+        self._check_closed()
+        if self.mode != READ:
+            import errno
+            raise IOError(errno.EBADF, "read() on write-only GzipFile object")
+
+        if self.extrasize <= 0 and self.fileobj is None:
+            return ''
+
+        readsize = 1024
+        if size < 0:        # get the whole thing
+            try:
+                while True:
+                    self._read(readsize)
+                    readsize = min(self.max_read_chunk, readsize * 2)
+            except EOFError:
+                size = self.extrasize
+        elif size == 0:
+            return ""
+        else:               # just get some more of it
+            try:
+                while size > self.extrasize:
+                    self._read(readsize)
+                    readsize = min(self.max_read_chunk, readsize * 2)
+            except EOFError:
+                if size > self.extrasize:
+                    size = self.extrasize
+
+        offset = self.offset - self.extrastart
+        chunk = self.extrabuf[offset: offset + size]
+        self.extrasize = self.extrasize - size
+
+        self.offset += size
+        return chunk
+
+    def _unread(self, buf):
+        self.extrasize = len(buf) + self.extrasize
+        self.offset -= len(buf)
+
+    def _read(self, size=1024):
+        if self.fileobj is None:
+            raise EOFError, "Reached EOF"
+
+        if self._new_member:
+            # If the _new_member flag is set, we have to
+            # jump to the next member, if there is one.
+            #
+            # First, check if we're at the end of the file;
+            # if so, it's time to stop; no more members to read.
+            pos = self.fileobj.tell()   # Save current position
+            self.fileobj.seek(0, 2)     # Seek to end of file
+            if pos == self.fileobj.tell():
+                raise EOFError, "Reached EOF"
+            else:
+                self.fileobj.seek( pos ) # Return to original position
+
+            self._init_read()
+            self._read_gzip_header()
+            self.decompress = zlib.decompressobj(-zlib.MAX_WBITS)
+            self._new_member = False
+
+        # Read a chunk of data from the file
+        buf = self.fileobj.read(size)
+
+        # If the EOF has been reached, flush the decompression object
+        # and mark this object as finished.
+
+        if buf == "":
+            uncompress = self.decompress.flush()
+            self._read_eof()
+            self._add_read_data( uncompress )
+            raise EOFError, 'Reached EOF'
+
+        uncompress = self.decompress.decompress(buf)
+        self._add_read_data( uncompress )
+
+        if self.decompress.unused_data != "":
+            # Ending case: we've come to the end of a member in the file,
+            # so seek back to the start of the unused data, finish up
+            # this member, and read a new gzip header.
+            # (The number of bytes to seek back is the length of the unused
+            # data, minus 8 because _read_eof() will rewind a further 8 bytes)
+            self.fileobj.seek( -len(self.decompress.unused_data)+8, 1)
+
+            # Check the CRC and file size, and set the flag so we read
+            # a new member on the next call
+            self._read_eof()
+            self._new_member = True
+
+    def _add_read_data(self, data):
+        self.crc = zlib.crc32(data, self.crc) & 0xffffffffL
+        offset = self.offset - self.extrastart
+        self.extrabuf = self.extrabuf[offset:] + data
+        self.extrasize = self.extrasize + len(data)
+        self.extrastart = self.offset
+        self.size = self.size + len(data)
+
+    def _read_eof(self):
+        # We've read to the end of the file, so we have to rewind in order
+        # to reread the 8 bytes containing the CRC and the file size.
+        # We check the that the computed CRC and size of the
+        # uncompressed data matches the stored values.  Note that the size
+        # stored is the true file size mod 2**32.
+        self.fileobj.seek(-8, 1)
+        crc32 = read32(self.fileobj)
+        isize = read32(self.fileobj)  # may exceed 2GB
+        if crc32 != self.crc:
+            raise IOError("CRC check failed %s != %s" % (hex(crc32),
+                                                         hex(self.crc)))
+        elif isize != (self.size & 0xffffffffL):
+            raise IOError, "Incorrect length of data produced"
+
+        # Gzip files can be padded with zeroes and still have archives.
+        # Consume all zero bytes and set the file position to the first
+        # non-zero byte. See http://www.gzip.org/#faq8
+        c = "\x00"
+        while c == "\x00":
+            c = self.fileobj.read(1)
+        if c:
+            self.fileobj.seek(-1, 1)
+
+    @property
+    def closed(self):
+        return self.fileobj is None
+
+    def close(self):
+        if self.fileobj is None:
+            return
+        if self.mode == WRITE:
+            self.fileobj.write(self.compress.flush())
+            write32u(self.fileobj, self.crc)
+            # self.size may exceed 2GB, or even 4GB
+            write32u(self.fileobj, self.size & 0xffffffffL)
+            self.fileobj = None
+        elif self.mode == READ:
+            self.fileobj = None
+        if self.myfileobj:
+            self.myfileobj.close()
+            self.myfileobj = None
+
+    def flush(self,zlib_mode=zlib.Z_SYNC_FLUSH):
+        self._check_closed()
+        if self.mode == WRITE:
+            # Ensure the compressor's buffer is flushed
+            self.fileobj.write(self.compress.flush(zlib_mode))
+            self.fileobj.flush()
+
+    def fileno(self):
+        """Invoke the underlying file object's fileno() method.
+
+        This will raise AttributeError if the underlying file object
+        doesn't support fileno().
+        """
+        return self.fileobj.fileno()
+
+    def rewind(self):
+        '''Return the uncompressed stream file position indicator to the
+        beginning of the file'''
+        if self.mode != READ:
+            raise IOError("Can't rewind in write mode")
+        self.fileobj.seek(0)
+        self._new_member = True
+        self.extrabuf = ""
+        self.extrasize = 0
+        self.extrastart = 0
+        self.offset = 0
+
+    def readable(self):
+        return self.mode == READ
+
+    def writable(self):
+        return self.mode == WRITE
+
+    def seekable(self):
+        return True
+
+    def seek(self, offset, whence=0):
+        if whence:
+            if whence == 1:
+                offset = self.offset + offset
+            else:
+                raise ValueError('Seek from end not supported')
+        if self.mode == WRITE:
+            if offset < self.offset:
+                raise IOError('Negative seek in write mode')
+            count = offset - self.offset
+            for i in range(count // 1024):
+                self.write(1024 * '\0')
+            self.write((count % 1024) * '\0')
+        elif self.mode == READ:
+            if offset == self.offset:
+                self.read(0) # to make sure that this file is open
+                return self.offset
+            if offset < self.offset:
+                # for negative seek, rewind and do positive seek
+                self.rewind()
+            count = offset - self.offset
+            for i in range(count // 1024):
+                self.read(1024)
+            self.read(count % 1024)
+
+        return self.offset
+
+    def readline(self, size=-1):
+        if size < 0:
+            # Shortcut common case - newline found in buffer.
+            offset = self.offset - self.extrastart
+            i = self.extrabuf.find('\n', offset) + 1
+            if i > 0:
+                self.extrasize -= i - offset
+                self.offset += i - offset
+                return self.extrabuf[offset: i]
+
+            size = sys.maxint
+            readsize = self.min_readsize
+        else:
+            readsize = size
+        bufs = []
+        while size != 0:
+            c = self.read(readsize)
+            i = c.find('\n')
+
+            # We set i=size to break out of the loop under two
+            # conditions: 1) there's no newline, and the chunk is
+            # larger than size, or 2) there is a newline, but the
+            # resulting line would be longer than 'size'.
+            if (size <= i) or (i == -1 and len(c) > size):
+                i = size - 1
+
+            if i >= 0 or c == '':
+                bufs.append(c[:i + 1])    # Add portion of last chunk
+                self._unread(c[i + 1:])   # Push back rest of chunk
+                break
+
+            # Append chunk to list, decrease 'size',
+            bufs.append(c)
+            size = size - len(c)
+            readsize = min(size, readsize * 2)
+        if readsize > self.min_readsize:
+            self.min_readsize = min(readsize, self.min_readsize * 2, 512)
+        return ''.join(bufs) # Return resulting line
+
+
+def _test():
+    # Act like gzip; with -d, act like gunzip.
+    # The input file is not deleted, however, nor are any other gzip
+    # options or features supported.
+    args = sys.argv[1:]
+    decompress = args and args[0] == "-d"
+    if decompress:
+        args = args[1:]
+    if not args:
+        args = ["-"]
+    for arg in args:
+        if decompress:
+            if arg == "-":
+                f = GzipFile(filename="", mode="rb", fileobj=sys.stdin)
+                g = sys.stdout
+            else:
+                if arg[-3:] != ".gz":
+                    print "filename doesn't end in .gz:", repr(arg)
+                    continue
+                f = open(arg, "rb")
+                g = __builtin__.open(arg[:-3], "wb")
+        else:
+            if arg == "-":
+                f = sys.stdin
+                g = GzipFile(filename="", mode="wb", fileobj=sys.stdout)
+            else:
+                f = __builtin__.open(arg, "rb")
+                g = open(arg + ".gz", "wb")
+        while True:
+            chunk = f.read(1024)
+            if not chunk:
+                break
+            g.write(chunk)
+        if g is not sys.stdout:
+            g.close()
+        if f is not sys.stdin:
+            f.close()
+
+if __name__ == '__main__':
+    _test()
diff --git a/lib-python/modified-2.7/tarfile.py b/lib-python/modified-2.7/tarfile.py
--- a/lib-python/modified-2.7/tarfile.py
+++ b/lib-python/modified-2.7/tarfile.py
@@ -252,8 +252,8 @@
        the high bit set. So we calculate two checksums, unsigned and
        signed.
     """
-    unsigned_chksum = 256 + sum(struct.unpack("148B", buf[:148]) + struct.unpack("356B", buf[156:512]))
-    signed_chksum = 256 + sum(struct.unpack("148b", buf[:148]) + struct.unpack("356b", buf[156:512]))
+    unsigned_chksum = 256 + sum(struct.unpack("148B8x356B", buf[:512]))
+    signed_chksum = 256 + sum(struct.unpack("148b8x356b", buf[:512]))
     return unsigned_chksum, signed_chksum
 
 def copyfileobj(src, dst, length=None):
@@ -265,7 +265,6 @@
     if length is None:
         shutil.copyfileobj(src, dst)
         return
-
     BUFSIZE = 16 * 1024
     blocks, remainder = divmod(length, BUFSIZE)
     for b in xrange(blocks):
@@ -802,19 +801,19 @@
         if self.closed:
             raise ValueError("I/O operation on closed file")
 
-        buf = ""
         if self.buffer:
             if size is None:
-                buf = self.buffer
+                buf = self.buffer + self.fileobj.read()
                 self.buffer = ""
             else:
                 buf = self.buffer[:size]
                 self.buffer = self.buffer[size:]
-
-        if size is None:
-            buf += self.fileobj.read()
+                buf += self.fileobj.read(size - len(buf))
         else:
-            buf += self.fileobj.read(size - len(buf))
+            if size is None:
+                buf = self.fileobj.read()
+            else:
+                buf = self.fileobj.read(size)
 
         self.position += len(buf)
         return buf
diff --git a/pypy/annotation/description.py b/pypy/annotation/description.py
--- a/pypy/annotation/description.py
+++ b/pypy/annotation/description.py
@@ -399,9 +399,7 @@
                 if b1 is object:
                     continue
                 if b1.__dict__.get('_mixin_', False):
-                    assert b1.__bases__ == () or b1.__bases__ == (object,), (
-                        "mixin class %r should have no base" % (b1,))
-                    self.add_sources_for_class(b1, mixin=True)
+                    self.add_mixin(b1)
                 else:
                     assert base is object, ("multiple inheritance only supported "
                                             "with _mixin_: %r" % (cls,))
@@ -469,6 +467,15 @@
                 return
         self.classdict[name] = Constant(value)
 
+    def add_mixin(self, base):
+        for subbase in base.__bases__:
+            if subbase is object:
+                continue
+            assert subbase.__dict__.get("_mixin_", False), ("Mixin class %r has non"
+                "mixin base class %r" % (base, subbase))
+            self.add_mixin(subbase)
+        self.add_sources_for_class(base, mixin=True)
+
     def add_sources_for_class(self, cls, mixin=False):
         for name, value in cls.__dict__.items():
             self.add_source_attribute(name, value, mixin)
diff --git a/pypy/doc/jit/pyjitpl5.rst b/pypy/doc/jit/pyjitpl5.rst
--- a/pypy/doc/jit/pyjitpl5.rst
+++ b/pypy/doc/jit/pyjitpl5.rst
@@ -103,7 +103,7 @@
 
 The meta-interpreter starts interpreting the JIT bytecode.  Each operation is
 executed and then recorded in a list of operations, called the trace.
-Operations can have a list of boxes that operate on, arguments.  Some operations
+Operations can have a list of boxes they operate on, arguments.  Some operations
 (like GETFIELD and GETARRAYITEM) also have special objects that describe how
 their arguments are laid out in memory.  All possible operations generated by
 tracing are listed in metainterp/resoperation.py.  When a (interpreter-level)
diff --git a/pypy/jit/backend/llgraph/llimpl.py b/pypy/jit/backend/llgraph/llimpl.py
--- a/pypy/jit/backend/llgraph/llimpl.py
+++ b/pypy/jit/backend/llgraph/llimpl.py
@@ -57,6 +57,12 @@
     else:
         return LLSupport.from_rstr(s)
 
+FLOAT_ARRAY_TP = lltype.Ptr(lltype.Array(lltype.Float, hints={"nolength": True}))
+def maybe_uncast(TP, array):
+    if array._TYPE.TO._hints.get("uncast_on_llgraph"):
+        array = rffi.cast(TP, array)
+    return array
+
 # a list of argtypes of all operations - couldn't find any and it's
 # very useful.  Note however that the table is half-broken here and
 # there, in ways that are sometimes a bit hard to fix; that's why
@@ -1079,7 +1085,7 @@
     if isinstance(TYPE, lltype.Ptr):
         if isinstance(x, (int, long, llmemory.AddressAsInt)):
             x = llmemory.cast_int_to_adr(x)
-        if TYPE is rffi.VOIDP:
+        if TYPE is rffi.VOIDP or TYPE.TO._hints.get("uncast_on_llgraph"):
             # assume that we want a "C-style" cast, without typechecking the value
             return rffi.cast(TYPE, x)
         return llmemory.cast_adr_to_ptr(x, TYPE)
@@ -1329,8 +1335,8 @@
     return cast_to_floatstorage(array.getitem(index))
 
 def do_getarrayitem_raw_float(array, index):
-    array = array.adr.ptr._obj
-    return cast_to_floatstorage(array.getitem(index))
+    array = maybe_uncast(FLOAT_ARRAY_TP, array.adr.ptr)
+    return cast_to_floatstorage(array._obj.getitem(index))
 
 def do_getarrayitem_gc_ptr(array, index):
     array = array._obj.container
@@ -1392,8 +1398,9 @@
     newvalue = cast_from_floatstorage(ITEMTYPE, newvalue)
     array.setitem(index, newvalue)
 
+
 def do_setarrayitem_raw_float(array, index, newvalue):
-    array = array.adr.ptr
+    array = maybe_uncast(FLOAT_ARRAY_TP, array.adr.ptr)
     ITEMTYPE = lltype.typeOf(array).TO.OF
     newvalue = cast_from_floatstorage(ITEMTYPE, newvalue)
     array._obj.setitem(index, newvalue)
diff --git a/pypy/jit/metainterp/test/test_rawmem.py b/pypy/jit/metainterp/test/test_rawmem.py
new file mode 100644
--- /dev/null
+++ b/pypy/jit/metainterp/test/test_rawmem.py
@@ -0,0 +1,22 @@
+from pypy.jit.metainterp.test.support import LLJitMixin
+from pypy.rpython.lltypesystem import lltype, rffi
+
+
+class TestJITRawMem(LLJitMixin):
+    def test_cast_void_ptr(self):
+        TP = lltype.Array(lltype.Float, hints={"nolength": True})
+        VOID_TP = lltype.Array(lltype.Void, hints={"nolength": True, "uncast_on_llgraph": True})
+        class A(object):
+            def __init__(self, x):
+                self.storage = rffi.cast(lltype.Ptr(VOID_TP), x)\
+
+        def f(n):
+            x = lltype.malloc(TP, n, flavor="raw", zero=True)
+            a = A(x)
+            s = 0.0
+            rffi.cast(lltype.Ptr(TP), a.storage)[0] = 1.0
+            s += rffi.cast(lltype.Ptr(TP), a.storage)[0]
+            lltype.free(x, flavor="raw")
+            return s
+        res = self.interp_operations(f, [10])
+        assert res == 1.0
\ No newline at end of file
diff --git a/pypy/module/_codecs/interp_codecs.py b/pypy/module/_codecs/interp_codecs.py
--- a/pypy/module/_codecs/interp_codecs.py
+++ b/pypy/module/_codecs/interp_codecs.py
@@ -687,11 +687,15 @@
 # support for the "string escape" codec
 # This is a bytes-to bytes transformation
 
- at unwrap_spec(errors='str_or_None')
-def escape_encode(space, w_string, errors='strict'):
-    w_repr = space.repr(w_string)
-    w_result = space.getslice(w_repr, space.wrap(1), space.wrap(-1))
-    return space.newtuple([w_result, space.len(w_string)])
+ at unwrap_spec(data=str, errors='str_or_None')
+def escape_encode(space, data, errors='strict'):
+    from pypy.objspace.std.stringobject import string_escape_encode
+    result = string_escape_encode(data, quote="'")
+    start = 1
+    end = len(result) - 1
+    assert end >= 0
+    w_result = space.wrap(result[start:end])
+    return space.newtuple([w_result, space.wrap(len(data))])
 
 @unwrap_spec(data=str, errors='str_or_None')
 def escape_decode(space, data, errors='strict'):
diff --git a/pypy/module/_codecs/test/test_codecs.py b/pypy/module/_codecs/test/test_codecs.py
--- a/pypy/module/_codecs/test/test_codecs.py
+++ b/pypy/module/_codecs/test/test_codecs.py
@@ -102,7 +102,6 @@
     
     def test_indexerror(self):
         test =   "\\"     # trailing backslash
-             
         raises (ValueError, test.decode,'string-escape')
 
     def test_charmap_decode(self):
@@ -292,6 +291,10 @@
         assert '\\0f'.decode('string_escape') == chr(0) + 'f'
         assert '\\08'.decode('string_escape') == chr(0) + '8'
 
+    def test_escape_encode(self):
+        assert '"'.encode('string_escape') == '"'
+        assert "'".encode('string_escape') == "\\'"
+
     def test_decode_utf8_different_case(self):
         constant = u"a"
         assert constant.encode("utf-8") == constant.encode("UTF-8")
diff --git a/pypy/module/bz2/interp_bz2.py b/pypy/module/bz2/interp_bz2.py
--- a/pypy/module/bz2/interp_bz2.py
+++ b/pypy/module/bz2/interp_bz2.py
@@ -446,7 +446,9 @@
             result = self.buffer[pos:pos + n]
             self.pos += n
         else:
-            result = self.buffer
+            pos = self.pos
+            assert pos >= 0
+            result = self.buffer[pos:]
             self.pos = 0
             self.buffer = ""
         self.readlength += len(result)
diff --git a/pypy/module/micronumpy/__init__.py b/pypy/module/micronumpy/__init__.py
--- a/pypy/module/micronumpy/__init__.py
+++ b/pypy/module/micronumpy/__init__.py
@@ -1,40 +1,45 @@
-
 from pypy.interpreter.mixedmodule import MixedModule
 
+
 class Module(MixedModule):
-
     applevel_name = 'numpy'
 
     interpleveldefs = {
         'array': 'interp_numarray.SingleDimArray',
+        'dtype': 'interp_dtype.W_Dtype',
+        'ufunc': 'interp_ufuncs.W_Ufunc',
+
         'zeros': 'interp_numarray.zeros',
         'empty': 'interp_numarray.zeros',
         'ones': 'interp_numarray.ones',
         'fromstring': 'interp_support.fromstring',
+    }
 
-        # ufuncs
-        'abs': 'interp_ufuncs.absolute',
-        'absolute': 'interp_ufuncs.absolute',
-        'add': 'interp_ufuncs.add',
-        'copysign': 'interp_ufuncs.copysign',
-        'divide': 'interp_ufuncs.divide',
-        'exp': 'interp_ufuncs.exp',
-        'fabs': 'interp_ufuncs.fabs',
-        'floor': 'interp_ufuncs.floor',
-        'maximum': 'interp_ufuncs.maximum',
-        'minimum': 'interp_ufuncs.minimum',
-        'multiply': 'interp_ufuncs.multiply',
-        'negative': 'interp_ufuncs.negative',
-        'reciprocal': 'interp_ufuncs.reciprocal',
-        'sign': 'interp_ufuncs.sign',
-        'subtract': 'interp_ufuncs.subtract',
-        'sin': 'interp_ufuncs.sin',
-        'cos': 'interp_ufuncs.cos',
-        'tan': 'interp_ufuncs.tan',
-        'arcsin': 'interp_ufuncs.arcsin',
-        'arccos': 'interp_ufuncs.arccos',
-        'arctan': 'interp_ufuncs.arctan',
-    }
+    # ufuncs
+    for exposed, impl in [
+        ("abs", "absolute"),
+        ("absolute", "absolute"),
+        ("add", "add"),
+        ("arccos", "arccos"),
+        ("arcsin", "arcsin"),
+        ("arctan", "arctan"),
+        ("copysign", "copysign"),
+        ("cos", "cos"),
+        ("divide", "divide"),
+        ("exp", "exp"),
+        ("fabs", "fabs"),
+        ("floor", "floor"),
+        ("maximum", "maximum"),
+        ("minimum", "minimum"),
+        ("multiply", "multiply"),
+        ("negative", "negative"),
+        ("reciprocal", "reciprocal"),
+        ("sign", "sign"),
+        ("sin", "sin"),
+        ("subtract", "subtract"),
+        ("tan", "tan"),
+    ]:
+        interpleveldefs[exposed] = "interp_ufuncs.get(space).%s" % impl
 
     appleveldefs = {
         'average': 'app_numpy.average',
diff --git a/pypy/module/micronumpy/compile.py b/pypy/module/micronumpy/compile.py
--- a/pypy/module/micronumpy/compile.py
+++ b/pypy/module/micronumpy/compile.py
@@ -3,56 +3,104 @@
 It should not be imported by the module itself
 """
 
-from pypy.module.micronumpy.interp_numarray import FloatWrapper, SingleDimArray, BaseArray
+from pypy.interpreter.baseobjspace import InternalSpaceCache, W_Root
+from pypy.module.micronumpy.interp_dtype import W_Float64Dtype
+from pypy.module.micronumpy.interp_numarray import Scalar, SingleDimArray, BaseArray
+from pypy.rlib.objectmodel import specialize
+
 
 class BogusBytecode(Exception):
     pass
 
-def create_array(size):
-    a = SingleDimArray(size)
+def create_array(dtype, size):
+    a = SingleDimArray(size, dtype=dtype)
     for i in range(size):
-        a.storage[i] = float(i % 10)
+        dtype.setitem(a.storage, i, dtype.box(float(i % 10)))
     return a
 
-class TrivialSpace(object):
-    def wrap(self, x):
-        return x
+class FakeSpace(object):
+    w_ValueError = None
+    w_TypeError = None
+
+    def __init__(self):
+        """NOT_RPYTHON"""
+        self.fromcache = InternalSpaceCache(self).getorbuild
 
     def issequence_w(self, w_obj):
-        # Completley wrong in the general case, but good enough for this.
-        return isinstance(w_obj, BaseArray)
+        return True
+
+    @specialize.argtype(1)
+    def wrap(self, obj):
+        if isinstance(obj, float):
+            return FloatObject(obj)
+        elif isinstance(obj, bool):
+            return BoolObject(obj)
+        elif isinstance(obj, int):
+            return IntObject(obj)
+        raise Exception
+
+    def float(self, w_obj):
+        assert isinstance(w_obj, FloatObject)
+        return w_obj
 
     def float_w(self, w_obj):
-        assert isinstance(w_obj, float)
-        return w_obj
+        return w_obj.floatval
+
+
+class FloatObject(W_Root):
+    def __init__(self, floatval):
+        self.floatval = floatval
+
+class BoolObject(W_Root):
+    def __init__(self, boolval):
+        self.boolval = boolval
+
+class IntObject(W_Root):
+    def __init__(self, intval):
+        self.intval = intval
+
+
+space = FakeSpace()
 
 def numpy_compile(bytecode, array_size):
-    space = TrivialSpace()
     stack = []
     i = 0
+    dtype = space.fromcache(W_Float64Dtype)
     for b in bytecode:
         if b == 'a':
-            stack.append(create_array(array_size))
+            stack.append(create_array(dtype, array_size))
             i += 1
         elif b == 'f':
-            stack.append(FloatWrapper(1.2))
+            stack.append(Scalar(dtype, dtype.box(1.2)))
         elif b == '+':
             right = stack.pop()
-            stack.append(stack.pop().descr_add(space, right))
+            res = stack.pop().descr_add(space, right)
+            assert isinstance(res, BaseArray)
+            stack.append(res)
         elif b == '-':
             right = stack.pop()
-            stack.append(stack.pop().descr_sub(space, right))
+            res = stack.pop().descr_sub(space, right)
+            assert isinstance(res, BaseArray)
+            stack.append(res)
         elif b == '*':
             right = stack.pop()
-            stack.append(stack.pop().descr_mul(space, right))
+            res = stack.pop().descr_mul(space, right)
+            assert isinstance(res, BaseArray)
+            stack.append(res)
         elif b == '/':
             right = stack.pop()
-            stack.append(stack.pop().descr_div(space, right))
+            res = stack.pop().descr_div(space, right)
+            assert isinstance(res, BaseArray)
+            stack.append(res)
         elif b == '%':
             right = stack.pop()
-            stack.append(stack.pop().descr_mod(space, right))
+            res = stack.pop().descr_mod(space, right)
+            assert isinstance(res, BaseArray)
+            stack.append(res)
         elif b == '|':
-            stack.append(stack.pop().descr_abs(space))
+            res = stack.pop().descr_abs(space)
+            assert isinstance(res, BaseArray)
+            stack.append(res)
         else:
             print "Unknown opcode: %s" % b
             raise BogusBytecode()
diff --git a/pypy/module/micronumpy/interp_dtype.py b/pypy/module/micronumpy/interp_dtype.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/micronumpy/interp_dtype.py
@@ -0,0 +1,356 @@
+import functools
+import math
+
+from pypy.interpreter.baseobjspace import Wrappable
+from pypy.interpreter.error import OperationError
+from pypy.interpreter.gateway import interp2app
+from pypy.interpreter.typedef import TypeDef, interp_attrproperty, GetSetProperty
+from pypy.module.micronumpy import signature
+from pypy.objspace.std.floatobject import float2string
+from pypy.rlib import rfloat
+from pypy.rlib.rarithmetic import widen
+from pypy.rlib.objectmodel import specialize, enforceargs
+from pypy.rlib.unroll import unrolling_iterable
+from pypy.rpython.lltypesystem import lltype, rffi
+
+
+SIGNEDLTR = "i"
+BOOLLTR = "b"
+FLOATINGLTR = "f"
+
+class W_Dtype(Wrappable):
+    def __init__(self, space):
+        pass
+
+    def descr__new__(space, w_subtype, w_dtype):
+        if space.is_w(w_dtype, space.w_None):
+            return space.fromcache(W_Float64Dtype)
+        elif space.isinstance_w(w_dtype, space.w_str):
+            dtype = space.str_w(w_dtype)
+            for alias, dtype_class in dtypes_by_alias:
+                if alias == dtype:
+                    return space.fromcache(dtype_class)
+        elif isinstance(space.interpclass_w(w_dtype), W_Dtype):
+            return w_dtype
+        elif space.isinstance_w(w_dtype, space.w_type):
+            for typename, dtype_class in dtypes_by_apptype:
+                if space.is_w(getattr(space, "w_%s" % typename), w_dtype):
+                    return space.fromcache(dtype_class)
+        raise OperationError(space.w_TypeError, space.wrap("data type not understood"))
+
+    def descr_repr(self, space):
+        return space.wrap("dtype('%s')" % self.name)
+
+    def descr_str(self, space):
+        return space.wrap(self.name)
+
+    def descr_get_shape(self, space):
+        return space.newtuple([])
+
+
+class BaseBox(object):
+    pass
+
+VOID_TP = lltype.Ptr(lltype.Array(lltype.Void, hints={'nolength': True, "uncast_on_llgraph": True}))
+
+def create_low_level_dtype(num, kind, name, aliases, applevel_types, T, valtype):
+    class Box(BaseBox):
+        def __init__(self, val):
+            self.val = val
+
+        def wrap(self, space):
+            return space.wrap(self.val)
+
+        def convert_to(self, dtype):
+            return dtype.adapt_val(self.val)
+    Box.__name__ = "%sBox" % T._name
+
+    TP = lltype.Ptr(lltype.Array(T, hints={'nolength': True}))
+    class W_LowLevelDtype(W_Dtype):
+        signature = signature.BaseSignature()
+
+        def erase(self, storage):
+            return rffi.cast(VOID_TP, storage)
+
+        def unerase(self, storage):
+            return rffi.cast(TP, storage)
+
+        @enforceargs(None, valtype)
+        def box(self, value):
+            return Box(value)
+
+        def unbox(self, box):
+            assert isinstance(box, Box)
+            return box.val
+
+        def unwrap(self, space, w_item):
+            raise NotImplementedError
+
+        def malloc(self, size):
+            # XXX find out why test_zjit explodes with tracking of allocations
+            return self.erase(lltype.malloc(TP.TO, size,
+                zero=True, flavor="raw",
+                track_allocation=False, add_memory_pressure=True
+            ))
+
+        def getitem(self, storage, i):
+            return Box(self.unerase(storage)[i])
+
+        def setitem(self, storage, i, item):
+            self.unerase(storage)[i] = self.unbox(item)
+
+        def setitem_w(self, space, storage, i, w_item):
+            self.setitem(storage, i, self.unwrap(space, w_item))
+
+        @specialize.argtype(1)
+        def adapt_val(self, val):
+            return self.box(rffi.cast(TP.TO.OF, val))
+
+    W_LowLevelDtype.__name__ = "W_%sDtype" % name.capitalize()
+    W_LowLevelDtype.num = num
+    W_LowLevelDtype.kind = kind
+    W_LowLevelDtype.name = name
+    W_LowLevelDtype.aliases = aliases
+    W_LowLevelDtype.applevel_types = applevel_types
+    W_LowLevelDtype.num_bytes = rffi.sizeof(T)
+    return W_LowLevelDtype
+
+
+def binop(func):
+    @functools.wraps(func)
+    def impl(self, v1, v2):
+        return self.adapt_val(func(self,
+            self.for_computation(self.unbox(v1)),
+            self.for_computation(self.unbox(v2)),
+        ))
+    return impl
+
+def unaryop(func):
+    @functools.wraps(func)
+    def impl(self, v):
+        return self.adapt_val(func(self, self.for_computation(self.unbox(v))))
+    return impl
+
+class ArithmaticTypeMixin(object):
+    _mixin_ = True
+
+    @binop
+    def add(self, v1, v2):
+        return v1 + v2
+    @binop
+    def sub(self, v1, v2):
+        return v1 - v2
+    @binop
+    def mul(self, v1, v2):
+        return v1 * v2
+    @binop
+    def div(self, v1, v2):
+        return v1 / v2
+
+    @unaryop
+    def pos(self, v):
+        return +v
+    @unaryop
+    def neg(self, v):
+        return -v
+    @unaryop
+    def abs(self, v):
+        return abs(v)
+
+    @binop
+    def max(self, v1, v2):
+        return max(v1, v2)
+    @binop
+    def min(self, v1, v2):
+        return min(v1, v2)
+
+    def bool(self, v):
+        return bool(self.for_computation(self.unbox(v)))
+    def ne(self, v1, v2):
+        return self.for_computation(self.unbox(v1)) != self.for_computation(self.unbox(v2))
+
+
+class FloatArithmeticDtype(ArithmaticTypeMixin):
+    _mixin_ = True
+
+    def for_computation(self, v):
+        return v
+
+    @binop
+    def mod(self, v1, v2):
+        return math.fmod(v1, v2)
+    @binop
+    def pow(self, v1, v2):
+        return math.pow(v1, v2)
+
+    @unaryop
+    def sign(self, v):
+        if v == 0.0:
+            return 0.0
+        return rfloat.copysign(1.0, v)
+    @unaryop
+    def reciprocal(self, v):
+        if v == 0.0:
+            return rfloat.copysign(rfloat.INFINITY, v)
+        return 1.0 / v
+    @unaryop
+    def fabs(self, v):
+        return math.fabs(v)
+    @unaryop
+    def floor(self, v):
+        return math.floor(v)
+
+    @binop
+    def copysign(self, v1, v2):
+        return math.copysign(v1, v2)
+    @unaryop
+    def exp(self, v):
+        try:
+            return math.exp(v)
+        except OverflowError:
+            return rfloat.INFINITY
+    @unaryop
+    def sin(self, v):
+        return math.sin(v)
+    @unaryop
+    def cos(self, v):
+        return math.cos(v)
+    @unaryop
+    def tan(self, v):
+        return math.tan(v)
+    @unaryop
+    def arcsin(self, v):
+        if v < -1.0 or  v > 1.0:
+            return rfloat.NAN
+        return math.asin(v)
+    @unaryop
+    def arccos(self, v):
+        if v < -1.0 or v > 1.0:
+            return rfloat.NAN
+        return math.acos(v)
+    @unaryop
+    def arctan(self, v):
+        return math.atan(v)
+
+class IntegerArithmeticDtype(ArithmaticTypeMixin):
+    _mixin_ = True
+
+    def unwrap(self, space, w_item):
+        return self.adapt_val(space.int_w(space.int(w_item)))
+
+    def for_computation(self, v):
+        return widen(v)
+
+    @binop
+    def mod(self, v1, v2):
+        return v1 % v2
+
+    @unaryop
+    def sign(self, v):
+        if v > 0:
+            return 1
+        elif v < 0:
+            return -1
+        else:
+            assert v == 0
+            return 0
+
+    def str_format(self, item):
+        return str(widen(self.unbox(item)))
+
+W_BoolDtype = create_low_level_dtype(
+    num = 0, kind = BOOLLTR, name = "bool",
+    aliases = ["?"],
+    applevel_types = ["bool"],
+    T = lltype.Bool,
+    valtype = bool,
+)
+class W_BoolDtype(IntegerArithmeticDtype, W_BoolDtype):
+    def unwrap(self, space, w_item):
+        return self.adapt_val(space.is_true(w_item))
+
+    def str_format(self, item):
+        v = self.unbox(item)
+        return "True" if v else "False"
+
+    def for_computation(self, v):
+        return int(v)
+
+W_Int8Dtype = create_low_level_dtype(
+    num = 1, kind = SIGNEDLTR, name = "int8",
+    aliases = ["int8"],
+    applevel_types = [],
+    T = rffi.SIGNEDCHAR,
+    valtype = rffi.SIGNEDCHAR._type,
+)
+class W_Int8Dtype(IntegerArithmeticDtype, W_Int8Dtype):
+    def unwrap(self, space, w_item):
+        return self.adapt_val(space.int_w(space.int(w_item)))
+
+W_Int32Dtype = create_low_level_dtype(
+    num = 5, kind = SIGNEDLTR, name = "int32",
+    aliases = ["i"],
+    applevel_types = [],
+    T = rffi.INT,
+    valtype = rffi.INT._type,
+)
+class W_Int32Dtype(IntegerArithmeticDtype, W_Int32Dtype):
+    pass
+
+W_Int64Dtype = create_low_level_dtype(
+    num = 9, kind = SIGNEDLTR, name = "int64",
+    aliases = [],
+    applevel_types = ["long"],
+    T = rffi.LONGLONG,
+    valtype = rffi.LONGLONG._type,
+)
+class W_Int64Dtype(IntegerArithmeticDtype, W_Int64Dtype):
+    pass
+
+W_Float64Dtype = create_low_level_dtype(
+    num = 12, kind = FLOATINGLTR, name = "float64",
+    aliases = [],
+    applevel_types = ["float"],
+    T = lltype.Float,
+    valtype = float,
+)
+class W_Float64Dtype(FloatArithmeticDtype, W_Float64Dtype):
+    def unwrap(self, space, w_item):
+        return self.adapt_val(space.float_w(space.float(w_item)))
+
+    def str_format(self, item):
+        return float2string(self.unbox(item), 'g', rfloat.DTSF_STR_PRECISION)
+
+ALL_DTYPES = [
+    W_BoolDtype,
+    W_Int8Dtype, W_Int32Dtype, W_Int64Dtype,
+    W_Float64Dtype
+]
+
+dtypes_by_alias = unrolling_iterable([
+    (alias, dtype)
+    for dtype in ALL_DTYPES
+    for alias in dtype.aliases
+])
+dtypes_by_apptype = unrolling_iterable([
+    (apptype, dtype)
+    for dtype in ALL_DTYPES
+    for apptype in dtype.applevel_types
+])
+dtypes_by_num_bytes = unrolling_iterable(sorted([
+    (dtype.num_bytes, dtype)
+    for dtype in ALL_DTYPES
+]))
+
+W_Dtype.typedef = TypeDef("dtype",
+    __module__ = "numpy",
+    __new__ = interp2app(W_Dtype.descr__new__.im_func),
+
+    __repr__ = interp2app(W_Dtype.descr_repr),
+    __str__ = interp2app(W_Dtype.descr_str),
+
+    num = interp_attrproperty("num", cls=W_Dtype),
+    kind = interp_attrproperty("kind", cls=W_Dtype),
+    shape = GetSetProperty(W_Dtype.descr_get_shape),
+)
+W_Dtype.typedef.acceptable_as_base_class = False
\ No newline at end of file
diff --git a/pypy/module/micronumpy/interp_numarray.py b/pypy/module/micronumpy/interp_numarray.py
--- a/pypy/module/micronumpy/interp_numarray.py
+++ b/pypy/module/micronumpy/interp_numarray.py
@@ -1,38 +1,22 @@
 from pypy.interpreter.baseobjspace import Wrappable
-from pypy.interpreter.error import OperationError, operationerrfmt
+from pypy.interpreter.error import OperationError
 from pypy.interpreter.gateway import interp2app, unwrap_spec
 from pypy.interpreter.typedef import TypeDef, GetSetProperty
-from pypy.module.micronumpy.interp_support import Signature
-from pypy.module.micronumpy import interp_ufuncs
-from pypy.objspace.std.floatobject import float2string as float2string_orig
+from pypy.module.micronumpy import interp_ufuncs, interp_dtype, signature
 from pypy.rlib import jit
-from pypy.rlib.rfloat import DTSF_STR_PRECISION
 from pypy.rpython.lltypesystem import lltype
 from pypy.tool.sourcetools import func_with_new_name
-import math
 
-TP = lltype.Array(lltype.Float, hints={'nolength': True})
 
 numpy_driver = jit.JitDriver(greens = ['signature'],
                              reds = ['result_size', 'i', 'self', 'result'])
-all_driver = jit.JitDriver(greens=['signature'], reds=['i', 'size', 'self'])
-any_driver = jit.JitDriver(greens=['signature'], reds=['i', 'size', 'self'])
-slice_driver1 = jit.JitDriver(greens=['signature'], reds=['i', 'j', 'step', 'stop', 'source', 'dest'])
-slice_driver2 = jit.JitDriver(greens=['signature'], reds=['i', 'j', 'step', 'stop', 'source', 'dest'])
-
-def add(v1, v2):
-    return v1 + v2
-def mul(v1, v2):
-    return v1 * v2
-def maximum(v1, v2):
-    return max(v1, v2)
-def minimum(v1, v2):
-    return min(v1, v2)
-
-def float2string(x):
-    return float2string_orig(x, 'g', DTSF_STR_PRECISION)
+all_driver = jit.JitDriver(greens=['signature'], reds=['i', 'size', 'self', 'dtype'])
+any_driver = jit.JitDriver(greens=['signature'], reds=['i', 'size', 'self', 'dtype'])
+slice_driver = jit.JitDriver(greens=['signature'], reds=['i', 'j', 'step', 'stop', 'source', 'dest'])
 
 class BaseArray(Wrappable):
+    _attrs_ = ["invalidates", "signature"]
+
     def __init__(self):
         self.invalidates = []
 
@@ -45,93 +29,92 @@
             arr.force_if_needed()
         del self.invalidates[:]
 
-    def _unaryop_impl(w_ufunc):
+    def add_invalidates(self, other):
+        self.invalidates.append(other)
+
+    def descr__new__(space, w_subtype, w_size_or_iterable, w_dtype=None):
+        l = space.listview(w_size_or_iterable)
+        if space.is_w(w_dtype, space.w_None):
+            w_dtype = None
+            for w_item in l:
+                w_dtype = interp_ufuncs.find_dtype_for_scalar(space, w_item, w_dtype)
+                if w_dtype is space.fromcache(interp_dtype.W_Float64Dtype):
+                    break
+            if w_dtype is None:
+                w_dtype = space.w_None
+
+        dtype = space.interp_w(interp_dtype.W_Dtype,
+            space.call_function(space.gettypefor(interp_dtype.W_Dtype), w_dtype)
+        )
+        arr = SingleDimArray(len(l), dtype=dtype)
+        i = 0
+        for w_elem in l:
+            dtype.setitem_w(space, arr.storage, i, w_elem)
+            i += 1
+        return arr
+
+    def _unaryop_impl(ufunc_name):
         def impl(self, space):
-            return w_ufunc(space, self)
-        return func_with_new_name(impl, "unaryop_%s_impl" % w_ufunc.__name__)
+            return getattr(interp_ufuncs.get(space), ufunc_name).call(space, [self])
+        return func_with_new_name(impl, "unaryop_%s_impl" % ufunc_name)
 
-    descr_pos = _unaryop_impl(interp_ufuncs.positive)
-    descr_neg = _unaryop_impl(interp_ufuncs.negative)
-    descr_abs = _unaryop_impl(interp_ufuncs.absolute)
+    descr_pos = _unaryop_impl("positive")
+    descr_neg = _unaryop_impl("negative")
+    descr_abs = _unaryop_impl("absolute")
 
-    def _binop_impl(w_ufunc):
+    def _binop_impl(ufunc_name):
         def impl(self, space, w_other):
-            return w_ufunc(space, self, w_other)
-        return func_with_new_name(impl, "binop_%s_impl" % w_ufunc.__name__)
+            return getattr(interp_ufuncs.get(space), ufunc_name).call(space, [self, w_other])
+        return func_with_new_name(impl, "binop_%s_impl" % ufunc_name)
 
-    descr_add = _binop_impl(interp_ufuncs.add)
-    descr_sub = _binop_impl(interp_ufuncs.subtract)
-    descr_mul = _binop_impl(interp_ufuncs.multiply)
-    descr_div = _binop_impl(interp_ufuncs.divide)
-    descr_pow = _binop_impl(interp_ufuncs.power)
-    descr_mod = _binop_impl(interp_ufuncs.mod)
+    descr_add = _binop_impl("add")
+    descr_sub = _binop_impl("subtract")
+    descr_mul = _binop_impl("multiply")
+    descr_div = _binop_impl("divide")
+    descr_pow = _binop_impl("power")
+    descr_mod = _binop_impl("mod")
 
-    def _binop_right_impl(w_ufunc):
+    def _binop_right_impl(ufunc_name):
         def impl(self, space, w_other):
-            w_other = FloatWrapper(space.float_w(w_other))
-            return w_ufunc(space, w_other, self)
-        return func_with_new_name(impl, "binop_right_%s_impl" % w_ufunc.__name__)
+            w_other = scalar_w(space,
+                interp_ufuncs.find_dtype_for_scalar(space, w_other, self.find_dtype()),
+                w_other
+            )
+            return getattr(interp_ufuncs.get(space), ufunc_name).call(space, [w_other, self])
+        return func_with_new_name(impl, "binop_right_%s_impl" % ufunc_name)
 
-    descr_radd = _binop_right_impl(interp_ufuncs.add)
-    descr_rsub = _binop_right_impl(interp_ufuncs.subtract)
-    descr_rmul = _binop_right_impl(interp_ufuncs.multiply)
-    descr_rdiv = _binop_right_impl(interp_ufuncs.divide)
-    descr_rpow = _binop_right_impl(interp_ufuncs.power)
-    descr_rmod = _binop_right_impl(interp_ufuncs.mod)
+    descr_radd = _binop_right_impl("add")
+    descr_rsub = _binop_right_impl("subtract")
+    descr_rmul = _binop_right_impl("multiply")
+    descr_rdiv = _binop_right_impl("divide")
+    descr_rpow = _binop_right_impl("power")
+    descr_rmod = _binop_right_impl("mod")
 
-    def _reduce_sum_prod_impl(function, init):
+    def _reduce_ufunc_impl(ufunc_name):
+        def impl(self, space):
+            return getattr(interp_ufuncs.get(space), ufunc_name).descr_reduce(space, self)
+        return func_with_new_name(impl, "reduce_%s_impl" % ufunc_name)
+
+    descr_sum = _reduce_ufunc_impl("add")
+    descr_prod = _reduce_ufunc_impl("multiply")
+    descr_max = _reduce_ufunc_impl("maximum")
+    descr_min = _reduce_ufunc_impl("minimum")
+
+    def _reduce_argmax_argmin_impl(op_name):
         reduce_driver = jit.JitDriver(greens=['signature'],
-                         reds = ['i', 'size', 'self', 'result'])
-
-        def loop(self, result, size):
-            i = 0
-            while i < size:
-                reduce_driver.jit_merge_point(signature=self.signature,
-                                              self=self, size=size, i=i,
-                                              result=result)
-                result = function(result, self.eval(i))
-                i += 1
-            return result
-
-        def impl(self, space):
-            return space.wrap(loop(self, init, self.find_size()))
-        return func_with_new_name(impl, "reduce_%s_impl" % function.__name__)
-
-    def _reduce_max_min_impl(function):
-        reduce_driver = jit.JitDriver(greens=['signature'],
-                         reds = ['i', 'size', 'self', 'result'])
-        def loop(self, result, size):
-            i = 1
-            while i < size:
-                reduce_driver.jit_merge_point(signature=self.signature,
-                                              self=self, size=size, i=i,
-                                              result=result)
-                result = function(result, self.eval(i))
-                i += 1
-            return result
-
-        def impl(self, space):
-            size = self.find_size()
-            if size == 0:
-                raise OperationError(space.w_ValueError,
-                    space.wrap("Can't call %s on zero-size arrays" \
-                            % function.__name__))
-            return space.wrap(loop(self, self.eval(0), size))
-        return func_with_new_name(impl, "reduce_%s_impl" % function.__name__)
-
-    def _reduce_argmax_argmin_impl(function):
-        reduce_driver = jit.JitDriver(greens=['signature'],
-                         reds = ['i', 'size', 'result', 'self', 'cur_best'])
+                         reds = ['i', 'size', 'result', 'self', 'cur_best', 'dtype'])
         def loop(self, size):
             result = 0
             cur_best = self.eval(0)
             i = 1
+            dtype = self.find_dtype()
             while i < size:
                 reduce_driver.jit_merge_point(signature=self.signature,
-                                              self=self, size=size, i=i,
-                                              result=result, cur_best=cur_best)
-                new_best = function(cur_best, self.eval(i))
-                if new_best != cur_best:
+                                              self=self, dtype=dtype,
+                                              size=size, i=i, result=result,
+                                              cur_best=cur_best)
+                new_best = getattr(dtype, op_name)(cur_best, self.eval(i))
+                if dtype.ne(new_best, cur_best):
                     result = i
                     cur_best = new_best
                 i += 1
@@ -141,16 +124,17 @@
             if size == 0:
                 raise OperationError(space.w_ValueError,
                     space.wrap("Can't call %s on zero-size arrays" \
-                            % function.__name__))
+                            % op_name))
             return space.wrap(loop(self, size))
-        return func_with_new_name(impl, "reduce_arg%s_impl" % function.__name__)
+        return func_with_new_name(impl, "reduce_arg%s_impl" % op_name)
 
     def _all(self):
         size = self.find_size()
+        dtype = self.find_dtype()
         i = 0
         while i < size:
-            all_driver.jit_merge_point(signature=self.signature, self=self, size=size, i=i)
-            if not self.eval(i):
+            all_driver.jit_merge_point(signature=self.signature, self=self, dtype=dtype, size=size, i=i)
+            if not dtype.bool(self.eval(i)):
                 return False
             i += 1
         return True
@@ -159,77 +143,44 @@
 
     def _any(self):
         size = self.find_size()
+        dtype = self.find_dtype()
         i = 0
         while i < size:
-            any_driver.jit_merge_point(signature=self.signature, self=self, size=size, i=i)
-            if self.eval(i):
+            any_driver.jit_merge_point(signature=self.signature, self=self, size=size, dtype=dtype, i=i)
+            if dtype.bool(self.eval(i)):
                 return True
             i += 1
         return False
     def descr_any(self, space):
         return space.wrap(self._any())
 
-    descr_sum = _reduce_sum_prod_impl(add, 0.0)
-    descr_prod = _reduce_sum_prod_impl(mul, 1.0)
-    descr_max = _reduce_max_min_impl(maximum)
-    descr_min = _reduce_max_min_impl(minimum)
-    descr_argmax = _reduce_argmax_argmin_impl(maximum)
-    descr_argmin = _reduce_argmax_argmin_impl(minimum)
-
-    def descr_sort(self, space):
-        size = self.find_size()
-        stack = [(0,size-1)]
-        first=0; last=size-1; splitpoint=first;
-        while (len(stack) > 0):
-            first, last = stack.pop()
-            while last>first:
-                #splitpoint = split(first,last)
-                x = self.eval(first)
-                splitpoint = first
-                unknown = first+1
-                while (unknown<=last):
-                    if (self.eval(unknown)<x):
-                        splitpoint = splitpoint + 1
-                        #interchange(splitpoint,unknown)
-                        temp = self.eval(splitpoint)
-                        self.storage[splitpoint] = self.eval(unknown)
-                        self.storage[unknown] = temp
-                    unknown = unknown + 1
-                #interchange(first,splitpoint)
-                temp = self.eval(splitpoint)
-                self.storage[splitpoint] = self.eval(first)
-                self.storage[first] = temp
-
-                if (last-splitpoint<splitpoint-first):
-                    stack.append((first,splitpoint-1));
-                    first = splitpoint + 1
-                else:
-                    stack.append((splitpoint+1,last));
-                    last = splitpoint - 1
-
+    descr_argmax = _reduce_argmax_argmin_impl("max")
+    descr_argmin = _reduce_argmax_argmin_impl("min")
 
     def descr_dot(self, space, w_other):
-        if isinstance(w_other, BaseArray):
+        w_other = convert_to_array(space, w_other)
+        if isinstance(w_other, Scalar):
+            return self.descr_mul(space, w_other)
+        else:
             w_res = self.descr_mul(space, w_other)
             assert isinstance(w_res, BaseArray)
             return w_res.descr_sum(space)
-        else:
-            return self.descr_mul(space, w_other)
 
     def _getnums(self, comma):
+        dtype = self.find_dtype()
         if self.find_size() > 1000:
             nums = [
-                float2string(self.eval(index))
+                dtype.str_format(self.eval(index))
                 for index in range(3)
             ]
             nums.append("..." + "," * comma)
             nums.extend([
-                float2string(self.eval(index))
+                dtype.str_format(self.eval(index))
                 for index in range(self.find_size() - 3, self.find_size())
             ])
         else:
             nums = [
-                float2string(self.eval(index))
+                dtype.str_format(self.eval(index))
                 for index in range(self.find_size())
             ]
         return nums
@@ -237,19 +188,28 @@
     def get_concrete(self):
         raise NotImplementedError
 
-    def descr_copy(self, space):
-        return new_numarray(space, self)
+    def descr_get_dtype(self, space):
+        return space.wrap(self.find_dtype())
 
     def descr_get_shape(self, space):
         return space.newtuple([self.descr_len(space)])
 
+    def descr_copy(self, space):
+        return space.call_function(space.gettypefor(BaseArray), self, self.find_dtype())
+
     def descr_len(self, space):
         return self.get_concrete().descr_len(space)
 
     def descr_repr(self, space):
         # Simple implementation so that we can see the array. Needs work.
         concrete = self.get_concrete()
-        return space.wrap("array([" + ", ".join(concrete._getnums(False)) + "])")
+        res = "array([" + ", ".join(concrete._getnums(False)) + "]"
+        dtype = concrete.find_dtype()
+        if (dtype is not space.fromcache(interp_dtype.W_Float64Dtype) and
+            dtype is not space.fromcache(interp_dtype.W_Int64Dtype)):
+            res += ", dtype=" + dtype.name
+        res += ")"
+        return space.wrap(res)
 
     def descr_str(self, space):
         # Simple implementation so that we can see the array. Needs work.
@@ -261,10 +221,13 @@
         start, stop, step, slice_length = space.decode_index4(w_idx, self.find_size())
         if step == 0:
             # Single index
-            return space.wrap(self.get_concrete().eval(start))
+            return self.get_concrete().eval(start).wrap(space)
         else:
             # Slice
-            res = SingleDimSlice(start, stop, step, slice_length, self, self.signature.transition(SingleDimSlice.static_signature))
+            new_sig = signature.Signature.find_sig([
+                SingleDimSlice.signature, self.signature
+            ])
+            res = SingleDimSlice(start, stop, step, slice_length, self, new_sig)
             return space.wrap(res)
 
     def descr_setitem(self, space, w_idx, w_value):
@@ -274,79 +237,82 @@
                                                               self.find_size())
         if step == 0:
             # Single index
-            self.get_concrete().setitem(start, space.float_w(w_value))
+            self.get_concrete().setitem_w(space, start, w_value)
         else:
             concrete = self.get_concrete()
             if isinstance(w_value, BaseArray):
-                # for now we just copy if setting part of an array from 
+                # for now we just copy if setting part of an array from
                 # part of itself. can be improved.
                 if (concrete.get_root_storage() ==
                     w_value.get_concrete().get_root_storage()):
-                    w_value = new_numarray(space, w_value)
+                    w_value = space.call_function(space.gettypefor(BaseArray), w_value)
+                    assert isinstance(w_value, BaseArray)
             else:
                 w_value = convert_to_array(space, w_value)
-            concrete.setslice(space, start, stop, step, 
+            concrete.setslice(space, start, stop, step,
                                                slice_length, w_value)
 
     def descr_mean(self, space):
         return space.wrap(space.float_w(self.descr_sum(space))/self.find_size())
 
-    def _sliceloop1(self, start, stop, step, source, dest):
+    def _sliceloop(self, start, stop, step, source, dest):
         i = start
         j = 0
-        while i < stop:
-            slice_driver1.jit_merge_point(signature=source.signature,
-                    step=step, stop=stop, i=i, j=j, source=source,
-                    dest=dest)
-            dest.storage[i] = source.eval(j)
+        while (step > 0 and i < stop) or (step < 0 and i > stop):
+            slice_driver.jit_merge_point(signature=source.signature, step=step,
+                                         stop=stop, i=i, j=j, source=source,
+                                         dest=dest)
+            dest.setitem(i, source.eval(j).convert_to(dest.find_dtype()))
             j += 1
             i += step
 
-    def _sliceloop2(self, start, stop, step, source, dest):
-        i = start
-        j = 0
-        while i > stop:
-            slice_driver2.jit_merge_point(signature=source.signature,
-                    step=step, stop=stop, i=i, j=j, source=source,
-                    dest=dest)
-            dest.storage[i] = source.eval(j)
-            j += 1
-            i += step
-
-def convert_to_array (space, w_obj):
+def convert_to_array(space, w_obj):
     if isinstance(w_obj, BaseArray):
         return w_obj
     elif space.issequence_w(w_obj):
         # Convert to array.
-        return new_numarray(space, w_obj)
+        w_obj = space.call_function(space.gettypefor(BaseArray), w_obj)
+        assert isinstance(w_obj, BaseArray)
+        return w_obj
     else:
         # If it's a scalar
-        return FloatWrapper(space.float_w(w_obj))
+        dtype = interp_ufuncs.find_dtype_for_scalar(space, w_obj)
+        return scalar_w(space, dtype, w_obj)
 
-class FloatWrapper(BaseArray):
+def scalar_w(space, dtype, w_obj):
+    return Scalar(dtype, dtype.unwrap(space, w_obj))
+
+class Scalar(BaseArray):
     """
     Intermediate class representing a float literal.
     """
-    signature = Signature()
+    signature = signature.BaseSignature()
 
-    def __init__(self, float_value):
+    _attrs_ = ["dtype", "value"]
+
+    def __init__(self, dtype, value):
         BaseArray.__init__(self)
-        self.float_value = float_value
+        self.dtype = dtype
+        self.value = value
 
     def find_size(self):
         raise ValueError
 
+    def find_dtype(self):
+        return self.dtype
+
     def eval(self, i):
-        return self.float_value
+        return self.value
 
 class VirtualArray(BaseArray):
     """
     Class for representing virtual arrays, such as binary ops or ufuncs
     """
-    def __init__(self, signature):
+    def __init__(self, signature, res_dtype):
         BaseArray.__init__(self)
         self.forced_result = None
         self.signature = signature
+        self.res_dtype = res_dtype
 
     def _del_sources(self):
         # Function for deleting references to source arrays, to allow garbage-collecting them
@@ -356,12 +322,12 @@
         i = 0
         signature = self.signature
         result_size = self.find_size()
-        result = SingleDimArray(result_size)
+        result = SingleDimArray(result_size, self.find_dtype())
         while i < result_size:
             numpy_driver.jit_merge_point(signature=signature,
                                          result_size=result_size, i=i,
                                          self=self, result=result)
-            result.storage[i] = self.eval(i)
+            result.dtype.setitem(result.storage, i, self.eval(i))
             i += 1
         return result
 
@@ -379,17 +345,22 @@
             return self.forced_result.eval(i)
         return self._eval(i)
 
+    def setitem(self, item, value):
+        return self.get_concrete().setitem(item, value)
+
     def find_size(self):
         if self.forced_result is not None:
             # The result has been computed and sources may be unavailable
             return self.forced_result.find_size()
         return self._find_size()
 
+    def find_dtype(self):
+        return self.res_dtype
+
 
 class Call1(VirtualArray):
-    def __init__(self, function, values, signature):
-        VirtualArray.__init__(self, signature)
-        self.function = function
+    def __init__(self, signature, res_dtype, values):
+        VirtualArray.__init__(self, signature, res_dtype)
         self.values = values
 
     def _del_sources(self):
@@ -398,16 +369,24 @@
     def _find_size(self):
         return self.values.find_size()
 
+    def _find_dtype(self):
+        return self.res_dtype
+
     def _eval(self, i):
-        return self.function(self.values.eval(i))
+        val = self.values.eval(i).convert_to(self.res_dtype)
+
+        sig = jit.promote(self.signature)
+        assert isinstance(sig, signature.Signature)
+        call_sig = sig.components[0]
+        assert isinstance(call_sig, signature.Call1)
+        return call_sig.func(self.res_dtype, val)
 
 class Call2(VirtualArray):
     """
     Intermediate class for performing binary operations.
     """
-    def __init__(self, function, left, right, signature):
-        VirtualArray.__init__(self, signature)
-        self.function = function
+    def __init__(self, signature, res_dtype, left, right):
+        VirtualArray.__init__(self, signature, res_dtype)
         self.left = left
         self.right = right
 
@@ -423,8 +402,14 @@
         return self.right.find_size()
 
     def _eval(self, i):
-        lhs, rhs = self.left.eval(i), self.right.eval(i)
-        return self.function(lhs, rhs)
+        lhs = self.left.eval(i).convert_to(self.res_dtype)
+        rhs = self.right.eval(i).convert_to(self.res_dtype)
+
+        sig = jit.promote(self.signature)
+        assert isinstance(sig, signature.Signature)
+        call_sig = sig.components[0]
+        assert isinstance(call_sig, signature.Call2)
+        return call_sig.func(self.res_dtype, lhs, rhs)
 
 class ViewArray(BaseArray):
     """
@@ -447,9 +432,13 @@
     def eval(self, i):
         return self.parent.eval(self.calc_index(i))
 
-    @unwrap_spec(item=int, value=float)
+    @unwrap_spec(item=int)
+    def setitem_w(self, space, item, w_value):
+        return self.parent.setitem_w(space, self.calc_index(item), w_value)
+
     def setitem(self, item, value):
-        return self.parent.setitem(self.calc_index(item), value)
+        # This is currently not possible to be called from anywhere.
+        raise NotImplementedError
 
     def descr_len(self, space):
         return space.wrap(self.find_size())
@@ -458,7 +447,7 @@
         raise NotImplementedError
 
 class SingleDimSlice(ViewArray):
-    static_signature = Signature()
+    signature = signature.BaseSignature()
 
     def __init__(self, start, stop, step, slice_length, parent, signature):
         ViewArray.__init__(self, parent, signature)
@@ -475,35 +464,32 @@
         self.size = slice_length
 
     def get_root_storage(self):
-        return self.parent.storage
+        return self.parent.get_concrete().get_root_storage()
 
     def find_size(self):
         return self.size
 
+    def find_dtype(self):
+        return self.parent.find_dtype()
+
     def setslice(self, space, start, stop, step, slice_length, arr):
         start = self.calc_index(start)
         if stop != -1:
             stop = self.calc_index(stop)
         step = self.step * step
-        if step > 0:
-            self._sliceloop1(start, stop, step, arr, self.parent)
-        else:
-            self._sliceloop2(start, stop, step, arr, self.parent)
+        self._sliceloop(start, stop, step, arr, self.parent)
 
     def calc_index(self, item):
         return (self.start + item * self.step)
 
 
 class SingleDimArray(BaseArray):
-    signature = Signature()
-
-    def __init__(self, size):
+    def __init__(self, size, dtype):
         BaseArray.__init__(self)
         self.size = size
-        self.storage = lltype.malloc(TP, size, zero=True,
-                                     flavor='raw', track_allocation=False,
-                                     add_memory_pressure=True)
-        # XXX find out why test_zjit explodes with trackign of allocations
+        self.dtype = dtype
+        self.storage = dtype.malloc(size)
+        self.signature = dtype.signature
 
     def get_concrete(self):
         return self
@@ -514,54 +500,52 @@
     def find_size(self):
         return self.size
 
+    def find_dtype(self):
+        return self.dtype
+
     def eval(self, i):
-        return self.storage[i]
+        return self.dtype.getitem(self.storage, i)
 
     def descr_len(self, space):
         return space.wrap(self.size)
 
+    def setitem_w(self, space, item, w_value):
+        self.invalidated()
+        self.dtype.setitem_w(space, self.storage, item, w_value)
+
     def setitem(self, item, value):
         self.invalidated()
-        self.storage[item] = value
+        self.dtype.setitem(self.storage, item, value)
 
     def setslice(self, space, start, stop, step, slice_length, arr):
-        if step > 0:
-            self._sliceloop1(start, stop, step, arr, self)
-        else:
-            self._sliceloop2(start, stop, step, arr, self)
+        self._sliceloop(start, stop, step, arr, self)
 
     def __del__(self):
         lltype.free(self.storage, flavor='raw', track_allocation=False)
 
-def new_numarray(space, w_size_or_iterable):
-    l = space.listview(w_size_or_iterable)
-    arr = SingleDimArray(len(l))
-    i = 0
-    for w_elem in l:
-        arr.storage[i] = space.float_w(space.float(w_elem))
-        i += 1
-    return arr
-
-def descr_new_numarray(space, w_type, w_size_or_iterable):
-    return space.wrap(new_numarray(space, w_size_or_iterable))
+ at unwrap_spec(size=int)
+def zeros(space, size, w_dtype=None):
+    dtype = space.interp_w(interp_dtype.W_Dtype,
+        space.call_function(space.gettypefor(interp_dtype.W_Dtype), w_dtype)
+    )
+    return space.wrap(SingleDimArray(size, dtype=dtype))
 
 @unwrap_spec(size=int)
-def zeros(space, size):
-    return space.wrap(SingleDimArray(size))
+def ones(space, size, w_dtype=None):
+    dtype = space.interp_w(interp_dtype.W_Dtype,
+        space.call_function(space.gettypefor(interp_dtype.W_Dtype), w_dtype)
+    )
 
- at unwrap_spec(size=int)
-def ones(space, size):
-    arr = SingleDimArray(size)
+    arr = SingleDimArray(size, dtype=dtype)
+    one = dtype.adapt_val(1)
     for i in xrange(size):
-        arr.storage[i] = 1.0
+        arr.dtype.setitem(arr.storage, i, one)
     return space.wrap(arr)
 
 BaseArray.typedef = TypeDef(
     'numarray',
-    __new__ = interp2app(descr_new_numarray),
+    __new__ = interp2app(BaseArray.descr__new__.im_func),
 
-    copy = interp2app(BaseArray.descr_copy),
-    shape = GetSetProperty(BaseArray.descr_get_shape),
 
     __len__ = interp2app(BaseArray.descr_len),
     __getitem__ = interp2app(BaseArray.descr_getitem),
@@ -585,6 +569,9 @@
     __repr__ = interp2app(BaseArray.descr_repr),
     __str__ = interp2app(BaseArray.descr_str),
 
+    dtype = GetSetProperty(BaseArray.descr_get_dtype),
+    shape = GetSetProperty(BaseArray.descr_get_shape),
+
     mean = interp2app(BaseArray.descr_mean),
     sum = interp2app(BaseArray.descr_sum),
     prod = interp2app(BaseArray.descr_prod),
@@ -595,5 +582,6 @@
     all = interp2app(BaseArray.descr_all),
     any = interp2app(BaseArray.descr_any),
     dot = interp2app(BaseArray.descr_dot),
-    sort = interp2app(BaseArray.descr_sort),
+
+    copy = interp2app(BaseArray.descr_copy),
 )
diff --git a/pypy/module/micronumpy/interp_support.py b/pypy/module/micronumpy/interp_support.py
--- a/pypy/module/micronumpy/interp_support.py
+++ b/pypy/module/micronumpy/interp_support.py
@@ -1,7 +1,8 @@
+from pypy.interpreter.error import OperationError
+from pypy.interpreter.gateway import unwrap_spec
+from pypy.module.micronumpy.interp_dtype import W_Float64Dtype
 from pypy.rlib.rstruct.runpack import runpack
 from pypy.rpython.lltypesystem import lltype, rffi
-from pypy.interpreter.error import OperationError
-from pypy.interpreter.gateway import unwrap_spec
 
 
 FLOAT_SIZE = rffi.sizeof(lltype.Float)
@@ -17,26 +18,17 @@
         raise OperationError(space.w_ValueError, space.wrap(
             "string length %d not divisable by %d" % (length, FLOAT_SIZE)))
 
-    a = SingleDimArray(number)
+    dtype = space.fromcache(W_Float64Dtype)
+    a = SingleDimArray(number, dtype=dtype)
 
     start = 0
     end = FLOAT_SIZE
     i = 0
     while i < number:
         part = s[start:end]
-        a.storage[i] = runpack('d', part)
+        a.dtype.setitem(a.storage, i, dtype.box(runpack('d', part)))
         i += 1
         start += FLOAT_SIZE
         end += FLOAT_SIZE
 
-    return space.wrap(a)
-
-class Signature(object):
-    def __init__(self):
-        self.transitions = {}
-
-    def transition(self, target):
-        if target in self.transitions:
-            return self.transitions[target]
-        self.transitions[target] = new = Signature()
-        return new
\ No newline at end of file
+    return space.wrap(a)
\ No newline at end of file
diff --git a/pypy/module/micronumpy/interp_ufuncs.py b/pypy/module/micronumpy/interp_ufuncs.py
--- a/pypy/module/micronumpy/interp_ufuncs.py
+++ b/pypy/module/micronumpy/interp_ufuncs.py
@@ -1,139 +1,273 @@
-import math
-
-from pypy.module.micronumpy.interp_support import Signature
-from pypy.rlib import rfloat
+from pypy.interpreter.baseobjspace import Wrappable
+from pypy.interpreter.error import OperationError, operationerrfmt
+from pypy.interpreter.gateway import interp2app
+from pypy.interpreter.typedef import TypeDef, GetSetProperty, interp_attrproperty
+from pypy.module.micronumpy import interp_dtype, signature
+from pypy.rlib import jit
 from pypy.tool.sourcetools import func_with_new_name
 
-def ufunc(func):
-    signature = Signature()
-    def impl(space, w_obj):
-        from pypy.module.micronumpy.interp_numarray import Call1, convert_to_array
-        if space.issequence_w(w_obj):
-            w_obj_arr = convert_to_array(space, w_obj)
-            w_res = Call1(func, w_obj_arr, w_obj_arr.signature.transition(signature))
-            w_obj_arr.invalidates.append(w_res)
-            return w_res
+
+reduce_driver = jit.JitDriver(
+    greens = ["signature"],
+    reds = ["i", "size", "self", "dtype", "value", "obj"]
+)
+
+class W_Ufunc(Wrappable):
+    _attrs_ = ["name", "promote_to_float", "promote_bools", "identity"]
+
+    def __init__(self, name, promote_to_float, promote_bools, identity):
+        self.name = name
+        self.promote_to_float = promote_to_float
+        self.promote_bools = promote_bools
+
+        self.identity = identity
+
+    def descr_repr(self, space):
+        return space.wrap("<ufunc '%s'>" % self.name)
+
+    def descr_get_identity(self, space):
+        if self.identity is None:
+            return space.w_None
+        return self.identity.wrap(space)
+
+    def descr_call(self, space, __args__):
+        try:
+            args_w = __args__.fixedunpack(self.argcount)
+        except ValueError, e:
+            raise OperationError(space.w_TypeError, space.wrap(str(e)))
+        return self.call(space, args_w)
+
+    def descr_reduce(self, space, w_obj):
+        from pypy.module.micronumpy.interp_numarray import convert_to_array, Scalar
+
+        if self.argcount != 2:
+            raise OperationError(space.w_ValueError, space.wrap("reduce only "
+                "supported for binary functions"))
+
+        assert isinstance(self, W_Ufunc2)
+        obj = convert_to_array(space, w_obj)
+        if isinstance(obj, Scalar):
+            raise OperationError(space.w_TypeError, space.wrap("cannot reduce "
+                "on a scalar"))
+
+        size = obj.find_size()
+        dtype = find_unaryop_result_dtype(
+            space, obj.find_dtype(),
+            promote_to_largest=True
+        )
+        start = 0
+        if self.identity is None:
+            if size == 0:
+                raise operationerrfmt(space.w_ValueError, "zero-size array to "
+                    "%s.reduce without identity", self.name)
+            value = obj.eval(0).convert_to(dtype)
+            start += 1
         else:
-            return space.wrap(func(space.float_w(w_obj)))
-    return func_with_new_name(impl, "%s_dispatcher" % func.__name__)
+            value = self.identity.convert_to(dtype)
+        new_sig = signature.Signature.find_sig([
+            self.reduce_signature, obj.signature
+        ])
+        return self.reduce(new_sig, start, value, obj, dtype, size).wrap(space)
 
-def ufunc2(func):
-    signature = Signature()
-    def impl(space, w_lhs, w_rhs):
-        from pypy.module.micronumpy.interp_numarray import Call2, convert_to_array
-        if space.issequence_w(w_lhs) or space.issequence_w(w_rhs):
-            w_lhs_arr = convert_to_array(space, w_lhs)
-            w_rhs_arr = convert_to_array(space, w_rhs)
-            new_sig = w_lhs_arr.signature.transition(signature).transition(w_rhs_arr.signature)
-            w_res = Call2(func, w_lhs_arr, w_rhs_arr, new_sig)
-            w_lhs_arr.invalidates.append(w_res)
-            w_rhs_arr.invalidates.append(w_res)
-            return w_res
+    def reduce(self, signature, start, value, obj, dtype, size):
+        i = start
+        while i < size:
+            reduce_driver.jit_merge_point(signature=signature, self=self,
+                                          value=value, obj=obj, i=i,
+                                          dtype=dtype, size=size)
+            value = self.func(dtype, value, obj.eval(i).convert_to(dtype))
+            i += 1
+        return value
+
+class W_Ufunc1(W_Ufunc):
+    argcount = 1
+
+    def __init__(self, func, name, promote_to_float=False, promote_bools=False,
+        identity=None):
+
+        W_Ufunc.__init__(self, name, promote_to_float, promote_bools, identity)
+        self.func = func
+        self.signature = signature.Call1(func)
+
+    def call(self, space, args_w):
+        from pypy.module.micronumpy.interp_numarray import (Call1,
+            convert_to_array, Scalar)
+
+        [w_obj] = args_w
+        w_obj = convert_to_array(space, w_obj)
+        res_dtype = find_unaryop_result_dtype(space,
+            w_obj.find_dtype(),
+            promote_to_float=self.promote_to_float,
+            promote_bools=self.promote_bools,
+        )
+        if isinstance(w_obj, Scalar):
+            return self.func(res_dtype, w_obj.value.convert_to(res_dtype)).wrap(space)
+
+        new_sig = signature.Signature.find_sig([self.signature, w_obj.signature])
+        w_res = Call1(new_sig, res_dtype, w_obj)
+        w_obj.add_invalidates(w_res)
+        return w_res
+
+
+class W_Ufunc2(W_Ufunc):
+    argcount = 2
+
+    def __init__(self, func, name, promote_to_float=False, promote_bools=False,
+        identity=None):
+
+        W_Ufunc.__init__(self, name, promote_to_float, promote_bools, identity)
+        self.func = func
+        self.signature = signature.Call2(func)
+        self.reduce_signature = signature.BaseSignature()
+
+    def call(self, space, args_w):
+        from pypy.module.micronumpy.interp_numarray import (Call2,
+            convert_to_array, Scalar)
+
+        [w_lhs, w_rhs] = args_w
+        w_lhs = convert_to_array(space, w_lhs)
+        w_rhs = convert_to_array(space, w_rhs)
+        res_dtype = find_binop_result_dtype(space,
+            w_lhs.find_dtype(), w_rhs.find_dtype(),
+            promote_to_float=self.promote_to_float,
+            promote_bools=self.promote_bools,
+        )
+        if isinstance(w_lhs, Scalar) and isinstance(w_rhs, Scalar):
+            return self.func(res_dtype, w_lhs.value, w_rhs.value).wrap(space)
+
+        new_sig = signature.Signature.find_sig([
+            self.signature, w_lhs.signature, w_rhs.signature
+        ])
+        w_res = Call2(new_sig, res_dtype, w_lhs, w_rhs)
+        w_lhs.add_invalidates(w_res)
+        w_rhs.add_invalidates(w_res)
+        return w_res
+
+
+W_Ufunc.typedef = TypeDef("ufunc",
+    __module__ = "numpy",
+
+    __call__ = interp2app(W_Ufunc.descr_call),
+    __repr__ = interp2app(W_Ufunc.descr_repr),
+
+    identity = GetSetProperty(W_Ufunc.descr_get_identity),
+    nin = interp_attrproperty("argcount", cls=W_Ufunc),
+
+    reduce = interp2app(W_Ufunc.descr_reduce),
+)
+
+def find_binop_result_dtype(space, dt1, dt2, promote_to_float=False,
+    promote_bools=False):
+    # dt1.num should be <= dt2.num
+    if dt1.num > dt2.num:
+        dt1, dt2 = dt2, dt1
+    # Some operations promote op(bool, bool) to return int8, rather than bool
+    if promote_bools and (dt1.kind == dt2.kind == interp_dtype.BOOLLTR):
+        return space.fromcache(interp_dtype.W_Int8Dtype)
+    if promote_to_float:
+        return find_unaryop_result_dtype(space, dt2, promote_to_float=True)
+    # If they're the same kind, choose the greater one.
+    if dt1.kind == dt2.kind:
+        return dt2
+
+    # Everything promotes to float, and bool promotes to everything.
+    if dt2.kind == interp_dtype.FLOATINGLTR or dt1.kind == interp_dtype.BOOLLTR:
+        return dt2
+
+    assert False
+
+def find_unaryop_result_dtype(space, dt, promote_to_float=False,
+    promote_bools=False, promote_to_largest=False):
+    if promote_bools and (dt.kind == interp_dtype.BOOLLTR):
+        return space.fromcache(interp_dtype.W_Int8Dtype)
+    if promote_to_float:
+        for bytes, dtype in interp_dtype.dtypes_by_num_bytes:
+            if dtype.kind == interp_dtype.FLOATINGLTR and dtype.num_bytes >= dt.num_bytes:
+                return space.fromcache(dtype)
+    if promote_to_largest:
+        if dt.kind == interp_dtype.BOOLLTR or dt.kind == interp_dtype.SIGNEDLTR:
+            return space.fromcache(interp_dtype.W_Int64Dtype)
+        elif dt.kind == interp_dtype.FLOATINGLTR:
+            return space.fromcache(interp_dtype.W_Float64Dtype)
         else:
-            return space.wrap(func(space.float_w(w_lhs), space.float_w(w_rhs)))
-    return func_with_new_name(impl, "%s_dispatcher" % func.__name__)
+            assert False
+    return dt
 
- at ufunc
-def absolute(value):
-    return abs(value)
+def find_dtype_for_scalar(space, w_obj, current_guess=None):
+    w_type = space.type(w_obj)
 
- at ufunc2
-def add(lvalue, rvalue):
-    return lvalue + rvalue
+    bool_dtype = space.fromcache(interp_dtype.W_BoolDtype)
+    int64_dtype = space.fromcache(interp_dtype.W_Int64Dtype)
 
- at ufunc2
-def copysign(lvalue, rvalue):
-    return rfloat.copysign(lvalue, rvalue)
+    if space.is_w(w_type, space.w_bool):
+        if current_guess is None:
+            return bool_dtype
+    elif space.is_w(w_type, space.w_int):
+        if (current_guess is None or current_guess is bool_dtype or
+            current_guess is int64_dtype):
+            return int64_dtype
+    return space.fromcache(interp_dtype.W_Float64Dtype)
 
- at ufunc2
-def divide(lvalue, rvalue):
-    return lvalue / rvalue
 
- at ufunc
-def exp(value):
-    try:
-        return math.exp(value)
-    except OverflowError:
-        return rfloat.INFINITY
+def ufunc_dtype_caller(ufunc_name, op_name, argcount):
+    if argcount == 1:
+        def impl(res_dtype, value):
+            return getattr(res_dtype, op_name)(value)
+    elif argcount == 2:
+        def impl(res_dtype, lvalue, rvalue):
+            return getattr(res_dtype, op_name)(lvalue, rvalue)
+    return func_with_new_name(impl, ufunc_name)
 
- at ufunc
-def fabs(value):
-    return math.fabs(value)
+class UfuncState(object):
+    def __init__(self, space):
+        "NOT_RPYTHON"
+        for ufunc_def in [
+            ("add", "add", 2, {"identity": 0}),
+            ("subtract", "sub", 2),
+            ("multiply", "mul", 2, {"identity": 1}),
+            ("divide", "div", 2, {"promote_bools": True}),
+            ("mod", "mod", 2, {"promote_bools": True}),
+            ("power", "pow", 2, {"promote_bools": True}),
 
- at ufunc2
-def maximum(lvalue, rvalue):
-    return max(lvalue, rvalue)
+            ("maximum", "max", 2),
+            ("minimum", "min", 2),
 
- at ufunc2
-def minimum(lvalue, rvalue):
-    return min(lvalue, rvalue)
+            ("copysign", "copysign", 2, {"promote_to_float": True}),
 
- at ufunc2
-def multiply(lvalue, rvalue):
-    return lvalue * rvalue
+            ("positive", "pos", 1),
+            ("negative", "neg", 1),
+            ("absolute", "abs", 1),
+            ("sign", "sign", 1, {"promote_bools": True}),
+            ("reciprocal", "reciprocal", 1),
 
-# Used by numarray for __pos__. Not visible from numpy application space.
- at ufunc
-def positive(value):
-    return value
+            ("fabs", "fabs", 1, {"promote_to_float": True}),
+            ("floor", "floor", 1, {"promote_to_float": True}),
+            ("exp", "exp", 1, {"promote_to_float": True}),
 
- at ufunc
-def negative(value):
-    return -value
+            ("sin", "sin", 1, {"promote_to_float": True}),
+            ("cos", "cos", 1, {"promote_to_float": True}),
+            ("tan", "tan", 1, {"promote_to_float": True}),
+            ("arcsin", "arcsin", 1, {"promote_to_float": True}),
+            ("arccos", "arccos", 1, {"promote_to_float": True}),
+            ("arctan", "arctan", 1, {"promote_to_float": True}),
+        ]:
+            self.add_ufunc(space, *ufunc_def)
 
- at ufunc
-def reciprocal(value):
-    if value == 0.0:
-        return rfloat.copysign(rfloat.INFINITY, value)
-    return 1.0 / value
+    def add_ufunc(self, space, ufunc_name, op_name, argcount, extra_kwargs=None):
+        if extra_kwargs is None:
+            extra_kwargs = {}
 
- at ufunc2
-def subtract(lvalue, rvalue):
-    return lvalue - rvalue
+        identity = extra_kwargs.get("identity")
+        if identity is not None:
+            identity = space.fromcache(interp_dtype.W_Int64Dtype).adapt_val(identity)
+        extra_kwargs["identity"] = identity
 
- at ufunc
-def floor(value):
-    return math.floor(value)
+        func = ufunc_dtype_caller(ufunc_name, op_name, argcount)
+        if argcount == 1:
+            ufunc = W_Ufunc1(func, ufunc_name, **extra_kwargs)
+        elif argcount == 2:
+            ufunc = W_Ufunc2(func, ufunc_name, **extra_kwargs)
+        setattr(self, ufunc_name, ufunc)
 
- at ufunc
-def sign(value):
-    if value == 0.0:
-        return 0.0
-    return rfloat.copysign(1.0, value)
-
- at ufunc
-def sin(value):
-    return math.sin(value)
-
- at ufunc
-def cos(value):
-    return math.cos(value)
-
- at ufunc
-def tan(value):
-    return math.tan(value)
-
- at ufunc2
-def power(lvalue, rvalue):
-    return math.pow(lvalue, rvalue)
-
- at ufunc2
-def mod(lvalue, rvalue):
-    return math.fmod(lvalue, rvalue)
-
-
- at ufunc
-def arcsin(value):
-    if value < -1.0 or  value > 1.0:
-        return rfloat.NAN
-    return math.asin(value)
-
- at ufunc
-def arccos(value):
-    if value < -1.0 or  value > 1.0:
-        return rfloat.NAN
-    return math.acos(value)
-
- at ufunc
-def arctan(value):
-    return math.atan(value)
+def get(space):
+    return space.fromcache(UfuncState)
\ No newline at end of file
diff --git a/pypy/module/micronumpy/signature.py b/pypy/module/micronumpy/signature.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/micronumpy/signature.py
@@ -0,0 +1,52 @@
+from pypy.rlib.objectmodel import r_dict, compute_identity_hash
+from pypy.rlib.rarithmetic import intmask
+
+
+def components_eq(lhs, rhs):
+    if len(lhs) != len(rhs):
+        return False
+    for i in range(len(lhs)):
+        v1, v2 = lhs[i], rhs[i]
+        if type(v1) is not type(v2) or not v1.eq(v2):
+            return False
+    return True
+
+def components_hash(components):
+    res = 0x345678
+    for component in components:
+        res = intmask((1000003 * res) ^ component.hash())
+    return res
+
+class BaseSignature(object):
+    _attrs_ = []
+
+    def eq(self, other):
+        return self is other
+
+    def hash(self):
+        return compute_identity_hash(self)
+
+class Signature(BaseSignature):
+    _known_sigs = r_dict(components_eq, components_hash)
+
+    _attrs_ = ["components"]
+    _immutable_fields_ = ["components[*]"]
+
+    def __init__(self, components):
+        self.components = components
+
+    @staticmethod
+    def find_sig(components):
+        return Signature._known_sigs.setdefault(components, Signature(components))
+
+class Call1(BaseSignature):
+    _immutable_fields_ = ["func"]
+
+    def __init__(self, func):
+        self.func = func
+
+class Call2(BaseSignature):
+    _immutable_fields_ = ["func"]
+
+    def __init__(self, func):
+        self.func = func
\ No newline at end of file
diff --git a/pypy/module/micronumpy/test/test_base.py b/pypy/module/micronumpy/test/test_base.py
--- a/pypy/module/micronumpy/test/test_base.py
+++ b/pypy/module/micronumpy/test/test_base.py
@@ -1,23 +1,36 @@
 from pypy.conftest import gettestobjspace
-from pypy.module.micronumpy.interp_numarray import SingleDimArray, FloatWrapper
+from pypy.module.micronumpy import interp_dtype
+from pypy.module.micronumpy.interp_numarray import SingleDimArray, Scalar
+from pypy.module.micronumpy.interp_ufuncs import (find_binop_result_dtype,
+        find_unaryop_result_dtype)
+
 
 class BaseNumpyAppTest(object):
     def setup_class(cls):
-        cls.space = gettestobjspace(usemodules=('micronumpy',))
+        cls.space = gettestobjspace(usemodules=['micronumpy'])
 
 class TestSignature(object):
     def test_binop_signature(self, space):
-        ar = SingleDimArray(10)
+        float64_dtype = space.fromcache(interp_dtype.W_Float64Dtype)
+
+        ar = SingleDimArray(10, dtype=float64_dtype)
         v1 = ar.descr_add(space, ar)
-        v2 = ar.descr_add(space, FloatWrapper(2.0))
+        v2 = ar.descr_add(space, Scalar(float64_dtype, 2.0))
         assert v1.signature is not v2.signature
-        v3 = ar.descr_add(space, FloatWrapper(1.0))
+        v3 = ar.descr_add(space, Scalar(float64_dtype, 1.0))
         assert v2.signature is v3.signature
         v4 = ar.descr_add(space, ar)
         assert v1.signature is v4.signature
 
+        bool_ar = SingleDimArray(10, dtype=space.fromcache(interp_dtype.W_BoolDtype))
+        v5 = ar.descr_add(space, bool_ar)
+        assert v5.signature is not v1.signature
+        assert v5.signature is not v2.signature
+        v6 = ar.descr_add(space, bool_ar)
+        assert v5.signature is v6.signature
+
     def test_slice_signature(self, space):
-        ar = SingleDimArray(10)
+        ar = SingleDimArray(10, dtype=space.fromcache(interp_dtype.W_Float64Dtype))
         v1 = ar.descr_getitem(space, space.wrap(slice(1, 5, 1)))
         v2 = ar.descr_getitem(space, space.wrap(slice(4, 6, 1)))
         assert v1.signature is v2.signature
@@ -25,3 +38,44 @@
         v3 = ar.descr_add(space, v1)
         v4 = ar.descr_add(space, v2)
         assert v3.signature is v4.signature
+
+class TestUfuncCoerscion(object):
+    def test_binops(self, space):
+        bool_dtype = space.fromcache(interp_dtype.W_BoolDtype)
+        int8_dtype = space.fromcache(interp_dtype.W_Int8Dtype)
+        int32_dtype = space.fromcache(interp_dtype.W_Int32Dtype)
+        float64_dtype = space.fromcache(interp_dtype.W_Float64Dtype)
+
+        # Basic pairing
+        assert find_binop_result_dtype(space, bool_dtype, bool_dtype) is bool_dtype
+        assert find_binop_result_dtype(space, bool_dtype, float64_dtype) is float64_dtype
+        assert find_binop_result_dtype(space, float64_dtype, bool_dtype) is float64_dtype
+        assert find_binop_result_dtype(space, int32_dtype, int8_dtype) is int32_dtype
+        assert find_binop_result_dtype(space, int32_dtype, bool_dtype) is int32_dtype
+
+        # With promote bool (happens on div), the result is that the op should
+        # promote bools to int8
+        assert find_binop_result_dtype(space, bool_dtype, bool_dtype, promote_bools=True) is int8_dtype
+        assert find_binop_result_dtype(space, bool_dtype, float64_dtype, promote_bools=True) is float64_dtype
+
+        # Coerce to floats
+        assert find_binop_result_dtype(space, bool_dtype, float64_dtype, promote_to_float=True) is float64_dtype
+
+    def test_unaryops(self, space):
+        bool_dtype = space.fromcache(interp_dtype.W_BoolDtype)
+        int8_dtype = space.fromcache(interp_dtype.W_Int8Dtype)
+        int32_dtype = space.fromcache(interp_dtype.W_Int32Dtype)
+        float64_dtype = space.fromcache(interp_dtype.W_Float64Dtype)
+
+        # Normal rules, everythign returns itself
+        assert find_unaryop_result_dtype(space, bool_dtype) is bool_dtype
+        assert find_unaryop_result_dtype(space, int8_dtype) is int8_dtype
+        assert find_unaryop_result_dtype(space, int32_dtype) is int32_dtype
+        assert find_unaryop_result_dtype(space, float64_dtype) is float64_dtype
+
+        # Coerce to floats, some of these will eventually be float16, or
+        # whatever our smallest float type is.
+        assert find_unaryop_result_dtype(space, bool_dtype, promote_to_float=True) is float64_dtype
+        assert find_unaryop_result_dtype(space, int8_dtype, promote_to_float=True) is float64_dtype
+        assert find_unaryop_result_dtype(space, int32_dtype, promote_to_float=True) is float64_dtype
+        assert find_unaryop_result_dtype(space, float64_dtype, promote_to_float=True) is float64_dtype
\ No newline at end of file
diff --git a/pypy/module/micronumpy/test/test_dtypes.py b/pypy/module/micronumpy/test/test_dtypes.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/micronumpy/test/test_dtypes.py
@@ -0,0 +1,101 @@
+from pypy.module.micronumpy.test.test_base import BaseNumpyAppTest
+
+
+class AppTestDtypes(BaseNumpyAppTest):
+    def test_dtype(self):
+        from numpy import dtype
+
+        d = dtype('?')
+        assert d.num == 0
+        assert d.kind == 'b'
+        assert dtype('int8').num == 1
+        assert dtype(d) is d
+        assert dtype(None) is dtype(float)
+        raises(TypeError, dtype, 1042)
+
+    def test_dtype_with_types(self):
+        from numpy import dtype
+
+        assert dtype(bool).num == 0
+        assert dtype(long).num == 9
+        assert dtype(float).num == 12
+
+    def test_array_dtype_attr(self):
+        from numpy import array, dtype
+
+        a = array(range(5), long)
+        assert a.dtype is dtype(long)
+
+    def test_repr_str(self):
+        from numpy import dtype
+
+        assert repr(dtype) == "<type 'numpy.dtype'>"
+        d = dtype('?')
+        assert repr(d) == "dtype('bool')"
+        assert str(d) == "bool"
+
+    def test_bool_array(self):
+        from numpy import array
+
+        a = array([0, 1, 2, 2.5], dtype='?')
+        assert a[0] is False
+        for i in xrange(1, 4):
+            assert a[i] is True
+
+    def test_copy_array_with_dtype(self):
+        from numpy import array
+        a = array([0, 1, 2, 3], dtype=long)
+        # int on 64-bit, long in 32-bit
+        assert isinstance(a[0], (int, long))
+        b = a.copy()
+        assert isinstance(b[0], (int, long))
+
+        a = array([0, 1, 2, 3], dtype=bool)
+        assert isinstance(a[0], bool)
+        b = a.copy()
+        assert isinstance(b[0], bool)
+
+    def test_zeros_bool(self):
+        from numpy import zeros
+        a = zeros(10, dtype=bool)
+        for i in range(10):
+            assert a[i] is False
+
+    def test_ones_bool(self):
+        from numpy import ones
+        a = ones(10, dtype=bool)
+        for i in range(10):
+            assert a[i] is True
+
+    def test_zeros_long(self):
+        from numpy import zeros
+        a = zeros(10, dtype=long)
+        for i in range(10):
+            assert isinstance(a[i], (int, long))
+            assert a[1] == 0
+
+    def test_ones_long(self):
+        from numpy import ones
+        a = ones(10, dtype=bool)
+        for i in range(10):
+            assert isinstance(a[i], (int, long))
+            assert a[1] == 1
+
+    def test_add_int8(self):
+        from numpy import array
+
+        a = array(range(5), dtype="int8")
+        b = a + a
+        for i in range(5):
+            assert b[i] == i * 2
+
+    def test_shape(self):
+        from numpy import dtype
+
+        assert dtype(long).shape == ()
+
+    def test_cant_subclass(self):
+        from numpy import dtype
+
+        # You can't subclass dtype
+        raises(TypeError, type, "Foo", (dtype,), {})
\ No newline at end of file
diff --git a/pypy/module/micronumpy/test/test_numarray.py b/pypy/module/micronumpy/test/test_numarray.py
--- a/pypy/module/micronumpy/test/test_numarray.py
+++ b/pypy/module/micronumpy/test/test_numarray.py
@@ -1,5 +1,3 @@
-import py
-
 from pypy.module.micronumpy.test.test_base import BaseNumpyAppTest
 from pypy.conftest import gettestobjspace
 
@@ -52,14 +50,18 @@
 
     def test_repr(self):
         from numpy import array, zeros
-        a = array(range(5))
+        a = array(range(5), float)
         assert repr(a) == "array([0.0, 1.0, 2.0, 3.0, 4.0])"
         a = zeros(1001)
         assert repr(a) == "array([0.0, 0.0, 0.0, ..., 0.0, 0.0, 0.0])"
+        a = array(range(5), long)
+        assert repr(a) == "array([0, 1, 2, 3, 4])"
+        a = array([True, False, True, False], "?")
+        assert repr(a) == "array([True, False, True, False], dtype=bool)"
 
     def test_repr_slice(self):
         from numpy import array, zeros
-        a = array(range(5))
+        a = array(range(5), float)
         b = a[1::2]
         assert repr(b) == "array([1.0, 3.0])"
         a = zeros(2002)
@@ -68,15 +70,23 @@
 
     def test_str(self):
         from numpy import array, zeros
-        a = array(range(5))
+        a = array(range(5), float)
         assert str(a) == "[0.0 1.0 2.0 3.0 4.0]"
         assert str((2*a)[:]) == "[0.0 2.0 4.0 6.0 8.0]"
         a = zeros(1001)
         assert str(a) == "[0.0 0.0 0.0 ..., 0.0 0.0 0.0]"
 
+        a = array(range(5), dtype=long)
+        assert str(a) == "[0 1 2 3 4]"
+        a = array([True, False, True, False], dtype="?")
+        assert str(a) == "[True False True False]"
+
+        a = array(range(5), dtype="int8")
+        assert str(a) == "[0 1 2 3 4]"
+
     def test_str_slice(self):
         from numpy import array, zeros
-        a = array(range(5))
+        a = array(range(5), float)
         b = a[1::2]
         assert str(b) == "[1.0 3.0]"
         a = zeros(2002)
@@ -132,7 +142,7 @@
 
     def test_setslice_list(self):
         from numpy import array
-        a = array(range(5))
+        a = array(range(5), float)
         b = [0., 1.]
         a[1:4:2] = b
         assert a[1] == 0.
@@ -140,7 +150,7 @@
 
     def test_setslice_constant(self):
         from numpy import array
-        a = array(range(5))
+        a = array(range(5), float)
         a[1:4:2] = 0.
         assert a[1] == 0.
         assert a[3] == 0.
@@ -167,6 +177,12 @@
         for i in range(5):
             assert b[i] == i + i
 
+        a = array([True, False, True, False], dtype="?")
+        b = array([True, True, False, False], dtype="?")
+        c = a + b
+        for i in range(4):
+            assert c[i] == bool(a[i] + b[i])
+
     def test_add_other(self):
         from numpy import array
         a = array(range(5))
@@ -220,12 +236,19 @@
             assert b[i] == i - 5
 
     def test_mul(self):
-        from numpy import array
+        from numpy import array, dtype
         a = array(range(5))
         b = a * a
         for i in range(5):
             assert b[i] == i * i
 
+        a = array(range(5), dtype=bool)
+        b = a * a
+        assert b.dtype is dtype(bool)
+        assert b[0] is False
+        for i in range(1, 5):
+            assert b[i] is True
+
     def test_mul_constant(self):
         from numpy import array
         a = array(range(5))
@@ -234,16 +257,22 @@
             assert b[i] == i * 5
 
     def test_div(self):
-        from numpy import array
+        from numpy import array, dtype
         a = array(range(1, 6))
         b = a / a
         for i in range(5):
             assert b[i] == 1
 
+        a = array(range(1, 6), dtype=bool)
+        b = a / a
+        assert b.dtype is dtype("int8")
+        for i in range(5):
+            assert b[i] == 1
+
     def test_div_other(self):
         from numpy import array
         a = array(range(5))
-        b = array([2, 2, 2, 2, 2])
+        b = array([2, 2, 2, 2, 2], float)
         c = a / b
         for i in range(5):
             assert c[i] == i / 2.0
@@ -257,7 +286,7 @@
 
     def test_pow(self):
         from numpy import array
-        a = array(range(5))
+        a = array(range(5), float)
         b = a ** a
         for i in range(5):
             print b[i], i**i
@@ -265,7 +294,7 @@
 
     def test_pow_other(self):
         from numpy import array
-        a = array(range(5))
+        a = array(range(5), float)
         b = array([2, 2, 2, 2, 2])
         c = a ** b
         for i in range(5):
@@ -273,7 +302,7 @@
 
     def test_pow_constant(self):
         from numpy import array
-        a = array(range(5))
+        a = array(range(5), float)
         b = a ** 2
         for i in range(5):
             assert b[i] == i ** 2
@@ -285,6 +314,12 @@
         for i in range(5):
             assert b[i] == 0
 
+        a = array(range(1, 6), float)
+        b = (a + 1) % a
+        assert b[0] == 0
+        for i in range(1, 5):
+            assert b[i] == 1
+
     def test_mod_other(self):
         from numpy import array
         a = array(range(5))
@@ -307,6 +342,10 @@
         for i in range(5):
             assert b[i] == a[i]
 
+        a = +array(range(5))
+        for i in range(5):
+            assert a[i] == i
+
     def test_neg(self):
         from numpy import array
         a = array([1.,-2.,3.,-4.,-5.])
@@ -314,6 +353,10 @@
         for i in range(5):
             assert b[i] == -a[i]
 
+        a = -array(range(5), dtype="int8")
+        for i in range(5):
+            assert a[i] == -i
+
     def test_abs(self):
         from numpy import array
         a = array([1.,-2.,3.,-4.,-5.])
@@ -321,6 +364,10 @@
         for i in range(5):
             assert b[i] == abs(a[i])
 
+        a = abs(array(range(-5, 5), dtype="int8"))
+        for i in range(-5, 5):
+            assert a[i + 5] == abs(i)
+
     def test_auto_force(self):
         from numpy import array
         a = array(range(5))
@@ -343,6 +390,12 @@
         for i in range(4):
             assert s[i] == a[i+1]
 
+        s = (a + a)[1:2]
+        assert len(s) == 1
+        assert s[0] == 2
+        s[:1] = array([5])
+        assert s[0] == 5
+
     def test_getslice_step(self):
         from numpy import array
         a = array(range(10))
@@ -388,6 +441,9 @@
         assert a.sum() == 10.0
         assert a[:4].sum() == 6.0
 
+        a = array([True] * 5, bool)
+        assert a.sum() == 5
+
     def test_prod(self):
         from numpy import array
         a = array(range(1,6))
@@ -420,6 +476,9 @@
         b = array([])
         raises(ValueError, "b.argmax()")
 
+        a = array(range(-5, 5))
+        assert a.argmax() == 9
+
     def test_argmin(self):
         from numpy import array
         a = array([-1.2, 3.4, 5.7, -3.0, 2.7])
@@ -427,24 +486,6 @@
         b = array([])
         raises(ValueError, "b.argmin()")
 
-    def test_sort(self):
-        from numpy import array
-        a = [3.0,4.0,0.0,-1.0]
-        b = array(a)
-        a.sort()
-        b.sort()
-        assert(len(a)==len(b))
-        for i in range(len(a)):
-            assert(a[i]==b[i])
-        a = array(list(reversed(range(6))))
-        b = array(range(6))
-        a.sort()
-        assert(len(a)==len(b))
-        for i in range(len(a)):
-            assert(a[i]==b[i])
-
-
-
     def test_all(self):
         from numpy import array
         a = array(range(5))
@@ -468,12 +509,25 @@
         a = array(range(5))
         assert a.dot(a) == 30.0
 
+        a = array(range(5))
+        assert a.dot(range(5)) == 30
+
     def test_dot_constant(self):
         from numpy import array
         a = array(range(5))
         b = a.dot(2.5)
         for i in xrange(5):
-            assert b[i] == 2.5*a[i]
+            assert b[i] == 2.5 * a[i]
+
+    def test_dtype_guessing(self):
+        from numpy import array, dtype
+
+        assert array([True]).dtype is dtype(bool)
+        assert array([True, 1]).dtype is dtype(long)
+        assert array([1, 2, 3]).dtype is dtype(long)
+        assert array([1.2, True]).dtype is dtype(float)
+        assert array([1.2, 5]).dtype is dtype(float)
+        assert array([]).dtype is dtype(float)
 
 
 class AppTestSupport(object):
@@ -487,5 +541,4 @@
         a = fromstring(self.data)
         for i in range(4):
             assert a[i] == i + 1
-        raises(ValueError, fromstring, "abc")
-
+        raises(ValueError, fromstring, "abc")
\ No newline at end of file
diff --git a/pypy/module/micronumpy/test/test_ufuncs.py b/pypy/module/micronumpy/test/test_ufuncs.py
--- a/pypy/module/micronumpy/test/test_ufuncs.py
+++ b/pypy/module/micronumpy/test/test_ufuncs.py
@@ -3,6 +3,32 @@
 
 
 class AppTestUfuncs(BaseNumpyAppTest):
+    def test_ufunc_instance(self):
+        from numpy import add, ufunc
+
+        assert isinstance(add, ufunc)
+        assert repr(add) == "<ufunc 'add'>"
+        assert repr(ufunc) == "<type 'numpy.ufunc'>"
+
+    def test_ufunc_attrs(self):
+        from numpy import add, multiply, sin
+
+        assert add.identity == 0
+        assert multiply.identity == 1
+        assert sin.identity is None
+
+        assert add.nin == 2
+        assert multiply.nin == 2
+        assert sin.nin == 1
+
+    def test_wrong_arguments(self):
+        from numpy import add, sin
+
+        raises(TypeError, add, 1)
+        raises(TypeError, add, 1, 2, 3)
+        raises(TypeError, sin, 1, 2)
+        raises(TypeError, sin)
+
     def test_single_item(self):
         from numpy import negative, sign, minimum
 
@@ -86,7 +112,7 @@
     def test_fabs(self):
         from numpy import array, fabs
         from math import fabs as math_fabs
-        
+
         a = array([-5.0, -0.0, 1.0])
         b = fabs(a)
         for i in range(3):
@@ -110,6 +136,10 @@
         for i in range(3):
             assert c[i] == max(a[i], b[i])
 
+        x = maximum(2, 3)
+        assert x == 3
+        assert isinstance(x, (int, long))
+
     def test_multiply(self):
         from numpy import array, multiply
 
@@ -120,7 +150,7 @@
             assert c[i] == a[i] * b[i]
 
     def test_sign(self):
-        from numpy import array, sign
+        from numpy import array, sign, dtype
 
         reference = [-1.0, 0.0, 0.0, 1.0]
         a = array([-5.0, -0.0, 0.0, 6.0])
@@ -128,6 +158,16 @@
         for i in range(4):
             assert b[i] == reference[i]
 
+        a = sign(array(range(-5, 5)))
+        ref = [-1, -1, -1, -1, -1, 0, 1, 1, 1, 1]
+        for i in range(10):
+            assert a[i] == ref[i]
+
+        a = sign(array([True, False], dtype=bool))
+        assert a.dtype == dtype("int8")
+        assert a[0] == 1
+        assert a[1] == 0
+
     def test_reciporocal(self):
         from numpy import array, reciprocal
 
@@ -165,6 +205,11 @@
         for i in range(4):
             assert c[i] == reference[i]
 
+        b = array([True, True, True, True], dtype=bool)
+        c = copysign(a, b)
+        for i in range(4):
+            assert c[i] == abs(a[i])
+
     def test_exp(self):
         import math
         from numpy import array, exp
@@ -188,6 +233,10 @@
         for i in range(len(a)):
             assert b[i] == math.sin(a[i])
 
+        a = sin(array([True, False], dtype=bool))
+        assert a[0] == sin(1)
+        assert a[1] == 0.0
+
     def test_cos(self):
         import math
         from numpy import array, cos
@@ -211,7 +260,7 @@
         import math
         from numpy import array, arcsin
 
-        a = array([-1, -0.5, -0.33, 0, 0.33, 0.5, 1])        
+        a = array([-1, -0.5, -0.33, 0, 0.33, 0.5, 1])
         b = arcsin(a)
         for i in range(len(a)):
             assert b[i] == math.asin(a[i])
@@ -230,7 +279,7 @@
         for i in range(len(a)):
             assert b[i] == math.acos(a[i])
 
-        
+
         a = array([-10, -1.5, -1.01, 1.01, 1.5, 10, float('nan'), float('inf'), float('-inf')])
         b = arccos(a)
         for f in b:
@@ -249,3 +298,16 @@
         b = arctan(a)
         assert math.isnan(b[0])
 
+    def test_reduce_errors(self):
+        from numpy import sin, add
+
+        raises(ValueError, sin.reduce, [1, 2, 3])
+        raises(TypeError, add.reduce, 1)
+
+    def test_reduce(self):
+        from numpy import add, maximum
+
+        assert add.reduce([1, 2, 3]) == 6
+        assert maximum.reduce([1]) == 1
+        assert maximum.reduce([1, 2, 3]) == 3
+        raises(ValueError, maximum.reduce, [])
\ No newline at end of file
diff --git a/pypy/module/micronumpy/test/test_zjit.py b/pypy/module/micronumpy/test/test_zjit.py
--- a/pypy/module/micronumpy/test/test_zjit.py
+++ b/pypy/module/micronumpy/test/test_zjit.py
@@ -1,34 +1,26 @@
 from pypy.jit.metainterp.test.support import LLJitMixin
+from pypy.module.micronumpy import interp_ufuncs, signature
+from pypy.module.micronumpy.compile import (numpy_compile, FakeSpace,
+    FloatObject)
+from pypy.module.micronumpy.interp_dtype import W_Float64Dtype, W_Int64Dtype
+from pypy.module.micronumpy.interp_numarray import (BaseArray, SingleDimArray,
+    SingleDimSlice, scalar_w)
+from pypy.rlib.nonconst import NonConstant
+from pypy.rpython.annlowlevel import llstr
 from pypy.rpython.test.test_llinterp import interpret
-from pypy.module.micronumpy.interp_numarray import (SingleDimArray, Signature,
-    FloatWrapper, Call2, SingleDimSlice, add, mul, Call1)
-from pypy.module.micronumpy.interp_ufuncs import negative
-from pypy.module.micronumpy.compile import numpy_compile
-from pypy.rlib.objectmodel import specialize
-from pypy.rlib.nonconst import NonConstant
 
-class FakeSpace(object):
-    w_ValueError = None
-
-    def issequence_w(self, w_obj):
-        return True
-
-    @specialize.argtype(1)
-    def wrap(self, w_obj):
-        return w_obj
-
-    def float_w(self, w_obj):
-        return float(w_obj)
 
 class TestNumpyJIt(LLJitMixin):
     def setup_class(cls):
         cls.space = FakeSpace()
+        cls.float64_dtype = cls.space.fromcache(W_Float64Dtype)
+        cls.int64_dtype = cls.space.fromcache(W_Int64Dtype)
 
     def test_add(self):
         def f(i):
-            ar = SingleDimArray(i)
-            v = Call2(add, ar, ar, Signature())
-            return v.get_concrete().storage[3]
+            ar = SingleDimArray(i, dtype=self.float64_dtype)
+            v = interp_ufuncs.get(self.space).add.call(self.space, [ar, ar])
+            return v.get_concrete().eval(3).val
 
         result = self.meta_interp(f, [5], listops=True, backendopt=True)
         self.check_loops({'getarrayitem_raw': 2, 'float_add': 1,
@@ -38,9 +30,14 @@
 
     def test_floatadd(self):
         def f(i):
-            ar = SingleDimArray(i)
-            v = Call2(add, ar, FloatWrapper(4.5), Signature())
-            return v.get_concrete().storage[3]
+            ar = SingleDimArray(i, dtype=self.float64_dtype)
+            v = interp_ufuncs.get(self.space).add.call(self.space, [
+                    ar,
+                    scalar_w(self.space, self.float64_dtype, self.space.wrap(4.5))
+                ],
+            )
+            assert isinstance(v, BaseArray)
+            return v.get_concrete().eval(3).val
 
         result = self.meta_interp(f, [5], listops=True, backendopt=True)
         self.check_loops({"getarrayitem_raw": 1, "float_add": 1,
@@ -50,10 +47,18 @@
 
     def test_sum(self):
         space = self.space
+        float64_dtype = self.float64_dtype
+        int64_dtype = self.int64_dtype
 
         def f(i):
-            ar = SingleDimArray(i)
-            return ar.descr_add(space, ar).descr_sum(space)
+            if NonConstant(False):
+                dtype = int64_dtype
+            else:
+                dtype = float64_dtype
+            ar = SingleDimArray(i, dtype=dtype)
+            v = ar.descr_add(space, ar).descr_sum(space)
+            assert isinstance(v, FloatObject)
+            return v.floatval
 
         result = self.meta_interp(f, [5], listops=True, backendopt=True)
         self.check_loops({"getarrayitem_raw": 2, "float_add": 2,
@@ -63,10 +68,18 @@
 
     def test_prod(self):
         space = self.space
+        float64_dtype = self.float64_dtype
+        int64_dtype = self.int64_dtype
 
         def f(i):
-            ar = SingleDimArray(i)
-            return ar.descr_add(space, ar).descr_prod(space)
+            if NonConstant(False):
+                dtype = int64_dtype
+            else:
+                dtype = float64_dtype
+            ar = SingleDimArray(i, dtype=dtype)
+            v = ar.descr_add(space, ar).descr_prod(space)
+            assert isinstance(v, FloatObject)
+            return v.floatval
 
         result = self.meta_interp(f, [5], listops=True, backendopt=True)
         self.check_loops({"getarrayitem_raw": 2, "float_add": 1,
@@ -76,32 +89,48 @@
 
     def test_max(self):
         space = self.space
+        float64_dtype = self.float64_dtype
+        int64_dtype = self.int64_dtype
 
         def f(i):
-            ar = SingleDimArray(i)
+            if NonConstant(False):
+                dtype = int64_dtype
+            else:
+                dtype = float64_dtype
+            ar = SingleDimArray(i, dtype=dtype)
             j = 0
             while j < i:
-                ar.get_concrete().storage[j] = float(j)
+                ar.get_concrete().setitem(j, float64_dtype.box(float(j)))
                 j += 1
-            return ar.descr_add(space, ar).descr_max(space)
+            v = ar.descr_add(space, ar).descr_max(space)
+            assert isinstance(v, FloatObject)
+            return v.floatval
 
         result = self.meta_interp(f, [5], listops=True, backendopt=True)
         self.check_loops({"getarrayitem_raw": 2, "float_add": 1,
                           "float_gt": 1, "int_add": 1,
-                          "int_lt": 1, "guard_true": 1, 
+                          "int_lt": 1, "guard_true": 1,
                           "guard_false": 1, "jump": 1})
         assert result == f(5)
 
     def test_min(self):
         space = self.space
+        float64_dtype = self.float64_dtype
+        int64_dtype = self.int64_dtype
 
         def f(i):
-            ar = SingleDimArray(i)
+            if NonConstant(False):
+                dtype = int64_dtype
+            else:
+                dtype = float64_dtype
+            ar = SingleDimArray(i, dtype=dtype)
             j = 0
             while j < i:
-                ar.get_concrete().storage[j] = float(j)
+                ar.get_concrete().setitem(j, float64_dtype.box(float(j)))
                 j += 1
-            return ar.descr_add(space, ar).descr_min(space)
+            v = ar.descr_add(space, ar).descr_min(space)
+            assert isinstance(v, FloatObject)
+            return v.floatval
 
         result = self.meta_interp(f, [5], listops=True, backendopt=True)
         self.check_loops({"getarrayitem_raw": 2, "float_add": 1,
@@ -112,14 +141,15 @@
 
     def test_argmin(self):
         space = self.space
+        float64_dtype = self.float64_dtype
 
         def f(i):
-            ar = SingleDimArray(i)
+            ar = SingleDimArray(i, dtype=NonConstant(float64_dtype))
             j = 0
             while j < i:
-                ar.get_concrete().storage[j] = float(j)
+                ar.get_concrete().setitem(j, float64_dtype.box(float(j)))
                 j += 1
-            return ar.descr_add(space, ar).descr_argmin(space)
+            return ar.descr_add(space, ar).descr_argmin(space).intval
 
         result = self.meta_interp(f, [5], listops=True, backendopt=True)
         self.check_loops({"getarrayitem_raw": 2, "float_add": 1,
@@ -130,14 +160,16 @@
 
     def test_all(self):
         space = self.space
+        float64_dtype = self.float64_dtype
 
         def f(i):
-            ar = SingleDimArray(i)
+            ar = SingleDimArray(i, dtype=NonConstant(float64_dtype))
             j = 0
             while j < i:
-                ar.get_concrete().storage[j] = 1.0
+                ar.get_concrete().setitem(j, float64_dtype.box(1.0))
                 j += 1
-            return ar.descr_add(space, ar).descr_all(space)
+            return ar.descr_add(space, ar).descr_all(space).boolval
+
         result = self.meta_interp(f, [5], listops=True, backendopt=True)
         self.check_loops({"getarrayitem_raw": 2, "float_add": 1,
                           "int_add": 1, "float_ne": 1,
@@ -146,10 +178,11 @@
 
     def test_any(self):
         space = self.space
+        float64_dtype = self.float64_dtype
 
         def f(i):
-            ar = SingleDimArray(i)
-            return ar.descr_add(space, ar).descr_any(space)
+            ar = SingleDimArray(i, dtype=NonConstant(float64_dtype))
+            return ar.descr_add(space, ar).descr_any(space).boolval
 
         result = self.meta_interp(f, [5], listops=True, backendopt=True)
         self.check_loops({"getarrayitem_raw": 2, "float_add": 1,
@@ -157,13 +190,17 @@
                           "int_lt": 1, "guard_true": 1, "jump": 1})
         assert result == f(5)
 
-    def test_already_forecd(self):
+    def test_already_forced(self):
+        space = self.space
+
         def f(i):
-            ar = SingleDimArray(i)
-            v1 = Call2(add, ar, FloatWrapper(4.5), Signature())
-            v2 = Call2(mul, v1, FloatWrapper(4.5), Signature())
+            ar = SingleDimArray(i, dtype=self.float64_dtype)
+            v1 = interp_ufuncs.get(self.space).add.call(space, [ar, scalar_w(space, self.float64_dtype, space.wrap(4.5))])
+            assert isinstance(v1, BaseArray)
+            v2 = interp_ufuncs.get(self.space).multiply.call(space, [v1, scalar_w(space, self.float64_dtype, space.wrap(4.5))])
             v1.force_if_needed()
-            return v2.get_concrete().storage[3]
+            assert isinstance(v2, BaseArray)
+            return v2.get_concrete().eval(3).val
 
         result = self.meta_interp(f, [5], listops=True, backendopt=True)
         # This is the sum of the ops for both loops, however if you remove the
@@ -177,10 +214,10 @@
     def test_ufunc(self):
         space = self.space
         def f(i):
-            ar = SingleDimArray(i)
-            v1 = Call2(add, ar, ar, Signature())
-            v2 = negative(space, v1)
-            return v2.get_concrete().storage[3]
+            ar = SingleDimArray(i, dtype=self.float64_dtype)
+            v1 = interp_ufuncs.get(self.space).add.call(space, [ar, ar])
+            v2 = interp_ufuncs.get(self.space).negative.call(space, [v1])
+            return v2.get_concrete().eval(3).val
 
         result = self.meta_interp(f, [5], listops=True, backendopt=True)
         self.check_loops({"getarrayitem_raw": 2, "float_add": 1, "float_neg": 1,
@@ -192,17 +229,15 @@
     def test_appropriate_specialization(self):
         space = self.space
         def f(i):
-            add_sig = Signature()
-            mul_sig = Signature()
-            ar = SingleDimArray(i)
+            ar = SingleDimArray(i, dtype=self.float64_dtype)
 
-            v1 = Call2(add, ar, ar, ar.signature.transition(add_sig))
-            v2 = negative(space, v1)
+            v1 = interp_ufuncs.get(self.space).add.call(space, [ar, ar])
+            v2 = interp_ufuncs.get(self.space).negative.call(space, [v1])
             v2.get_concrete()
 
             for i in xrange(5):
-                v1 = Call2(mul, ar, ar, ar.signature.transition(mul_sig))
-                v2 = negative(space, v1)
+                v1 = interp_ufuncs.get(self.space).multiply.call(space, [ar, ar])
+                v2 = interp_ufuncs.get(self.space).negative.call(space, [v1])
                 v2.get_concrete()
 
         self.meta_interp(f, [5], listops=True, backendopt=True)
@@ -212,10 +247,13 @@
     def test_slice(self):
         def f(i):
             step = 3
-            ar = SingleDimArray(step*i)
-            s = SingleDimSlice(0, step*i, step, i, ar, ar.signature.transition(SingleDimSlice.static_signature))
-            v = Call2(add, s, s, Signature())
-            return v.get_concrete().storage[3]
+            ar = SingleDimArray(step*i, dtype=self.float64_dtype)
+            new_sig = signature.Signature.find_sig([
+                SingleDimSlice.signature, ar.signature
+            ])
+            s = SingleDimSlice(0, step*i, step, i, ar, new_sig)
+            v = interp_ufuncs.get(self.space).add.call(self.space, [s, s])
+            return v.get_concrete().eval(3).val
 
         result = self.meta_interp(f, [5], listops=True, backendopt=True)
         self.check_loops({'int_mul': 1, 'getarrayitem_raw': 2, 'float_add': 1,
@@ -227,11 +265,17 @@
         def f(i):
             step1 = 2
             step2 = 3
-            ar = SingleDimArray(step2*i)
-            s1 = SingleDimSlice(0, step1*i, step1, i, ar, ar.signature.transition(SingleDimSlice.static_signature))
-            s2 = SingleDimSlice(0, step2*i, step2, i, ar, ar.signature.transition(SingleDimSlice.static_signature))
-            v = Call2(add, s1, s2, Signature())
-            return v.get_concrete().storage[3]
+            ar = SingleDimArray(step2*i, dtype=self.float64_dtype)
+            new_sig = signature.Signature.find_sig([
+                SingleDimSlice.signature, ar.signature
+            ])
+            s1 = SingleDimSlice(0, step1*i, step1, i, ar, new_sig)
+            new_sig = signature.Signature.find_sig([
+                SingleDimSlice.signature, s1.signature
+            ])
+            s2 = SingleDimSlice(0, step2*i, step2, i, ar, new_sig)
+            v = interp_ufuncs.get(self.space).add.call(self.space, [s1, s2])
+            return v.get_concrete().eval(3).val
 
         result = self.meta_interp(f, [5], listops=True, backendopt=True)
         self.check_loops({'int_mul': 2, 'getarrayitem_raw': 2, 'float_add': 1,
@@ -241,18 +285,16 @@
 
     def test_setslice(self):
         space = self.space
+        float64_dtype = self.float64_dtype
 
         def f(i):
             step = NonConstant(3)
-            ar = SingleDimArray(step*i)
-            ar2 = SingleDimArray(i)
-            ar2.storage[1] = 5.5
-            if NonConstant(False):
-                arg = ar2
-            else:
-                arg = ar2.descr_add(space, ar2)
+            ar = SingleDimArray(step*i, dtype=float64_dtype)
+            ar2 = SingleDimArray(i, dtype=float64_dtype)
+            ar2.get_concrete().setitem(1, float64_dtype.box(5.5))
+            arg = ar2.descr_add(space, ar2)
             ar.setslice(space, 0, step*i, step, i, arg)
-            return ar.get_concrete().storage[3]
+            return ar.get_concrete().eval(3).val
 
         result = self.meta_interp(f, [5], listops=True, backendopt=True)
         self.check_loops({'getarrayitem_raw': 2,
@@ -267,12 +309,11 @@
         x = x.compute()
         assert isinstance(x, SingleDimArray)
         assert x.size == 10
-        assert x.storage[0] == 0
-        assert x.storage[1] == ((1 + 1) * 1.2) / 1.2 - 1
-    
+        assert x.eval(0).val == 0
+        assert x.eval(1).val == ((1 + 1) * 1.2) / 1.2 - 1
+
     def test_translation(self):
         # we import main to check if the target compiles
         from pypy.translator.goal.targetnumpystandalone import main
-        from pypy.rpython.annlowlevel import llstr
-        
+
         interpret(main, [llstr('af+'), 100])
diff --git a/pypy/objspace/std/stringobject.py b/pypy/objspace/std/stringobject.py
--- a/pypy/objspace/std/stringobject.py
+++ b/pypy/objspace/std/stringobject.py
@@ -913,12 +913,16 @@
 def repr__String(space, w_str):
     s = w_str._value
 
-    buf = StringBuilder(len(s) + 2)
-
     quote = "'"
     if quote in s and '"' not in s:
         quote = '"'
 
+    return space.wrap(string_escape_encode(s, quote))
+
+def string_escape_encode(s, quote):
+
+    buf = StringBuilder(len(s) + 2)
+
     buf.append(quote)
     startslice = 0
 
@@ -959,7 +963,7 @@
 
     buf.append(quote)
 
-    return space.wrap(buf.build())
+    return buf.build()
 
 
 DEFAULT_NOOP_TABLE = ''.join([chr(i) for i in range(256)])
diff --git a/pypy/rlib/nonconst.py b/pypy/rlib/nonconst.py
--- a/pypy/rlib/nonconst.py
+++ b/pypy/rlib/nonconst.py
@@ -24,6 +24,12 @@
     def __add__(self, other):
         return self.__dict__['constant'] + other
 
+    def __radd__(self, other):
+        return other + self.__dict__['constant']
+
+    def __mul__(self, other):
+        return self.__dict__['constant'] * other
+
 class EntryNonConstant(ExtRegistryEntry):
     _about_ = NonConstant
 
diff --git a/pypy/rlib/parsing/tree.py b/pypy/rlib/parsing/tree.py
--- a/pypy/rlib/parsing/tree.py
+++ b/pypy/rlib/parsing/tree.py
@@ -6,9 +6,16 @@
         content = ["digraph G{"]
         content.extend(self.dot())
         content.append("}")
-        p = py.test.ensuretemp("automaton").join("temp.dot")
+        try:
+            p = py.test.ensuretemp("automaton").join("temp.dot")
+            remove = False
+        except AttributeError: # pytest lacks ensuretemp, make a normal one
+            p = py.path.local.mkdtemp().join('automaton.dot')
+            remove = True
         p.write("\n".join(content))
         graphclient.display_dot_file(str(p))
+        if remove:
+            p.dirpath().remove()
 
 class Symbol(Node):
 
diff --git a/pypy/rlib/rerased.py b/pypy/rlib/rerased.py
--- a/pypy/rlib/rerased.py
+++ b/pypy/rlib/rerased.py
@@ -117,6 +117,10 @@
 
     return erase, unerase
 
+def new_static_erasing_pair(name):
+    erase, unerase = new_erasing_pair(name)
+    return staticmethod(erase), staticmethod(unerase)
+
 
 # ---------- implementation-specific ----------
 
diff --git a/pypy/rlib/runicode.py b/pypy/rlib/runicode.py
--- a/pypy/rlib/runicode.py
+++ b/pypy/rlib/runicode.py
@@ -1403,7 +1403,7 @@
                                     s, pos, pos + unicode_bytes)
             result.append(res)
             continue
-        result.append(unichr(t))
+        result.append(UNICHR(t))
         pos += unicode_bytes
     return result.build(), pos
 
diff --git a/pypy/rpython/lltypesystem/ll2ctypes.py b/pypy/rpython/lltypesystem/ll2ctypes.py
--- a/pypy/rpython/lltypesystem/ll2ctypes.py
+++ b/pypy/rpython/lltypesystem/ll2ctypes.py
@@ -20,7 +20,7 @@
 from pypy.rpython.extfunc import ExtRegistryEntry
 from pypy.rlib.objectmodel import Symbolic, ComputedIntSymbolic
 from pypy.tool.uid import fixid
-from pypy.rlib.rarithmetic import r_uint, r_singlefloat, r_longfloat, intmask
+from pypy.rlib.rarithmetic import r_uint, r_singlefloat, r_longfloat, base_int, intmask
 from pypy.annotation import model as annmodel
 from pypy.rpython.llinterp import LLInterpreter, LLException
 from pypy.rpython.lltypesystem.rclass import OBJECT, OBJECT_VTABLE
@@ -113,7 +113,7 @@
         rffi.LONGLONG:   ctypes.c_longlong,
         rffi.ULONGLONG:  ctypes.c_ulonglong,
         rffi.SIZE_T:     ctypes.c_size_t,
-        lltype.Bool:     ctypes.c_long, # XXX
+        lltype.Bool:     ctypes.c_bool,
         llmemory.Address:  ctypes.c_void_p,
         llmemory.GCREF:    ctypes.c_void_p,
         llmemory.WeakRef:  ctypes.c_void_p, # XXX
@@ -1142,6 +1142,8 @@
             cvalue = 0
     elif isinstance(cvalue, (str, unicode)):
         cvalue = ord(cvalue)     # character -> integer
+    elif hasattr(RESTYPE, "_type") and issubclass(RESTYPE._type, base_int):
+        cvalue = int(cvalue)
 
     if not isinstance(cvalue, (int, long, float)):
         raise NotImplementedError("casting %r to %r" % (TYPE1, RESTYPE))
diff --git a/pypy/tool/error.py b/pypy/tool/error.py
--- a/pypy/tool/error.py
+++ b/pypy/tool/error.py
@@ -7,8 +7,8 @@
 import sys
 
 import py
-log = py.log.Producer("error") 
-py.log.setconsumer("error", ansi_log) 
+log = py.log.Producer("error")
+py.log.setconsumer("error", ansi_log)
 
 SHOW_TRACEBACK = False
 SHOW_ANNOTATIONS = True
@@ -17,7 +17,7 @@
 from pypy.interpreter.pytraceback import offset2lineno
 import traceback
 
-def source_lines(graph, block, operindex=None, offset=None, long=False, \
+def source_lines1(graph, block, operindex=None, offset=None, long=False, \
     show_lines_of_code=SHOW_DEFAULT_LINES_OF_CODE):
     if block is not None:
         if block is graph.returnblock:
@@ -61,6 +61,10 @@
         lines.append("")
         return lines
 
+def source_lines(graph, *args, **kwds):
+    lines = source_lines1(graph, *args, **kwds)
+    return ['In %r:' % (graph,)] + lines
+
 class FlowingError(Exception):
     pass
 
@@ -125,8 +129,16 @@
         if func is None:
             r = repr(desc)
         else:
-            r = "function %s <%s, line %s>" % (func.func_name,
-                   func.func_code.co_filename, func.func_code.co_firstlineno)
+            try:
+                if isinstance(func, type):
+                    func_name = "%s.__init__" % func.__name__
+                    func = func.__init__.im_func
+                else:
+                    func_name = func.func_name
+                r = "function %s <%s, line %s>" % (func_name,
+                       func.func_code.co_filename, func.func_code.co_firstlineno)
+            except (AttributeError, TypeError):
+                r = repr(desc)
         msg.append("  %s returning" % (r,))
         if hasattr(desc, 'getuniquegraph'):
             graph = desc.getuniquegraph()
@@ -155,7 +167,7 @@
                 msg.append("%8s: %s" % (v, s_v))
         msg.append('')
         msg += source_lines(graph, block, operindex, long=True)
-        
+
     if called_from_graph is not None:
         msg.append(".. called from %r" % (called_from_graph,))
     if s_value.origin is not None:
@@ -184,7 +196,7 @@
     import traceback
     errmsg = ["Error:\n"]
     exc, val, tb = sys.exc_info()
-    
+
     errmsg.extend([" %s" % line for line in traceback.format_exception(exc, val, [])])
     block = getattr(val, '__annotator_block', None)
     if block:


More information about the pypy-commit mailing list