1.1 --- a/encoders.py Sun Nov 14 00:50:17 2021 +0100
1.2 +++ b/encoders.py Sun Nov 28 02:03:21 2021 +0100
1.3 @@ -3,7 +3,7 @@
1.4 """
1.5 Encoder functions, producing representations of program objects.
1.6
1.7 -Copyright (C) 2016, 2017, 2018 Paul Boddie <paul@boddie.org.uk>
1.8 +Copyright (C) 2016, 2017, 2018, 2021 Paul Boddie <paul@boddie.org.uk>
1.9
1.10 This program is free software; you can redistribute it and/or modify it under
1.11 the terms of the GNU General Public License as published by the Free Software
1.12 @@ -286,6 +286,16 @@
1.13 "<accessor>", "<context>", "<name>", "<private_context>", "<target_accessor>"
1.14 )
1.15
1.16 +# Instructions that need to be customised for certain attributes.
1.17 +
1.18 +via_object_ops = (
1.19 + "__store_via_object", "__check_and_store_via_object",
1.20 + )
1.21 +
1.22 +# NOTE: This duplicates a definition in transresults.
1.23 +
1.24 +special_attributes = ("__args__", "__data__", "__key__", "__size__")
1.25 +
1.26 def encode_access_instruction(instruction, subs, accessor_index, context_index):
1.27
1.28 """
1.29 @@ -379,6 +389,11 @@
1.30 elif not args:
1.31 op = "&%s" % encode_path(op)
1.32
1.33 + # Substitute the operation for certain attributes.
1.34 +
1.35 + if op in via_object_ops and args[1] in special_attributes:
1.36 + op = "%s_internal" % op
1.37 +
1.38 return "%s%s" % (op, argstr), substituted
1.39
1.40 def encode_access_instruction_arg(arg, subs, op, accessor_index, context_index):
2.1 --- a/generator.py Sun Nov 14 00:50:17 2021 +0100
2.2 +++ b/generator.py Sun Nov 28 02:03:21 2021 +0100
2.3 @@ -192,6 +192,7 @@
2.4 print >>f_code, """\
2.5 #include <string.h>
2.6 #include <stdio.h>
2.7 +#include <threads.h>
2.8 #include "gc.h"
2.9 #include "signals.h"
2.10 #include "types.h"
2.11 @@ -277,8 +278,9 @@
2.12 # Write a table for all objects.
2.13
2.14 table = []
2.15 - self.populate_table(Reference(kind, path), table)
2.16 - self.write_table(f_decls, f_defs, table_name, structure_size, table)
2.17 + self.populate_table(ref, table)
2.18 + self.write_table(f_decls, f_defs, table_name, structure_size,
2.19 + table, ref)
2.20
2.21 # Generate function instances.
2.22
2.23 @@ -320,6 +322,9 @@
2.24 # Signature: __attr <name>(...);
2.25
2.26 parameters = self.importer.function_parameters[path]
2.27 +
2.28 + # Include the context plus the original parameters.
2.29 +
2.30 l = ["__attr"] * (len(parameters) + 1)
2.31 print >>f_signatures, "__attr %s(%s);" % (encode_function_pointer(path), ", ".join(l))
2.32
2.33 @@ -766,26 +771,41 @@
2.34 f_consts.write(" %s = %d" % (pos_encoder(attrname), i))
2.35 print >>f_consts, "\n };"
2.36
2.37 - def write_table(self, f_decls, f_defs, table_name, structure_size, table):
2.38 + def write_table(self, f_decls, f_defs, table_name, structure_size, table,
2.39 + ref):
2.40
2.41 """
2.42 Write the declarations to 'f_decls' and definitions to 'f_defs' for
2.43 the object having the given 'table_name' and the given 'structure_size',
2.44 with 'table' details used to populate the definition.
2.45 +
2.46 + To support value copying, the 'ref' is provided to be able to encode the
2.47 + structure size.
2.48 """
2.49
2.50 print >>f_decls, "extern const __table %s;\n" % table_name
2.51
2.52 + # Generate an object size of 0 for non-copyable types.
2.53 +
2.54 + path = ref.get_origin()
2.55 +
2.56 + if ref.get_kind() == "<instance>" and self.trailing_data_types.has_key(path):
2.57 + obj_type = encode_symbol("obj", path) or "__obj"
2.58 + obj_size = "sizeof(%s)" % obj_type
2.59 + else:
2.60 + obj_size = "0"
2.61 +
2.62 # Write the corresponding definition.
2.63
2.64 print >>f_defs, """\
2.65 const __table %s = {
2.66 %s,
2.67 + %s,
2.68 {
2.69 %s
2.70 }
2.71 };
2.72 -""" % (table_name, structure_size,
2.73 +""" % (table_name, structure_size, obj_size,
2.74 ",\n ".join(table))
2.75
2.76 def write_parameter_table(self, f_decls, f_defs, table_name, min_parameters,
2.77 @@ -1137,13 +1157,24 @@
2.78 the 'attrs' mapping, adding entries to the 'trailing' member collection.
2.79 """
2.80
2.81 + if self.get_trailing_data_type(ref):
2.82 + trailing.append(encode_literal_constant_value(attrs["__trailing__"]))
2.83 +
2.84 + def get_trailing_data_type(self, ref):
2.85 +
2.86 + """
2.87 + For the structure having the given 'ref', return the type of any
2.88 + trailing data.
2.89 + """
2.90 +
2.91 structure_ref = self.get_target_structure(ref)
2.92
2.93 # Instances with trailing data.
2.94
2.95 - if structure_ref.get_kind() == "<instance>" and \
2.96 - structure_ref.get_origin() in self.trailing_data_types:
2.97 - trailing.append(encode_literal_constant_value(attrs["__trailing__"]))
2.98 + if structure_ref.get_kind() == "<instance>":
2.99 + return self.trailing_data_types.get(structure_ref.get_origin())
2.100 + else:
2.101 + return None
2.102
2.103 def get_target_structure(self, ref):
2.104
2.105 @@ -1300,28 +1331,44 @@
2.106 """
2.107
2.108 print >>f_code, """\
2.109 +_Thread_local __attr __stack;
2.110 +
2.111 +/* Global used to prevent compiler over-optimisation. */
2.112 +
2.113 +__attr __stack_global;
2.114 +
2.115 int main(int argc, char *argv[])
2.116 {
2.117 __exc __tmp_exc;
2.118 + __attr __stack_base;
2.119
2.120 GC_INIT();
2.121
2.122 __signals_install_handlers();
2.123 + __stack = __stack_init();
2.124 +
2.125 + /* Record the stack accessor on the function stack for libgc. */
2.126 +
2.127 + __stack_base = __stack;
2.128 + __stack_global = __stack_base;
2.129
2.130 __Try
2.131 {"""
2.132
2.133 + # Write a main function invocation for all but the native modules.
2.134 +
2.135 for name in self.importer.order_modules():
2.136 + parts = name.split(".")
2.137 +
2.138 + if parts[0] == "native":
2.139 + continue
2.140 +
2.141 function_name = "__main_%s" % encode_path(name)
2.142 print >>f_signatures, "void %s();" % function_name
2.143 -
2.144 - # Omit the native modules.
2.145 + print >>f_code, """\
2.146 + %s();""" % function_name
2.147
2.148 - parts = name.split(".")
2.149 -
2.150 - if parts[0] != "native":
2.151 - print >>f_code, """\
2.152 - %s();""" % function_name
2.153 + # Finish the main section with an exception handler.
2.154
2.155 print >>f_code, """\
2.156 }
3.1 --- a/templates/native/common.c Sun Nov 14 00:50:17 2021 +0100
3.2 +++ b/templates/native/common.c Sun Nov 28 02:03:21 2021 +0100
3.3 @@ -29,7 +29,7 @@
3.4 __attr __new_int(__int n)
3.5 {
3.6 /* Create a new int and set the trailing data. */
3.7 - __attr attr = __NEWINSTANCEIM(__builtins___int_int);
3.8 + __attr attr = __NEWINSTANCE_STACK(__builtins___int_int);
3.9 __set_trailing_data(attr, __builtins___int_int, n);
3.10 return __TO_MUTABLE(attr);
3.11 }
3.12 @@ -38,9 +38,9 @@
3.13 {
3.14 /* Create a new string and mutate the __data__, __size__ and __key__ attributes. */
3.15 __attr attr = __NEWINSTANCE(__builtins___str_str);
3.16 - __store_via_object(__VALUE(attr), __data__, (__attr) {.strvalue=s});
3.17 - __store_via_object(__VALUE(attr), __size__, (__attr) {.sizevalue=size});
3.18 - __store_via_object(__VALUE(attr), __key__, __NULL);
3.19 + __store_via_object_internal(__VALUE(attr), __data__, (__attr) {.strvalue=s});
3.20 + __store_via_object_internal(__VALUE(attr), __size__, (__attr) {.sizevalue=size});
3.21 + __store_via_object_internal(__VALUE(attr), __key__, __NULL);
3.22 return attr;
3.23 }
3.24
3.25 @@ -48,14 +48,14 @@
3.26 {
3.27 /* Create a new list and mutate the __data__ attribute. */
3.28 __attr attr = __NEWINSTANCE(__builtins___list_list);
3.29 - __store_via_object(__VALUE(attr), __data__, (__attr) {.seqvalue=f});
3.30 + __store_via_object_internal(__VALUE(attr), __data__, (__attr) {.seqvalue=f});
3.31 return attr;
3.32 }
3.33
3.34 __attr __new_float(__float n)
3.35 {
3.36 /* Create a new float and set the trailing data. */
3.37 - __attr attr = __NEWINSTANCEIM(__builtins___float_float);
3.38 + __attr attr = __NEWINSTANCE_STACK(__builtins___float_float);
3.39 __set_trailing_data(attr, __builtins___float_float, n);
3.40 return __TO_MUTABLE(attr);
3.41 }
3.42 @@ -70,13 +70,14 @@
3.43 if (size >= capacity)
3.44 {
3.45 /* NOTE: Consider various restrictions on capacity increases. */
3.46 - n = capacity ? capacity * 2 : 1;
3.47 + n = capacity * 2 > size ? capacity * 2 : size + 1;
3.48 newdata = (__fragment *) __REALLOCATE(data, __FRAGMENT_SIZE(n));
3.49 newdata->capacity = n;
3.50 }
3.51
3.52 /* Insert the new element and increment the list size. */
3.53 - newdata->attrs[size] = value;
3.54 + newdata->attrs[size] = __RAWVALUE(0);
3.55 + __store_target(&newdata->attrs[size], value);
3.56 newdata->size = size + 1;
3.57
3.58 return newdata;
4.1 --- a/templates/native/iconv.c Sun Nov 14 00:50:17 2021 +0100
4.2 +++ b/templates/native/iconv.c Sun Nov 28 02:03:21 2021 +0100
4.3 @@ -87,8 +87,10 @@
4.4
4.5 /* Mutate the state to indicate the next input buffer position. */
4.6
4.7 - f->attrs[1] = __new_int(start + remaining - inbytesleft);
4.8 - f->attrs[2] = __new_int(inbytesleft);
4.9 + f->attrs[1] = __RAWVALUE(0);
4.10 + f->attrs[2] = __RAWVALUE(0);
4.11 + __store_target(&f->attrs[1], __new_int(start + remaining - inbytesleft));
4.12 + __store_target(&f->attrs[2], __new_int(inbytesleft));
4.13
4.14 /* Incomplete sequence: raise the string in an OSError instead. */
4.15
5.1 --- a/templates/native/list.c Sun Nov 14 00:50:17 2021 +0100
5.2 +++ b/templates/native/list.c Sun Nov 28 02:03:21 2021 +0100
5.3 @@ -56,7 +56,7 @@
5.4
5.5 /* Replace the __data__ attribute if appropriate. */
5.6 if (newdata != data)
5.7 - __store_via_object(__VALUE(self), __data__, ((__attr) {.seqvalue=newdata}));
5.8 + __store_via_object_internal(__VALUE(self), __data__, ((__attr) {.seqvalue=newdata}));
5.9 return __builtins___none_None;
5.10 }
5.11
5.12 @@ -79,12 +79,16 @@
5.13
5.14 /* Copy the elements from the other list and increment the list size. */
5.15 for (i = size, j = 0; j < other_size; i++, j++)
5.16 - newdata->attrs[i] = other_data->attrs[j];
5.17 + {
5.18 + newdata->attrs[i] = __RAWVALUE(0);
5.19 + __store_target(&newdata->attrs[i], other_data->attrs[j]);
5.20 + }
5.21 +
5.22 newdata->size = n;
5.23
5.24 /* Replace the __data__ attribute if appropriate. */
5.25 if (newdata != data)
5.26 - __store_via_object(__VALUE(self), __data__, ((__attr) {.seqvalue=newdata}));
5.27 + __store_via_object_internal(__VALUE(self), __data__, ((__attr) {.seqvalue=newdata}));
5.28 return __builtins___none_None;
5.29 }
5.30
5.31 @@ -120,7 +124,7 @@
5.32 __int i = __TOINT(index);
5.33
5.34 /* Set the element. */
5.35 - elements[i] = value;
5.36 + __store_target(&elements[i], value);
5.37 return __builtins___none_None;
5.38 }
5.39
6.1 --- a/templates/ops.c Sun Nov 14 00:50:17 2021 +0100
6.2 +++ b/templates/ops.c Sun Nov 28 02:03:21 2021 +0100
6.3 @@ -37,6 +37,24 @@
6.4 return (pos < obj->table->size) && (obj->table->attrs[pos] == code);
6.5 }
6.6
6.7 +/* Generic load wrapper employing temporary stack storage. */
6.8 +
6.9 +__attr __load(__attr value)
6.10 +{
6.11 + /* Copy values where appropriate. */
6.12 +
6.13 + if (__COPYABLE(value))
6.14 + {
6.15 + size_t value_size = __INSTANCE_SIZE(__VALUE(value));
6.16 + __attr target = __stack_allocate(__stack, value_size);
6.17 +
6.18 + __COPY_TO(__VALUE(value), __VALUE(target), value_size);
6.19 + return __TO_MUTABLE(target);
6.20 + }
6.21 + else
6.22 + return value;
6.23 +}
6.24 +
6.25 /* Direct access and manipulation of static objects. */
6.26
6.27 __attr __load_static_ignore(__ref obj)
6.28 @@ -76,8 +94,71 @@
6.29
6.30 /* Direct storage operations. */
6.31
6.32 +__attr __store_local(__attr target, __attr value)
6.33 +{
6.34 + /* Copy values where appropriate. */
6.35 +
6.36 + if (__COPYABLE(value))
6.37 + {
6.38 + size_t value_size = __INSTANCE_SIZE(__VALUE(value));
6.39 +
6.40 + /* Allocate new space for values if the target is not a mutable value
6.41 + or refers to an object that is too small for the value. */
6.42 +
6.43 + if ((__VALUE(target) == NULL) || !__MUTABLE(target) || (value_size > __INSTANCE_SIZE(__VALUE(target))))
6.44 + target = __stack_allocate(__stack, value_size);
6.45 +
6.46 + __COPY_TO(__VALUE(value), __VALUE(target), value_size);
6.47 + return __TO_MUTABLE(target);
6.48 + }
6.49 + else
6.50 + return value;
6.51 +}
6.52 +
6.53 +void __store_target(__attr *target, __attr value)
6.54 +{
6.55 + /* Copy values where appropriate. */
6.56 +
6.57 + if (__COPYABLE(value))
6.58 + {
6.59 + size_t value_size = __INSTANCE_SIZE(__VALUE(value));
6.60 +
6.61 + if ((__VALUE(*target) == NULL) || (!__MUTABLE(*target)) || (value_size > __INSTANCE_SIZE(__VALUE(*target))))
6.62 + *target = __ATTRVALUE(__ALLOCATEIM(1, value_size));
6.63 +
6.64 + __COPY_TO(__VALUE(value), __VALUE(*target), value_size);
6.65 + *target = __TO_MUTABLE(*target);
6.66 + }
6.67 + else
6.68 + *target = value;
6.69 +}
6.70 +
6.71 int __store_via_object__(__ref obj, int pos, __attr value)
6.72 {
6.73 + /* Copy values where appropriate. */
6.74 +
6.75 + if (__COPYABLE(value))
6.76 + {
6.77 + size_t value_size = __INSTANCE_SIZE(__VALUE(value));
6.78 + __attr target = obj->attrs[pos];
6.79 +
6.80 + /* Allocate new space for values if the target is not a mutable value
6.81 + or refers to an object that is too small for the value. */
6.82 +
6.83 + if ((__VALUE(target) == NULL) || (!__MUTABLE(target)) || (value_size > __INSTANCE_SIZE(__VALUE(target))))
6.84 + target = __ATTRVALUE(__ALLOCATEIM(1, value_size));
6.85 +
6.86 + __COPY_TO(__VALUE(value), __VALUE(target), value_size);
6.87 + obj->attrs[pos] = __TO_MUTABLE(target);
6.88 + }
6.89 + else
6.90 + obj->attrs[pos] = value;
6.91 +
6.92 + return 1;
6.93 +}
6.94 +
6.95 +int __store_via_object_internal__(__ref obj, int pos, __attr value)
6.96 +{
6.97 obj->attrs[pos] = value;
6.98 return 1;
6.99 }
6.100 @@ -215,6 +296,20 @@
6.101 return 0;
6.102 }
6.103
6.104 +int __check_and_store_via_object_internal__(__ref obj, int pos, int code, __attr value)
6.105 +{
6.106 + if (__HASATTR(obj, pos, code))
6.107 + {
6.108 + __store_via_object_internal__(obj, pos, value);
6.109 + return 1;
6.110 + }
6.111 +
6.112 + /* No suitable attribute. */
6.113 +
6.114 + __raise_type_error();
6.115 + return 0;
6.116 +}
6.117 +
6.118 int __check_and_store_via_any__(__ref obj, int pos, int code, __attr value)
6.119 {
6.120 if (__check_and_store_via_object__(obj, pos, code, value))
6.121 @@ -438,9 +533,95 @@
6.122
6.123 /* Copying of structures. */
6.124
6.125 -__ref __COPY(__ref obj, int size)
6.126 +__ref __COPY(__ref obj, size_t size)
6.127 {
6.128 __ref copy = (__ref) __ALLOCATE(1, size);
6.129 memcpy(copy, obj, size);
6.130 return copy;
6.131 }
6.132 +
6.133 +void __COPY_TO(__ref source, __ref target, size_t size)
6.134 +{
6.135 + memcpy(target, source, size);
6.136 +}
6.137 +
6.138 +/* Stack management. */
6.139 +
6.140 +__attr __stack_init()
6.141 +{
6.142 + __attr __stack;
6.143 +
6.144 + __stack.stackdesc = (__stackdesc *) __ALLOCATE(1, sizeof(__stackdesc));
6.145 + __stack.stackdesc->current = NULL;
6.146 + __stack_expand(__stack);
6.147 +
6.148 + return __stack;
6.149 +}
6.150 +
6.151 +__attr __stack_allocate(__attr __stack, size_t size)
6.152 +{
6.153 + char *result;
6.154 + __section *section = __stack.stackdesc->current;
6.155 +
6.156 + if (section->limit - section->level < size)
6.157 + {
6.158 + __stack_expand(__stack);
6.159 + section = __stack.stackdesc->current;
6.160 + }
6.161 +
6.162 + result = section->level;
6.163 + section->level += size;
6.164 +
6.165 + return __ATTRVALUE(result);
6.166 +}
6.167 +
6.168 +void __stack_expand(__attr __stack)
6.169 +{
6.170 + __section *current = __stack.stackdesc->current;
6.171 + __section *section = (__section *) __ALLOCATE(1, sizeof(__section));
6.172 + char *base = (char *) __ALLOCATEIM(1, __STACK_SECTION_SIZE);
6.173 +
6.174 + section->base = base;
6.175 + section->level = base;
6.176 + section->limit = base + __STACK_SECTION_SIZE;
6.177 + section->previous = current;
6.178 +
6.179 + __stack.stackdesc->current = section;
6.180 +}
6.181 +
6.182 +__attr __return(__attr result, __section *section, char *level)
6.183 +{
6.184 + __ref obj = __VALUE(result);
6.185 + char *target = level;
6.186 + size_t size;
6.187 +
6.188 + if (__COPYABLE(result))
6.189 + {
6.190 + size = __INSTANCE_SIZE(obj);
6.191 +
6.192 + /* Test for space in the section. */
6.193 +
6.194 + if (size > section->limit - level)
6.195 + {
6.196 + __stack_expand(__stack);
6.197 + section = __stack.stackdesc->current;
6.198 + target = section->base;
6.199 + }
6.200 +
6.201 + /* Copy into the stack and adjust the level. */
6.202 +
6.203 + __COPY_TO(obj, (__ref) target, size);
6.204 + level = target + size;
6.205 +
6.206 + /* Reference the new location of the object. */
6.207 +
6.208 + result = __MUTABLEVALUE(target);
6.209 + }
6.210 +
6.211 + /* Set the level and current section.*/
6.212 +
6.213 + section->level = level;
6.214 + __stack.stackdesc->current = section;
6.215 +
6.216 + return result;
6.217 +}
7.1 --- a/templates/ops.h Sun Nov 14 00:50:17 2021 +0100
7.2 +++ b/templates/ops.h Sun Nov 28 02:03:21 2021 +0100
7.3 @@ -44,12 +44,15 @@
7.4
7.5 /* Direct storage operations. */
7.6
7.7 +void __store_target(__attr *target, __attr value);
7.8 int __store_via_class__(__ref obj, int pos, __attr value);
7.9 int __store_via_object__(__ref obj, int pos, __attr value);
7.10 +int __store_via_object_internal__(__ref obj, int pos, __attr value);
7.11 int __get_class_and_store__(__ref obj, int pos, __attr value);
7.12
7.13 #define __store_via_class(OBJ, ATTRNAME, VALUE) (__store_via_class__(OBJ, __ATTRPOS(ATTRNAME), VALUE))
7.14 #define __store_via_object(OBJ, ATTRNAME, VALUE) (__store_via_object__(OBJ, __ATTRPOS(ATTRNAME), VALUE))
7.15 +#define __store_via_object_internal(OBJ, ATTRNAME, VALUE) (__store_via_object_internal__(OBJ, __ATTRPOS(ATTRNAME), VALUE))
7.16 #define __get_class_and_store(OBJ, ATTRNAME, VALUE) (__get_class_and_store__(OBJ, __ATTRPOS(ATTRNAME), VALUE))
7.17
7.18 /* Introspection. */
7.19 @@ -93,10 +96,12 @@
7.20
7.21 int __check_and_store_via_class__(__ref obj, int pos, int code, __attr value);
7.22 int __check_and_store_via_object__(__ref obj, int pos, int code, __attr value);
7.23 +int __check_and_store_via_object_internal__(__ref obj, int pos, int code, __attr value);
7.24 int __check_and_store_via_any__(__ref obj, int pos, int code, __attr value);
7.25
7.26 #define __check_and_store_via_class(OBJ, ATTRNAME, VALUE) (__check_and_store_via_class__(OBJ, __ATTRPOS(ATTRNAME), __ATTRCODE(ATTRNAME), VALUE))
7.27 #define __check_and_store_via_object(OBJ, ATTRNAME, VALUE) (__check_and_store_via_object__(OBJ, __ATTRPOS(ATTRNAME), __ATTRCODE(ATTRNAME), VALUE))
7.28 +#define __check_and_store_via_object_internal(OBJ, ATTRNAME, VALUE) (__check_and_store_via_object_internal__(OBJ, __ATTRPOS(ATTRNAME), __ATTRCODE(ATTRNAME), VALUE))
7.29 #define __check_and_store_via_any(OBJ, ATTRNAME, VALUE) (__check_and_store_via_any__(OBJ, __ATTRPOS(ATTRNAME), __ATTRCODE(ATTRNAME), VALUE))
7.30
7.31 /* Context-related operations. */
7.32 @@ -151,6 +156,24 @@
7.33
7.34 /* Copying of structures. */
7.35
7.36 -__ref __COPY(__ref obj, int size);
7.37 +__ref __COPY(__ref obj, size_t size);
7.38 +void __COPY_TO(__ref source, __ref target, size_t size);
7.39 +
7.40 +/* Stack management. */
7.41 +
7.42 +extern _Thread_local __attr __stack;
7.43 +
7.44 +#define __STACK_SECTION_SIZE 4096
7.45 +
7.46 +__attr __stack_init();
7.47 +__attr __stack_allocate(__attr __stack, size_t size);
7.48 +void __stack_expand(__attr __stack);
7.49 +void __stack_contract(__attr __stack, char *level);
7.50 +
7.51 +/* Stack access. */
7.52 +
7.53 +__attr __load(__attr value);
7.54 +__attr __store_local(__attr target, __attr value);
7.55 +__attr __return(__attr result, __section *section, char *level);
7.56
7.57 #endif /* __OPS_H__ */
8.1 --- a/templates/progops.c Sun Nov 14 00:50:17 2021 +0100
8.2 +++ b/templates/progops.c Sun Nov 28 02:03:21 2021 +0100
8.3 @@ -42,6 +42,13 @@
8.4 return __ATTRVALUE(obj);
8.5 }
8.6
8.7 +__attr __new_stack(const __table * table, __ref cls, size_t size)
8.8 +{
8.9 + __attr attr = __stack_allocate(__stack, size);
8.10 + __init(__VALUE(attr), table, cls);
8.11 + return attr;
8.12 +}
8.13 +
8.14 __attr __new_wrapper(__attr context, __attr attr)
8.15 {
8.16 return __new___builtins___core_wrapper(__NULL, context, attr);
8.17 @@ -69,7 +76,10 @@
8.18 /* Copy the given number of values. */
8.19
8.20 for (i = 0; i < number; i++)
8.21 - data->attrs[i] = args[i];
8.22 + {
8.23 + data->attrs[i] = __RAWVALUE(0);
8.24 + __store_target(&data->attrs[i], args[i]);
8.25 + }
8.26
8.27 data->size = number;
8.28 }
8.29 @@ -81,7 +91,7 @@
8.30
8.31 /* Store a reference to the data in the object's __data__ attribute. */
8.32
8.33 - __store_via_object(__VALUE(self), __data__, (__attr) {.seqvalue=data});
8.34 + __store_via_object_internal(__VALUE(self), __data__, (__attr) {.seqvalue=data});
8.35 __newdata_sequence(number, data, args);
8.36 return self;
8.37 }
8.38 @@ -97,7 +107,7 @@
8.39
8.40 /* Store a reference to the data in the object's __data__ attribute. */
8.41
8.42 - __store_via_object(__VALUE(self), __data__, (__attr) {.seqvalue=data});
8.43 + __store_via_object_internal(__VALUE(self), __data__, (__attr) {.seqvalue=data});
8.44 __newdata_sequence(number, data, args);
8.45 return self;
8.46 }
8.47 @@ -207,8 +217,10 @@
8.48 /* Invoke the given callable, supplying keyword argument details in the given
8.49 codes and arguments arrays, indicating the number of arguments described.
8.50 The number of positional arguments is specified, and such arguments then
8.51 - follow as conventional function arguments. Typically, at least one argument
8.52 - is specified, starting with any context argument.
8.53 + follow as conventional function arguments.
8.54 +
8.55 + Typically, at least one argument is specified, starting with any context
8.56 + argument.
8.57 */
8.58
8.59 __attr __invoke(__attr callable, int always_callable,
8.60 @@ -220,9 +232,11 @@
8.61 __attr target = __unwrap_callable(callable);
8.62
8.63 /* Obtain the __args__ special member, referencing the parameter table. */
8.64 +
8.65 + const __ptable *ptable = __check_and_load_via_object(__VALUE(target), __args__).ptable;
8.66 +
8.67 /* Refer to the table and minimum/maximum. */
8.68
8.69 - const __ptable *ptable = __check_and_load_via_object(__VALUE(target), __args__).ptable;
8.70 const unsigned int min = ptable->min, max = ptable->max;
8.71
8.72 /* Reserve enough space for the arguments. */
8.73 @@ -270,10 +284,13 @@
8.74 /* Check the table entry against the supplied argument details.
8.75 Set the argument but only if it does not overwrite positional
8.76 arguments. */
8.77 - /* NOTE: Should use a more specific exception. */
8.78
8.79 if ((pos == -1) || (pos < nargs))
8.80 + {
8.81 + /* NOTE: Should use a more specific exception. */
8.82 +
8.83 __raise_type_error();
8.84 + }
8.85
8.86 /* Set the argument using the appropriate position. */
8.87
8.88 @@ -290,7 +307,8 @@
8.89 }
8.90
8.91 /* Call with the prepared arguments via a special adaptor function that
8.92 - converts the array to an argument list. */
8.93 + converts the array to an argument list. The context argument occupies
8.94 + position #0. */
8.95
8.96 return __call_with_args(
8.97 always_callable ?
8.98 @@ -336,7 +354,8 @@
8.99
8.100 return value == (__ref) &__predefined___builtins___boolean_True ? 1 :
8.101 value == (__ref) &__predefined___builtins___boolean_False ? 0 :
8.102 - __VALUE(__fn___builtins___boolean_bool(__NULL, attr)) == (__ref) &__predefined___builtins___boolean_True;
8.103 + __VALUE(__fn___builtins___boolean_bool(__NULL, attr)) ==
8.104 + (__ref) &__predefined___builtins___boolean_True;
8.105 }
8.106
8.107 /* Conversion of trailing data to an integer. */
9.1 --- a/templates/progops.h Sun Nov 14 00:50:17 2021 +0100
9.2 +++ b/templates/progops.h Sun Nov 28 02:03:21 2021 +0100
9.3 @@ -26,6 +26,7 @@
9.4 /* Generic instantiation operations, defining common members. */
9.5
9.6 __attr __new(const __table *table, __ref cls, size_t size, int immutable);
9.7 +__attr __new_stack(const __table *table, __ref cls, size_t size);
9.8 __attr __new_wrapper(__attr context, __attr attr);
9.9
9.10 /* Generic internal data allocation. */
9.11 @@ -86,6 +87,7 @@
9.12 #define __INSTANCETABLE(CLS) (__InstanceTable_##CLS)
9.13 #define __NEWINSTANCE(CLS) __new(&__INSTANCETABLE(CLS), &CLS, __INSTANCESIZE(CLS), 0)
9.14 #define __NEWINSTANCEIM(CLS) __new(&__INSTANCETABLE(CLS), &CLS, __INSTANCESIZE(CLS), 1)
9.15 +#define __NEWINSTANCE_STACK(CLS) __new_stack(&__INSTANCETABLE(CLS), &CLS, __INSTANCESIZE(CLS))
9.16 #define __ISINSTANCE(ATTR, TYPE) __BOOL(__fn_native_introspection_isinstance(__NULL, ATTR, TYPE))
9.17
9.18 /* Operations for accessing trailing data. */
10.1 --- a/templates/types.h Sun Nov 14 00:50:17 2021 +0100
10.2 +++ b/templates/types.h Sun Nov 28 02:03:21 2021 +0100
10.3 @@ -42,6 +42,7 @@
10.4 typedef struct __table
10.5 {
10.6 const __pos size;
10.7 + const size_t obj_size; /* size for value instance copying */
10.8 const __code attrs[];
10.9 } __table;
10.10
10.11 @@ -80,6 +81,11 @@
10.12
10.13 typedef _Float64 __float;
10.14
10.15 +/* Introduce value stack section and descriptor. */
10.16 +
10.17 +typedef struct __section __section;
10.18 +typedef struct __stackdesc __stackdesc;
10.19 +
10.20 /* Attribute value interpretations. */
10.21
10.22 typedef union __attr
10.23 @@ -101,6 +107,11 @@
10.24 __fragment * seqvalue; /* sequence data */
10.25 void * datavalue; /* object-specific data */
10.26 __int sizevalue; /* object-specific size */
10.27 +
10.28 + /* Value stack parameter member. */
10.29 +
10.30 + __stackdesc *stackdesc; /* reference to value stack descriptor */
10.31 +
10.32 } __attr;
10.33
10.34 typedef struct __obj
10.35 @@ -115,7 +126,7 @@
10.36
10.37 } __obj;
10.38
10.39 -#define __INSTANCE_SIZE(NUMBER) ((NUMBER) * sizeof(__attr) + sizeof(__table *) + sizeof(__ppos))
10.40 +#define __INSTANCE_SIZE(REF) ((REF)->table->obj_size)
10.41
10.42 /* Fragments are simple collections of attributes employed by sequence types.
10.43 They provide the basis of lists and tuples. */
10.44 @@ -128,17 +139,33 @@
10.45
10.46 #define __FRAGMENT_SIZE(NUMBER) ((NUMBER) * sizeof(__attr) + 2 * sizeof(__int))
10.47
10.48 +/* Sections are used to provide the value stack. */
10.49 +
10.50 +typedef struct __section
10.51 +{
10.52 + char *base, *level, *limit;
10.53 + __section *previous;
10.54 +} __section;
10.55 +
10.56 +/* The value stack descriptor references the current value stack section. */
10.57 +
10.58 +typedef struct __stackdesc
10.59 +{
10.60 + __section *current;
10.61 +} __stackdesc;
10.62 +
10.63 /* Attribute interpretation. */
10.64
10.65 #define __NUM_TAG_BITS 2
10.66 -#define __TAG_COPYABLE 0b01UL
10.67 #define __TAG_MUTABLE 0b10UL
10.68 #define __TAG_MASK 0b11UL
10.69
10.70 -#define __COPYABLE(ATTR) ((ATTR).rawvalue & __TAG_COPYABLE)
10.71 +#define __COPYABLE(ATTR) (__VALUE(ATTR)->table->obj_size != 0)
10.72 #define __MUTABLE(ATTR) ((ATTR).rawvalue & __TAG_MUTABLE)
10.73 #define __TO_IMMUTABLE(ATTR) ((__attr) {.rawvalue=(ATTR).rawvalue & (~__TAG_MUTABLE)})
10.74 -#define __TO_MUTABLE(ATTR) ((__attr) {.rawvalue=(ATTR).rawvalue | __TAG_MASK})
10.75 +#define __TO_MUTABLE(ATTR) ((__attr) {.rawvalue=(ATTR).rawvalue | __TAG_MUTABLE})
10.76 +#define __MUTABLEVALUE(REF) ((__attr) {.rawvalue=(uintptr_t) REF | __TAG_MUTABLE})
10.77 +#define __RAWVALUE(VALUE) ((__attr) {.rawvalue=VALUE})
10.78
10.79 /* Attribute value setting. */
10.80
12.1 --- a/translator.py Sun Nov 14 00:50:17 2021 +0100
12.2 +++ b/translator.py Sun Nov 28 02:03:21 2021 +0100
12.3 @@ -3,7 +3,7 @@
12.4 """
12.5 Translate programs.
12.6
12.7 -Copyright (C) 2015, 2016, 2017, 2018 Paul Boddie <paul@boddie.org.uk>
12.8 +Copyright (C) 2015-2018, 2021 Paul Boddie <paul@boddie.org.uk>
12.9
12.10 This program is free software; you can redistribute it and/or modify it under
12.11 the terms of the GNU General Public License as published by the Free Software
12.12 @@ -37,7 +37,7 @@
12.13 AliasResult, AttrResult, Expression, InstantiationResult, \
12.14 InvocationResult, LogicalOperationResult, \
12.15 LogicalResult, NegationResult, PredefinedConstantRef, \
12.16 - ReturnRef
12.17 + ReturnRef, special_attributes
12.18 from StringIO import StringIO
12.19 import compiler
12.20 import sys
12.21 @@ -619,7 +619,8 @@
12.22 del self.attrs[0]
12.23 return AttrResult(output, refs, location,
12.24 context_identity, context_identity_verified,
12.25 - accessor_test, accessor_stored)
12.26 + accessor_test, accessor_stored, n.attrname,
12.27 + self.in_assignment)
12.28
12.29 def init_substitutions(self):
12.30
12.31 @@ -806,9 +807,23 @@
12.32 if ref and not ref.static():
12.33 parent, attrname = path.rsplit(".", 1)
12.34
12.35 - self.writestmt("__store_via_object(&%s, %s, __load_via_object(&%s, %s));" % (
12.36 - encode_path(class_name), name,
12.37 - encode_path(parent), attrname
12.38 + # NOTE: This is a superficial test for internal attributes that
12.39 + # NOTE: relies on such attributes being used directly and passed
12.40 + # NOTE: to native code.
12.41 +
12.42 + if name in special_attributes:
12.43 + store_op = "__store_via_object_internal"
12.44 + else:
12.45 + store_op = "__store_via_object"
12.46 +
12.47 + if attrname in special_attributes:
12.48 + load_op = "__load_via_object_internal"
12.49 + else:
12.50 + load_op = "__load_via_object"
12.51 +
12.52 + self.writestmt("%s(&%s, %s, %s(&%s, %s));" % (
12.53 + store_op, encode_path(class_name), name,
12.54 + load_op, encode_path(parent), attrname
12.55 ))
12.56
12.57 def process_from_node(self, n):
12.58 @@ -883,6 +898,11 @@
12.59 compiler.ast.AssAttr(compiler.ast.Name("self"), name, "OP_ASSIGN"),
12.60 compiler.ast.Name(name))
12.61
12.62 + # Record the value stack level.
12.63 +
12.64 + self.writestmt("__section *__stack_section = __stack.stackdesc->current;")
12.65 + self.writestmt("char *__stack_level = __stack_section->level; (void) __stack_level;")
12.66 +
12.67 # Produce the body and any additional return statement.
12.68
12.69 expr = self.process_structure_node(n.code) or \
12.70 @@ -1281,8 +1301,8 @@
12.71 self.record_temp("__tmp_values")
12.72
12.73 # Arguments are presented in a temporary frame array with any context
12.74 - # always being the first argument. Where it would be unused, it may be
12.75 - # set to null.
12.76 + # always being the first argument. Where the context would be unused, it
12.77 + # may be set to null.
12.78
12.79 if context_required:
12.80 if have_access_context:
12.81 @@ -1292,6 +1312,8 @@
12.82 else:
12.83 context_arg = "__NULL"
12.84
12.85 + # Introduce any context.
12.86 +
12.87 args = [context_arg]
12.88 reserved_args = 1
12.89
12.90 @@ -1324,12 +1346,9 @@
12.91 for i, arg in enumerate(n.args):
12.92 argexpr = self.process_structure_node(arg)
12.93
12.94 - # Obtain an appropriate argument representation. This prevents
12.95 - # copyable values from being mutable, but care must be taken to
12.96 - # prevent special internal attribute values represented using
12.97 - # attributes from being modified.
12.98 -
12.99 - argrepr = argexpr.as_arg()
12.100 + # Obtain an appropriate argument representation.
12.101 +
12.102 + argrepr = str(argexpr)
12.103
12.104 # Store a keyword argument, either in the argument list or
12.105 # in a separate keyword argument list for subsequent lookup.
12.106 @@ -1758,7 +1777,7 @@
12.107 if self.in_try_finally or self.in_try_except:
12.108 self.writestmt("__Return(%s);" % expr)
12.109 else:
12.110 - self.writestmt("return %s;" % expr)
12.111 + self.writestmt("return __return(%s, __stack_section, __stack_level);" % expr)
12.112
12.113 return ReturnRef()
12.114
12.115 @@ -2131,11 +2150,13 @@
12.116
12.117 if names:
12.118 names.sort()
12.119 - self.writeline("__attr %s;" % ", ".join(names))
12.120 + for n in names:
12.121 + self.writeline("__attr %s = (__attr) {.rawvalue = 0};" % n)
12.122
12.123 if volatile_names:
12.124 volatile_names.sort()
12.125 - self.writeline("volatile __attr %s;" % ", ".join(volatile_names))
12.126 + for n in volatile_names:
12.127 + self.writeline("volatile __attr %s = (__attr) {.rawvalue = 0};" % n)
12.128
12.129 self.flush_unit(name, out)
12.130
13.1 --- a/transresults.py Sun Nov 14 00:50:17 2021 +0100
13.2 +++ b/transresults.py Sun Nov 28 02:03:21 2021 +0100
13.3 @@ -24,6 +24,8 @@
13.4 from results import ConstantValueRef, InstanceRef, LiteralSequenceRef, NameRef, \
13.5 ResolvedNameRef, Result
13.6
13.7 +special_attributes = ("__args__", "__data__", "__key__", "__size__")
13.8 +
13.9 # Classes representing intermediate translation results.
13.10
13.11 class ReturnRef:
13.12 @@ -59,12 +61,6 @@
13.13 def __repr__(self):
13.14 return "Expression(%r)" % self.s
13.15
13.16 - def as_arg(self):
13.17 -
13.18 - "Return the expression without any mutable tag."
13.19 -
13.20 - return self.s
13.21 -
13.22 class TrResolvedNameRef(ResolvedNameRef):
13.23
13.24 "A reference to a name in the translation."
13.25 @@ -114,54 +110,58 @@
13.26 # Qualified names must be converted into parent-relative assignments.
13.27
13.28 elif self.parent:
13.29 - return "__store_via_object(&%s, %s, %s)" % (
13.30 - encode_path(self.parent), self.attrname, self.expr)
13.31 +
13.32 + # NOTE: This is a superficial test for internal attributes that
13.33 + # NOTE: relies on such attributes being used directly and passed
13.34 + # NOTE: to native code.
13.35 +
13.36 + if self.attrname in special_attributes:
13.37 + op = "__store_via_object_internal"
13.38 + else:
13.39 + op = "__store_via_object"
13.40 +
13.41 + return "%s(&%s, %s, %s)" % (
13.42 + op, encode_path(self.parent), self.attrname, self.expr)
13.43
13.44 # All other assignments involve the names as they were given.
13.45
13.46 else:
13.47 - return "%s = %s" % (self.attrname, self.expr)
13.48 + return "%s = __store_local(%s, %s)" % (self.attrname, self.attrname, self.expr)
13.49
13.50 # Expressions.
13.51
13.52 - elif self.static_name:
13.53 - return "__ATTRVALUE(&%s)" % self.static_name
13.54 + if self.static_name:
13.55 + s = "__ATTRVALUE(&%s)" % self.static_name
13.56
13.57 # Qualified names must be converted into parent-relative accesses.
13.58
13.59 elif self.parent:
13.60 - return "__load_via_object(&%s, %s)" % (
13.61 - encode_path(self.parent), self.attrname)
13.62 +
13.63 + # NOTE: This is a superficial test for internal attributes that
13.64 + # NOTE: relies on such attributes being used directly and passed
13.65 + # NOTE: to native code.
13.66 +
13.67 + if self.attrname in special_attributes:
13.68 + op = "__load_via_object_internal"
13.69 + else:
13.70 + op = "__load_via_object"
13.71 +
13.72 + s = "%s(&%s, %s)" % (
13.73 + op, encode_path(self.parent), self.attrname)
13.74
13.75 # All other accesses involve the names as they were given.
13.76
13.77 else:
13.78 - return "(%s)" % self.attrname
13.79 -
13.80 - def as_arg(self):
13.81 -
13.82 - "Return the expression without any mutable tag."
13.83 -
13.84 - s = self.__str__()
13.85 + s = "(%s)" % self.attrname
13.86
13.87 - # NOTE: This is a superficial test for internal attributes that relies
13.88 - # NOTE: on such attributes being used directly and passed to native
13.89 - # NOTE: code.
13.90 -
13.91 - if self.attrname in ("__data__", "__size__"):
13.92 - return s
13.93 - else:
13.94 - return "__TO_IMMUTABLE(%s)" % s
13.95 + return "__load(%s)" % s
13.96
13.97 class TrConstantValueRef(ConstantValueRef):
13.98
13.99 "A constant value reference in the translation."
13.100
13.101 def __str__(self):
13.102 - return encode_literal_constant(self.number)
13.103 -
13.104 - def as_arg(self):
13.105 - return self.__str__()
13.106 + return "__load(%s)" % encode_literal_constant(self.number)
13.107
13.108 class TrLiteralSequenceRef(LiteralSequenceRef):
13.109
13.110 @@ -170,9 +170,6 @@
13.111 def __str__(self):
13.112 return str(self.node)
13.113
13.114 - def as_arg(self):
13.115 - return self.__str__()
13.116 -
13.117 class TrInstanceRef(InstanceRef):
13.118
13.119 "A reference representing instantiation of a class."
13.120 @@ -193,15 +190,13 @@
13.121 def __repr__(self):
13.122 return "TrResolvedInstanceRef(%r, %r)" % (self.ref, self.expr)
13.123
13.124 - def as_arg(self):
13.125 - return self.__str__()
13.126 -
13.127 class AttrResult(Result, InstructionSequence):
13.128
13.129 "A translation result for an attribute access."
13.130
13.131 def __init__(self, instructions, refs, location, context_identity,
13.132 - context_identity_verified, accessor_test, accessor_stored):
13.133 + context_identity_verified, accessor_test, accessor_stored,
13.134 + attrname, assignment):
13.135
13.136 InstructionSequence.__init__(self, instructions)
13.137 self.refs = refs
13.138 @@ -210,6 +205,8 @@
13.139 self.context_identity_verified = context_identity_verified
13.140 self.accessor_test = accessor_test
13.141 self.accessor_stored = accessor_stored
13.142 + self.attrname = attrname
13.143 + self.assignment = assignment
13.144
13.145 def references(self):
13.146 return self.refs
13.147 @@ -244,16 +241,23 @@
13.148 return bool(self.instructions)
13.149
13.150 def __str__(self):
13.151 - return encode_instructions(self.instructions)
13.152 + s = encode_instructions(self.instructions)
13.153 +
13.154 + # NOTE: This includes a superficial test for internal attributes that
13.155 + # NOTE: relies on such attributes being used directly and passedto
13.156 + # NOTE: native code.
13.157 +
13.158 + if self.assignment or self.accessor_test or self.attrname in special_attributes:
13.159 + return s
13.160 + else:
13.161 + return "__load(%s)" % s
13.162
13.163 def __repr__(self):
13.164 - return "AttrResult(%r, %r, %r, %r, %r, %r, %r)" % (
13.165 + return "AttrResult(%r, %r, %r, %r, %r, %r, %r, %r, %r)" % (
13.166 self.instructions, self.refs, self.location,
13.167 self.context_identity, self.context_identity_verified,
13.168 - self.accessor_test, self.accessor_stored)
13.169 -
13.170 - def as_arg(self):
13.171 - return self.__str__()
13.172 + self.accessor_test, self.accessor_stored, self.attrname,
13.173 + self.assignment)
13.174
13.175 class AliasResult(NameRef, Result):
13.176
13.177 @@ -308,9 +312,6 @@
13.178 def __repr__(self):
13.179 return "AliasResult(%r, %r)" % (self.name_ref, self.refs)
13.180
13.181 - def as_arg(self):
13.182 - return self.__str__()
13.183 -
13.184 class InvocationResult(Result, InstructionSequence):
13.185
13.186 "A translation result for an invocation."
13.187 @@ -321,9 +322,6 @@
13.188 def __repr__(self):
13.189 return "InvocationResult(%r)" % self.instructions
13.190
13.191 - def as_arg(self):
13.192 - return self.__str__()
13.193 -
13.194 class InstantiationResult(InvocationResult, TrInstanceRef):
13.195
13.196 "An instantiation result acting like an invocation result."
13.197 @@ -364,9 +362,6 @@
13.198 def __repr__(self):
13.199 return "PredefinedConstantRef(%r)" % self.value
13.200
13.201 - def as_arg(self):
13.202 - return self.__str__()
13.203 -
13.204 class LogicalResult(Result):
13.205
13.206 "A logical expression result."
13.207 @@ -412,9 +407,6 @@
13.208 def __repr__(self):
13.209 return "NegationResult(%r)" % self.expr
13.210
13.211 - def as_arg(self):
13.212 - return self.__str__()
13.213 -
13.214 class LogicalOperationResult(LogicalResult):
13.215
13.216 "A logical operation result."
13.217 @@ -487,7 +479,4 @@
13.218 def __repr__(self):
13.219 return "LogicalOperationResult(%r, %r)" % (self.exprs, self.conjunction)
13.220
13.221 - def as_arg(self):
13.222 - return self.__str__()
13.223 -
13.224 # vim: tabstop=4 expandtab shiftwidth=4