Lichen

Changeset

961:d1fe5052f956
2021-11-14 Paul Boddie raw files shortlog changelog graph Introduced copyable and mutable flags in the tagged region of attribute values. Such flags are set when new integer and floating point values are created, but the mutable flag is cleared when such attributes are propagated between functions in order to prevent values being replaced upon assignment to parameter names, this being a concern when value copying is introduced. tagged-address-values
templates/types.h (file) translator.py (file) transresults.py (file)
     1.1 --- a/templates/types.h	Sun Nov 14 00:37:32 2021 +0100
     1.2 +++ b/templates/types.h	Sun Nov 14 00:42:49 2021 +0100
     1.3 @@ -130,12 +130,15 @@
     1.4  
     1.5  /* Attribute interpretation. */
     1.6  
     1.7 -#define __NUM_TAG_BITS      1
     1.8 -#define __TAG_MUTABLE       0b1
     1.9 -#define __TAG_MASK          0b1
    1.10 +#define __NUM_TAG_BITS      2
    1.11 +#define __TAG_COPYABLE      0b01UL
    1.12 +#define __TAG_MUTABLE       0b10UL
    1.13 +#define __TAG_MASK          0b11UL
    1.14  
    1.15 -#define __MUTABLE(ATTR)     (((ATTR).rawvalue & __TAG_MASK) == __TAG_MUTABLE)
    1.16 -#define __TO_MUTABLE(ATTR)  ((__attr) (((ATTR).rawvalue & (~__TAG_MASK)) | __TAG_MUTABLE))
    1.17 +#define __COPYABLE(ATTR)    ((ATTR).rawvalue & __TAG_COPYABLE)
    1.18 +#define __MUTABLE(ATTR)     ((ATTR).rawvalue & __TAG_MUTABLE)
    1.19 +#define __TO_IMMUTABLE(ATTR) ((__attr) {.rawvalue=(ATTR).rawvalue & (~__TAG_MUTABLE)})
    1.20 +#define __TO_MUTABLE(ATTR)   ((__attr) {.rawvalue=(ATTR).rawvalue | __TAG_MASK})
    1.21  
    1.22  /* Attribute value setting. */
    1.23  
     2.1 --- a/translator.py	Sun Nov 14 00:37:32 2021 +0100
     2.2 +++ b/translator.py	Sun Nov 14 00:42:49 2021 +0100
     2.3 @@ -1324,6 +1324,13 @@
     2.4          for i, arg in enumerate(n.args):
     2.5              argexpr = self.process_structure_node(arg)
     2.6  
     2.7 +            # Obtain an appropriate argument representation. This prevents
     2.8 +            # copyable values from being mutable, but care must be taken to
     2.9 +            # prevent special internal attribute values represented using
    2.10 +            # attributes from being modified.
    2.11 +
    2.12 +            argrepr = argexpr.as_arg()
    2.13 +
    2.14              # Store a keyword argument, either in the argument list or
    2.15              # in a separate keyword argument list for subsequent lookup.
    2.16  
    2.17 @@ -1338,12 +1345,12 @@
    2.18                      except ValueError:
    2.19                          raise TranslateError("Argument %s is not recognised." % arg.name,
    2.20                                               self.get_namespace_path(), n)
    2.21 -                    args[argnum + reserved_args] = str(argexpr)
    2.22 +                    args[argnum + reserved_args] = argrepr
    2.23  
    2.24                  # Otherwise, store the details in a separate collection.
    2.25  
    2.26                  else:
    2.27 -                    kwargs.append(str(argexpr))
    2.28 +                    kwargs.append(argrepr)
    2.29                      kwcodes.append("{%s, %s}" % (
    2.30                          encode_ppos(arg.name), encode_pcode(arg.name)))
    2.31  
    2.32 @@ -1352,7 +1359,7 @@
    2.33  
    2.34              else:
    2.35                  try:
    2.36 -                    args[i + reserved_args] = str(argexpr)
    2.37 +                    args[i + reserved_args] = argrepr
    2.38                  except IndexError:
    2.39                      raise TranslateError("Too many arguments specified.",
    2.40                                           self.get_namespace_path(), n)
     3.1 --- a/transresults.py	Sun Nov 14 00:37:32 2021 +0100
     3.2 +++ b/transresults.py	Sun Nov 14 00:42:49 2021 +0100
     3.3 @@ -59,6 +59,12 @@
     3.4      def __repr__(self):
     3.5          return "Expression(%r)" % self.s
     3.6  
     3.7 +    def as_arg(self):
     3.8 +
     3.9 +        "Return the expression without any mutable tag."
    3.10 +
    3.11 +        return self.s
    3.12 +
    3.13  class TrResolvedNameRef(ResolvedNameRef):
    3.14  
    3.15      "A reference to a name in the translation."
    3.16 @@ -132,6 +138,21 @@
    3.17          else:
    3.18              return "(%s)" % self.attrname
    3.19  
    3.20 +    def as_arg(self):
    3.21 +
    3.22 +        "Return the expression without any mutable tag."
    3.23 +
    3.24 +        s = self.__str__()
    3.25 +
    3.26 +        # NOTE: This is a superficial test for internal attributes that relies
    3.27 +        # NOTE: on such attributes being used directly and passed to native
    3.28 +        # NOTE: code.
    3.29 +
    3.30 +        if self.attrname in ("__data__", "__size__"):
    3.31 +            return s
    3.32 +        else:
    3.33 +            return "__TO_IMMUTABLE(%s)" % s
    3.34 +
    3.35  class TrConstantValueRef(ConstantValueRef):
    3.36  
    3.37      "A constant value reference in the translation."
    3.38 @@ -139,6 +160,9 @@
    3.39      def __str__(self):
    3.40          return encode_literal_constant(self.number)
    3.41  
    3.42 +    def as_arg(self):
    3.43 +        return self.__str__()
    3.44 +
    3.45  class TrLiteralSequenceRef(LiteralSequenceRef):
    3.46  
    3.47      "A reference representing a sequence of values."
    3.48 @@ -146,6 +170,9 @@
    3.49      def __str__(self):
    3.50          return str(self.node)
    3.51  
    3.52 +    def as_arg(self):
    3.53 +        return self.__str__()
    3.54 +
    3.55  class TrInstanceRef(InstanceRef):
    3.56  
    3.57      "A reference representing instantiation of a class."
    3.58 @@ -166,6 +193,9 @@
    3.59      def __repr__(self):
    3.60          return "TrResolvedInstanceRef(%r, %r)" % (self.ref, self.expr)
    3.61  
    3.62 +    def as_arg(self):
    3.63 +        return self.__str__()
    3.64 +
    3.65  class AttrResult(Result, InstructionSequence):
    3.66  
    3.67      "A translation result for an attribute access."
    3.68 @@ -222,6 +252,9 @@
    3.69                  self.context_identity, self.context_identity_verified,
    3.70                  self.accessor_test, self.accessor_stored)
    3.71  
    3.72 +    def as_arg(self):
    3.73 +        return self.__str__()
    3.74 +
    3.75  class AliasResult(NameRef, Result):
    3.76  
    3.77      "An alias for other values."
    3.78 @@ -275,6 +308,9 @@
    3.79      def __repr__(self):
    3.80          return "AliasResult(%r, %r)" % (self.name_ref, self.refs)
    3.81  
    3.82 +    def as_arg(self):
    3.83 +        return self.__str__()
    3.84 +
    3.85  class InvocationResult(Result, InstructionSequence):
    3.86  
    3.87      "A translation result for an invocation."
    3.88 @@ -285,6 +321,9 @@
    3.89      def __repr__(self):
    3.90          return "InvocationResult(%r)" % self.instructions
    3.91  
    3.92 +    def as_arg(self):
    3.93 +        return self.__str__()
    3.94 +
    3.95  class InstantiationResult(InvocationResult, TrInstanceRef):
    3.96  
    3.97      "An instantiation result acting like an invocation result."
    3.98 @@ -325,6 +364,9 @@
    3.99      def __repr__(self):
   3.100          return "PredefinedConstantRef(%r)" % self.value
   3.101  
   3.102 +    def as_arg(self):
   3.103 +        return self.__str__()
   3.104 +
   3.105  class LogicalResult(Result):
   3.106  
   3.107      "A logical expression result."
   3.108 @@ -370,6 +412,9 @@
   3.109      def __repr__(self):
   3.110          return "NegationResult(%r)" % self.expr
   3.111  
   3.112 +    def as_arg(self):
   3.113 +        return self.__str__()
   3.114 +
   3.115  class LogicalOperationResult(LogicalResult):
   3.116  
   3.117      "A logical operation result."
   3.118 @@ -442,4 +487,7 @@
   3.119      def __repr__(self):
   3.120          return "LogicalOperationResult(%r, %r)" % (self.exprs, self.conjunction)
   3.121  
   3.122 +    def as_arg(self):
   3.123 +        return self.__str__()
   3.124 +
   3.125  # vim: tabstop=4 expandtab shiftwidth=4