Lichen

Changeset

755:5fd3c0524204
2017-03-21 Paul Boddie raw files shortlog changelog graph Added support for an integer cache containing specific pre-allocated objects. integer-cache
common.py (file) generator.py (file) templates/native/common.c (file)
     1.1 --- a/common.py	Tue Mar 21 01:15:38 2017 +0100
     1.2 +++ b/common.py	Tue Mar 21 18:08:44 2017 +0100
     1.3 @@ -1188,6 +1188,15 @@
     1.4      finally:
     1.5          f.close()
     1.6  
     1.7 +def indent(indent, s):
     1.8 +
     1.9 +    "Insert 'indent' before every line in 's'."
    1.10 +
    1.11 +    l = []
    1.12 +    for line in s.split("\n"):
    1.13 +        l.append(indent + line)
    1.14 +    return "\n".join(l)
    1.15 +
    1.16  # General encoding.
    1.17  
    1.18  def sorted_output(x):
     2.1 --- a/generator.py	Tue Mar 21 01:15:38 2017 +0100
     2.2 +++ b/generator.py	Tue Mar 21 18:08:44 2017 +0100
     2.3 @@ -19,7 +19,7 @@
     2.4  this program.  If not, see <http://www.gnu.org/licenses/>.
     2.5  """
     2.6  
     2.7 -from common import CommonOutput, copy
     2.8 +from common import CommonOutput, copy, indent
     2.9  from encoders import encode_code, \
    2.10                       encode_function_pointer, \
    2.11                       encode_instantiator_pointer, \
    2.12 @@ -44,6 +44,7 @@
    2.13  
    2.14      function_type = "__builtins__.core.function"
    2.15      none_type = "__builtins__.none.NoneType"
    2.16 +    int_type = "__builtins__.int.int"
    2.17      string_type = "__builtins__.str.string"
    2.18      type_type = "__builtins__.core.type"
    2.19      unicode_type = "__builtins__.unicode.utf8string"
    2.20 @@ -359,6 +360,10 @@
    2.21              for constant, n in self.optimiser.constants.items():
    2.22                  self.make_literal_constant(f_decls, f_defs, n, constant)
    2.23  
    2.24 +            # Generate pre-allocated objects.
    2.25 +
    2.26 +            self.make_preallocated_objects(f_decls, f_defs)
    2.27 +
    2.28              # Finish the main source file.
    2.29  
    2.30              self.write_main_program(f_code, f_signatures)
    2.31 @@ -494,6 +499,48 @@
    2.32          finally:
    2.33              f_instancepos.close()
    2.34  
    2.35 +    def make_preallocated_objects(self, f_decls, f_defs):
    2.36 +
    2.37 +        """
    2.38 +        Write pre-allocated object declarations to 'f_decls' and definitions to
    2.39 +        'f_defs'.
    2.40 +        """
    2.41 +
    2.42 +        ref = Reference("<instance>", self.int_type)
    2.43 +        table_name = encode_tablename(ref.get_kind(), ref.get_origin())
    2.44 +        attrs = self.get_instance_attributes_for_reference(ref)
    2.45 +        specific_instance_type = encode_symbol("inst", self.int_type)
    2.46 +
    2.47 +        integers = []
    2.48 +        integer_cache_size = 256
    2.49 +        i = 0
    2.50 +
    2.51 +        while i < integer_cache_size:
    2.52 +            attrs["__data__"] = i
    2.53 +            structure = []
    2.54 +            self.populate_structure(ref, attrs, ref.get_kind(), structure)
    2.55 +            integers.append(indent("    ", self.get_structure_definition(table_name, structure)))
    2.56 +            i += 1
    2.57 +
    2.58 +        # Generate an array of specific instances.
    2.59 +
    2.60 +        print >>f_defs, """\
    2.61 +%s __integer_cache[%d] = {
    2.62 +%s
    2.63 +    };""" % (specific_instance_type, integer_cache_size, ",\n    ".join(integers))
    2.64 +
    2.65 +        # Generate a declaration for the specific instance type.
    2.66 +
    2.67 +        structure_size = encode_size("<instance>", self.int_type)
    2.68 +        self.write_instance_structure(f_decls, self.int_type, structure_size, "inst")
    2.69 +
    2.70 +        # Generate declarations for the size of the array and the array itself.
    2.71 +
    2.72 +        print >>f_decls, """\
    2.73 +#define __INTEGER_CACHE_SIZE %d
    2.74 +%s __integer_cache[%d];""" % (integer_cache_size, specific_instance_type,
    2.75 +                              integer_cache_size)
    2.76 +
    2.77      def make_literal_constant(self, f_decls, f_defs, n, constant):
    2.78  
    2.79          """
    2.80 @@ -531,8 +578,8 @@
    2.81          """
    2.82          Write constant details to 'f_decls' (to declare a structure) and to
    2.83          'f_defs' (to define the contents) for the constant described by 'ref'
    2.84 -        having the given 'path' and 'structure_name' (for the constant structure
    2.85 -        itself).
    2.86 +        having the given 'const_path' (used to refer to the structure using an
    2.87 +        attribute) and 'structure_name' (for the constant structure itself).
    2.88  
    2.89          The additional 'data' and 'encoding' are used to describe specific
    2.90          values.
    2.91 @@ -541,9 +588,7 @@
    2.92          # Obtain the attributes.
    2.93  
    2.94          cls = ref.get_origin()
    2.95 -        indexes = self.optimiser.attr_table[ref]
    2.96 -        attrnames = self.get_attribute_names(indexes)
    2.97 -        attrs = self.get_instance_attributes(cls, attrnames)
    2.98 +        attrs = self.get_instance_attributes_for_reference(ref)
    2.99  
   2.100          # Set the data, if provided.
   2.101  
   2.102 @@ -595,8 +640,9 @@
   2.103  
   2.104          # Define a macro for the constant.
   2.105  
   2.106 -        attr_name = encode_path(const_path)
   2.107 -        print >>f_decls, "#define %s __ATTRVALUE(&%s)" % (attr_name, structure_name)
   2.108 +        if const_path:
   2.109 +            print >>f_decls, "#define %s __ATTRVALUE(&%s)" % (
   2.110 +                encode_path(const_path), structure_name)
   2.111  
   2.112      def make_parameter_table(self, f_decls, f_defs, argmin, parameters):
   2.113  
   2.114 @@ -740,11 +786,12 @@
   2.115  """ % (table_name, min_parameters, max_parameters, structure_size,
   2.116         ",\n        ".join(members))
   2.117  
   2.118 -    def write_instance_structure(self, f_decls, path, structure_size):
   2.119 +    def write_instance_structure(self, f_decls, path, structure_size, prefix="obj"):
   2.120  
   2.121          """
   2.122          Write a declaration to 'f_decls' for the object having the given 'path'
   2.123 -        and the given 'structure_size'.
   2.124 +        and the given 'structure_size'. The optional 'prefix' can be used to
   2.125 +        modify the declared type.
   2.126          """
   2.127  
   2.128          # Write an instance-specific type definition for instances of classes.
   2.129 @@ -756,7 +803,7 @@
   2.130      __pos pos;
   2.131      __attr attrs[%s];
   2.132  } %s;
   2.133 -""" % (structure_size, encode_symbol("obj", path))
   2.134 +""" % (structure_size, encode_symbol(prefix, path))
   2.135  
   2.136      def write_structure(self, f_decls, f_defs, structure_name, table_name, structure, path=None):
   2.137  
   2.138 @@ -769,19 +816,28 @@
   2.139          if f_decls:
   2.140              print >>f_decls, "extern __obj %s;\n" % encode_path(structure_name)
   2.141  
   2.142 +        structure_details = self.get_structure_definition(table_name, structure, path)
   2.143 +        print >>f_defs, """\
   2.144 +__obj %s = %s;""" % (encode_path(structure_name), structure_details)
   2.145 +
   2.146 +    def get_structure_definition(self, table_name, structure, path=None):
   2.147 +
   2.148 +        """
   2.149 +        Return a structure employing 'table_name', the given 'structure'
   2.150 +        members, and any identifying static 'path'.
   2.151 +        """
   2.152 +
   2.153          is_class = path and self.importer.get_object(path).has_kind("<class>")
   2.154          pos = is_class and encode_pos(encode_type_attribute(path)) or str(self.instancepos)
   2.155  
   2.156 -        print >>f_defs, """\
   2.157 -__obj %s = {
   2.158 +        return """\
   2.159 +{
   2.160      &%s,
   2.161      %s,
   2.162      {
   2.163          %s
   2.164 -    }};
   2.165 -""" % (
   2.166 -            encode_path(structure_name), table_name, pos,
   2.167 -            ",\n        ".join(structure))
   2.168 +    }
   2.169 +}""" % (table_name, pos, ",\n        ".join(structure))
   2.170  
   2.171      def get_argument_limits(self, path):
   2.172  
   2.173 @@ -842,6 +898,18 @@
   2.174  
   2.175          return attrs
   2.176  
   2.177 +    def get_instance_attributes_for_reference(self, ref):
   2.178 +
   2.179 +        """
   2.180 +        Return a mapping of attribute names to references for attributes
   2.181 +        belonging to instances of the given 'ref' referencing a class.
   2.182 +        """
   2.183 +
   2.184 +        cls = ref.get_origin()
   2.185 +        indexes = self.optimiser.attr_table[ref]
   2.186 +        attrnames = self.get_attribute_names(indexes)
   2.187 +        return self.get_instance_attributes(cls, attrnames)
   2.188 +
   2.189      def get_instance_attributes(self, name, attrnames):
   2.190  
   2.191          """
     3.1 --- a/templates/native/common.c	Tue Mar 21 01:15:38 2017 +0100
     3.2 +++ b/templates/native/common.c	Tue Mar 21 18:08:44 2017 +0100
     3.3 @@ -28,6 +28,12 @@
     3.4  
     3.5  __attr __new_int(int i)
     3.6  {
     3.7 +    /* Search the integer cache first. */
     3.8 +    if ((i >= 0) && (i < __INTEGER_CACHE_SIZE))
     3.9 +    {
    3.10 +        return __ATTRVALUE((__ref) &__integer_cache[i]);
    3.11 +    }
    3.12 +
    3.13      /* Create a new integer and mutate the __data__ attribute. */
    3.14      __attr attr = __NEWINSTANCE(__builtins___int_int);
    3.15      attr.value->attrs[__ATTRPOS(__data__)].intvalue = i;