about summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorFlorent Monjalet <florent.monjalet@gmail.com>2015-11-29 22:03:11 +0100
committerFlorent Monjalet <florent.monjalet@gmail.com>2016-01-18 14:02:31 +0100
commitd19f4c1dbdd2f1f451d03551abb0e5ebf4d455be (patch)
tree5a3a75837113862062be156e5f7a449307a65ea9
parent8c5c79ea86c229618c483b6928dbf405c353048a (diff)
downloadmiasm-d19f4c1dbdd2f1f451d03551abb0e5ebf4d455be.tar.gz
miasm-d19f4c1dbdd2f1f451d03551abb0e5ebf4d455be.zip
MemStruct: big refactor in process
Doc is currently incoherent, impl will also be completed
-rw-r--r--example/jitter/memstruct.py29
-rw-r--r--miasm2/analysis/mem.py480
-rw-r--r--test/analysis/mem.py246
3 files changed, 407 insertions, 348 deletions
diff --git a/example/jitter/memstruct.py b/example/jitter/memstruct.py
index 645c019e..6e8e13af 100644
--- a/example/jitter/memstruct.py
+++ b/example/jitter/memstruct.py
@@ -36,15 +36,15 @@ class ListNode(PinnedStruct):
     ]
 
     def get_next(self):
-        if self.next == 0:
+        if self.next.val == 0:
             return None
-        return self.deref_next
+        return self.next.deref
 
     def get_data(self, data_type=None):
         if data_type is not None:
-            return self.deref_data.cast(data_type)
+            return self.data.deref.cast(data_type)
         else:
-            return self.deref_data
+            return self.data.deref
 
 
 class LinkedList(PinnedStruct):
@@ -60,12 +60,12 @@ class LinkedList(PinnedStruct):
         """Returns the head ListNode instance"""
         if self.head == 0:
             return None
-        return self.deref_head
+        return self.head.deref
 
     def get_tail(self):
         if self.tail == 0:
             return None
-        return self.deref_tail
+        return self.tail.deref
 
     def push(self, data):
         # Allocate a new node
@@ -112,7 +112,7 @@ class LinkedList(PinnedStruct):
         if not self.empty():
             cur = self.get_head()
             while cur is not None:
-                yield cur.deref_data
+                yield cur.data.deref
                 cur = cur.get_next()
 
 
@@ -123,9 +123,9 @@ class DataArray(PinnedStruct):
         ("val1", Num("B")),
         ("val2", Num("B")),
         # Ptr can also be instanciated with a PinnedField as an argument, a special
-        # PinnedStruct containing only one field named "value" will be created, so
+        # PinnedStruct containing only one field named "val" will be created, so
         # that Ptr can point to a PinnedStruct instance. Here,
-        # data_array.deref_array.value will allow to access an Array
+        # data_array.array.deref.val will allow to access an Array
         ("arrayptr", Ptr("<I", PinnedSizedArray, Num("B"), 16)),
         # Array of 10 uint8
         ("array", Array(Num("B"), 16)),
@@ -163,7 +163,8 @@ link.push(DataArray(vm))
 # Size has been updated
 assert link.size == 3
 # If you get it directly from the VM, it is updated as well
-raw_size = vm.get_mem(link.get_addr("size"), link.get_field_type("size").size())
+raw_size = vm.get_mem(link.get_addr("size"), link.get_type()
+                                                 .get_field_type("size").size())
 assert raw_size == '\x03\x00\x00\x00'
 
 print "The linked list just built:"
@@ -182,7 +183,7 @@ assert link.size == 2
 # Make the Array Ptr point to the data's array field
 data.arrayptr = data.get_addr("array")
 # Now the pointer dereference is equal to the array field's value
-assert data.deref_arrayptr == data.array
+assert data.arrayptr.deref == data.array
 
 # Let's say that it is a DataStr:
 datastr = data.cast(DataStr)
@@ -201,9 +202,9 @@ datastr.valshort = 0x1122
 assert data.val1 == 0x22 and data.val2 == 0x11
 
 # Let's play with strings
-memstr = datastr.deref_data
+memstr = datastr.data.deref
 # Note that memstr is PinnedStr(..., "utf16")
-memstr.value = 'Miams'
+memstr.val = 'Miams'
 
 print "Cast data.array to PinnedStr and set the string value:"
 print repr(memstr)
@@ -216,7 +217,7 @@ assert list(data.array)[:len(raw_miams_array)] == raw_miams_array
 assert data.array.cast(PinnedStr, "utf16") == memstr
 # Default is "ansi"
 assert data.array.cast(PinnedStr) != memstr
-assert data.array.cast(PinnedStr, "utf16").value == memstr.value
+assert data.array.cast(PinnedStr, "utf16").val == memstr.val
 
 print "See that the original array has been modified:"
 print repr(data)
diff --git a/miasm2/analysis/mem.py b/miasm2/analysis/mem.py
index 2c5e488c..2b2b3a72 100644
--- a/miasm2/analysis/mem.py
+++ b/miasm2/analysis/mem.py
@@ -72,7 +72,7 @@ of PinnedType with a custom implementation:
     - PinnedSizedArray: a sized PinnedArray, can be automatically allocated in memory
       and allows more operations than PinnedArray
     - pin: a function that dynamically generates a PinnedStruct subclass from a
-      Type. This class has only one field named "value".
+      Type. This class has only one field named "val".
 
 A PinnedType do not always have a static size (cls.sizeof()) nor a dynamic size
 (self.get_size()).
@@ -171,14 +171,14 @@ def set_str_utf16(vm, addr, s):
 
 def pin(field):
     """Generate a PinnedStruct subclass from a field. The field's value can
-    be accessed through self.value or self.deref_value if field is a Ptr.
+    be accessed through self.val or self.deref_val if field is a Ptr.
 
     @field: a Type instance.
     """
     if field in DYN_MEM_STRUCT_CACHE:
         return DYN_MEM_STRUCT_CACHE[field]
 
-    fields = [("value", field)]
+    fields = [("val", field)]
     # Build a type to contain the field type
     mem_type = type("Pinned%r" % field, (PinnedStruct,), {'fields': fields})
     DYN_MEM_STRUCT_CACHE[field] = mem_type
@@ -316,7 +316,11 @@ class Num(RawStruct):
 
 class Ptr(Num):
     """Special case of number of which value indicates the address of a
-    PinnedType. Provides deref_<field> as well as <field> when used, to set and
+    PinnedType.
+    
+    FIXME: DOC
+
+    Provides deref_<field> as well as <field> when used, to set and
     get the pointed PinnedType.
     """
 
@@ -360,7 +364,7 @@ class Ptr(Num):
             else:
                 raise ValueError("Unsupported usecase for PinnedSelf, sorry")
         if isinstance(self._dst_type, Type):
-            self._dst_type = pin(self._dst_type)
+            self._dst_type = self._dst_type.pinned
 
     @property
     def dst_type(self):
@@ -368,11 +372,28 @@ class Ptr(Num):
         self._fix_dst_type()
         return self._dst_type
 
+    def set(self, vm, addr, val):
+        if isinstance(val, PinnedType) and isinstance(val.get_type(), Ptr):
+            self.set_val(vm, addr, val.val)
+        else:
+            super(Ptr, self).set(vm, addr, val)
+
+    def get(self, vm, addr):
+        return self.pinned(vm, addr)
+
+    def get_val(self, vm, addr):
+        return super(Ptr, self).get(vm, addr)
+
+    def set_val(self, vm, addr, val):
+        return super(Ptr, self).set(vm, addr, val)
+
     def deref_get(self, vm, addr):
         """Deserializes the data in @vm (VmMngr) at @addr to self.dst_type.
         Equivalent to a pointer dereference rvalue in C.
         """
-        return self.dst_type(vm, addr, *self._type_args, **self._type_kwargs)
+        dst_addr = self.get_val(vm, addr)
+        return self.dst_type(vm, dst_addr,
+                             *self._type_args, **self._type_kwargs)
 
     def deref_set(self, vm, addr, val):
         """Serializes the @val PinnedType subclass instance in @vm (VmMngr) at
@@ -384,7 +405,8 @@ class Ptr(Num):
                         self._dst_type.__name__, val.__class__.__name__)
 
         # Actual job
-        vm.set_mem(addr, str(val))
+        dst_addr = self.get_val(vm, addr)
+        vm.set_mem(dst_addr, str(val))
 
     def _get_pinned_base_class(self):
         return PinnedPtr
@@ -403,7 +425,7 @@ class Ptr(Num):
             self._type_args))
 
 
-class Inline(Type):
+class Struct(Type):
     """Field used to inline a PinnedType in another PinnedType. Equivalent to
     having a struct field in a C struct.
 
@@ -424,34 +446,145 @@ class Inline(Type):
     TODO: make the Inline implicit when setting a field to be a PinnedStruct
     """
 
-    def __init__(self, inlined_type, *type_args, **type_kwargs):
-        if not issubclass(inlined_type, PinnedStruct):
-            raise ValueError("inlined type if Inline must be a PinnedStruct")
-        self._il_type = inlined_type
-        self._type_args = type_args
-        self._type_kwargs = type_kwargs
+    def __init__(self, name, fields):
+        self.name = name
+        # fields is immutable
+        self._fields = tuple(fields)
+        self._gen_fields()
+
+    def _gen_fields(self):
+        """Precompute useful metadata on self.fields."""
+        self._fields_desc = {}
+        offset = 0
+        for name, field in self._fields:
+            # For reflexion
+            field._set_self_type(self)
+            self._gen_field(name, field, offset)
+            offset += field.size()
+        self._size = offset
+
+    def _gen_field(self, name, field, offset):
+        """Generate only one field
+
+        @name: (str) the name of the field
+        @field: (Type instance) the field type
+        @offset: (int) the offset of the field in the structure
+        """
+        self._fields_desc[name] = {"field": field, "offset": offset}
+
+    @property
+    def fields(self):
+        return self._fields
 
     def set(self, vm, addr, val):
         raw = str(val)
         vm.set_mem(addr, raw)
 
     def get(self, vm, addr):
-        return self._il_type(vm, addr)
+        return self.pinned(vm, addr)
+
+    def get_field(self, vm, addr, name):
+        """get a field value by name.
+
+        useless most of the time since fields are accessible via self.<name>.
+        """
+        if name not in self._fields_desc:
+            raise ValueError("'%s' type has no field '%s'"
+                             % (self, name))
+        field = self.get_field_type(name)
+        offset = self.get_offset(name)
+        return field.get(vm, addr + offset)
+
+    def set_field(self, vm, addr, name, val):
+        """set a field value by name. @val is the python value corresponding to
+        this field type.
+
+        useless most of the time since fields are accessible via self.<name>.
+        """
+        if name not in self._fields_desc:
+            raise AttributeError("'%s' object has no attribute '%s'"
+                                 % (self.__class__.__name__, name))
+        field = self.get_field_type(name)
+        offset = self.get_offset(name)
+        field.set(vm, addr + offset, val)
 
     def size(self):
-        return self._il_type.sizeof()
+        # Child classes can set self._size if their size is not the sum of
+        # their fields
+        return sum(a["field"].size() for a in self._fields_desc.itervalues())
+
+    def get_offset(self, field_name):
+        """
+        @field_name: (str, optional) the name of the field to get the
+            offset of
+        """
+        if field_name not in self._fields_desc:
+            raise ValueError("This structure has no %s field" % field_name)
+        return self._fields_desc[field_name]['offset']
+
+    def get_field_type(self, name):
+        """return the type subclass instance describing field @name."""
+        # TODO: move it to Struct
+        return self._fields_desc[name]['field']
+
+    #def _build_pinned_type(self):
+    #    mem_type = type("PinnedStruct%s" % self.name,
+    #                    (PinnedStruct,),
+    #                    {'_type': self})
+    #    return mem_type
+
+    def _get_pinned_base_class(self):
+        return PinnedStruct
 
     def __repr__(self):
-        return "%s(%r)" % (self.__class__.__name__, self._il_type)
+        return "Struct%s" % self.name
 
     def __eq__(self, other):
         return self.__class__ == other.__class__ and \
-                self._il_type == other._il_type and \
-                self._type_args == other._type_args and \
-                self._type_kwargs == other._type_kwargs
+                self.fields == other.fields and \
+                self.name == other.name
 
     def __hash__(self):
-        return hash((self.__class__, self._il_type, self._type_args))
+        # Only hash name, not fields, because if a field is a Ptr to this
+        # Struct type, an infinite loop occurs
+        return hash((self.__class__, self.name))
+
+
+class Union(Struct):
+    """Allows to put multiple fields at the same offset in a PinnedStruct, similar
+    to unions in C. The Union will have the size of the largest of its fields.
+
+    Example:
+
+        class Example(PinnedStruct):
+            fields = [("uni", Union([
+                                  ("f1", Num("<B")),
+                                  ("f2", Num("<H"))
+                              ])
+                     )]
+
+        ex = Example(vm, addr)
+        ex.uni.f2 = 0x1234
+        assert ex.uni.f1 == 0x34
+    """
+
+    def __init__(self, field_list):
+        """field_list is a [(name, field)] list, see the class doc"""
+        super(Union, self).__init__("union", field_list)
+
+    def size(self):
+        return max(field.size() for _, field in self.fields)
+
+    def get_offset(self, field_name):
+        return 0
+
+    def _get_pinned_base_class(self):
+        return PinnedUnion
+
+    def __repr__(self):
+        fields_repr = ', '.join("%s: %r" % (name, field)
+                                for name, field in self.fields)
+        return "%s(%s)" % (self.__class__.__name__, fields_repr)
 
 
 class Array(Type):
@@ -529,56 +662,6 @@ class Array(Type):
         return hash((self.__class__, self.field_type, self.array_len))
 
 
-# TODO: PinnedUnion
-class Union(Type):
-    """Allows to put multiple fields at the same offset in a PinnedStruct, similar
-    to unions in C. The Union will have the size of the largest of its fields.
-
-    Example:
-
-        class Example(PinnedStruct):
-            fields = [("uni", Union([
-                                  ("f1", Num("<B")),
-                                  ("f2", Num("<H"))
-                              ])
-                     )]
-
-        ex = Example(vm, addr)
-        ex.f2 = 0x1234
-        assert ex.f1 == 0x34
-        assert ex.uni == '\x34\x12'
-        assert ex.get_addr("f1") == ex.get_addr("f2")
-    """
-
-    def __init__(self, field_list):
-        """field_list is a [(name, field)] list, see the class doc"""
-        self.field_list = field_list
-
-    def size(self):
-        return max(field.size() for _, field in self.field_list)
-
-    def set(self, vm, addr, val):
-        if not isinstance(val, str) or not len(str) == self.size():
-            raise ValueError("Union can only be set with raw str of the Union's"
-                             " size")
-        vm.set_mem(vm, addr, val)
-
-    def get(self, vm, addr):
-        return vm.get_mem(addr, self.size())
-
-    def __repr__(self):
-        fields_repr = ', '.join("%s: %r" % (name, field)
-                                for name, field in self.field_list)
-        return "%s(%s)" % (self.__class__.__name__, fields_repr)
-
-    def __eq__(self, other):
-        return self.__class__ == other.__class__ and \
-                self.field_list == other.field_list
-
-    def __hash__(self):
-        return hash((self.__class__, tuple(self.field_list)))
-
-
 class Bits(Type):
     """Helper class for BitField, not very useful on its own. Represents some
     bits of a Num.
@@ -686,9 +769,6 @@ class BitField(Union):
     def set(self, vm, addr, val):
         self._num.set(vm, addr, val)
 
-    def get(self, vm, addr):
-        return self._num.get(vm, addr)
-
     def __eq__(self, other):
         return self.__class__ == other.__class__ and \
                 self._num == other._num and super(BitField, self).__eq__(other)
@@ -697,9 +777,13 @@ class BitField(Union):
         return hash((super(BitField, self).__hash__(), self._num))
 
 
+# TODO
+class Str(Type):
+    pass
+
 class Void(Type):
     """Represents the C void type."""
-    
+
     def _build_pinned_type(self):
         return PinnedVoid
 
@@ -727,19 +811,20 @@ class _MetaPinnedStruct(_MetaPinnedType):
 
     def __init__(cls, name, bases, dct):
         super(_MetaPinnedStruct, cls).__init__(name, bases, dct)
-        cls.gen_fields()
+        if cls.fields is not None:
+            cls.fields = tuple(cls.fields)
+        if cls.get_type() is not None or cls.fields is not None:
+            cls.gen_fields()
 
 
 class PinnedType(object):
     __metaclass__ = _MetaPinnedType
 
     _size = None
+    _type = None
 
-    # Classic usage methods
-
-    def __init__(self, vm, addr=None, *args, **kwargs):
+    def __init__(self, vm, addr=None, type_=None):
         global ALLOCATOR
-        super(PinnedType, self).__init__(*args, **kwargs)
         self._vm = vm
         if addr is None:
             if ALLOCATOR is None:
@@ -749,6 +834,11 @@ class PinnedType(object):
             self._addr = ALLOCATOR(vm, self.get_size())
         else:
             self._addr = addr
+        if type_ is not None:
+            self._type = type_
+        if self._type is None:
+            raise ValueError("Subclass PinnedType and define cls._type or pass "
+                             "a type to the constructor")
 
     def get_addr(self, field=None):
         """Return the address of this PinnedType or one of its fields.
@@ -759,10 +849,17 @@ class PinnedType(object):
         return self._addr
 
     @classmethod
+    def get_type(cls):
+        """Returns the Type instance representing the C type of this PinnedType.
+        """
+        return cls._type
+
+    @classmethod
     def sizeof(cls):
-        """ABSTRACT Return the static size of this type.
+        """Return the static size of this type. By default, it is the size
+        of the underlying type.
         """
-        raise NotImplementedError("Abstract")
+        return cls._type.size()
 
     def get_size(self):
         """Return the dynamic size of this structure (e.g. the size of an
@@ -811,15 +908,7 @@ class PinnedType(object):
         return self.raw()
 
     def __repr__(self):
-        attrs = sorted(self._attrs.iteritems(), key=lambda a: a[1]["offset"])
-        out = []
-        for name, attr in attrs:
-            field = attr["field"]
-            val_repr = repr(self.get_field(name))
-            if '\n' in val_repr:
-                val_repr = '\n' + indent(val_repr, 4)
-            out.append("%s: %r = %s" % (name, field, val_repr))
-        return '%r:\n' % self.__class__ + indent('\n'.join(out), 2)
+        return "Pinned%r" % self._type
 
     def __eq__(self, other):
         return self.__class__ == other.__class__ and str(self) == str(other)
@@ -829,15 +918,6 @@ class PinnedType(object):
 
 
 class PinnedValue(PinnedType):
-    _type = None
-
-    def __init__(self, vm, addr=None, type_=None):
-        super(PinnedValue, self).__init__(vm, addr)
-        if type_ is not None:
-            self._type = type_
-        if self._type is None:
-            raise ValueError("Subclass PinnedPtr and define cls._type or pass a"
-                             " Ptr to the constructor")
 
     @property
     def val(self):
@@ -895,16 +975,7 @@ class PinnedStruct(PinnedType):
     See the various Type doc for more information.
     """
     __metaclass__ = _MetaPinnedStruct
-
-    fields = []
-
-    @classmethod
-    def sizeof(cls):
-        # Child classes can set cls._size if their size is not the sum of
-        # their fields
-        if cls._size is None:
-            return sum(a["field"].size() for a in cls._attrs.itervalues())
-        return cls._size
+    fields = None
 
     def get_addr(self, field_name=None):
         """
@@ -912,28 +983,17 @@ class PinnedStruct(PinnedType):
             address of
         """
         if field_name is not None:
-            if field_name not in self._attrs:
-                raise ValueError("This structure has no %s field" % field_name)
-            offset = self._attrs[field_name]['offset']
+            offset = self._type.get_offset(field_name)
         else:
             offset = 0
         return self._addr + offset
 
-    def get_field_type(self, name):
-        """return the type subclass instance describing field @name."""
-        return self._attrs[name]['field']
-
     def get_field(self, name):
         """get a field value by name.
 
         useless most of the time since fields are accessible via self.<name>.
         """
-        if name not in self._attrs:
-            raise attributeerror("'%s' object has no attribute '%s'"
-                                 % (self.__class__.__name__, name))
-        field = self._attrs[name]["field"]
-        offset = self._attrs[name]["offset"]
-        return field.get(self._vm, self.get_addr() + offset)
+        return self._type.get_field(self._vm, self.get_addr(), name)
 
     def set_field(self, name, val):
         """set a field value by name. @val is the python value corresponding to
@@ -941,37 +1001,7 @@ class PinnedStruct(PinnedType):
 
         useless most of the time since fields are accessible via self.<name>.
         """
-        if name not in self._attrs:
-            raise attributeerror("'%s' object has no attribute '%s'"
-                                 % (self.__class__.__name__, name))
-        field = self._attrs[name]["field"]
-        offset = self._attrs[name]["offset"]
-        field.set(self._vm, self.get_addr() + offset, val)
-
-    def deref_field(self, name):
-        """get the memstruct pointed by <name> field.
-
-        useless most of the time since fields are accessible via
-        self.deref_<name>.
-        """
-        addr = self.get_field(name)
-        field = self._attrs[name]["field"]
-        assert isinstance(field, Ptr),\
-               "programming error: field should be a Ptr"
-        return field.deref_get(self._vm, addr)
-
-    def set_deref_field(self, name, val):
-        """set the memstruct pointed by <name> field. @val should be of the
-        type of the pointed memstruct. the field must be a Ptr.
-
-        useless most of the time since fields are accessible via
-        self.deref_<name>.
-        """
-        addr = self.get_field(name)
-        field = self._attrs[name]["field"]
-        assert isinstance(field, Ptr),\
-               "programming error: field should be a Ptr"
-        field.deref_set(self._vm, addr, val)
+        return self._type.set_field(self._vm, self.get_addr(), name, val)
 
     def cast_field(self, field, other_type, *type_args, **type_kwargs):
         """
@@ -981,7 +1011,7 @@ class PinnedStruct(PinnedType):
                           *type_args, **type_kwargs)
 
 
-    # Field generation methods, voluntarily public to be able to regen fields
+    # Field generation methods, voluntarily public to be able to gen fields
     # after class definition
 
     @classmethod
@@ -1006,56 +1036,59 @@ class PinnedStruct(PinnedType):
             class B(PinnedStruct):
                 fields = [("a", Ptr("I", A))]
 
-            A.fields = [("b", Ptr("I", B))]
-            a.gen_field()
+            A.gen_fields([("b", Ptr("I", B))])
         """
-        if fields is None:
-            fields = cls.fields
-        cls._attrs = {}
-        offset = 0
-        for name, field in cls.fields:
-            # For reflexion
-            field._set_self_type(cls)
-            cls.gen_field(name, field, offset)
-            offset += field.size()
-        cls._size = offset
+        if fields is not None:
+            if cls.fields is not None:
+                raise ValueError("Cannot regen fields of a class. Setting "
+                                 "cls.fields at class definition and calling "
+                                 "gen_fields are mutually exclusive.")
+            cls.fields = fields
+
+        if cls._type is None:
+            if cls.fields is None:
+                raise ValueError("Cannot create a PinnedStruct subclass without"
+                                 " a cls._type or a cls.fields")
+            cls._type = cls._gen_type(cls.fields)
+
+        if cls._type in DYN_MEM_STRUCT_CACHE:
+            # FIXME: Maybe a warning would be better?
+            raise RuntimeError("Another PinnedType has the same type as this "
+                               "one. Use it instead.")
+
+        # Register this class so that another one will not be created when
+        # calling cls._type.pinned
+        DYN_MEM_STRUCT_CACHE[cls._type] = cls
+
+        cls._gen_attributes()
 
     @classmethod
-    def gen_field(cls, name, field, offset):
-        """Generate only one field
-
-        @name: (str) the name of the field
-        @field: (Type instance) the field type
-        @offset: (int) the offset of the field in the structure
-        """
-        cls._gen_simple_attr(name, field, offset)
-        if isinstance(field, Union):
-            cls._gen_union_attr(field, offset)
+    def _gen_attributes(cls):
+        # Generate self.<name> getter and setters
+        for name, field in cls._type.fields:
+            setattr(cls, name, property(
+                lambda self, name=name: self.get_field(name),
+                lambda self, val, name=name: self.set_field(name, val)
+            ))
 
     @classmethod
-    def _gen_simple_attr(cls, name, field, offset):
-        cls._attrs[name] = {"field": field, "offset": offset}
-
-        # Generate self.<name> getter and setter
-        setattr(cls, name, property(
-            lambda self: self.get_field(name),
-            lambda self, val: self.set_field(name, val)
-        ))
-
-        # Generate self.deref_<name> getter and setter if this field is a
-        # Ptr
-        if isinstance(field, Ptr):
-            setattr(cls, "deref_%s" % name, property(
-                lambda self: self.deref_field(name),
-                lambda self, val: self.set_deref_field(name, val)
-            ))
+    def _gen_type(cls, fields):
+        return Struct(cls.__name__, fields)
+
+    def __repr__(self):
+        out = []
+        for name, field in self._type.fields:
+            val_repr = repr(self.get_field(name))
+            if '\n' in val_repr:
+                val_repr = '\n' + indent(val_repr, 4)
+            out.append("%s: %r = %s" % (name, field, val_repr))
+        return '%r:\n' % self.__class__ + indent('\n'.join(out), 2)
 
+
+class PinnedUnion(PinnedStruct):
     @classmethod
-    def _gen_union_attr(cls, union_field, offset):
-        if not isinstance(union_field, Union):
-            raise ValueError("field should be an Union instance")
-        for name, field in union_field.field_list:
-            cls.gen_field(name, field, offset)
+    def _gen_type(cls, fields):
+        return Union(fields)
 
 
 class PinnedSelf(PinnedStruct):
@@ -1069,13 +1102,16 @@ class PinnedSelf(PinnedStruct):
                 ("data", Ptr("<I", PinnedVoid)),
             ]
     """
-    pass
+    def __repr__(self):
+        return self.__class__.__name__
 
 
 class PinnedVoid(PinnedType):
     """Placeholder for e.g. Ptr to an undetermined type. Useful mostly when
     casted to another type. Allows to implement C's "void*" pattern.
     """
+    _type = Void()
+
     def __repr__(self):
         return self.__class__.__name__
 
@@ -1083,6 +1119,14 @@ class PinnedVoid(PinnedType):
 class PinnedPtr(PinnedValue):
 
     @property
+    def val(self):
+        return self._type.get_val(self._vm, self._addr)
+
+    @val.setter
+    def val(self, value):
+        return self._type.set_val(self._vm, self._addr, value)
+
+    @property
     def deref(self):
         return self._type.deref_get(self._vm, self._addr)
 
@@ -1090,6 +1134,10 @@ class PinnedPtr(PinnedValue):
     def deref(self, val):
         return self._type.deref_set(self._vm, self._addr, val)
 
+    def __repr__(self):
+        return "*%s" % hex(self.val)
+
+
 
 # This does not use _MetaPinnedStruct features, impl is custom for strings,
 # because they are unsized. The only memory field is self.value.
@@ -1101,7 +1149,7 @@ class PinnedStr(PinnedType):
     that the utf16 implementation is a bit buggy...
 
     The string value can be got or set (with python str/unicode) through the
-    self.value attribute. String encoding/decoding is handled by the class.
+    self.val attribute. String encoding/decoding is handled by the class.
 
     This type is dynamically sized only (get_size is implemented, not sizeof).
     """
@@ -1109,11 +1157,12 @@ class PinnedStr(PinnedType):
         # TODO: encoding as lambda
         if encoding not in ["ansi", "utf16"]:
             raise NotImplementedError("Only 'ansi' and 'utf16' are implemented")
-        super(PinnedStr, self).__init__(vm, addr)
+        # FIXME: Str type
+        super(PinnedStr, self).__init__(vm, addr, Str())
         self._enc = encoding
 
     @property
-    def value(self):
+    def val(self):
         """Set the string value in memory"""
         if self._enc == "ansi":
             get_str = get_str_ansi
@@ -1123,8 +1172,8 @@ class PinnedStr(PinnedType):
             raise NotImplementedError("Only 'ansi' and 'utf16' are implemented")
         return get_str(self._vm, self.get_addr())
 
-    @value.setter
-    def value(self, s):
+    @val.setter
+    def val(self, s):
         """Get the string value from memory"""
         if self._enc == "ansi":
             set_str = set_str_ansi
@@ -1139,7 +1188,7 @@ class PinnedStr(PinnedType):
         underneath to determine the size, it may therefore read a lot of memory
         and provoke mem faults (analogous to strlen).
         """
-        val = self.value
+        val = self.val
         if self._enc == "ansi":
             return len(val) + 1
         elif self._enc == "utf16":
@@ -1153,7 +1202,7 @@ class PinnedStr(PinnedType):
         return raw
 
     def __repr__(self):
-        return "%r(%s): %r" % (self.__class__, self._enc, self.value)
+        return "%r(%s): %r" % (self.__class__, self._enc, self.val)
 
 
 class PinnedArray(PinnedType):
@@ -1167,9 +1216,6 @@ class PinnedArray(PinnedType):
         array[4:8] = [0, 1, 2, 3]
         print array[20]
 
-    If the @field_type is a Ptr, deref_get(index) and deref_set(index) can be
-    used to dereference a field at a given index in the array.
-
     mem_array_type can be used to generate a type that includes the field_type.
     Such a generated type can be instanciated with only vm and addr, as are
     other PinnedTypes.
@@ -1183,7 +1229,9 @@ class PinnedArray(PinnedType):
             raise NotImplementedError(
                 "Provide field_type to instanciate this class, "
                 "or generate a subclass with mem_array_type.")
-        super(PinnedArray, self).__init__(vm, addr)
+        # FIXME: use underlying Array type
+        super(PinnedArray, self).__init__(vm, addr,
+                                          Array(self._field_type, None))
 
     @property
     def field_type(self):
@@ -1226,12 +1274,6 @@ class PinnedArray(PinnedType):
         else:
             return self._field_type.get(self._vm, self.index2addr(idx))
 
-    def deref_get(self, idx):
-        """If self.field_type is a Ptr, return the PinnedType self[idx] points
-        to.
-        """
-        return self._field_type.deref_get(self._vm, self[idx])
-
     def __setitem__(self, idx, item):
         if isinstance(idx, slice):
             idx = self._normalize_slice(idx)
@@ -1243,12 +1285,6 @@ class PinnedArray(PinnedType):
         else:
             self._field_type.set(self._vm, self.index2addr(idx), item)
 
-    def deref_set(self, idx, item):
-        """If self.field_type is a Ptr, set the PinnedType self[idx] points
-        to with @item.
-        """
-        self._field_type.deref_set(self._vm, self[idx], item)
-
     # just a shorthand
     def as_mem_str(self, encoding="ansi"):
         return self.cast(PinnedStr, encoding)
diff --git a/test/analysis/mem.py b/test/analysis/mem.py
index 5c0388f3..dca3346b 100644
--- a/test/analysis/mem.py
+++ b/test/analysis/mem.py
@@ -7,9 +7,9 @@ import struct
 from miasm2.analysis.machine import Machine
 from miasm2.analysis.mem import PinnedStruct, Num, Ptr, PinnedStr, PinnedArray,\
                                 PinnedSizedArray, Array, mem_array_type,\
-                                mem_sized_array_type, RawStruct, Inline, pin,\
+                                mem_sized_array_type, RawStruct, pin,\
                                 Union, BitField, PinnedSelf, PinnedVoid, Bits, \
-                                set_allocator
+                                set_allocator, PinnedUnion, Struct
 from miasm2.jitter.csts import PAGE_READ, PAGE_WRITE
 from miasm2.os_dep.common import heap
 
@@ -24,8 +24,7 @@ class MyStruct(PinnedStruct):
         # Number field: just struct.pack fields with one value
         ("num", Num("I")),
         ("flags", Num("B")),
-        # Ptr fields are Num, but they can also be dereferenced
-        # (self.deref_<field>). Deref can be read and set.
+        # TODO: comment
         ("other", Ptr("I", OtherStruct)),
         # Ptr to a variable length String
         ("s", Ptr("I", PinnedStr)),
@@ -61,15 +60,15 @@ assert memval == 3
 mstruct.memset()
 assert mstruct.num == 0
 assert mstruct.flags == 0
-assert mstruct.other == 0
-assert mstruct.s == 0
-assert mstruct.i == 0
+assert mstruct.other.val == 0
+assert mstruct.s.val == 0
+assert mstruct.i.val == 0
 mstruct.memset('\x11')
 assert mstruct.num == 0x11111111
 assert mstruct.flags == 0x11
-assert mstruct.other == 0x11111111
-assert mstruct.s == 0x11111111
-assert mstruct.i == 0x11111111
+assert mstruct.other.val == 0x11111111
+assert mstruct.s.val == 0x11111111
+assert mstruct.i.val == 0x11111111
 
 
 # From now, just use heap.vm_alloc
@@ -85,19 +84,21 @@ other.foo = 0x1234
 assert other.foo == 0x1234
 
 ## Basic usage
-mstruct.other = other.get_addr()
-assert mstruct.other == other.get_addr()
-assert mstruct.deref_other == other
-assert mstruct.deref_other.foo == 0x1234
+mstruct.other.val = other.get_addr()
+# This also works for now:
+# mstruct.other = other.get_addr()
+assert mstruct.other.val == other.get_addr()
+assert mstruct.other.deref == other
+assert mstruct.other.deref.foo == 0x1234
 
 ## Deref assignment
 other2 = OtherStruct(jitter.vm)
 other2.foo = 0xbeef
-assert mstruct.deref_other != other2
-mstruct.deref_other = other2
-assert mstruct.deref_other == other2
-assert mstruct.deref_other.foo == 0xbeef
-assert mstruct.other == other.get_addr() # Addr did not change
+assert mstruct.other.deref != other2
+mstruct.other.deref = other2
+assert mstruct.other.deref == other2
+assert mstruct.other.deref.foo == 0xbeef
+assert mstruct.other.val == other.get_addr() # Addr did not change
 assert other.foo == 0xbeef # Deref assignment copies by value
 assert other2.foo == 0xbeef
 assert other.get_addr() != other2.get_addr() # Not the same address
@@ -105,11 +106,12 @@ assert other == other2 # But same value
 
 ## Same stuff for Ptr to PinnedField
 alloc_addr = my_heap.vm_alloc(jitter.vm,
-                              mstruct.get_field_type("i").dst_type.sizeof())
+                              mstruct.get_type().get_field_type("i")
+                                     .dst_type.sizeof())
 mstruct.i = alloc_addr
-mstruct.deref_i.value = 8
-assert mstruct.deref_i.value == 8
-assert mstruct.i == alloc_addr
+mstruct.i.deref.val = 8
+assert mstruct.i.deref.val == 8
+assert mstruct.i.val == alloc_addr
 memval = struct.unpack("I", jitter.vm.get_mem(alloc_addr, 4))[0]
 assert memval == 8
 
@@ -117,37 +119,37 @@ assert memval == 8
 # Str tests
 ## Basic tests
 memstr = PinnedStr(jitter.vm, addr_str)
-memstr.value = ""
-assert memstr.value == ""
+memstr.val = ""
+assert memstr.val == ""
 assert jitter.vm.get_mem(memstr.get_addr(), 1) == '\x00'
-memstr.value = "lala"
+memstr.val = "lala"
 assert jitter.vm.get_mem(memstr.get_addr(), memstr.get_size()) == 'lala\x00'
 jitter.vm.set_mem(memstr.get_addr(), 'MIAMs\x00')
-assert memstr.value == 'MIAMs'
+assert memstr.val == 'MIAMs'
 
 ## Ptr(PinnedStr) manipulations
-mstruct.s = memstr.get_addr()
-assert mstruct.s == addr_str
-assert mstruct.deref_s == memstr
-assert mstruct.deref_s.value == 'MIAMs'
-mstruct.deref_s.value = "That's all folks!"
-assert mstruct.deref_s.value == "That's all folks!"
-assert memstr.value == "That's all folks!"
+mstruct.s.val = memstr.get_addr()
+assert mstruct.s.val == addr_str
+assert mstruct.s.deref == memstr
+assert mstruct.s.deref.val == 'MIAMs'
+mstruct.s.deref.val = "That's all folks!"
+assert mstruct.s.deref.val == "That's all folks!"
+assert memstr.val == "That's all folks!"
 
 ## Other address, same value, same encoding
 memstr2 = PinnedStr(jitter.vm, addr_str2)
-memstr2.value = "That's all folks!"
+memstr2.val = "That's all folks!"
 assert memstr2.get_addr() != memstr.get_addr()
 assert memstr2 == memstr
 
 ## Same value, other encoding
 memstr3 = PinnedStr(jitter.vm, addr_str3, "utf16")
-memstr3.value = "That's all folks!"
+memstr3.val = "That's all folks!"
 assert memstr3.get_addr() != memstr.get_addr()
 assert memstr3.get_size() != memstr.get_size() # Size is different
 assert str(memstr3) != str(memstr) # Pinned representation is different
 assert memstr3 != memstr # Encoding is different, so they are not eq
-assert memstr3.value == memstr.value # But the python value is the same
+assert memstr3.val == memstr.val # But the python value is the same
 
 
 # PinnedArray tests
@@ -254,7 +256,7 @@ for val in ms2.s2:
     assert val == 2
 
 
-# Inline tests
+# Inlining a PinnedType tests
 class InStruct(PinnedStruct):
     fields = [
         ("foo", Num("B")),
@@ -264,7 +266,7 @@ class InStruct(PinnedStruct):
 class ContStruct(PinnedStruct):
     fields = [
         ("one", Num("B")),
-        ("instruct", Inline(InStruct)),
+        ("instruct", InStruct.get_type()),
         ("last", Num("B")),
     ]
 
@@ -298,7 +300,7 @@ class UniStruct(PinnedStruct):
     fields = [
         ("one", Num("B")),
         ("union", Union([
-            ("instruct", Inline(InStruct)),
+            ("instruct", InStruct.get_type()),
             ("i", Num(">I")),
         ])),
         ("last", Num("B")),
@@ -308,20 +310,21 @@ uni = UniStruct(jitter.vm)
 jitter.vm.set_mem(uni.get_addr(), ''.join(chr(x) for x in xrange(len(uni))))
 assert len(uni) == 6 # 1 + max(InStruct.sizeof(), 4) + 1
 assert uni.one == 0x00
-assert uni.instruct.foo == 0x01
-assert uni.instruct.bar == 0x02
-assert uni.i == 0x01020304
+assert uni.union.instruct.foo == 0x01
+assert uni.union.instruct.bar == 0x02
+assert uni.union.i == 0x01020304
 assert uni.last == 0x05
-uni.instruct.foo = 0x02
-assert uni.i == 0x02020304
-uni.i = 0x11223344
-assert uni.instruct.foo == 0x11
-assert uni.instruct.bar == 0x22
+uni.union.instruct.foo = 0x02
+assert uni.union.i == 0x02020304
+uni.union.i = 0x11223344
+assert uni.union.instruct.foo == 0x11
+assert uni.union.instruct.bar == 0x22
 
 
 # BitField test
-class BitStruct(PinnedStruct):
+class BitStruct(PinnedUnion):
     fields = [
+        ("flags_num", Num("H")),
         ("flags", BitField(Num("H"), [
             ("f1_1", 1),
             ("f2_5", 5),
@@ -332,24 +335,24 @@ class BitStruct(PinnedStruct):
 
 bit = BitStruct(jitter.vm)
 bit.memset()
-assert bit.flags == 0
-assert bit.f1_1 == 0
-assert bit.f2_5 == 0
-assert bit.f3_8 == 0
-assert bit.f4_1 == 0
-bit.f1_1 = 1
-bit.f2_5 = 0b10101
-bit.f3_8 = 0b10000001
-assert bit.flags == 0b0010000001101011
-assert bit.f1_1 == 1
-assert bit.f2_5 == 0b10101
-assert bit.f3_8 == 0b10000001
-assert bit.f4_1 == 0
-bit.flags = 0b1101010101011100
-assert bit.f1_1 == 0
-assert bit.f2_5 == 0b01110
-assert bit.f3_8 == 0b01010101
-assert bit.f4_1 == 1
+assert bit.flags_num == 0
+assert bit.flags.f1_1 == 0
+assert bit.flags.f2_5 == 0
+assert bit.flags.f3_8 == 0
+assert bit.flags.f4_1 == 0
+bit.flags.f1_1 = 1
+bit.flags.f2_5 = 0b10101
+bit.flags.f3_8 = 0b10000001
+assert bit.flags_num == 0b0010000001101011
+assert bit.flags.f1_1 == 1
+assert bit.flags.f2_5 == 0b10101
+assert bit.flags.f3_8 == 0b10000001
+assert bit.flags.f4_1 == 0
+bit.flags_num = 0b1101010101011100
+assert bit.flags.f1_1 == 0
+assert bit.flags.f2_5 == 0b01110
+assert bit.flags.f3_8 == 0b01010101
+assert bit.flags.f4_1 == 1
 
 
 # Unhealthy ideas
@@ -363,72 +366,83 @@ class UnhealthyIdeas(PinnedStruct):
         ("pppself", Ptr("I", Ptr("I", Ptr("I", PinnedSelf)))),
     ]
 
-# Other way to handle self dependency and circular dependencies
-# NOTE: in this case, PinnedSelf would have been fine
-UnhealthyIdeas.fields.append(
-    ("pppself2", Ptr("I", Ptr("I", Ptr("I", UnhealthyIdeas)))))
-# Regen all fields
-UnhealthyIdeas.gen_fields()
-
 p_size = Ptr("I", PinnedVoid).size()
 
 ideas = UnhealthyIdeas(jitter.vm)
 ideas.memset()
 ideas.pself = ideas.get_addr()
-assert ideas == ideas.deref_pself
+assert ideas == ideas.pself.deref
 
 ideas.apself[0] = ideas.get_addr()
-assert ideas.apself.deref_get(0) == ideas
+assert ideas.apself[0].deref == ideas
 ideas.apself[1] = my_heap.vm_alloc(jitter.vm, UnhealthyIdeas.sizeof())
-ideas.apself.deref_set(1, ideas)
+ideas.apself[1].deref = ideas
 assert ideas.apself[1] != ideas.get_addr()
-assert ideas.apself.deref_get(1) == ideas
+assert ideas.apself[1].deref == ideas
 
 ideas.ppself = my_heap.vm_alloc(jitter.vm, p_size)
-ideas.deref_ppself.value = ideas.get_addr()
-assert ideas.deref_ppself.value == ideas.get_addr()
-assert ideas.deref_ppself.deref_value == ideas
+ideas.ppself.deref.val = ideas.get_addr()
+assert ideas.ppself.deref.val == ideas.get_addr()
+assert ideas.ppself.deref.deref == ideas
 
-ideas.deref_ppself.value = my_heap.vm_alloc(jitter.vm, UnhealthyIdeas.sizeof())
-ideas.deref_ppself.deref_value = ideas
-assert ideas.deref_ppself.value != ideas.get_addr()
-assert ideas.deref_ppself.deref_value == ideas
+ideas.ppself.deref.val = my_heap.vm_alloc(jitter.vm, UnhealthyIdeas.sizeof())
+ideas.ppself.deref.deref = ideas
+assert ideas.ppself.deref.val != ideas.get_addr()
+assert ideas.ppself.deref.deref == ideas
 
 ideas.pppself = my_heap.vm_alloc(jitter.vm, p_size)
-ideas.deref_pppself.value = my_heap.vm_alloc(jitter.vm, p_size)
-ideas.deref_pppself.deref_value.value = ideas.get_addr()
-assert ideas.deref_pppself.deref_value.deref_value == ideas
+ideas.pppself.deref.val = my_heap.vm_alloc(jitter.vm, p_size)
+ideas.pppself.deref.deref.val = ideas.get_addr()
+assert ideas.pppself.deref.deref.deref == ideas
+
+
+# Circular dependencies
+class A(PinnedStruct):
+    pass
+
+class B(PinnedStruct):
+    fields = [("a", Ptr("I", A)),]
+
+# Gen A's fields after declaration
+A.gen_fields([("b", Ptr("I", B)),])
+
+a = A(jitter.vm)
+b = B(jitter.vm)
+a.b.val = b.get_addr()
+b.a.val = a.get_addr()
+assert a.b.deref == b
+assert b.a.deref == a
 
 
 # Cast tests
 # PinnedStruct cast
-PinnedInt = pin(Num("I"))
-PinnedShort = pin(Num("H"))
+PinnedInt = Num("I").pinned
+PinnedShort = Num("H").pinned
 dword = PinnedInt(jitter.vm)
-dword.value = 0x12345678
+dword.val = 0x12345678
 assert isinstance(dword.cast(PinnedShort), PinnedShort)
-assert dword.cast(PinnedShort).value == 0x5678
+assert dword.cast(PinnedShort).val == 0x5678
 
 # Field cast
 ms2.s2[0] = 0x34
 ms2.s2[1] = 0x12
-assert ms2.cast_field("s2", PinnedShort).value == 0x1234
+assert ms2.cast_field("s2", PinnedShort).val == 0x1234
 
 # Other method
-assert PinnedShort(jitter.vm, ms2.get_addr("s2")).value == 0x1234
+assert PinnedShort(jitter.vm, ms2.get_addr("s2")).val == 0x1234
 
 # Manual cast inside an Array
 ms2.s2[4] = 0xcd
 ms2.s2[5] = 0xab
-assert PinnedShort(jitter.vm, ms2.s2.index2addr(4)).value == 0xabcd
+assert PinnedShort(jitter.vm, ms2.s2.index2addr(4)).val == 0xabcd
 
 # void* style cast
-PinnedPtrVoid = pin(Ptr("I", PinnedVoid))
-PinnedPtrMyStruct = pin(Ptr("I", MyStruct))
+PinnedPtrVoid = Ptr("I", PinnedVoid).pinned
+PinnedPtrMyStruct = Ptr("I", MyStruct).pinned
 p = PinnedPtrVoid(jitter.vm)
-p.value = mstruct.get_addr()
-assert p.deref_value.cast(MyStruct) == mstruct
-assert p.cast(PinnedPtrMyStruct).deref_value == mstruct
+p.val = mstruct.get_addr()
+assert p.deref.cast(MyStruct) == mstruct
+assert p.cast(PinnedPtrMyStruct).deref == mstruct
 
 # Field equality tests
 assert RawStruct("IH") == RawStruct("IH")
@@ -438,11 +452,19 @@ assert Num(">I") != Num("<I")
 assert Ptr("I", MyStruct) == Ptr("I", MyStruct)
 assert Ptr(">I", MyStruct) != Ptr("<I", MyStruct)
 assert Ptr("I", MyStruct) != Ptr("I", MyStruct2)
-assert Inline(MyStruct) == Inline(MyStruct)
-assert Inline(MyStruct) != Inline(MyStruct2)
+assert MyStruct.get_type() == MyStruct.get_type()
+assert MyStruct.get_type() != MyStruct2.get_type()
 assert Array(Num("H"), 12) == Array(Num("H"), 12)
 assert Array(Num("H"), 11) != Array(Num("H"), 12)
 assert Array(Num("I"), 12) != Array(Num("H"), 12)
+assert Struct("a", [("f1", Num("B")), ("f2", Num("H"))]) == \
+        Struct("a", [("f1", Num("B")), ("f2", Num("H"))])
+assert Struct("a", [("f2", Num("B")), ("f2", Num("H"))]) != \
+        Struct("a", [("f1", Num("B")), ("f2", Num("H"))])
+assert Struct("a", [("f1", Num("B")), ("f2", Num("H"))]) != \
+        Struct("a", [("f1", Num("I")), ("f2", Num("H"))])
+assert Struct("a", [("f1", Num("B")), ("f2", Num("H"))]) != \
+        Struct("b", [("f1", Num("B")), ("f2", Num("H"))])
 assert Union([("f1", Num("B")), ("f2", Num("H"))]) == \
         Union([("f1", Num("B")), ("f2", Num("H"))])
 assert Union([("f2", Num("B")), ("f2", Num("H"))]) != \
@@ -463,17 +485,17 @@ assert BitField(Num("B"), [("f1", 1), ("f2", 4), ("f3", 1)]) != \
         BitField(Num("B"), [("f1", 2), ("f2", 4), ("f3", 1)])
 
 
-# Quick pin(PinnedField)/PinnedField hash test:
-assert pin(Num("f"))(jitter.vm, addr) == pin(Num("f"))(jitter.vm, addr)
+# Quick PinnedField.pinned/PinnedField hash test
+assert Num("f").pinned(jitter.vm, addr) == Num("f").pinned(jitter.vm, addr)
 # Types are cached
-assert pin(Num("f")) == pin(Num("f"))
-assert pin(Num("d")) != pin(Num("f"))
-assert pin(Union([("f1", Num("I")), ("f2", Num("H"))])) == \
-        pin(Union([("f1", Num("I")), ("f2", Num("H"))]))
+assert Num("f").pinned == Num("f").pinned
+assert Num("d").pinned != Num("f").pinned
+assert Union([("f1", Num("I")), ("f2", Num("H"))]).pinned == \
+        Union([("f1", Num("I")), ("f2", Num("H"))]).pinned
 assert mem_array_type(Num("B")) == mem_array_type(Num("B"))
 assert mem_array_type(Num("I")) != mem_array_type(Num("B"))
-assert mem_sized_array_type(Num("B"), 20) == mem_sized_array_type(Num("B"), 20)
-assert mem_sized_array_type(Num("B"), 19) != mem_sized_array_type(Num("B"), 20)
+assert Array(Num("B"), 20).pinned == Array(Num("B"), 20).pinned
+assert Array(Num("B"), 19).pinned != Array(Num("B"), 20).pinned
 
 
 # Repr tests
@@ -485,8 +507,8 @@ print repr(cont), '\n'
 print repr(uni), '\n'
 print repr(bit), '\n'
 print repr(ideas), '\n'
-print repr(pin(Array(Inline(MyStruct2), 2))(jitter.vm, addr)), '\n'
-print repr(pin(Num("f"))(jitter.vm, addr)), '\n'
+print repr(Array(MyStruct2.get_type(), 2).pinned(jitter.vm, addr)), '\n'
+print repr(Num("f").pinned(jitter.vm, addr)), '\n'
 print repr(memarray)
 print repr(memsarray)
 print repr(memstr)