# HG changeset patch # User Paul Boddie # Date 1486996536 -3600 # Node ID 722f838eab064e9fe519c83fdd04013e97e5093a # Parent d7769551b05117c79acb90286edadbb5eda41c0a Introduced method wrapper usage to hold context information in order to experiment with smaller attribute sizes. diff -r d7769551b051 -r 722f838eab06 encoders.py --- a/encoders.py Sun Feb 12 23:24:42 2017 +0100 +++ b/encoders.py Mon Feb 13 15:35:36 2017 +0100 @@ -207,7 +207,7 @@ ) static_ops = ( - "__load_static", + "__load_static_ignore", "__load_static_replace", "__load_static_test", ) reference_acting_ops = attribute_ops + checked_ops + typename_ops @@ -274,8 +274,7 @@ # Obtain addresses of static objects. elif op in static_ops: - a[0] = "&%s" % a[0] - a[1] = "&%s" % a[1] + a[-1] = "&%s" % a[-1] argstr = "(%s)" % ", ".join(map(str, a)) diff -r d7769551b051 -r 722f838eab06 generator.py --- a/generator.py Sun Feb 12 23:24:42 2017 +0100 +++ b/generator.py Mon Feb 13 15:35:36 2017 +0100 @@ -533,7 +533,7 @@ # Define a macro for the constant. attr_name = encode_path(const_path) - print >>f_decls, "#define %s ((__attr) {{.context=&%s, .value=&%s}})" % (attr_name, structure_name, structure_name) + print >>f_decls, "#define %s ((__attr) {.value=&%s})" % (attr_name, structure_name) def make_parameter_table(self, f_decls, f_defs, parameters): @@ -874,16 +874,10 @@ if kind == "": attr = encode_instantiator_pointer(attr) - unbound_attr = attr - - # Provide bound method and unbound function pointers if - # populating methods in a class. - else: attr = encode_function_pointer(attr) - unbound_attr = "__unbound_method" - structure.append("{{.inv=%s, .fn=%s}}" % (unbound_attr, attr)) + structure.append("{.fn=%s}" % attr) continue # Special argument specification member. @@ -892,7 +886,7 @@ signature = self.get_signature_for_callable(ref.get_origin()) ptable = encode_tablename("", signature) - structure.append("{{.min=%s, .ptable=&%s}}" % (attr, ptable)) + structure.append("{.min=%s, .ptable=&%s}" % (attr, ptable)) continue # Special internal data member. @@ -906,8 +900,8 @@ # Special internal key member. elif attrname == "__key__": - structure.append("{{.code=%s, .pos=%s}}" % (attr and encode_symbol("code", attr) or "0", - attr and encode_symbol("pos", attr) or "0")) + structure.append("{.code=%s, .pos=%s}" % (attr and encode_symbol("code", attr) or "0", + attr and encode_symbol("pos", attr) or "0")) continue # Special cases. @@ -950,13 +944,33 @@ # object paths. value = path.rsplit(".", 1)[0] - structure.append("{{.context=0, .value=&%s}}" % encode_path(value)) + structure.append("{.value=&%s}" % encode_path(value)) + continue + + # Special context member. + # Set the context depending on the kind of attribute. + # For methods: + # For other attributes: __NULL + + elif attrname == "__context__": + path = ref.get_origin() + + # Contexts of methods are derived from their object paths. + + context = "0" + + if ref.get_kind() == "": + parent = path.rsplit(".", 1)[0] + if self.importer.classes.has_key(parent): + context = "&%s" % encode_path(parent) + + structure.append("{.value=%s}" % context) continue # Special class relationship attributes. elif is_type_attribute(attrname): - structure.append("{{.context=0, .value=&%s}}" % encode_path(decode_type_attribute(attrname))) + structure.append("{.value=&%s}" % encode_path(decode_type_attribute(attrname))) continue # All other kinds of members. @@ -995,33 +1009,22 @@ if kind == "" and origin == self.none_type: attr_path = encode_predefined_reference(self.none_value) - return "{{.context=&%s, .value=&%s}} /* %s */" % (attr_path, attr_path, name) + return "{.value=&%s} /* %s */" % (attr_path, name) # Predefined constant members. if (path, name) in self.predefined_constant_members: attr_path = encode_predefined_reference("%s.%s" % (path, name)) - return "{{.context=&%s, .value=&%s}} /* %s */" % (attr_path, attr_path, name) + return "{.value=&%s} /* %s */" % (attr_path, name) # General undetermined members. if kind in ("", ""): attr_path = encode_predefined_reference(self.none_value) - return "{{.context=&%s, .value=&%s}} /* %s */" % (attr_path, attr_path, name) - - # Set the context depending on the kind of attribute. - # For methods: {&, &} - # For other attributes: {&, &} + return "{.value=&%s} /* %s */" % (attr_path, name) else: - if kind == "" and structure_type == "": - parent = origin.rsplit(".", 1)[0] - context = "&%s" % encode_path(parent) - elif kind == "": - context = "&%s" % encode_path(origin) - else: - context = "0" - return "{{.context=%s, .value=&%s}}" % (context, encode_path(origin)) + return "{.value=&%s}" % encode_path(origin) def append_defaults(self, path, structure): @@ -1129,7 +1132,7 @@ } __Catch(__tmp_exc) { - if (__ISINSTANCE(__tmp_exc.arg, ((__attr) {{.context=0, .value=&__builtins___exception_system_SystemExit}}))) + if (__ISINSTANCE(__tmp_exc.arg, ((__attr) {.value=&__builtins___exception_system_SystemExit}))) return __load_via_object( __load_via_object(__tmp_exc.arg.value, %s).value, %s).intvalue; diff -r d7769551b051 -r 722f838eab06 inspector.py --- a/inspector.py Sun Feb 12 23:24:42 2017 +0100 +++ b/inspector.py Mon Feb 13 15:35:36 2017 +0100 @@ -521,14 +521,17 @@ # class. Function instances provide these attributes. if class_name != "__builtins__.core.function": + self.set_name("__fn__") # special instantiator attribute self.set_name("__args__") # special instantiator attribute - # Provide leafname and parent attributes. + # Provide leafname, parent and context attributes. parent, leafname = class_name.rsplit(".", 1) self.set_name("__name__", self.get_constant("string", leafname).reference()) - self.set_name("__parent__") + + if class_name != "__builtins__.core.function": + self.set_name("__parent__") self.process_structure_node(n.code) self.exit_namespace() diff -r d7769551b051 -r 722f838eab06 lib/__builtins__/core.py --- a/lib/__builtins__/core.py Sun Feb 12 23:24:42 2017 +0100 +++ b/lib/__builtins__/core.py Mon Feb 13 15:35:36 2017 +0100 @@ -86,6 +86,7 @@ self.__args__ = None self.__name__ = None self.__parent__ = None + self.__context__ = None def __bool__(self): @@ -122,6 +123,17 @@ __repr__ = __str__ +class wrapper: + + "A special method wrapper." + + def __init__(self, context, value): + + "Initialise a wrapper with the given 'context' and wrapped 'value'." + + self.__context__ = context + self.__value__ = value + class Exception: "The root of all exception types." diff -r d7769551b051 -r 722f838eab06 optimiser.py --- a/optimiser.py Sun Feb 12 23:24:42 2017 +0100 +++ b/optimiser.py Mon Feb 13 15:35:36 2017 +0100 @@ -510,16 +510,21 @@ emit(("__store_via_object", parent, attrname, "")) elif final_method in ("static", "static-invoke"): - parent, attrname = origin.rsplit(".", 1) - accessor = ("__load_static", parent, origin) + accessor = ("__load_static_ignore", origin) # Wrap accesses in context operations. if context_test == "test": - emit(("__test_context", context_var, accessor)) + if final_method in ("static", "static-invoke"): + emit(("__load_static_test", context_var, origin)) + else: + emit(("__test_context", context_var, accessor)) elif context_test == "replace": - emit(("__update_context", context_var, accessor)) + if final_method in ("static", "static-invoke"): + emit(("__load_static_replace", context_var, origin)) + else: + emit(("__update_context", context_var, accessor)) elif final_method not in ("assign", "static-assign"): emit(accessor) diff -r d7769551b051 -r 722f838eab06 templates/native/iconv.c --- a/templates/native/iconv.c Sun Feb 12 23:24:42 2017 +0100 +++ b/templates/native/iconv.c Mon Feb 13 15:35:36 2017 +0100 @@ -156,7 +156,6 @@ /* Return the descriptor as an opaque value. */ - attr.context = 0; attr.datavalue = (void *) result; return attr; } diff -r d7769551b051 -r 722f838eab06 templates/native/io.c --- a/templates/native/io.c Sun Feb 12 23:24:42 2017 +0100 +++ b/templates/native/io.c Mon Feb 13 15:35:36 2017 +0100 @@ -80,7 +80,6 @@ else { - attr.context = 0; attr.datavalue = (void *) f; return attr; } @@ -113,7 +112,6 @@ else { - attr.context = 0; attr.datavalue = (void *) f; return attr; } diff -r d7769551b051 -r 722f838eab06 templates/ops.c --- a/templates/ops.c Sun Feb 12 23:24:42 2017 +0100 +++ b/templates/ops.c Mon Feb 13 15:35:36 2017 +0100 @@ -25,10 +25,19 @@ /* Direct access and manipulation of static objects. */ -__attr __load_static(__ref parent, __ref obj) +__attr __load_static_ignore(__ref obj) +{ + return (__attr) {.value=obj}; +} + +__attr __load_static_replace(__ref context, __ref obj) { - __attr out = {.context=parent, .value=obj}; - return out; + return __update_context(context, (__attr) {.value=obj}); +} + +__attr __load_static_test(__ref context, __ref obj) +{ + return __test_context(context, (__attr) {.value=obj}); } /* Direct retrieval operations, returning and setting attributes. */ @@ -192,9 +201,11 @@ __attr __test_context(__ref context, __attr attr) { + __ref attrcontext = __CONTEXT_AS_VALUE(attr).value; + /* Preserve any existing null or instance context. */ - if ((attr.context == 0) || __is_instance(attr.context)) + if ((attrcontext == 0) || __is_instance(attrcontext)) return attr; /* Test any instance context against the context employed by the @@ -202,7 +213,7 @@ if (__is_instance(context)) { - if (__test_common_instance(context, __TYPEPOS(attr.context), __TYPECODE(attr.context))) + if (__test_common_instance(context, __TYPEPOS(attrcontext), __TYPECODE(attrcontext))) return __update_context(context, attr); else __raise_type_error(); @@ -210,7 +221,7 @@ /* Test for access to a type class attribute using a type instance. */ - if (__test_specific_type(attr.context, &__TYPE_CLASS_TYPE) && __is_type_instance(context)) + if (__test_specific_type(attrcontext, &__TYPE_CLASS_TYPE) && __is_type_instance(context)) return __update_context(context, attr); /* Otherwise, preserve the attribute as retrieved. */ @@ -220,47 +231,55 @@ __attr __update_context(__ref context, __attr attr) { - __attr out = {.context=context, .value=attr.value}; - return out; + return __new_wrapper(context, attr); } /* Context testing for invocations. */ -int __type_method_invocation(__attr attr) +int __type_method_invocation(__ref context, __attr target) { - __attr parent; + __ref targetcontext = __CONTEXT_AS_VALUE(target).value; /* Require instances, not classes, where methods are function instances. */ - if (!__is_instance(attr.value)) + if (!__is_instance(target.value)) return 0; - /* Access the parent of the callable and test if it is the type object. */ + /* Access the context of the callable and test if it is the type object. */ - parent = __check_and_load_via_object_null(attr.value, __ATTRPOS(__parent__), __ATTRCODE(__parent__)); - return ((parent.value != 0) && __test_specific_type(parent.value, &__TYPE_CLASS_TYPE) && __is_type_instance(attr.context)); + return ((targetcontext != 0) && __test_specific_type(targetcontext, &__TYPE_CLASS_TYPE) && __is_type_instance(context)); } -__attr (*__get_function(__attr attr))(__attr[]) +__attr __unwrap_callable(__attr callable) { + __attr value = __check_and_load_via_object_null(callable.value, __ATTRPOS(__value__), __ATTRCODE(__value__)); + return value.value ? value : callable; +} + +__attr (*__get_function(__ref context, __attr target))(__attr[]) +{ + target = __unwrap_callable(target); + /* Require null or instance contexts for functions and methods respectively, or type instance contexts for type methods. */ - if ((attr.context == 0) || __is_instance(attr.context) || __type_method_invocation(attr)) - return __load_via_object(attr.value, __ATTRPOS(__fn__)).fn; + if ((context == 0) || __is_instance(context) || __type_method_invocation(context, target)) + return __load_via_object(target.value, __ATTRPOS(__fn__)).fn; else - return __load_via_object(attr.value, __ATTRPOS(__fn__)).inv; + return __unbound_method; } -__attr (*__check_and_get_function(__attr attr))(__attr[]) +__attr (*__check_and_get_function(__ref context, __attr target))(__attr[]) { + target = __unwrap_callable(target); + /* Require null or instance contexts for functions and methods respectively, or type instance contexts for type methods. */ - if ((attr.context == 0) || __is_instance(attr.context) || __type_method_invocation(attr)) - return __check_and_load_via_object(attr.value, __ATTRPOS(__fn__), __ATTRCODE(__fn__)).fn; + if ((context == 0) || __is_instance(context) || __type_method_invocation(context, target)) + return __check_and_load_via_object(target.value, __ATTRPOS(__fn__), __ATTRCODE(__fn__)).fn; else - return __check_and_load_via_object(attr.value, __ATTRPOS(__fn__), __ATTRCODE(__fn__)).inv; + return __unbound_method; } /* Basic structure tests. */ @@ -295,10 +314,7 @@ __attr __CONTEXT_AS_VALUE(__attr attr) { - __attr out; - out.context = attr.context; - out.value = attr.context; - return out; + return __check_and_load_via_object_null(attr.value, __ATTRPOS(__context__), __ATTRCODE(__context__)); } /* Type testing. */ @@ -310,7 +326,6 @@ int __ISNULL(__attr value) { - /* (value.context == __NULL.context) is superfluous */ return (value.value == 0); /* __NULL.value */ } diff -r d7769551b051 -r 722f838eab06 templates/ops.h --- a/templates/ops.h Sun Feb 12 23:24:42 2017 +0100 +++ b/templates/ops.h Mon Feb 13 15:35:36 2017 +0100 @@ -24,7 +24,9 @@ /* Direct access and manipulation of static objects. */ -__attr __load_static(__ref parent, __ref obj); +__attr __load_static_ignore(__ref obj); +__attr __load_static_replace(__ref context, __ref obj); +__attr __load_static_test(__ref context, __ref obj); /* Direct retrieval operations, returning attributes. */ @@ -77,8 +79,9 @@ /* Context testing for invocations. */ -__attr (*__get_function(__attr attr))(__attr[]); -__attr (*__check_and_get_function(__attr attr))(__attr[]); +__attr __unwrap_callable(__attr callable); +__attr (*__get_function(__ref context, __attr target))(__attr[]); +__attr (*__check_and_get_function(__ref context, __attr target))(__attr[]); /* Basic structure tests. */ diff -r d7769551b051 -r 722f838eab06 templates/progops.c --- a/templates/progops.c Sun Feb 12 23:24:42 2017 +0100 +++ b/templates/progops.c Mon Feb 13 15:35:36 2017 +0100 @@ -30,11 +30,14 @@ __attr __new(const __table * table, __ref cls, size_t size) { __ref obj = (__ref) __ALLOCATE(1, size); - __attr self = {.context=obj, .value=obj}; - __attr tmp = {.context=0, .value=cls}; obj->table = table; - __store_via_object(obj, __ATTRPOS(__class__), tmp); - return self; + __store_via_object(obj, __ATTRPOS(__class__), (__attr) {.value=cls}); + return (__attr) {.value=obj}; +} + +__attr __new_wrapper(__ref context, __attr attr) +{ + return __new___builtins___core_wrapper((__attr[]) {__NULL, {.value=context}, attr}); } /* Generic internal data allocation. */ @@ -181,9 +184,13 @@ unsigned int nkwargs, __param kwcodes[], __attr kwargs[], unsigned int nargs, __attr args[]) { + /* Unwrap any wrapped function. */ + + __attr target = __unwrap_callable(callable); + /* Obtain the __args__ special member, referencing the parameter table. */ - __attr minparams = __check_and_load_via_object(callable.value, __ATTRPOS(__args__), __ATTRCODE(__args__)); + __attr minparams = __check_and_load_via_object(target.value, __ATTRPOS(__args__), __ATTRCODE(__args__)); /* Refer to the table and minimum/maximum. */ @@ -240,12 +247,12 @@ for (pos = nargs; pos < max; pos++) { if (allargs[pos].value == 0) - allargs[pos] = __GETDEFAULT(callable.value, pos - min); + allargs[pos] = __GETDEFAULT(target.value, pos - min); } /* Call with the prepared arguments. */ - return (always_callable ? __get_function(callable) : __check_and_get_function(callable))(allargs); + return (always_callable ? __get_function(allargs[0].value, target) : __check_and_get_function(allargs[0].value, target))(allargs); } /* Error routines. */ diff -r d7769551b051 -r 722f838eab06 templates/progops.h --- a/templates/progops.h Sun Feb 12 23:24:42 2017 +0100 +++ b/templates/progops.h Mon Feb 13 15:35:36 2017 +0100 @@ -25,6 +25,7 @@ /* Generic instantiation operations, defining common members. */ __attr __new(const __table *table, __ref cls, size_t size); +__attr __new_wrapper(__ref context, __attr attr); /* Generic internal data allocation. */ diff -r d7769551b051 -r 722f838eab06 templates/types.h --- a/templates/types.h Sun Feb 12 23:24:42 2017 +0100 +++ b/templates/types.h Mon Feb 13 15:35:36 2017 +0100 @@ -51,44 +51,35 @@ const __param params[]; } __ptable; -/* Attributes are context and value pairs. +/* Attributes are values referring to objects or encoding other information. Objects are collections of attributes. Object references are references to tables and collections of attributes. Attribute references are references to single attributes. */ typedef struct __obj __obj; typedef struct __fragment __fragment; +typedef union __attr __attr; +typedef __obj * __ref; -typedef struct __attr +typedef union __attr { - /* One of... */ - union - { - struct { - __obj * context; /* attribute context */ - __obj * value; /* attribute value */ - }; - struct { - __ppos min; /* minimum number of parameters */ - const __ptable * ptable; /* parameter table */ - }; - struct { - __pcode code; /* parameter table code for key */ - __ppos pos; /* parameter table position for key */ - }; - struct { - struct __attr (*inv)(); /* unbound callable details */ - struct __attr (*fn)(); /* callable details */ - }; - union - { - int intvalue; /* integer value */ - double floatvalue; /* floating point value */ - char * strvalue; /* string value */ - __fragment * seqvalue; /* sequence data */ - void * datavalue; /* object-specific data */ - }; + __ref value; /* attribute value */ + struct { + __ppos min; /* minimum number of parameters */ + const __ptable * ptable; /* parameter table */ + }; + struct { + __pcode code; /* parameter table code for key */ + __ppos pos; /* parameter table position for key */ }; + struct { + __attr (*fn)(); /* callable details */ + }; + int intvalue; /* integer value */ + double floatvalue; /* floating point value */ + char * strvalue; /* string value */ + __fragment * seqvalue; /* sequence data */ + void * datavalue; /* object-specific data */ } __attr; typedef struct __obj @@ -98,7 +89,7 @@ __attr attrs[]; /* attributes */ } __obj; -typedef __obj * __ref; +#define __INSTANCE_SIZE(NUMBER) ((NUMBER) * sizeof(__attr) + sizeof(__table *) + sizeof(__ppos)) /* Fragments are simple collections of attributes employed by sequence types. They provide the basis of lists and tuples. */ @@ -109,7 +100,7 @@ __attr attrs[]; } __fragment; -#define __FRAGMENT_SIZE(NUMBER) (NUMBER * sizeof(__attr) + 2 * sizeof(unsigned int)) +#define __FRAGMENT_SIZE(NUMBER) ((NUMBER) * sizeof(__attr) + 2 * sizeof(unsigned int)) /* Special instance position value. The pos member of __obj refers to the special type attribute for classes, indicating which position holds the @@ -119,7 +110,7 @@ /* Special null values. */ -#define __NULL ((__attr) {{.context=0, .value=0}}) +#define __NULL ((__attr) {.value=0}) /* Function pointer type. */ diff -r d7769551b051 -r 722f838eab06 translator.py --- a/translator.py Sun Feb 12 23:24:42 2017 +0100 +++ b/translator.py Mon Feb 13 15:35:36 2017 +0100 @@ -142,7 +142,7 @@ elif static_name: parent = ref.parent() context = ref.has_kind("") and encode_path(parent) or None - return "((__attr) {{.context=%s, .value=&%s}})" % (context and "&%s" % context or "0", static_name) + return "((__attr) {.value=&%s})" % static_name # Qualified names must be converted into parent-relative accesses. @@ -875,7 +875,7 @@ if not ref.static(): self.process_assignment_for_object( - n.name, make_expression("((__attr) {{.context=0, .value=&%s}})" % + n.name, make_expression("((__attr) {.value=&%s})" % encode_path(class_name))) self.enter_namespace(n.name) @@ -1054,9 +1054,7 @@ context = self.is_method(objpath) self.process_assignment_for_object(original_name, - make_expression("((__attr) {{.context=%s, .value=&%s}})" % ( - context and "&%s" % encode_path(context) or "0", - encode_path(objpath)))) + make_expression("((__attr) {.value=&%s})" % encode_path(objpath))) def process_function_defaults(self, n, name, objpath, instance_name=None): @@ -1349,7 +1347,8 @@ self.record_temp("__tmp_targets") if context_required: - stages.append("__get_function(__tmp_targets[%d])" % self.function_target) + stages.append("__get_function(__CONTEXT_AS_VALUE(__tmp_targets[%d]).value, __tmp_targets[%d])" % ( + self.function_target, self.function_target)) else: stages.append("__load_via_object(__tmp_targets[%d].value, %s).fn" % ( self.function_target, encode_symbol("pos", "__fn__"))) @@ -1414,14 +1413,14 @@ # Without defaults, produce an attribute referring to the function. if not defaults: - return make_expression("((__attr) {{.context=0, .value=&%s}})" % encode_path(function_name)) + return make_expression("((__attr) {.value=&%s})" % encode_path(function_name)) # With defaults, copy the function structure and set the defaults on the # copy. else: self.record_temp("__tmp_value") - return make_expression("(__tmp_value = __COPY(&%s, sizeof(%s)), %s, (__attr) {{.context=0, .value=__tmp_value}})" % ( + return make_expression("(__tmp_value = __COPY(&%s, sizeof(%s)), %s, (__attr) {.value=__tmp_value})" % ( encode_path(function_name), encode_symbol("obj", function_name), ", ".join(defaults)))