about summary refs log tree commit diff stats
path: root/miasm2/expression/expression.py
diff options
context:
space:
mode:
authorCamille Mougey <commial@gmail.com>2016-11-07 12:24:51 +0100
committerGitHub <noreply@github.com>2016-11-07 12:24:51 +0100
commit3af8c4a5a6668cc89a4df3fb66222f4147a896b9 (patch)
tree21a7d7ad5d6da120e8e23e0b92725073d4d4e27c /miasm2/expression/expression.py
parenta15e0faca425c6e2591448e510bf14f1c3f04e14 (diff)
parentf0fbc59a663774dc4f4861308bee3f91ccd9746d (diff)
downloadmiasm-3af8c4a5a6668cc89a4df3fb66222f4147a896b9.tar.gz
miasm-3af8c4a5a6668cc89a4df3fb66222f4147a896b9.zip
Merge pull request #445 from serpilliere/symb_exec_clean
Symb exec clean
Diffstat (limited to 'miasm2/expression/expression.py')
-rw-r--r--miasm2/expression/expression.py623
1 files changed, 341 insertions, 282 deletions
diff --git a/miasm2/expression/expression.py b/miasm2/expression/expression.py
index d04530c3..324d5fea 100644
--- a/miasm2/expression/expression.py
+++ b/miasm2/expression/expression.py
@@ -114,28 +114,52 @@ class Expr(object):
 
     "Parent class for Miasm Expressions"
 
-    __slots__ = ["is_term", "is_simp", "is_canon",
-                 "is_eval", "_hash", "_repr", "_size",
-                 "is_var_ident"]
+    __slots__ = ["__hash", "__repr", "__size"]
 
+    all_exprs = set()
+    args2expr = {}
+    canon_exprs = set()
+    use_singleton = True
 
     def set_size(self, value):
         raise ValueError('size is not mutable')
 
     def __init__(self):
-        self.is_term = False   # Terminal expression
-        self.is_simp = False   # Expression already simplified
-        self.is_canon = False  # Expression already canonised
-        self.is_eval = False   # Expression already evalued
-        self.is_var_ident = False # Expression not identifier
+        self.__hash = None
+        self.__repr = None
+        self.__size = None
 
-        self._hash = None
-        self._repr = None
+    size = property(lambda self: self.__size)
 
-    size = property(lambda self: self._size)
+    @staticmethod
+    def get_object(cls, args):
+        if not cls.use_singleton:
+            return object.__new__(cls, args)
+
+        expr = Expr.args2expr.get((cls, args))
+        if expr is None:
+            expr = object.__new__(cls, args)
+            Expr.args2expr[(cls, args)] = expr
+        return expr
+
+    def __new__(cls, *args, **kwargs):
+        expr = object.__new__(cls, *args, **kwargs)
+        return expr
+
+    def get_is_canon(self):
+        return self in Expr.canon_exprs
+
+    def set_is_canon(self, value):
+        assert(value is True)
+        Expr.canon_exprs.add(self)
+
+    is_canon = property(get_is_canon, set_is_canon)
 
     # Common operations
 
+    def __str__(self):
+        raise NotImplementedError("Abstract Method")
+
     def __getitem__(self, i):
         if not isinstance(i, slice):
             raise TypeError("Expression: Bad slice: %s" % i)
@@ -153,14 +177,14 @@ class Expr(object):
         return False
 
     def __repr__(self):
-        if self._repr is None:
-            self._repr = self._exprrepr()
-        return self._repr
+        if self.__repr is None:
+            self.__repr = self._exprrepr()
+        return self.__repr
 
     def __hash__(self):
-        if self._hash is None:
-            self._hash = self._exprhash()
-        return self._hash
+        if self.__hash is None:
+            self.__hash = self._exprhash()
+        return self.__hash
 
     def pre_eq(self, other):
         """Return True if ids are equal;
@@ -264,8 +288,6 @@ class Expr(object):
                     new_e = ExprOp(e.op, *args)
                 else:
                     new_e = e
-            elif isinstance(e, ExprCompose):
-                new_e = ExprCompose(canonize_expr_list_compose(e.args))
             else:
                 new_e = e
             new_e.is_canon = True
@@ -287,8 +309,7 @@ class Expr(object):
             return self
         ad_size = size - self.size
         n = ExprInt(0, ad_size)
-        return ExprCompose([(self, 0, self.size),
-                            (n, self.size, size)])
+        return ExprCompose(self, n)
 
     def signExtend(self, size):
         """Sign extend to size
@@ -298,12 +319,10 @@ class Expr(object):
         if self.size == size:
             return self
         ad_size = size - self.size
-        c = ExprCompose([(self, 0, self.size),
-                         (ExprCond(self.msb(),
-                                   ExprInt(size2mask(ad_size), ad_size),
-                                   ExprInt(0, ad_size)),
-                          self.size, size)
-                         ])
+        c = ExprCompose(self,
+                        ExprCond(self.msb(),
+                                 ExprInt(size2mask(ad_size), ad_size),
+                                 ExprInt(0, ad_size)))
         return c
 
     def graph_recursive(self, graph):
@@ -341,7 +360,8 @@ class ExprInt(Expr):
      - Constant 0x12345678 on 32bits
      """
 
-    __slots__ = ["_arg"]
+    __slots__ = Expr.__slots__ + ["__arg"]
+
 
     def __init__(self, num, size=None):
         """Create an ExprInt from a modint or num/size
@@ -351,31 +371,36 @@ class ExprInt(Expr):
         super(ExprInt, self).__init__()
 
         if is_modint(num):
-            self._arg = num
-            self._size = self.arg.size
+            self.__arg = num
+            self.__size = self.arg.size
             if size is not None and num.size != size:
                 raise RuntimeError("size must match modint size")
         elif size is not None:
-            self._arg = mod_size2uint[size](num)
-            self._size = self.arg.size
+            self.__arg = mod_size2uint[size](num)
+            self.__size = self.arg.size
         else:
             raise ValueError('arg must by modint or (int,size)! %s' % num)
 
-    arg = property(lambda self: self._arg)
+    size = property(lambda self: self.__size)
+    arg = property(lambda self: self.__arg)
 
-    def __eq__(self, other):
-        res = self.pre_eq(other)
-        if res is not None:
-            return res
-        return (self._arg == other._arg and
-                self._size == other._size)
+    def __getstate__(self):
+        return int(self.__arg), self.__size
+
+    def __setstate__(self, state):
+        self.__init__(*state)
+
+    def __new__(cls, arg, size=None):
+        if size is None:
+            size = arg.size
+        return Expr.get_object(cls, (arg, size))
 
     def __get_int(self):
         "Return self integer representation"
-        return int(self._arg & size2mask(self._size))
+        return int(self.__arg & size2mask(self.__size))
 
     def __str__(self):
-        if self._arg < 0:
+        if self.__arg < 0:
             return str("-0x%X" % (- self.__get_int()))
         else:
             return str("0x%X" % self.__get_int())
@@ -390,10 +415,10 @@ class ExprInt(Expr):
         return set()
 
     def _exprhash(self):
-        return hash((EXPRINT, self._arg, self._size))
+        return hash((EXPRINT, self.__arg, self.__size))
 
     def _exprrepr(self):
-        return "%s(%r)" % (self.__class__.__name__, self._arg)
+        return "%s(0x%X)" % (self.__class__.__name__, self.__get_int())
 
     def __contains__(self, e):
         return self == e
@@ -403,7 +428,7 @@ class ExprInt(Expr):
         return self
 
     def copy(self):
-        return ExprInt(self._arg)
+        return ExprInt(self.__arg)
 
     def depth(self):
         return 1
@@ -428,7 +453,7 @@ class ExprId(Expr):
      - variable v1
      """
 
-    __slots__ = ["_name"]
+    __slots__ = Expr.__slots__ + ["__name"]
 
     def __init__(self, name, size=32):
         """Create an identifier
@@ -437,19 +462,22 @@ class ExprId(Expr):
         """
         super(ExprId, self).__init__()
 
-        self._name, self._size = name, size
+        self.__name, self.__size = name, size
 
-    name = property(lambda self: self._name)
+    size = property(lambda self: self.__size)
+    name = property(lambda self: self.__name)
 
-    def __eq__(self, other):
-        res = self.pre_eq(other)
-        if res is not None:
-            return res
-        return (self._name == other._name and
-                self._size == other._size)
+    def __getstate__(self):
+        return self.__name, self.__size
+
+    def __setstate__(self, state):
+        self.__init__(*state)
+
+    def __new__(cls, name, size=32):
+        return Expr.get_object(cls, (name, size))
 
     def __str__(self):
-        return str(self._name)
+        return str(self.__name)
 
     def get_r(self, mem_read=False, cst_read=False):
         return set([self])
@@ -459,10 +487,10 @@ class ExprId(Expr):
 
     def _exprhash(self):
         # TODO XXX: hash size ??
-        return hash((EXPRID, self._name, self._size))
+        return hash((EXPRID, self.__name, self.__size))
 
     def _exprrepr(self):
-        return "%s(%r, %d)" % (self.__class__.__name__, self._name, self._size)
+        return "%s(%r, %d)" % (self.__class__.__name__, self.__name, self.__size)
 
     def __contains__(self, e):
         return self == e
@@ -472,7 +500,7 @@ class ExprId(Expr):
         return self
 
     def copy(self):
-        return ExprId(self._name, self._size)
+        return ExprId(self.__name, self.__size)
 
     def depth(self):
         return 1
@@ -489,7 +517,7 @@ class ExprAff(Expr):
      - var1 <- 2
     """
 
-    __slots__ = ["_src", "_dst"]
+    __slots__ = Expr.__slots__ + ["__dst", "__src"]
 
     def __init__(self, dst, src):
         """Create an ExprAff for dst <- src
@@ -506,80 +534,75 @@ class ExprAff(Expr):
 
         if isinstance(dst, ExprSlice):
             # Complete the source with missing slice parts
-            self._dst = dst.arg
+            self.__dst = dst.arg
             rest = [(ExprSlice(dst.arg, r[0], r[1]), r[0], r[1])
                     for r in dst.slice_rest()]
             all_a = [(src, dst.start, dst.stop)] + rest
             all_a.sort(key=lambda x: x[1])
-            self._src = ExprCompose(all_a)
+            args = [expr for (expr, _, _) in all_a]
+            self.__src = ExprCompose(*args)
 
         else:
-            self._dst, self._src = dst, src
+            self.__dst, self.__src = dst, src
+
+        self.__size = self.dst.size
 
-        self._size = self.dst.size
+    size = property(lambda self: self.__size)
+    dst = property(lambda self: self.__dst)
+    src = property(lambda self: self.__src)
 
-    dst = property(lambda self: self._dst)
-    src = property(lambda self: self._src)
+    def __getstate__(self):
+        return self.__dst, self.__src
+
+    def __setstate__(self, state):
+        self.__init__(*state)
+
+    def __new__(cls, dst, src):
+        return Expr.get_object(cls, (dst, src))
 
     def __str__(self):
-        return "%s = %s" % (str(self._dst), str(self._src))
+        return "%s = %s" % (str(self.__dst), str(self.__src))
 
     def get_r(self, mem_read=False, cst_read=False):
-        elements = self._src.get_r(mem_read, cst_read)
-        if isinstance(self._dst, ExprMem) and mem_read:
-            elements.update(self._dst.arg.get_r(mem_read, cst_read))
+        elements = self.__src.get_r(mem_read, cst_read)
+        if isinstance(self.__dst, ExprMem) and mem_read:
+            elements.update(self.__dst.arg.get_r(mem_read, cst_read))
         return elements
 
     def get_w(self):
-        if isinstance(self._dst, ExprMem):
-            return set([self._dst])  # [memreg]
+        if isinstance(self.__dst, ExprMem):
+            return set([self.__dst])  # [memreg]
         else:
-            return self._dst.get_w()
+            return self.__dst.get_w()
 
     def _exprhash(self):
-        return hash((EXPRAFF, hash(self._dst), hash(self._src)))
+        return hash((EXPRAFF, hash(self.__dst), hash(self.__src)))
 
     def _exprrepr(self):
-        return "%s(%r, %r)" % (self.__class__.__name__, self._dst, self._src)
+        return "%s(%r, %r)" % (self.__class__.__name__, self.__dst, self.__src)
 
-    def __contains__(self, e):
-        return self == e or self._src.__contains__(e) or self._dst.__contains__(e)
-
-    # XXX /!\ for hackish expraff to slice
-    def get_modified_slice(self):
-        """Return an Expr list of extra expressions needed during the
-        object instanciation"""
-
-        dst = self._dst
-        if not isinstance(self._src, ExprCompose):
-            raise ValueError("Get mod slice not on expraff slice", str(self))
-        modified_s = []
-        for arg in self._src.args:
-            if (not isinstance(arg[0], ExprSlice) or
-                    arg[0].arg != dst or
-                    arg[1] != arg[0].start or
-                    arg[2] != arg[0].stop):
-                # If x is not the initial expression
-                modified_s.append(arg)
-        return modified_s
+    def __contains__(self, expr):
+        return (self == expr or
+                self.__src.__contains__(expr) or
+                self.__dst.__contains__(expr))
 
     @visit_chk
     def visit(self, cb, tv=None):
-        dst, src = self._dst.visit(cb, tv), self._src.visit(cb, tv)
-        if dst == self._dst and src == self._src:
+        dst, src = self.__dst.visit(cb, tv), self.__src.visit(cb, tv)
+        if dst == self.__dst and src == self.__src:
             return self
         else:
             return ExprAff(dst, src)
 
     def copy(self):
-        return ExprAff(self._dst.copy(), self._src.copy())
+        return ExprAff(self.__dst.copy(), self.__src.copy())
 
     def depth(self):
-        return max(self._src.depth(), self._dst.depth()) + 1
+        return max(self.__src.depth(), self.__dst.depth()) + 1
 
     def graph_recursive(self, graph):
         graph.add_node(self)
-        for arg in [self._src, self._dst]:
+        for arg in [self.__src, self.__dst]:
             arg.graph_recursive(graph)
             graph.add_uniq_edge(self, arg)
 
@@ -594,7 +617,7 @@ class ExprCond(Expr):
      - if (cond) then ... else ...
     """
 
-    __slots__ = ["_cond", "_src1", "_src2"]
+    __slots__ = Expr.__slots__ + ["__cond", "__src1", "__src2"]
 
     def __init__(self, cond, src1, src2):
         """Create an ExprCond
@@ -605,65 +628,74 @@ class ExprCond(Expr):
 
         super(ExprCond, self).__init__()
 
+        self.__cond, self.__src1, self.__src2 = cond, src1, src2
         assert(src1.size == src2.size)
+        self.__size = self.src1.size
 
-        self._cond, self._src1, self._src2 = cond, src1, src2
-        self._size = self.src1.size
+    size = property(lambda self: self.__size)
+    cond = property(lambda self: self.__cond)
+    src1 = property(lambda self: self.__src1)
+    src2 = property(lambda self: self.__src2)
 
-    cond = property(lambda self: self._cond)
-    src1 = property(lambda self: self._src1)
-    src2 = property(lambda self: self._src2)
+    def __getstate__(self):
+        return self.__cond, self.__src1, self.__src2
+
+    def __setstate__(self, state):
+        self.__init__(*state)
+
+    def __new__(cls, cond, src1, src2):
+        return Expr.get_object(cls, (cond, src1, src2))
 
     def __str__(self):
-        return "(%s?(%s,%s))" % (str(self._cond), str(self._src1), str(self._src2))
+        return "(%s?(%s,%s))" % (str(self.__cond), str(self.__src1), str(self.__src2))
 
     def get_r(self, mem_read=False, cst_read=False):
-        out_src1 = self._src1.get_r(mem_read, cst_read)
-        out_src2 = self._src2.get_r(mem_read, cst_read)
-        return self._cond.get_r(mem_read,
-                                cst_read).union(out_src1).union(out_src2)
+        out_src1 = self.src1.get_r(mem_read, cst_read)
+        out_src2 = self.src2.get_r(mem_read, cst_read)
+        return self.cond.get_r(mem_read,
+                               cst_read).union(out_src1).union(out_src2)
 
     def get_w(self):
         return set()
 
     def _exprhash(self):
         return hash((EXPRCOND, hash(self.cond),
-                     hash(self._src1), hash(self._src2)))
+                     hash(self.__src1), hash(self.__src2)))
 
     def _exprrepr(self):
         return "%s(%r, %r, %r)" % (self.__class__.__name__,
-                                   self._cond, self._src1, self._src2)
+                                   self.__cond, self.__src1, self.__src2)
 
     def __contains__(self, e):
         return (self == e or
-                self._cond.__contains__(e) or
-                self._src1.__contains__(e) or
-                self._src2.__contains__(e))
+                self.cond.__contains__(e) or
+                self.src1.__contains__(e) or
+                self.src2.__contains__(e))
 
     @visit_chk
     def visit(self, cb, tv=None):
-        cond = self._cond.visit(cb, tv)
-        src1 = self._src1.visit(cb, tv)
-        src2 = self._src2.visit(cb, tv)
-        if (cond == self._cond and
-            src1 == self._src1 and
-                src2 == self._src2):
+        cond = self.__cond.visit(cb, tv)
+        src1 = self.__src1.visit(cb, tv)
+        src2 = self.__src2.visit(cb, tv)
+        if (cond == self.__cond and
+            src1 == self.__src1 and
+                src2 == self.__src2):
             return self
         return ExprCond(cond, src1, src2)
 
     def copy(self):
-        return ExprCond(self._cond.copy(),
-                        self._src1.copy(),
-                        self._src2.copy())
+        return ExprCond(self.__cond.copy(),
+                        self.__src1.copy(),
+                        self.__src2.copy())
 
     def depth(self):
-        return max(self._cond.depth(),
-                   self._src1.depth(),
-                   self._src2.depth()) + 1
+        return max(self.__cond.depth(),
+                   self.__src1.depth(),
+                   self.__src2.depth()) + 1
 
     def graph_recursive(self, graph):
         graph.add_node(self)
-        for arg in [self._cond, self._src1, self._src2]:
+        for arg in [self.__cond, self.__src1, self.__src2]:
             arg.graph_recursive(graph)
             graph.add_uniq_edge(self, arg)
 
@@ -677,7 +709,7 @@ class ExprMem(Expr):
      - Memory write
     """
 
-    __slots__ = ["_arg", "_size"]
+    __slots__ = Expr.__slots__ + ["__arg"]
 
     def __init__(self, arg, size=32):
         """Create an ExprMem
@@ -691,16 +723,26 @@ class ExprMem(Expr):
             raise ValueError(
                 'ExprMem: arg must be an Expr (not %s)' % type(arg))
 
-        self._arg, self._size = arg, size
+        self.__arg, self.__size = arg, size
+
+    size = property(lambda self: self.__size)
+    arg = property(lambda self: self.__arg)
 
-    arg = property(lambda self: self._arg)
+    def __getstate__(self):
+        return self.__arg, self.__size
+
+    def __setstate__(self, state):
+        self.__init__(*state)
+
+    def __new__(cls, arg, size=32):
+        return Expr.get_object(cls, (arg, size))
 
     def __str__(self):
-        return "@%d[%s]" % (self._size, str(self._arg))
+        return "@%d[%s]" % (self.size, str(self.arg))
 
     def get_r(self, mem_read=False, cst_read=False):
         if mem_read:
-            return set(self._arg.get_r(mem_read, cst_read).union(set([self])))
+            return set(self.__arg.get_r(mem_read, cst_read).union(set([self])))
         else:
             return set([self])
 
@@ -708,36 +750,36 @@ class ExprMem(Expr):
         return set([self])  # [memreg]
 
     def _exprhash(self):
-        return hash((EXPRMEM, hash(self._arg), self._size))
+        return hash((EXPRMEM, hash(self.__arg), self.__size))
 
     def _exprrepr(self):
         return "%s(%r, %r)" % (self.__class__.__name__,
-                               self._arg, self._size)
+                               self.__arg, self.__size)
 
-    def __contains__(self, e):
-        return self == e or self._arg.__contains__(e)
+    def __contains__(self, expr):
+        return self == expr or self.__arg.__contains__(expr)
 
     @visit_chk
     def visit(self, cb, tv=None):
-        arg = self._arg.visit(cb, tv)
-        if arg == self._arg:
+        arg = self.__arg.visit(cb, tv)
+        if arg == self.__arg:
             return self
-        return ExprMem(arg, self._size)
+        return ExprMem(arg, self.size)
 
     def copy(self):
-        arg = self._arg.copy()
-        return ExprMem(arg, size=self._size)
+        arg = self.arg.copy()
+        return ExprMem(arg, size=self.size)
 
     def is_op_segm(self):
-        return isinstance(self._arg, ExprOp) and self._arg.op == 'segm'
+        return isinstance(self.__arg, ExprOp) and self.__arg.op == 'segm'
 
     def depth(self):
-        return self._arg.depth() + 1
+        return self.__arg.depth() + 1
 
     def graph_recursive(self, graph):
         graph.add_node(self)
-        self._arg.graph_recursive(graph)
-        graph.add_uniq_edge(self, self._arg)
+        self.__arg.graph_recursive(graph)
+        graph.add_uniq_edge(self, self.__arg)
 
 
 class ExprOp(Expr):
@@ -750,7 +792,7 @@ class ExprOp(Expr):
      - parity bit(var1)
     """
 
-    __slots__ = ["_op", "_args"]
+    __slots__ = Expr.__slots__ + ["__op", "__args"]
 
     def __init__(self, op, *args):
         """Create an ExprOp
@@ -772,44 +814,44 @@ class ExprOp(Expr):
         if not isinstance(op, str):
             raise ValueError("ExprOp: 'op' argument must be a string")
 
-        self._op, self._args = op, tuple(args)
+        self.__op, self.__args = op, tuple(args)
 
         # Set size for special cases
-        if self._op in [
+        if self.__op in [
                 '==', 'parity', 'fcom_c0', 'fcom_c1', 'fcom_c2', 'fcom_c3',
                 'fxam_c0', 'fxam_c1', 'fxam_c2', 'fxam_c3',
                 "access_segment_ok", "load_segment_limit_ok", "bcdadd_cf",
                 "ucomiss_zf", "ucomiss_pf", "ucomiss_cf"]:
             sz = 1
-        elif self._op in [TOK_INF, TOK_INF_SIGNED,
-                          TOK_INF_UNSIGNED, TOK_INF_EQUAL,
-                          TOK_INF_EQUAL_SIGNED, TOK_INF_EQUAL_UNSIGNED,
-                          TOK_EQUAL, TOK_POS,
-                          TOK_POS_STRICT,
-                          ]:
+        elif self.__op in [TOK_INF, TOK_INF_SIGNED,
+                           TOK_INF_UNSIGNED, TOK_INF_EQUAL,
+                           TOK_INF_EQUAL_SIGNED, TOK_INF_EQUAL_UNSIGNED,
+                           TOK_EQUAL, TOK_POS,
+                           TOK_POS_STRICT,
+                           ]:
             sz = 1
-        elif self._op in ['mem_16_to_double', 'mem_32_to_double',
-                          'mem_64_to_double', 'mem_80_to_double',
-                          'int_16_to_double', 'int_32_to_double',
-                          'int_64_to_double', 'int_80_to_double']:
+        elif self.__op in ['mem_16_to_double', 'mem_32_to_double',
+                           'mem_64_to_double', 'mem_80_to_double',
+                           'int_16_to_double', 'int_32_to_double',
+                           'int_64_to_double', 'int_80_to_double']:
             sz = 64
-        elif self._op in ['double_to_mem_16', 'double_to_int_16',
-                          'float_trunc_to_int_16', 'double_trunc_to_int_16']:
+        elif self.__op in ['double_to_mem_16', 'double_to_int_16',
+                           'float_trunc_to_int_16', 'double_trunc_to_int_16']:
             sz = 16
-        elif self._op in ['double_to_mem_32', 'double_to_int_32',
-                          'float_trunc_to_int_32', 'double_trunc_to_int_32',
-                          'double_to_float']:
+        elif self.__op in ['double_to_mem_32', 'double_to_int_32',
+                           'float_trunc_to_int_32', 'double_trunc_to_int_32',
+                           'double_to_float']:
             sz = 32
-        elif self._op in ['double_to_mem_64', 'double_to_int_64',
-                          'float_trunc_to_int_64', 'double_trunc_to_int_64',
-                          'float_to_double']:
+        elif self.__op in ['double_to_mem_64', 'double_to_int_64',
+                           'float_trunc_to_int_64', 'double_trunc_to_int_64',
+                           'float_to_double']:
             sz = 64
-        elif self._op in ['double_to_mem_80', 'double_to_int_80',
-                          'float_trunc_to_int_80',
-                          'double_trunc_to_int_80']:
+        elif self.__op in ['double_to_mem_80', 'double_to_int_80',
+                           'float_trunc_to_int_80',
+                           'double_trunc_to_int_80']:
             sz = 80
-        elif self._op in ['segm']:
-            sz = self._args[1].size
+        elif self.__op in ['segm']:
+            sz = self.__args[1].size
         else:
             if None in sizes:
                 sz = None
@@ -817,256 +859,275 @@ class ExprOp(Expr):
                 # All arguments have the same size
                 sz = list(sizes)[0]
 
-        self._size = sz
+        self.__size = sz
 
-    op = property(lambda self: self._op)
-    args = property(lambda self: self._args)
+    size = property(lambda self: self.__size)
+    op = property(lambda self: self.__op)
+    args = property(lambda self: self.__args)
+
+    def __getstate__(self):
+        return self.__op, self.__args
+
+    def __setstate__(self, state):
+        op, args = state
+        self.__init__(op, *args)
+
+    def __new__(cls, op, *args):
+        return Expr.get_object(cls, (op, args))
 
     def __str__(self):
         if self.is_associative():
-            return '(' + self._op.join([str(arg) for arg in self._args]) + ')'
-        if (self._op.startswith('call_func_') or
-            self._op == 'cpuid' or
-            len(self._args) > 2 or
-                self._op in ['parity', 'segm']):
-            return self._op + '(' + ', '.join([str(arg) for arg in self._args]) + ')'
-        if len(self._args) == 2:
-            return ('(' + str(self._args[0]) +
-                    ' ' + self.op + ' ' + str(self._args[1]) + ')')
+            return '(' + self.__op.join([str(arg) for arg in self.__args]) + ')'
+        if (self.__op.startswith('call_func_') or
+            self.__op == 'cpuid' or
+            len(self.__args) > 2 or
+                self.__op in ['parity', 'segm']):
+            return self.__op + '(' + ', '.join([str(arg) for arg in self.__args]) + ')'
+        if len(self.__args) == 2:
+            return ('(' + str(self.__args[0]) +
+                    ' ' + self.op + ' ' + str(self.__args[1]) + ')')
         else:
             return reduce(lambda x, y: x + ' ' + str(y),
-                          self._args,
-                          '(' + str(self._op)) + ')'
+                          self.__args,
+                          '(' + str(self.__op)) + ')'
 
     def get_r(self, mem_read=False, cst_read=False):
         return reduce(lambda elements, arg:
-                      elements.union(arg.get_r(mem_read, cst_read)), self._args, set())
+                      elements.union(arg.get_r(mem_read, cst_read)), self.__args, set())
 
     def get_w(self):
         raise ValueError('op cannot be written!', self)
 
     def _exprhash(self):
-        h_hargs = [hash(arg) for arg in self._args]
-        return hash((EXPROP, self._op, tuple(h_hargs)))
+        h_hargs = [hash(arg) for arg in self.__args]
+        return hash((EXPROP, self.__op, tuple(h_hargs)))
 
     def _exprrepr(self):
-        return "%s(%r, %s)" % (self.__class__.__name__, self._op,
-                               ', '.join(repr(arg) for arg in self._args))
+        return "%s(%r, %s)" % (self.__class__.__name__, self.__op,
+                               ', '.join(repr(arg) for arg in self.__args))
 
     def __contains__(self, e):
         if self == e:
             return True
-        for arg in self._args:
+        for arg in self.__args:
             if arg.__contains__(e):
                 return True
         return False
 
     def is_function_call(self):
-        return self._op.startswith('call')
+        return self.__op.startswith('call')
 
     def is_associative(self):
         "Return True iff current operation is associative"
-        return (self._op in ['+', '*', '^', '&', '|'])
+        return (self.__op in ['+', '*', '^', '&', '|'])
 
     def is_commutative(self):
         "Return True iff current operation is commutative"
-        return (self._op in ['+', '*', '^', '&', '|'])
+        return (self.__op in ['+', '*', '^', '&', '|'])
 
     @visit_chk
     def visit(self, cb, tv=None):
-        args = [arg.visit(cb, tv) for arg in self._args]
-        modified = any([arg[0] != arg[1] for arg in zip(self._args, args)])
+        args = [arg.visit(cb, tv) for arg in self.__args]
+        modified = any([arg[0] != arg[1] for arg in zip(self.__args, args)])
         if modified:
-            return ExprOp(self._op, *args)
+            return ExprOp(self.__op, *args)
         return self
 
     def copy(self):
-        args = [arg.copy() for arg in self._args]
-        return ExprOp(self._op, *args)
+        args = [arg.copy() for arg in self.__args]
+        return ExprOp(self.__op, *args)
 
     def depth(self):
-        depth = [arg.depth() for arg in self._args]
+        depth = [arg.depth() for arg in self.__args]
         return max(depth) + 1
 
     def graph_recursive(self, graph):
         graph.add_node(self)
-        for arg in self._args:
+        for arg in self.__args:
             arg.graph_recursive(graph)
             graph.add_uniq_edge(self, arg)
 
 
 class ExprSlice(Expr):
 
-    __slots__ = ["_arg", "_start", "_stop"]
+    __slots__ = Expr.__slots__ + ["__arg", "__start", "__stop"]
 
     def __init__(self, arg, start, stop):
         super(ExprSlice, self).__init__()
 
         assert(start < stop)
+        self.__arg, self.__start, self.__stop = arg, start, stop
+        self.__size = self.__stop - self.__start
 
-        self._arg, self._start, self._stop = arg, start, stop
-        self._size = self._stop - self._start
+    size = property(lambda self: self.__size)
+    arg = property(lambda self: self.__arg)
+    start = property(lambda self: self.__start)
+    stop = property(lambda self: self.__stop)
 
-    arg = property(lambda self: self._arg)
-    start = property(lambda self: self._start)
-    stop = property(lambda self: self._stop)
+    def __getstate__(self):
+        return self.__arg, self.__start, self.__stop
+
+    def __setstate__(self, state):
+        self.__init__(*state)
+
+    def __new__(cls, arg, start, stop):
+        return Expr.get_object(cls, (arg, start, stop))
 
     def __str__(self):
-        return "%s[%d:%d]" % (str(self._arg), self._start, self._stop)
+        return "%s[%d:%d]" % (str(self.__arg), self.__start, self.__stop)
 
     def get_r(self, mem_read=False, cst_read=False):
-        return self._arg.get_r(mem_read, cst_read)
+        return self.__arg.get_r(mem_read, cst_read)
 
     def get_w(self):
-        return self._arg.get_w()
+        return self.__arg.get_w()
 
     def _exprhash(self):
-        return hash((EXPRSLICE, hash(self._arg), self._start, self._stop))
+        return hash((EXPRSLICE, hash(self.__arg), self.__start, self.__stop))
 
     def _exprrepr(self):
-        return "%s(%r, %d, %d)" % (self.__class__.__name__, self._arg,
-                                   self._start, self._stop)
+        return "%s(%r, %d, %d)" % (self.__class__.__name__, self.__arg,
+                                   self.__start, self.__stop)
 
-    def __contains__(self, e):
-        if self == e:
+    def __contains__(self, expr):
+        if self == expr:
             return True
-        return self._arg.__contains__(e)
+        return self.__arg.__contains__(expr)
 
     @visit_chk
     def visit(self, cb, tv=None):
-        arg = self._arg.visit(cb, tv)
-        if arg == self._arg:
+        arg = self.__arg.visit(cb, tv)
+        if arg == self.__arg:
             return self
-        return ExprSlice(arg, self._start, self._stop)
+        return ExprSlice(arg, self.__start, self.__stop)
 
     def copy(self):
-        return ExprSlice(self._arg.copy(), self._start, self._stop)
+        return ExprSlice(self.__arg.copy(), self.__start, self.__stop)
 
     def depth(self):
-        return self._arg.depth() + 1
+        return self.__arg.depth() + 1
 
     def slice_rest(self):
         "Return the completion of the current slice"
-        size = self._arg.size
-        if self._start >= size or self._stop > size:
+        size = self.__arg.size
+        if self.__start >= size or self.__stop > size:
             raise ValueError('bad slice rest %s %s %s' %
-                             (size, self._start, self._stop))
+                             (size, self.__start, self.__stop))
 
-        if self._start == self._stop:
+        if self.__start == self.__stop:
             return [(0, size)]
 
         rest = []
-        if self._start != 0:
-            rest.append((0, self._start))
-        if self._stop < size:
-            rest.append((self._stop, size))
+        if self.__start != 0:
+            rest.append((0, self.__start))
+        if self.__stop < size:
+            rest.append((self.__stop, size))
 
         return rest
 
     def graph_recursive(self, graph):
         graph.add_node(self)
-        self._arg.graph_recursive(graph)
-        graph.add_uniq_edge(self, self._arg)
+        self.__arg.graph_recursive(graph)
+        graph.add_uniq_edge(self, self.__arg)
 
 
 class ExprCompose(Expr):
 
     """
-    Compose is like a hambuger.
-    It's arguments are tuple of:  (Expression, start, stop)
-    start and stop are intergers, determining Expression position in the compose.
-
-    Burger Example:
-    ExprCompose([(salad, 0, 3), (cheese, 3, 10), (beacon, 10, 16)])
-    In the example, salad.size == 3.
+    Compose is like a hambuger. It concatenate Expressions
     """
 
-    __slots__ = ["_args"]
+    __slots__ = Expr.__slots__ + ["__args"]
 
-    def __init__(self, args):
+    def __init__(self, *args):
         """Create an ExprCompose
         The ExprCompose is contiguous and starts at 0
-        @args: tuple(Expr, int, int)
+        @args: [Expr, Expr, ...]
+        DEPRECATED:
+        @args: [(Expr, int, int), (Expr, int, int), ...]
         """
 
         super(ExprCompose, self).__init__()
 
-        last_stop = 0
-        args = sorted(args, key=itemgetter(1))
-        for e, start, stop in args:
-            if e.size != stop - start:
-                raise ValueError(
-                    "sanitycheck: ExprCompose args must have correct size!" +
-                    " %r %r %r" % (e, e.size, stop - start))
-            if last_stop != start:
-                raise ValueError(
-                    "sanitycheck: ExprCompose args must be contiguous!" +
-                    " %r" % (args))
-            last_stop = stop
+        is_new_style = args and isinstance(args[0], Expr)
+        if not is_new_style:
+            warnings.warn('DEPRECATION WARNING: use "ExprCompose(a, b) instead of'+
+                          'ExprCemul_ir_block(self, addr, step=False)" instead of emul_ir_bloc')
+
+        self.__args = tuple(args)
+        self.__size = sum([arg.size for arg in args])
+
+    size = property(lambda self: self.__size)
+    args = property(lambda self: self.__args)
 
-        # Transform args to lists
-        o = []
-        for e, a, b in args:
-            assert(a >= 0 and b >= 0)
-            o.append(tuple([e, a, b]))
-        self._args = tuple(o)
+    def __getstate__(self):
+        return self.__args
 
-        self._size = self._args[-1][2]
+    def __setstate__(self, state):
+        self.__init__(state)
 
-    args = property(lambda self: self._args)
+    def __new__(cls, *args):
+        is_new_style = args and isinstance(args[0], Expr)
+        if not is_new_style:
+            assert len(args) == 1
+            args = args[0]
+        return Expr.get_object(cls, tuple(args))
 
     def __str__(self):
-        return '{' + ', '.join(['%s,%d,%d' %
-                                (str(arg[0]), arg[1], arg[2]) for arg in self._args]) + '}'
+        return '{' + ', '.join([str(arg) for arg in self.__args]) + '}'
 
     def get_r(self, mem_read=False, cst_read=False):
         return reduce(lambda elements, arg:
-                      elements.union(arg[0].get_r(mem_read, cst_read)), self._args, set())
+                      elements.union(arg.get_r(mem_read, cst_read)), self.__args, set())
 
     def get_w(self):
         return reduce(lambda elements, arg:
-                      elements.union(arg[0].get_w()), self._args, set())
+                      elements.union(arg.get_w()), self.__args, set())
 
     def _exprhash(self):
-        h_args = [EXPRCOMPOSE] + [(hash(arg[0]), arg[1], arg[2])
-                                  for arg in self._args]
+        h_args = [EXPRCOMPOSE] + [hash(arg) for arg in self.__args]
         return hash(tuple(h_args))
 
     def _exprrepr(self):
-        return "%s(%r)" % (self.__class__.__name__, self._args)
+        return "%s([%r])" % (self.__class__.__name__, self.__args)
 
     def __contains__(self, e):
         if self == e:
             return True
-        for arg in self._args:
+        for arg in self.__args:
             if arg == e:
                 return True
-            if arg[0].__contains__(e):
+            if arg.__contains__(e):
                 return True
         return False
 
     @visit_chk
     def visit(self, cb, tv=None):
-        args = [(arg[0].visit(cb, tv), arg[1], arg[2]) for arg in self._args]
-        modified = any([arg[0] != arg[1] for arg in zip(self._args, args)])
+        args = [arg.visit(cb, tv) for arg in self.__args]
+        modified = any([arg != arg_new for arg, arg_new in zip(self.__args, args)])
         if modified:
-            return ExprCompose(args)
+            return ExprCompose(*args)
         return self
 
     def copy(self):
-        args = [(arg[0].copy(), arg[1], arg[2]) for arg in self._args]
-        return ExprCompose(args)
+        args = [arg.copy() for arg in self.__args]
+        return ExprCompose(*args)
 
     def depth(self):
-        depth = [arg[0].depth() for arg in self._args]
+        depth = [arg.depth() for arg in self.__args]
         return max(depth) + 1
 
     def graph_recursive(self, graph):
         graph.add_node(self)
         for arg in self.args:
-            arg[0].graph_recursive(graph)
-            graph.add_uniq_edge(self, arg[0])
+            arg.graph_recursive(graph)
+            graph.add_uniq_edge(self, arg)
 
+    def iter_args(self):
+        index = 0
+        for arg in self.__args:
+            yield index, arg
+            index += arg.size
 
 # Expression order for comparaison
 expr_order_dict = {ExprId: 1,
@@ -1094,7 +1155,7 @@ def compare_exprs_compose(e1, e2):
 def compare_expr_list_compose(l1_e, l2_e):
     # Sort by list elements in incremental order, then by list size
     for i in xrange(min(len(l1_e), len(l2_e))):
-        x = compare_exprs_compose(l1_e[i], l2_e[i])
+        x = compare_exprs(l1_e[i], l2_e[i])
         if x:
             return x
     return cmp(len(l1_e), len(l2_e))
@@ -1325,9 +1386,7 @@ def MatchExpr(e, m, tks, result=None):
         if not isinstance(m, ExprCompose):
             return False
         for a1, a2 in zip(e.args, m.args):
-            if a1[1] != a2[1] or a1[2] != a2[2]:
-                return False
-            r = MatchExpr(a1[0], a2[0], tks, result)
+            r = MatchExpr(a1, a2, tks, result)
             if r is False:
                 return False
         return result