diff --git a/docs/codegen-module/4-ft.html b/docs/codegen-module/4-ft.html index 1aa10e10f..03fd4346f 100644 --- a/docs/codegen-module/4-ft.html +++ b/docs/codegen-module/4-ft.html @@ -279,6 +279,7 @@ function togglePopup(material_id) { enum DECLARE_INSTANCE_MTID enum END_INSTANCE_MTID enum ASSIGN_PROPERTY_MTID +enum PROPERTY_OFFSET_MTID
 VOID_METHOD_TYPE(DECLARE_CLASS_MTID, code_generation_target *cgt, code_generation *gen, text_stream *class_name)
@@ -307,6 +308,11 @@ function togglePopup(material_id) {
     CodeGen::Targets::assign_property(gen, property_name, mangled, as_att);
     DISCARD_TEXT(mangled)
 }
+
+VOID_METHOD_TYPE(PROPERTY_OFFSET_MTID, code_generation_target *cgt, code_generation *gen, text_stream *property_name, int pos, int as_att)
+void CodeGen::Targets::property_offset(code_generation *gen, text_stream *property_name, int pos, int as_att) {
+    VOID_METHOD_CALL(gen->target, PROPERTY_OFFSET_MTID, gen, property_name, pos, as_att);
+}
 

§13.

@@ -314,7 +320,7 @@ function togglePopup(material_id) {
 VOID_METHOD_TYPE(OFFER_PRAGMA_MTID, code_generation_target *cgt, code_generation *gen, inter_tree_node *P, text_stream *tag, text_stream *content)
-void CodeGen::Targets::offer_pragma(code_generation *gen, inter_tree_node *P, text_stream *tag, text_stream *content) {
+void CodeGen::Targets::offer_pragma(code_generation *gen, inter_tree_node *P, text_stream *tag, text_stream *content) {
     VOID_METHOD_CALL(gen->target, OFFER_PRAGMA_MTID, gen, P, tag, content);
 }
 
@@ -326,10 +332,10 @@ function togglePopup(material_id) {
 VOID_METHOD_TYPE(BEGIN_CONSTANT_MTID, code_generation_target *cgt, code_generation *gen, text_stream *const_name, int continues, int ifndef_me)
 VOID_METHOD_TYPE(END_CONSTANT_MTID, code_generation_target *cgt, code_generation *gen, text_stream *const_name, int ifndef_me)
-void CodeGen::Targets::begin_constant(code_generation *gen, text_stream *const_name, int continues, int ifndef_me) {
+void CodeGen::Targets::begin_constant(code_generation *gen, text_stream *const_name, int continues, int ifndef_me) {
     VOID_METHOD_CALL(gen->target, BEGIN_CONSTANT_MTID, gen, const_name, continues, ifndef_me);
 }
-void CodeGen::Targets::end_constant(code_generation *gen, text_stream *const_name, int ifndef_me) {
+void CodeGen::Targets::end_constant(code_generation *gen, text_stream *const_name, int ifndef_me) {
     VOID_METHOD_CALL(gen->target, END_CONSTANT_MTID, gen, const_name, ifndef_me);
 }
 
@@ -345,16 +351,16 @@ function togglePopup(material_id) { VOID_METHOD_TYPE(BEGIN_FUNCTION_CODE_MTID, code_generation_target *cgt, code_generation *gen) VOID_METHOD_TYPE(PLACE_LABEL_MTID, code_generation_target *cgt, code_generation *gen, text_stream *label_name) VOID_METHOD_TYPE(END_FUNCTION_MTID, code_generation_target *cgt, int pass, code_generation *gen, inter_symbol *fn) -void CodeGen::Targets::begin_function(int pass, code_generation *gen, inter_symbol *fn) { +void CodeGen::Targets::begin_function(int pass, code_generation *gen, inter_symbol *fn) { VOID_METHOD_CALL(gen->target, BEGIN_FUNCTION_MTID, pass, gen, fn); } -void CodeGen::Targets::begin_function_code(code_generation *gen) { +void CodeGen::Targets::begin_function_code(code_generation *gen) { VOID_METHOD_CALL(gen->target, BEGIN_FUNCTION_CODE_MTID, gen); } -void CodeGen::Targets::place_label(code_generation *gen, text_stream *label_name) { +void CodeGen::Targets::place_label(code_generation *gen, text_stream *label_name) { VOID_METHOD_CALL(gen->target, PLACE_LABEL_MTID, gen, label_name); } -void CodeGen::Targets::end_function(int pass, code_generation *gen, inter_symbol *fn) { +void CodeGen::Targets::end_function(int pass, code_generation *gen, inter_symbol *fn) { VOID_METHOD_CALL(gen->target, END_FUNCTION_MTID, pass, gen, fn); } @@ -368,13 +374,13 @@ function togglePopup(material_id) { VOID_METHOD_TYPE(BEGIN_FUNCTION_CALL_MTID, code_generation_target *cgt, code_generation *gen, inter_symbol *fn, int argc) VOID_METHOD_TYPE(ARGUMENT_MTID, code_generation_target *cgt, code_generation *gen, inter_tree_node *F, inter_symbol *fn, int argc, int of_argc) VOID_METHOD_TYPE(END_FUNCTION_CALL_MTID, code_generation_target *cgt, code_generation *gen, inter_symbol *fn, int argc) -void CodeGen::Targets::begin_function_call(code_generation *gen, inter_symbol *fn, int argc) { +void CodeGen::Targets::begin_function_call(code_generation *gen, inter_symbol *fn, int argc) { VOID_METHOD_CALL(gen->target, BEGIN_FUNCTION_CALL_MTID, gen, fn, argc); } -void CodeGen::Targets::argument(code_generation *gen, inter_tree_node *F, inter_symbol *fn, int argc, int of_argc) { +void CodeGen::Targets::argument(code_generation *gen, inter_tree_node *F, inter_symbol *fn, int argc, int of_argc) { VOID_METHOD_CALL(gen->target, ARGUMENT_MTID, gen, F, fn, argc, of_argc); } -void CodeGen::Targets::end_function_call(code_generation *gen, inter_symbol *fn, int argc) { +void CodeGen::Targets::end_function_call(code_generation *gen, inter_symbol *fn, int argc) { VOID_METHOD_CALL(gen->target, END_FUNCTION_CALL_MTID, gen, fn, argc); } @@ -388,13 +394,13 @@ function togglePopup(material_id) { VOID_METHOD_TYPE(BEGIN_OPCODE_MTID, code_generation_target *cgt, code_generation *gen, text_stream *opcode) VOID_METHOD_TYPE(SUPPLY_OPERAND_MTID, code_generation_target *cgt, code_generation *gen, inter_tree_node *F, int is_label) VOID_METHOD_TYPE(END_OPCODE_MTID, code_generation_target *cgt, code_generation *gen) -void CodeGen::Targets::begin_opcode(code_generation *gen, text_stream *opcode) { +void CodeGen::Targets::begin_opcode(code_generation *gen, text_stream *opcode) { VOID_METHOD_CALL(gen->target, BEGIN_OPCODE_MTID, gen, opcode); } -void CodeGen::Targets::supply_operand(code_generation *gen, inter_tree_node *F, int is_label) { +void CodeGen::Targets::supply_operand(code_generation *gen, inter_tree_node *F, int is_label) { VOID_METHOD_CALL(gen->target, SUPPLY_OPERAND_MTID, gen, F, is_label); } -void CodeGen::Targets::end_opcode(code_generation *gen) { +void CodeGen::Targets::end_opcode(code_generation *gen) { VOID_METHOD_CALL(gen->target, END_OPCODE_MTID, gen); } @@ -412,19 +418,19 @@ function togglePopup(material_id) { VOID_METHOD_TYPE(BEGIN_ARRAY_MTID, code_generation_target *cgt, code_generation *gen, text_stream *const_name, int format) VOID_METHOD_TYPE(ARRAY_ENTRY_MTID, code_generation_target *cgt, code_generation *gen, text_stream *entry, int format) VOID_METHOD_TYPE(END_ARRAY_MTID, code_generation_target *cgt, code_generation *gen, int format) -void CodeGen::Targets::begin_array(code_generation *gen, text_stream *const_name, int format) { +void CodeGen::Targets::begin_array(code_generation *gen, text_stream *const_name, int format) { VOID_METHOD_CALL(gen->target, BEGIN_ARRAY_MTID, gen, const_name, format); } -void CodeGen::Targets::array_entry(code_generation *gen, text_stream *entry, int format) { +void CodeGen::Targets::array_entry(code_generation *gen, text_stream *entry, int format) { VOID_METHOD_CALL(gen->target, ARRAY_ENTRY_MTID, gen, entry, format); } -void CodeGen::Targets::mangled_array_entry(code_generation *gen, text_stream *entry, int format) { +void CodeGen::Targets::mangled_array_entry(code_generation *gen, text_stream *entry, int format) { TEMPORARY_TEXT(mangled) CodeGen::Targets::mangle(gen, mangled, entry); VOID_METHOD_CALL(gen->target, ARRAY_ENTRY_MTID, gen, mangled, format); DISCARD_TEXT(mangled) } -void CodeGen::Targets::end_array(code_generation *gen, int format) { +void CodeGen::Targets::end_array(code_generation *gen, int format) { VOID_METHOD_CALL(gen->target, END_ARRAY_MTID, gen, format); } diff --git a/docs/codegen-module/4-iap.html b/docs/codegen-module/4-iap.html index 9ffbc8f2a..fec5ab96b 100644 --- a/docs/codegen-module/4-iap.html +++ b/docs/codegen-module/4-iap.html @@ -975,34 +975,20 @@ though this won't happen for any property created by I7 source text.
     if (properties_found) {
-        TEMPORARY_TEXT(pm_writer)
-        WRITE_TO(pm_writer, "[ CreatePropertyOffsets i;\n"); STREAM_INDENT(pm_writer);
-        WRITE_TO(pm_writer, "for (i=0: i<attributed_property_offsets_SIZE: i++)"); STREAM_INDENT(pm_writer);
-        WRITE_TO(pm_writer, "attributed_property_offsets-->i = -1;\n"); STREAM_OUTDENT(pm_writer);
-        WRITE_TO(pm_writer, "for (i=0: i<valued_property_offsets_SIZE: i++)"); STREAM_INDENT(pm_writer);
-        WRITE_TO(pm_writer, "valued_property_offsets-->i = -1;\n"); STREAM_OUTDENT(pm_writer);
-
         CodeGen::Targets::begin_array(gen, I"property_metadata", WORD_ARRAY_FORMAT);
         int pos = 0;
         for (int p=0; p<no_properties; p++) {
             inter_symbol *prop_name = props_in_source_order[p];
-            WRITE("! offset %d: property %S\n", pos, CodeGen::CL::name(prop_name));
             if (Inter::Symbols::get_flag(prop_name, ATTRIBUTE_MARK_BIT))
-                WRITE_TO(pm_writer, "attributed_property_offsets");
+                CodeGen::Targets::property_offset(gen, CodeGen::CL::name(prop_name), pos, TRUE);
             else
-                WRITE_TO(pm_writer, "valued_property_offsets");
-            WRITE_TO(pm_writer, "-->%S = %d;\n", CodeGen::CL::name(prop_name), pos);
-
+                CodeGen::Targets::property_offset(gen, CodeGen::CL::name(prop_name), pos, FALSE);
             Write the property name in double quotes5.11.1;
             Write a list of kinds or objects which are permitted to have this property5.11.2;
             CodeGen::Targets::mangled_array_entry(gen, I"NULL", WORD_ARRAY_FORMAT);
             pos++;
         }
         CodeGen::Targets::end_array(gen, WORD_ARRAY_FORMAT);
-        STREAM_OUTDENT(pm_writer);
-        WRITE_TO(pm_writer, "];\n");
-        WRITE("%S", pm_writer);
-        DISCARD_TEXT(pm_writer)
     }
 
diff --git a/docs/codegen-module/5-fi6.html b/docs/codegen-module/5-fi6.html index 13b0fe100..3588f7ae4 100644 --- a/docs/codegen-module/5-fi6.html +++ b/docs/codegen-module/5-fi6.html @@ -94,6 +94,7 @@ function togglePopup(material_id) { METHOD_ADD(cgt, COMPILE_LITERAL_TEXT_MTID, CodeGen::I6::compile_literal_text); METHOD_ADD(cgt, DECLARE_PROPERTY_MTID, CodeGen::I6::declare_property); METHOD_ADD(cgt, DECLARE_ATTRIBUTE_MTID, CodeGen::I6::declare_attribute); + METHOD_ADD(cgt, PROPERTY_OFFSET_MTID, CodeGen::I6::property_offset); METHOD_ADD(cgt, PREPARE_VARIABLE_MTID, CodeGen::I6::prepare_variable); METHOD_ADD(cgt, DECLARE_VARIABLE_MTID, CodeGen::I6::declare_variable); METHOD_ADD(cgt, DECLARE_CLASS_MTID, CodeGen::I6::declare_class); @@ -118,6 +119,7 @@ function togglePopup(material_id) { METHOD_ADD(cgt, ARRAY_ENTRY_MTID, CodeGen::I6::array_entry); METHOD_ADD(cgt, END_ARRAY_MTID, CodeGen::I6::end_array); METHOD_ADD(cgt, OFFER_PRAGMA_MTID, CodeGen::I6::offer_pragma) + METHOD_ADD(cgt, END_GENERATION_MTID, CodeGen::I6::end_generation); inform6_target = cgt; } @@ -163,6 +165,7 @@ now a bitmap of flags for tracing actions, calls to object routines, and so on. enum code_at_eof_I7CGS enum verbs_at_eof_I7CGS enum stubs_at_eof_I7CGS +enum property_offset_creator_I7CGS
 int CodeGen::I6::begin_generation(code_generation_target *cgt, code_generation *gen) {
@@ -191,6 +194,7 @@ now a bitmap of flags for tracing actions, calls to object routines, and so on.
     gen->segments[code_at_eof_I7CGS] = CodeGen::new_segment();
     gen->segments[verbs_at_eof_I7CGS] = CodeGen::new_segment();
     gen->segments[stubs_at_eof_I7CGS] = CodeGen::new_segment();
+    gen->segments[property_offset_creator_I7CGS] = CodeGen::new_segment();
 
     generated_segment *saved = CodeGen::select(gen, compiler_versioning_matter_I7CGS);
     text_stream *OUT = CodeGen::current(gen);
@@ -198,10 +202,28 @@ now a bitmap of flags for tracing actions, calls to object routines, and so on.
     WRITE("Global debug_flag;\n");
     CodeGen::deselect(gen, saved);
 
+    saved = CodeGen::select(gen, property_offset_creator_I7CGS);
+    OUT = CodeGen::current(gen);
+    WRITE("[ CreatePropertyOffsets i;\n"); INDENT;
+    WRITE("for (i=0: i<attributed_property_offsets_SIZE: i++)"); INDENT;
+    WRITE("attributed_property_offsets-->i = -1;\n"); OUTDENT;
+    WRITE("for (i=0: i<valued_property_offsets_SIZE: i++)"); INDENT;
+    WRITE("valued_property_offsets-->i = -1;\n"); OUTDENT;
+    CodeGen::deselect(gen, saved);
+
     return FALSE;
 }
 
-int CodeGen::I6::general_segment(code_generation_target *cgt, code_generation *gen, inter_tree_node *P) {
+int CodeGen::I6::end_generation(code_generation_target *cgt, code_generation *gen) {
+    generated_segment *saved = CodeGen::select(gen, property_offset_creator_I7CGS);
+    text_stream *OUT = CodeGen::current(gen);
+    OUTDENT;
+    WRITE("];\n");
+    CodeGen::deselect(gen, saved);
+    return FALSE;
+}
+
+int CodeGen::I6::general_segment(code_generation_target *cgt, code_generation *gen, inter_tree_node *P) {
     switch (P->W.data[ID_IFLD]) {
         case CONSTANT_IST: {
             inter_symbol *con_name =
@@ -221,24 +243,24 @@ now a bitmap of flags for tracing actions, calls to object routines, and so on.
     return CodeGen::I6::default_segment(cgt);
 }
 
-int CodeGen::I6::default_segment(code_generation_target *cgt) {
+int CodeGen::I6::default_segment(code_generation_target *cgt) {
     return main_matter_I7CGS;
 }
-int CodeGen::I6::constant_segment(code_generation_target *cgt, code_generation *gen) {
+int CodeGen::I6::constant_segment(code_generation_target *cgt, code_generation *gen) {
     return early_matter_I7CGS;
 }
-int CodeGen::I6::basic_constant_segment(code_generation_target *cgt, code_generation *gen, int depth) {
+int CodeGen::I6::basic_constant_segment(code_generation_target *cgt, code_generation *gen, int depth) {
     if (depth >= 10) depth = 10;
     return constants_1_I7CGS + depth - 1;
 }
-int CodeGen::I6::property_segment(code_generation_target *cgt) {
+int CodeGen::I6::property_segment(code_generation_target *cgt) {
     return predeclarations_I7CGS;
 }
-int CodeGen::I6::tl_segment(code_generation_target *cgt) {
+int CodeGen::I6::tl_segment(code_generation_target *cgt) {
     return text_literals_code_I7CGS;
 }
 
-void CodeGen::I6::offer_pragma(code_generation_target *cgt, code_generation *gen,
+void CodeGen::I6::offer_pragma(code_generation_target *cgt, code_generation *gen,
     inter_tree_node *P, text_stream *tag, text_stream *content) {
     if (Str::eq(tag, I"target_I6")) {
         generated_segment *saved = CodeGen::select(gen, pragmatic_matter_I7CGS);
@@ -248,11 +270,11 @@ now a bitmap of flags for tracing actions, calls to object routines, and so on.
     }
 }
 
-void CodeGen::I6::mangle(code_generation_target *cgt, OUTPUT_STREAM, text_stream *identifier) {
+void CodeGen::I6::mangle(code_generation_target *cgt, OUTPUT_STREAM, text_stream *identifier) {
     WRITE("%S", identifier);
 }
 
-int CodeGen::I6::compile_primitive(code_generation_target *cgt, code_generation *gen,
+int CodeGen::I6::compile_primitive(code_generation_target *cgt, code_generation *gen,
     inter_symbol *prim_name, inter_tree_node *P) {
     text_stream *OUT = CodeGen::current(gen);
     int suppress_terminal_semicolon = FALSE;
@@ -611,7 +633,7 @@ then the result.
 

§3.

-void CodeGen::I6::compile_dictionary_word(code_generation_target *cgt, code_generation *gen,
+void CodeGen::I6::compile_dictionary_word(code_generation_target *cgt, code_generation *gen,
     text_stream *S, int pluralise) {
     text_stream *OUT = CodeGen::current(gen);
     int n = 0;
@@ -636,7 +658,7 @@ then the result.
 

§4.

-void CodeGen::I6::compile_literal_number(code_generation_target *cgt,
+void CodeGen::I6::compile_literal_number(code_generation_target *cgt,
     code_generation *gen, inter_ti val, int hex_mode) {
     text_stream *OUT = CodeGen::current(gen);
     if (hex_mode) WRITE("$%x", val);
@@ -646,7 +668,7 @@ then the result.
 

§5.

-void CodeGen::I6::compile_literal_text(code_generation_target *cgt, code_generation *gen,
+void CodeGen::I6::compile_literal_text(code_generation_target *cgt, code_generation *gen,
     text_stream *S, int printing_mode, int box_mode) {
     text_stream *OUT = CodeGen::current(gen);
     WRITE("\"");
@@ -708,7 +730,7 @@ trick called "stubbing", these being "stub definitions".)
 

-void CodeGen::I6::declare_property(code_generation_target *cgt, code_generation *gen,
+void CodeGen::I6::declare_property(code_generation_target *cgt, code_generation *gen,
     inter_symbol *prop_name, int used) {
     text_stream *name = CodeGen::CL::name(prop_name);
     if (used) {
@@ -722,15 +744,24 @@ trick called "stubbing", these being "stub definitions".)
     }
 }
 
-void CodeGen::I6::declare_attribute(code_generation_target *cgt, code_generation *gen,
+void CodeGen::I6::declare_attribute(code_generation_target *cgt, code_generation *gen,
     text_stream *prop_name) {
     WRITE_TO(CodeGen::current(gen), "Attribute %S;\n", prop_name);
 }
+
+void CodeGen::I6::property_offset(code_generation_target *cgt, code_generation *gen, text_stream *prop, int pos, int as_attr) {
+    generated_segment *saved = CodeGen::select(gen, property_offset_creator_I7CGS);
+    text_stream *OUT = CodeGen::current(gen);
+    if (as_attr) WRITE("attributed_property_offsets");
+    else WRITE("valued_property_offsets");
+    WRITE("-->%S = %d;\n", prop, pos);
+    CodeGen::deselect(gen, saved);
+}
 

§7.

-int CodeGen::I6::prepare_variable(code_generation_target *cgt, code_generation *gen,
+int CodeGen::I6::prepare_variable(code_generation_target *cgt, code_generation *gen,
     inter_tree_node *P, inter_symbol *var_name, int k) {
     if (Inter::Symbols::read_annotation(var_name, EXPLICIT_VARIABLE_IANN) != 1) {
         if (Inter::Symbols::read_annotation(var_name, ASSIMILATED_IANN) != 1) {
@@ -743,7 +774,7 @@ trick called "stubbing", these being "stub definitions".)
     return k;
 }
 
-int CodeGen::I6::declare_variable(code_generation_target *cgt, code_generation *gen,
+int CodeGen::I6::declare_variable(code_generation_target *cgt, code_generation *gen,
     inter_tree_node *P, inter_symbol *var_name, int k, int of) {
     if (Inter::Symbols::read_annotation(var_name, ASSIMILATED_IANN) == 1) {
         generated_segment *saved = CodeGen::select(gen, main_matter_I7CGS);
@@ -771,27 +802,27 @@ trick called "stubbing", these being "stub definitions".)
     return k;
 }
 
-void CodeGen::I6::declare_class(code_generation_target *cgt, code_generation *gen, text_stream *class_name) {
+void CodeGen::I6::declare_class(code_generation_target *cgt, code_generation *gen, text_stream *class_name) {
     text_stream *OUT = CodeGen::current(gen);
     WRITE("Class %S\n", class_name);
 }
 
-void CodeGen::I6::end_class(code_generation_target *cgt, code_generation *gen, text_stream *class_name) {
+void CodeGen::I6::end_class(code_generation_target *cgt, code_generation *gen, text_stream *class_name) {
     text_stream *OUT = CodeGen::current(gen);
     WRITE(";\n");
 }
 
-void CodeGen::I6::declare_instance(code_generation_target *cgt, code_generation *gen, text_stream *class_name, text_stream *instance_name) {
+void CodeGen::I6::declare_instance(code_generation_target *cgt, code_generation *gen, text_stream *class_name, text_stream *instance_name) {
     text_stream *OUT = CodeGen::current(gen);
     WRITE("%S %S", class_name, instance_name);
 }
 
-void CodeGen::I6::end_instance(code_generation_target *cgt, code_generation *gen, text_stream *class_name, text_stream *instance_name) {
+void CodeGen::I6::end_instance(code_generation_target *cgt, code_generation *gen, text_stream *class_name, text_stream *instance_name) {
     text_stream *OUT = CodeGen::current(gen);
     WRITE(";\n");
 }
 
-void CodeGen::I6::assign_property(code_generation_target *cgt, code_generation *gen, text_stream *property_name, text_stream *val, int as_att) {
+void CodeGen::I6::assign_property(code_generation_target *cgt, code_generation *gen, text_stream *property_name, text_stream *val, int as_att) {
     text_stream *OUT = CodeGen::current(gen);
     if (as_att) {
         if (Str::eq(val, I"0")) WRITE("    has %S\n", property_name);
@@ -801,7 +832,7 @@ trick called "stubbing", these being "stub definitions".)
     }
 }
 
-void CodeGen::I6::declare_local_variable(code_generation_target *cgt, int pass,
+void CodeGen::I6::declare_local_variable(code_generation_target *cgt, int pass,
     code_generation *gen, inter_tree_node *P, inter_symbol *var_name) {
     if (pass == 2) {
         text_stream *OUT = CodeGen::current(gen);
@@ -809,71 +840,71 @@ trick called "stubbing", these being "stub definitions".)
     }
 }
 
-void CodeGen::I6::begin_constant(code_generation_target *cgt, code_generation *gen, text_stream *const_name, int continues, int ifndef_me) {
+void CodeGen::I6::begin_constant(code_generation_target *cgt, code_generation *gen, text_stream *const_name, int continues, int ifndef_me) {
     text_stream *OUT = CodeGen::current(gen);
     if (ifndef_me) WRITE("#ifndef %S;\n", const_name);
     WRITE("Constant %S", const_name);
     if (continues) WRITE(" = ");
 }
-void CodeGen::I6::end_constant(code_generation_target *cgt, code_generation *gen, text_stream *const_name, int ifndef_me) {
+void CodeGen::I6::end_constant(code_generation_target *cgt, code_generation *gen, text_stream *const_name, int ifndef_me) {
     text_stream *OUT = CodeGen::current(gen);
     WRITE(";\n");
     if (ifndef_me) WRITE("#endif;\n");
 }
 
-void CodeGen::I6::begin_function(code_generation_target *cgt, int pass, code_generation *gen, inter_symbol *fn) {
+void CodeGen::I6::begin_function(code_generation_target *cgt, int pass, code_generation *gen, inter_symbol *fn) {
     text_stream *fn_name = CodeGen::CL::name(fn);
     if (pass == 2) {
         text_stream *OUT = CodeGen::current(gen);
         WRITE("[ %S", fn_name);
     }
 }
-void CodeGen::I6::begin_function_code(code_generation_target *cgt, code_generation *gen) {
+void CodeGen::I6::begin_function_code(code_generation_target *cgt, code_generation *gen) {
     text_stream *OUT = CodeGen::current(gen);
     WRITE(";");
 }
-void CodeGen::I6::place_label(code_generation_target *cgt, code_generation *gen, text_stream *label_name) {
+void CodeGen::I6::place_label(code_generation_target *cgt, code_generation *gen, text_stream *label_name) {
     text_stream *OUT = CodeGen::current(gen);
     WRITE("%S;\n", label_name);
 }
-void CodeGen::I6::end_function(code_generation_target *cgt, int pass, code_generation *gen, inter_symbol *fn) {
+void CodeGen::I6::end_function(code_generation_target *cgt, int pass, code_generation *gen, inter_symbol *fn) {
     if (pass == 2) {
         text_stream *OUT = CodeGen::current(gen);
         WRITE("];");
     }
 }
 
-void CodeGen::I6::begin_function_call(code_generation_target *cgt, code_generation *gen, inter_symbol *fn, int argc) {
+void CodeGen::I6::begin_function_call(code_generation_target *cgt, code_generation *gen, inter_symbol *fn, int argc) {
     text_stream *fn_name = CodeGen::CL::name(fn);
     text_stream *OUT = CodeGen::current(gen);
     WRITE("%S(", fn_name);
 }
-void CodeGen::I6::argument(code_generation_target *cgt, code_generation *gen, inter_tree_node *F, inter_symbol *fn, int argc, int of_argc) {
+void CodeGen::I6::argument(code_generation_target *cgt, code_generation *gen, inter_tree_node *F, inter_symbol *fn, int argc, int of_argc) {
     text_stream *OUT = CodeGen::current(gen);
     if (argc > 0) WRITE(", ");
     CodeGen::FC::frame(gen, F);
 }
-void CodeGen::I6::end_function_call(code_generation_target *cgt, code_generation *gen, inter_symbol *fn, int argc) {
+void CodeGen::I6::end_function_call(code_generation_target *cgt, code_generation *gen, inter_symbol *fn, int argc) {
     text_stream *OUT = CodeGen::current(gen);
     WRITE(")");
 }
 
-void CodeGen::I6::begin_opcode(code_generation_target *cgt, code_generation *gen, text_stream *opcode) {
+void CodeGen::I6::begin_opcode(code_generation_target *cgt, code_generation *gen, text_stream *opcode) {
     text_stream *OUT = CodeGen::current(gen);
     WRITE("%S", opcode);
 }
-void CodeGen::I6::supply_operand(code_generation_target *cgt, code_generation *gen, inter_tree_node *F, int is_label) {
+void CodeGen::I6::supply_operand(code_generation_target *cgt, code_generation *gen, inter_tree_node *F, int is_label) {
     text_stream *OUT = CodeGen::current(gen);
     WRITE(" ");
     if (is_label) WRITE("?");
     CodeGen::FC::frame(gen, F);
 }
-void CodeGen::I6::end_opcode(code_generation_target *cgt, code_generation *gen) {
+void CodeGen::I6::end_opcode(code_generation_target *cgt, code_generation *gen) {
     text_stream *OUT = CodeGen::current(gen);
     WRITE(";");
 }
 
-void CodeGen::I6::begin_array(code_generation_target *cgt, code_generation *gen, text_stream *array_name, int format) {
+void CodeGen::I6::begin_array(code_generation_target *cgt, code_generation *gen, text_stream *array_name, int format) {
     text_stream *OUT = CodeGen::current(gen);
     WRITE("Array %S ", array_name);
     switch (format) {
@@ -884,12 +915,12 @@ trick called "stubbing", these being "stub definitions".)
     }
 }
 
-void CodeGen::I6::array_entry(code_generation_target *cgt, code_generation *gen, text_stream *entry, int format) {
+void CodeGen::I6::array_entry(code_generation_target *cgt, code_generation *gen, text_stream *entry, int format) {
     text_stream *OUT = CodeGen::current(gen);
     WRITE(" (%S)", entry);
 }
 
-void CodeGen::I6::end_array(code_generation_target *cgt, code_generation *gen, int format) {
+void CodeGen::I6::end_array(code_generation_target *cgt, code_generation *gen, int format) {
     text_stream *OUT = CodeGen::current(gen);
     WRITE(";\n");
 }
diff --git a/docs/codegen-module/5-fnc.html b/docs/codegen-module/5-fnc.html
index ed6a75d90..3994599cf 100644
--- a/docs/codegen-module/5-fnc.html
+++ b/docs/codegen-module/5-fnc.html
@@ -94,6 +94,7 @@ function togglePopup(material_id) {
     METHOD_ADD(cgt, COMPILE_LITERAL_TEXT_MTID, CodeGen::C::compile_literal_text);
     METHOD_ADD(cgt, DECLARE_PROPERTY_MTID, CodeGen::C::declare_property);
     METHOD_ADD(cgt, DECLARE_ATTRIBUTE_MTID, CodeGen::C::declare_attribute);
+    METHOD_ADD(cgt, PROPERTY_OFFSET_MTID, CodeGen::C::property_offset);
     METHOD_ADD(cgt, PREPARE_VARIABLE_MTID, CodeGen::C::prepare_variable);
     METHOD_ADD(cgt, DECLARE_VARIABLE_MTID, CodeGen::C::declare_variable);
     METHOD_ADD(cgt, DECLARE_CLASS_MTID, CodeGen::C::declare_class);
@@ -165,6 +166,7 @@ function togglePopup(material_id) {
     gen->segments[code_at_eof_I7CGS] = CodeGen::new_segment();
     gen->segments[verbs_at_eof_I7CGS] = CodeGen::new_segment();
     gen->segments[stubs_at_eof_I7CGS] = CodeGen::new_segment();
+    gen->segments[property_offset_creator_I7CGS] = CodeGen::new_segment();
     gen->segments[c_mem_I7CGS] = CodeGen::new_segment();
     gen->segments[c_initialiser_I7CGS] = CodeGen::new_segment();
 
@@ -225,6 +227,24 @@ function togglePopup(material_id) {
     WRITE("i7val ref = 0;\n");
     CodeGen::deselect(gen, saved);
 
+    saved = CodeGen::select(gen, property_offset_creator_I7CGS);
+    OUT = CodeGen::current(gen);
+    WRITE("i7val fn_");
+    CodeGen::C::mangle(cgt, OUT, I"CreatePropertyOffsets");
+    WRITE("(int argc) {\n"); INDENT;
+    WRITE("for (int i=0; i<");
+    CodeGen::C::mangle(cgt, OUT, I"attributed_property_offsets_SIZE");
+    WRITE("; i++)"); INDENT;
+    WRITE("write_i7_lookup(i7mem, ");
+    CodeGen::C::mangle(cgt, OUT, I"attributed_property_offsets");
+    WRITE(", i, -1);\n"); OUTDENT;
+    WRITE("for (int i=0; i<");
+    CodeGen::C::mangle(cgt, OUT, I"valued_property_offsets_SIZE");
+    WRITE("; i++)"); INDENT;
+    WRITE("write_i7_lookup(i7mem, ");
+    CodeGen::C::mangle(cgt, OUT, I"valued_property_offsets");
+    WRITE(", i, -1);\n"); OUTDENT;
+    CodeGen::deselect(gen, saved);
     return FALSE;
 }
 
@@ -246,6 +266,13 @@ function togglePopup(material_id) {
     WRITE("return ref;\n");
     WRITE("}\n");
     CodeGen::deselect(gen, saved);
+
+    saved = CodeGen::select(gen, property_offset_creator_I7CGS);
+    OUT = CodeGen::current(gen);
+    WRITE("return 0;\n");
+    OUTDENT;
+    WRITE("}\n");
+    CodeGen::deselect(gen, saved);
     return FALSE;
 }
 
@@ -898,11 +925,23 @@ trick called "stubbing", these being "stub definitions".)
     WRITE(" %d\n", C_property_enumeration_counter++);
     CodeGen::deselect(gen, saved);
 }
+
+void CodeGen::C::property_offset(code_generation_target *cgt, code_generation *gen, text_stream *prop, int pos, int as_attr) {
+    generated_segment *saved = CodeGen::select(gen, property_offset_creator_I7CGS);
+    text_stream *OUT = CodeGen::current(gen);
+    WRITE("write_i7_lookup(i7mem, ");
+    if (as_attr) CodeGen::C::mangle(cgt, OUT, I"attributed_property_offsets");
+    else CodeGen::C::mangle(cgt, OUT, I"valued_property_offsets");
+    WRITE(", ");
+    CodeGen::C::mangle(cgt, OUT, prop);
+    WRITE(", %d);\n", pos);
+    CodeGen::deselect(gen, saved);
+}
 

§8.

-int CodeGen::C::prepare_variable(code_generation_target *cgt, code_generation *gen,
+int CodeGen::C::prepare_variable(code_generation_target *cgt, code_generation *gen,
     inter_tree_node *P, inter_symbol *var_name, int k) {
     if (Inter::Symbols::read_annotation(var_name, EXPLICIT_VARIABLE_IANN) != 1) {
         if (Inter::Symbols::read_annotation(var_name, ASSIMILATED_IANN) != 1) {
@@ -917,7 +956,7 @@ trick called "stubbing", these being "stub definitions".)
     return k;
 }
 
-int CodeGen::C::declare_variable(code_generation_target *cgt, code_generation *gen,
+int CodeGen::C::declare_variable(code_generation_target *cgt, code_generation *gen,
     inter_tree_node *P, inter_symbol *var_name, int k, int of) {
     if (Inter::Symbols::read_annotation(var_name, ASSIMILATED_IANN) == 1) {
         generated_segment *saved = CodeGen::select(gen, main_matter_I7CGS);
@@ -949,7 +988,7 @@ trick called "stubbing", these being "stub definitions".)
     return k;
 }
 
-void CodeGen::C::begin_constant(code_generation_target *cgt, code_generation *gen, text_stream *const_name, int continues, int ifndef_me) {
+void CodeGen::C::begin_constant(code_generation_target *cgt, code_generation *gen, text_stream *const_name, int continues, int ifndef_me) {
     text_stream *OUT = CodeGen::current(gen);
     if (ifndef_me) {
         WRITE("#ifndef ");
@@ -960,7 +999,7 @@ trick called "stubbing", these being "stub definitions".)
     CodeGen::C::mangle(cgt, OUT, const_name);
     if (continues) WRITE(" ");
 }
-void CodeGen::C::end_constant(code_generation_target *cgt, code_generation *gen, text_stream *const_name, int ifndef_me) {
+void CodeGen::C::end_constant(code_generation_target *cgt, code_generation *gen, text_stream *const_name, int ifndef_me) {
     text_stream *OUT = CodeGen::current(gen);
     WRITE("\n");
     if (ifndef_me) WRITE("#endif\n");
@@ -993,14 +1032,14 @@ trick called "stubbing", these being "stub definitions".)
     CodeGen::deselect(gen, saved);
 }
 
-void CodeGen::C::make_veneer_fcf(code_generation *gen, text_stream *unmangled_name) {
+void CodeGen::C::make_veneer_fcf(code_generation *gen, text_stream *unmangled_name) {
     final_c_function *fcf = CodeGen::C::create_fcf(unmangled_name);
     CodeGen::C::declare_fcf(gen, fcf);
 }
 
 final_c_function *C_fn_being_found = NULL;
 
-void CodeGen::C::begin_function(code_generation_target *cgt, int pass, code_generation *gen, inter_symbol *fn) {
+void CodeGen::C::begin_function(code_generation_target *cgt, int pass, code_generation *gen, inter_symbol *fn) {
     text_stream *fn_name = CodeGen::CL::name(fn);
     C_fn_parameter_count = 0;
     if (pass == 1) {
@@ -1013,6 +1052,7 @@ trick called "stubbing", these being "stub definitions".)
         WRITE_TO(C_fn_prototype, "(int __argc");
     }
     if (pass == 2) {
+        C_fn_being_found = RETRIEVE_POINTER_final_c_function(fn->translation_data);
         text_stream *OUT = CodeGen::current(gen);
         WRITE("i7val fn_");
         CodeGen::C::mangle(cgt, OUT, fn_name);
@@ -1020,12 +1060,17 @@ trick called "stubbing", these being "stub definitions".)
     }
 }
 
-void CodeGen::C::begin_function_code(code_generation_target *cgt, code_generation *gen) {
+void CodeGen::C::begin_function_code(code_generation_target *cgt, code_generation *gen) {
     text_stream *OUT = CodeGen::current(gen);
     WRITE(") {");
+    if (C_fn_being_found) {
+        if (FALSE) {
+            WRITE("printf(\"called %S\\n\");\n", C_fn_being_found->identifier_as_constant);
+        }
+    }
 }
 
-void CodeGen::C::place_label(code_generation_target *cgt, code_generation *gen, text_stream *label_name) {
+void CodeGen::C::place_label(code_generation_target *cgt, code_generation *gen, text_stream *label_name) {
     text_stream *OUT = CodeGen::current(gen);
     LOOP_THROUGH_TEXT(pos, label_name)
         if (Str::get(pos) != '.')
@@ -1033,7 +1078,7 @@ trick called "stubbing", these being "stub definitions".)
     WRITE(": ;\n", label_name);
 }
 
-void CodeGen::C::end_function(code_generation_target *cgt, int pass, code_generation *gen, inter_symbol *fn) {
+void CodeGen::C::end_function(code_generation_target *cgt, int pass, code_generation *gen, inter_symbol *fn) {
     if (pass == 1) {
         WRITE_TO(C_fn_prototype, ")");
 
@@ -1051,7 +1096,17 @@ trick called "stubbing", these being "stub definitions".)
     }
 }
 
-void CodeGen::C::begin_function_call(code_generation_target *cgt, code_generation *gen, inter_symbol *fn, int argc) {
+void CodeGen::C::begin_function_call(code_generation_target *cgt, code_generation *gen, inter_symbol *fn, int argc) {
+    inter_tree_node *D = fn->definition;
+    if ((D) && (D->W.data[ID_IFLD] == CONSTANT_IST) && (D->W.data[FORMAT_CONST_IFLD] == CONSTANT_DIRECT)) {
+        inter_ti val1 = D->W.data[DATA_CONST_IFLD];
+        inter_ti val2 = D->W.data[DATA_CONST_IFLD + 1];
+        if (Inter::Symbols::is_stored_in_data(val1, val2)) {
+            inter_symbol *aliased = InterSymbolsTables::symbol_from_data_pair_and_table(val1, val2, Inter::Packages::scope_of(D));
+            if (aliased) fn = aliased;
+        }
+    }
+
     text_stream *fn_name = CodeGen::CL::name(fn);
     text_stream *OUT = CodeGen::current(gen);
     WRITE("fn_");
@@ -1064,7 +1119,7 @@ trick called "stubbing", these being "stub definitions".)
         }
     }
 }
-void CodeGen::C::argument(code_generation_target *cgt, code_generation *gen, inter_tree_node *F, inter_symbol *fn, int argc, int of_argc) {
+void CodeGen::C::argument(code_generation_target *cgt, code_generation *gen, inter_tree_node *F, inter_symbol *fn, int argc, int of_argc) {
     text_stream *OUT = CodeGen::current(gen);
     if (GENERAL_POINTER_IS_NULL(fn->translation_data) == FALSE) {
         final_c_function *fcf = RETRIEVE_POINTER_final_c_function(fn->translation_data);
@@ -1075,7 +1130,7 @@ trick called "stubbing", these being "stub definitions".)
         CodeGen::FC::frame(gen, F);
     }
 }
-void CodeGen::C::end_function_call(code_generation_target *cgt, code_generation *gen, inter_symbol *fn, int argc) {
+void CodeGen::C::end_function_call(code_generation_target *cgt, code_generation *gen, inter_symbol *fn, int argc) {
     if (GENERAL_POINTER_IS_NULL(fn->translation_data)) {
         text_stream *OUT = CodeGen::current(gen);
         WRITE(")");
@@ -1101,7 +1156,8 @@ trick called "stubbing", these being "stub definitions".)
 }
 
 int C_operand_count = 0, C_operand_branches = FALSE; inter_tree_node *C_operand_label = NULL;
-void CodeGen::C::begin_opcode(code_generation_target *cgt, code_generation *gen, text_stream *opcode) {
+int C_pointer_on_operand = -1;
+void CodeGen::C::begin_opcode(code_generation_target *cgt, code_generation *gen, text_stream *opcode) {
     text_stream *OUT = CodeGen::current(gen);
     C_operand_branches = FALSE;
     C_operand_label = NULL;
@@ -1112,17 +1168,30 @@ trick called "stubbing", these being "stub definitions".)
         if (Str::get(pos) != '@')
             PUT(Str::get(pos));
     WRITE("("); C_operand_count = 0;
+    C_pointer_on_operand = -1;
+    if (Str::eq(opcode, I"@gestalt")) C_pointer_on_operand = 3;
+    if (Str::eq(opcode, I"@glk")) C_pointer_on_operand = 3;
 }
-void CodeGen::C::supply_operand(code_generation_target *cgt, code_generation *gen, inter_tree_node *F, int is_label) {
+void CodeGen::C::supply_operand(code_generation_target *cgt, code_generation *gen, inter_tree_node *F, int is_label) {
     text_stream *OUT = CodeGen::current(gen);
     if (is_label) {
         C_operand_label = F;
     } else {
         if (C_operand_count++ > 0) WRITE(", ");
-        CodeGen::FC::frame(gen, F);
+        if (C_operand_count == C_pointer_on_operand) {
+            TEMPORARY_TEXT(write_to)
+            CodeGen::select_temporary(gen, write_to);
+            CodeGen::FC::frame(gen, F);
+            CodeGen::deselect_temporary(gen);
+            if (Str::eq(write_to, I"0")) WRITE("NULL");
+            else WRITE("&%S", write_to);
+            DISCARD_TEXT(write_to)
+        } else {
+            CodeGen::FC::frame(gen, F);
+        }
     }
 }
-void CodeGen::C::end_opcode(code_generation_target *cgt, code_generation *gen) {
+void CodeGen::C::end_opcode(code_generation_target *cgt, code_generation *gen) {
     text_stream *OUT = CodeGen::current(gen);
     WRITE(")");
     if (C_operand_branches) {
@@ -1133,7 +1202,7 @@ trick called "stubbing", these being "stub definitions".)
     }
 }
 
-void CodeGen::C::declare_local_variable(code_generation_target *cgt, int pass,
+void CodeGen::C::declare_local_variable(code_generation_target *cgt, int pass,
     code_generation *gen, inter_tree_node *P, inter_symbol *var_name) {
     C_fn_parameter_count++;
     if (pass == 1) {
@@ -1163,7 +1232,7 @@ trick called "stubbing", these being "stub definitions".)
     }
 }
 
-void CodeGen::C::declare_class(code_generation_target *cgt, code_generation *gen, text_stream *class_name) {
+void CodeGen::C::declare_class(code_generation_target *cgt, code_generation *gen, text_stream *class_name) {
     C_class_counter++;
     if (C_class_counter == 1) {
         CodeGen::C::declare_class_inner(cgt, gen, I"Class");
@@ -1194,10 +1263,10 @@ trick called "stubbing", these being "stub definitions".)
     CodeGen::deselect(gen, saved);
 }
 
-void CodeGen::C::end_class(code_generation_target *cgt, code_generation *gen, text_stream *class_name) {
+void CodeGen::C::end_class(code_generation_target *cgt, code_generation *gen, text_stream *class_name) {
 }
 
-void CodeGen::C::declare_instance(code_generation_target *cgt, code_generation *gen, text_stream *class_name, text_stream *instance_name) {
+void CodeGen::C::declare_instance(code_generation_target *cgt, code_generation *gen, text_stream *class_name, text_stream *instance_name) {
     generated_segment *saved = CodeGen::select(gen, predeclarations_I7CGS);
     text_stream *OUT = CodeGen::current(gen);
     WRITE("#define ");
@@ -1213,10 +1282,10 @@ trick called "stubbing", these being "stub definitions".)
     CodeGen::deselect(gen, saved);
 }
 
-void CodeGen::C::end_instance(code_generation_target *cgt, code_generation *gen, text_stream *class_name, text_stream *instance_name) {
+void CodeGen::C::end_instance(code_generation_target *cgt, code_generation *gen, text_stream *class_name, text_stream *instance_name) {
 }
 
-void CodeGen::C::assign_property(code_generation_target *cgt, code_generation *gen, text_stream *property_name, text_stream *val, int as_att) {
+void CodeGen::C::assign_property(code_generation_target *cgt, code_generation *gen, text_stream *property_name, text_stream *val, int as_att) {
     generated_segment *saved = CodeGen::select(gen, c_initialiser_I7CGS);
     text_stream *OUT = CodeGen::current(gen);
     WRITE("i7_assign(ref, ");
@@ -1228,7 +1297,7 @@ trick called "stubbing", these being "stub definitions".)
 int C_array_entry_count = 0;
 text_stream *C_array_name = NULL;
 
-void CodeGen::C::begin_array(code_generation_target *cgt, code_generation *gen, text_stream *array_name, int format) {
+void CodeGen::C::begin_array(code_generation_target *cgt, code_generation *gen, text_stream *array_name, int format) {
     generated_segment *saved = CodeGen::select(gen, predeclarations_I7CGS);
     text_stream *OUT = CodeGen::current(gen);
     WRITE("#define ");
diff --git a/inform7/Figures/memory-diagnostics.txt b/inform7/Figures/memory-diagnostics.txt
index 47397acc0..9cabef2bb 100644
--- a/inform7/Figures/memory-diagnostics.txt
+++ b/inform7/Figures/memory-diagnostics.txt
@@ -1,11 +1,11 @@
-Total memory consumption was 399390K = 390 MB
+Total memory consumption was 398279K = 389 MB
 
-60.2% was used for 1995514 objects, in 371138 frames in 301 x 800K = 240800K = 235 MB:
+60.2% was used for 1995518 objects, in 371142 frames in 300 x 800K = 240000K = 234 MB:
 
     10.2%  inter_tree_node_array                    58 x 8192 = 475136 objects, 41813824 bytes
      7.0%  text_stream_array                        5128 x 100 = 512800 objects, 28880896 bytes
      4.2%  linked_list                              30846 objects, 17273760 bytes
-     3.8%  inter_symbol_array                       139 x 1024 = 142336 objects, 15946080 bytes
+     3.9%  inter_symbol_array                       139 x 1024 = 142336 objects, 15946080 bytes
      2.5%  parse_node                               129399 objects, 10351920 bytes
      1.8%  verb_conjugation                         160 objects, 7425280 bytes
      1.3%  parse_node_annotation_array              345 x 500 = 172500 objects, 5531040 bytes
@@ -96,7 +96,7 @@ Total memory consumption was 399390K = 390 MB
      ----  nonlocal_variable                        93 objects, 20088 bytes
      ----  property                                 146 objects, 19856 bytes
      ----  timed_rules_rfd_data                     400 objects, 19200 bytes
-     ----  method                                   390 objects, 18720 bytes
+     ----  method                                   393 objects, 18864 bytes
      ----  pcalc_prop_deferral                      86 objects, 17888 bytes
      ----  instance                                 167 objects, 17368 bytes
      ----  parse_node_tree                          20 objects, 17280 bytes
@@ -169,9 +169,9 @@ Total memory consumption was 399390K = 390 MB
      ----  pipeline_stage                           19 objects, 912 bytes
      ----  inbuild_requirement                      22 objects, 880 bytes
      ----  code_generation                          1 object, 864 bytes
+     ----  generated_segment                        27 objects, 864 bytes
      ----  control_structure_phrase                 12 objects, 864 bytes
      ----  cached_understanding                     21 objects, 840 bytes
-     ----  generated_segment                        26 objects, 832 bytes
      ----  phrase_option_array                      1 x 100 objects, 824 bytes
      ----  target_vm                                6 objects, 816 bytes
      ----  inter_data_type                          14 objects, 784 bytes
@@ -237,7 +237,7 @@ Total memory consumption was 399390K = 390 MB
 
 39.7% was used for memory not allocated for objects:
 
-    21.1%  text stream storage                      86549224 bytes in 530500 claims
+    21.1%  text stream storage                      86230488 bytes in 530517 claims
      4.4%  dictionary storage                       18153984 bytes in 33230 claims
      ----  sorting                                  744 bytes in 3 claims
      1.7%  source text                              7200000 bytes in 3 claims
@@ -255,5 +255,5 @@ Total memory consumption was 399390K = 390 MB
      ----  code generation workspace for objects    9648 bytes in 9 claims
      ----  emitter array storage                    161920 bytes in 2064 claims
 
-18.7% was overhead - 76759160 bytes = 74960K = 73 MB
+18.6% was overhead - 75939784 bytes = 74159K = 72 MB
 
diff --git a/inform7/Figures/timings-diagnostics.txt b/inform7/Figures/timings-diagnostics.txt
index 7e8a1e5d5..a3f61f7d8 100644
--- a/inform7/Figures/timings-diagnostics.txt
+++ b/inform7/Figures/timings-diagnostics.txt
@@ -1,8 +1,8 @@
 100.0% in inform7 run
-     55.2% in compilation to Inter
-         40.0% in //Sequence::undertake_queued_tasks//
+     54.9% in compilation to Inter
+         39.9% in //Sequence::undertake_queued_tasks//
           3.5% in //MajorNodes::pre_pass//
-          2.5% in //MajorNodes::pass_1//
+          2.6% in //MajorNodes::pass_1//
           1.5% in //RTPhrasebook::compile_entries//
           1.4% in //ImperativeDefinitions::assess_all//
           1.1% in //RTKindConstructors::compile//
@@ -16,12 +16,12 @@
           0.1% in //RTKindConstructors::compile_permissions//
           0.1% in //Task::make_built_in_kind_constructors//
           0.1% in //World::stages_II_and_III//
-          2.0% not specifically accounted for
-     42.8% in running Inter pipeline
-         10.9% in step preparation
-          9.8% in inter step 7/14: consolidate-text
+          1.8% not specifically accounted for
+     43.0% in running Inter pipeline
+         10.8% in step preparation
+          9.9% in inter step 7/14: consolidate-text
           8.2% in inter step 14/14: generate inform6 -> auto.inf
-          7.9% in inter step 2/14: link
+          8.0% in inter step 2/14: link
           1.5% in inter step 10/14: make-identifiers-unique
           0.4% in inter step 11/14: reconcile-verbs
           0.2% in inter step 13/14: eliminate-redundant-operations
@@ -29,8 +29,9 @@
           0.2% in inter step 8/14: resolve-external-symbols
           0.2% in inter step 9/14: inspect-plugs
           0.1% in inter step 12/14: eliminate-redundant-labels
+          0.1% in inter step 3/14: merge-template <- none
           0.1% in inter step 4/14: parse-linked-matter
           0.1% in inter step 5/14: resolve-conditional-compilation
-          2.4% not specifically accounted for
-      1.7% in supervisor
-      0.2% not specifically accounted for
+          2.3% not specifically accounted for
+      1.6% in supervisor
+      0.3% not specifically accounted for
diff --git a/inform7/Internal/Miscellany/inform7_clib.h b/inform7/Internal/Miscellany/inform7_clib.h
index 77f401366..86c042368 100644
--- a/inform7/Internal/Miscellany/inform7_clib.h
+++ b/inform7/Internal/Miscellany/inform7_clib.h
@@ -8,6 +8,7 @@ typedef struct i7varargs {
 } i7varargs;
 
 i7val i7_tmp = 0;
+int i7_seed = 197;
 
 #define I7BYTE_3(V) ((V & 0xFF000000) >> 24)
 #define I7BYTE_2(V) ((V & 0x00FF0000) >> 16)
@@ -29,156 +30,180 @@ void write_i7_lookup(i7byte i7bytes[], i7val offset, i7val ind, i7val V) {
 }
 
 void glulx_accelfunc(i7val x, i7val y) {
-	printf("Unimplemented.\n");
+	printf("Unimplemented: glulx_accelfunc.\n");
 }
 
 void glulx_accelparam(i7val x, i7val y) {
-	printf("Unimplemented.\n");
+	printf("Unimplemented: glulx_accelparam.\n");
 }
 
 void glulx_call(i7val x, i7val i7varargc, i7val z) {
-	printf("Unimplemented.\n");
+	printf("Unimplemented: glulx_call.\n");
 }
 
 void glulx_copy(i7val x, i7val y) {
-	printf("Unimplemented.\n");
+	printf("Unimplemented: glulx_copy.\n");
 }
 
 void glulx_div(i7val x, i7val y, i7val z) {
-	printf("Unimplemented.\n");
+	printf("Unimplemented: glulx_div.\n");
 }
 
 void glulx_exp(i7val x, i7val y) {
-	printf("Unimplemented.\n");
+	printf("Unimplemented: glulx_exp.\n");
 }
 
 void glulx_fadd(i7val x, i7val y, i7val z) {
-	printf("Unimplemented.\n");
+	printf("Unimplemented: glulx_fadd.\n");
 }
 
 void glulx_fdiv(i7val x, i7val y, i7val z) {
-	printf("Unimplemented.\n");
+	printf("Unimplemented: glulx_fdiv.\n");
 }
 
 void glulx_floor(i7val x, i7val y) {
-	printf("Unimplemented.\n");
+	printf("Unimplemented: glulx_floor.\n");
 }
 
 void glulx_fmod(i7val x, i7val y, i7val z, i7val w) {
-	printf("Unimplemented.\n");
+	printf("Unimplemented: glulx_fmod.\n");
 }
 
 void glulx_fmul(i7val x, i7val y, i7val z) {
-	printf("Unimplemented.\n");
+	printf("Unimplemented: glulx_fmul.\n");
 }
 
 void glulx_fsub(i7val x, i7val y, i7val z) {
-	printf("Unimplemented.\n");
+	printf("Unimplemented: glulx_fsub.\n");
 }
 
 void glulx_ftonumn(i7val x, i7val y) {
-	printf("Unimplemented.\n");
+	printf("Unimplemented: glulx_ftonumn.\n");
 }
 
 void glulx_ftonumz(i7val x, i7val y) {
-	printf("Unimplemented.\n");
+	printf("Unimplemented: glulx_ftonumz.\n");
 }
 
-void glulx_gestalt(i7val x, i7val y, i7val z) {
-	printf("Unimplemented.\n");
+void glulx_gestalt(i7val x, i7val y, i7val *z) {
+	*z = 1;
 }
 
-void glulx_glk(i7val x, i7val i7varargc, i7val z) {
-	printf("Unimplemented.\n");
+void glulx_glk(i7val glk_api_selector, i7val i7varargc, i7val *z) {
+	int rv = 0;
+	switch (glk_api_selector) {
+		case 4: // selectpr for glk_gestalt
+			rv = 1; break;
+		case 32: // selector for glk_window_iterate
+			rv = 0; break;
+		case 35: // selector for glk_window_open
+			rv = 1; break;
+		case 47: // selector for glk_set_window
+			rv = 0; break;
+		case 64: // selector for glk_stream_iterate
+			rv = 0; break;
+		case 100: // selector for glk_fileref_iterate
+			rv = 0; break;
+		case 176: // selector for glk_stylehint_set
+			rv = 0; break;
+		case 240: // selector for glk_schannel_iterate
+			rv = 0; break;
+		case 242: // selector for glk_schannel_create
+			rv = 0; break;
+		default:
+			printf("Unimplemented: glulx_glk %d.\n", glk_api_selector);
+			rv = 0; break;
+	}
+	if (z) *z = rv;
 }
 
 int glulx_jeq(i7val x, i7val y) {
-	printf("Unimplemented.\n");
+	printf("Unimplemented: glulx_jeq.\n");
 	return 0;
 }
 
 int glulx_jfeq(i7val x, i7val y, i7val z) {
-	printf("Unimplemented.\n");
+	printf("Unimplemented: glulx_jfeq.\n");
 	return 0;
 }
 
 int glulx_jfge(i7val x, i7val y) {
-	printf("Unimplemented.\n");
+	printf("Unimplemented: glulx_jfge.\n");
 	return 0;
 }
 
 int glulx_jflt(i7val x, i7val y) {
-	printf("Unimplemented.\n");
+	printf("Unimplemented: glulx_jflt.\n");
 	return 0;
 }
 
 int glulx_jisinf(i7val x) {
-	printf("Unimplemented.\n");
+	printf("Unimplemented: glulx_jisinf.\n");
 	return 0;
 }
 
 int glulx_jisnan(i7val x) {
-	printf("Unimplemented.\n");
+	printf("Unimplemented: glulx_jisnan.\n");
 	return 0;
 }
 
 int glulx_jleu(i7val x, i7val y) {
-	printf("Unimplemented.\n");
+	printf("Unimplemented: glulx_jleu.\n");
 	return 0;
 }
 
 int glulx_jnz(i7val x) {
-	printf("Unimplemented.\n");
+	printf("Unimplemented: glulx_jnz.\n");
 	return 0;
 }
 
 int glulx_jz(i7val x) {
-	printf("Unimplemented.\n");
+	printf("Unimplemented: glulx_jz.\n");
 	return 0;
 }
 
 void glulx_log(i7val x, i7val y) {
-	printf("Unimplemented.\n");
+	printf("Unimplemented: glulx_log.\n");
 }
 
 void glulx_malloc(i7val x, i7val y) {
-	printf("Unimplemented.\n");
+	printf("Unimplemented: glulx_malloc.\n");
 }
 
 void glulx_mcopy(i7val x, i7val y, i7val z) {
-	printf("Unimplemented.\n");
+	printf("Unimplemented: glulx_mcopy.\n");
 }
 
 void glulx_mfree(i7val x) {
-	printf("Unimplemented.\n");
+	printf("Unimplemented: glulx_mfree.\n");
 }
 
 void glulx_mod(i7val x, i7val y, i7val z) {
-	printf("Unimplemented.\n");
+	printf("Unimplemented: glulx_mod.\n");
 }
 
 void glulx_neg(i7val x, i7val y) {
-	printf("Unimplemented.\n");
+	printf("Unimplemented: glulx_neg.\n");
 }
 
 void glulx_numtof(i7val x, i7val y) {
-	printf("Unimplemented.\n");
+	printf("Unimplemented: glulx_numtof.\n");
 }
 
 void glulx_quit(void) {
-	printf("Unimplemented.\n");
+	printf("Unimplemented: glulx_quit.\n");
 }
 
 void glulx_random(i7val x, i7val y) {
-	printf("Unimplemented.\n");
+	printf("Unimplemented: glulx_random.\n");
 }
 
 void glulx_setiosys(i7val x, i7val y) {
-	printf("Unimplemented.\n");
+	// Deliberately ignored: we are using stdout, not glk
 }
 
 void glulx_setrandom(i7val x) {
-	printf("Unimplemented.\n");
+	i7_seed = (int) x;
 }
 
 void glulx_streamchar(i7val x) {
@@ -186,11 +211,11 @@ void glulx_streamchar(i7val x) {
 }
 
 void glulx_streamnum(i7val x) {
-	printf("Unimplemented.\n");
+	printf("Unimplemented: glulx_streamnum.\n");
 }
 
 void glulx_streamstr(i7val x) {
-	printf("Unimplemented.\n");
+	printf("Unimplemented: glulx_streamstr.\n");
 }
 
 void glulx_streamunichar(i7val x) {
@@ -198,25 +223,25 @@ void glulx_streamunichar(i7val x) {
 }
 
 void glulx_sub(i7val x, i7val y, i7val z) {
-	printf("Unimplemented.\n");
+	printf("Unimplemented: glulx_sub.\n");
 }
 
 void glulx_ushiftr(i7val x, i7val y, i7val z) {
-	printf("Unimplemented.\n");
+	printf("Unimplemented: glulx_ushiftr.\n");
 }
 
 int i7_has(i7val obj, i7val attr) {
-	printf("Unimplemented.\n");
+	printf("Unimplemented: i7_has.\n");
 	return 0;
 }
 
 int i7_ofclass(i7val obj, i7val cl) {
-	printf("Unimplemented.\n");
+	printf("Unimplemented: i7_ofclass.\n");
 	return 0;
 }
 
 void i7_print_address(i7val x) {
-	printf("Unimplemented.\n");
+	printf("Unimplemented: i7_print_address.\n");
 }
 
 void i7_print_char(i7val x) {
@@ -224,70 +249,71 @@ void i7_print_char(i7val x) {
 }
 
 void i7_print_def_art(i7val x) {
-	printf("Unimplemented.\n");
+	printf("Unimplemented: i7_print_def_art.\n");
 }
 
 void i7_print_indef_art(i7val x) {
-	printf("Unimplemented.\n");
+	printf("Unimplemented: i7_print_indef_art.\n");
 }
 
 void i7_print_name(i7val x) {
-	printf("Unimplemented.\n");
+	printf("Unimplemented: i7_print_name.\n");
 }
 
 void i7_print_object(i7val x) {
-	printf("Unimplemented.\n");
+	printf("Unimplemented: i7_print_object.\n");
 }
 
 void i7_print_property(i7val x) {
-	printf("Unimplemented.\n");
+	printf("Unimplemented: i7_print_property.\n");
 }
 
 int i7_provides(i7val obj, i7val prop) {
-	printf("Unimplemented.\n");
+	printf("Unimplemented: i7_provides.\n");
 	return 0;
 }
 
 i7val i7_pull(void) {
-	printf("Unimplemented.\n");
+	printf("Unimplemented: i7_pull.\n");
 	return (i7val) 0;
 }
 
 void i7_push(i7val x) {
-	printf("Unimplemented.\n");
+	printf("Unimplemented: i7_push.\n");
 }
 
 i7val i7_prop_value(i7val obj, i7val pr) {
-	printf("Unimplemented.\n");
+	printf("Unimplemented: i7_prop_value.\n");
 	return 0;
 }
 
 void i7_assign(i7val owner, i7val prop, i7val val, i7val inst) {
-	printf("Unimplemented.\n");
+	printf("Unimplemented: i7_assign.\n");
 }
 
 i7val i7_prop_len(i7val obj, i7val pr) {
-	printf("Unimplemented.\n");
+	printf("Unimplemented: i7_prop_len.\n");
 	return 0;
 }
 
 i7val i7_prop_addr(i7val obj, i7val pr) {
-	printf("Unimplemented.\n");
+	printf("Unimplemented: i7_prop_addr.\n");
 	return 0;
 }
 
 i7val fn_i7_mgl_metaclass(int n, i7val v) {
-	printf("Unimplemented.\n");
+	printf("Unimplemented: fn_i7_mgl_metaclass.\n");
 	return 0;
 }
 
 i7val fn_i7_mgl_random(int n, i7val v) {
-	printf("Unimplemented.\n");
-	return 0;
+	if (i7_seed < 1000) return ((i7val) ((i7_seed++) % n));
+	i7_seed = i7_seed*i7_seed;
+	return (((i7_seed*i7_seed) & 0xFF00) / 0x100) % n;
 }
 
 i7val i7_gen_call(i7val fn_ref, i7val *args, int argc, int call_message) {
-	printf("Unimplemented.\n");
+	printf("Unimplemented: i7_gen_call.\n");
 	return 0;
 }
 
@@ -354,42 +380,42 @@ i7val i7_ccall_3(i7val fn_ref, i7val v, i7val v2, i7val v3) {
 }
 
 i7val fn_i7_mgl_Z__Region(int argc, i7val x) {
-	printf("Unimplemented.\n");
+	printf("Unimplemented: fn_i7_mgl_Z__Region.\n");
 	return 0;
 }
 
 i7val fn_i7_mgl_CP__Tab(int argc, i7val x) {
-	printf("Unimplemented.\n");
+	printf("Unimplemented: fn_i7_mgl_CP__Tab.\n");
 	return 0;
 }
 
 i7val fn_i7_mgl_RA__Pr(int argc, i7val x) {
-	printf("Unimplemented.\n");
+	printf("Unimplemented: fn_i7_mgl_RA__Pr.\n");
 	return 0;
 }
 
 i7val fn_i7_mgl_RL__Pr(int argc, i7val x) {
-	printf("Unimplemented.\n");
+	printf("Unimplemented: fn_i7_mgl_RL__Pr.\n");
 	return 0;
 }
 
 i7val fn_i7_mgl_OC__Cl(int argc, i7val x) {
-	printf("Unimplemented.\n");
+	printf("Unimplemented: fn_i7_mgl_OC__Cl.\n");
 	return 0;
 }
 
 i7val fn_i7_mgl_RV__Pr(int argc, i7val x) {
-	printf("Unimplemented.\n");
+	printf("Unimplemented: fn_i7_mgl_RV__Pr.\n");
 	return 0;
 }
 
 i7val fn_i7_mgl_OP__Pr(int argc, i7val x) {
-	printf("Unimplemented.\n");
+	printf("Unimplemented: fn_i7_mgl_OP__Pr.\n");
 	return 0;
 }
 
 i7val fn_i7_mgl_CA__Pr(int argc, i7val x) {
-	printf("Unimplemented.\n");
+	printf("Unimplemented: fn_i7_mgl_CA__Pr.\n");
 	return 0;
 }
 
diff --git a/inter/.gitignore b/inter/.gitignore
index d88eb43e5..2f1a6a778 100644
--- a/inter/.gitignore
+++ b/inter/.gitignore
@@ -32,6 +32,7 @@ Tests/Toys/_I6_Object_Code/
 Tests/Toys/_I6_Output_Actual/
 Tests/C/_C/
 Tests/C/_Textual/
+Tests/C/_Results_Actual/
 Tests/Valid/_Binary/
 Tests/Valid/_Console/
 Tests/Valid/_Textual/
diff --git a/inter/Tests/inter.intest b/inter/Tests/inter.intest
index 0c272824b..04965b676 100644
--- a/inter/Tests/inter.intest
+++ b/inter/Tests/inter.intest
@@ -246,7 +246,6 @@
 	set: $OFILE = $WORK/Example.inform/Build/$CASE.o
 	step: $I7 `$I7OPTIONS -format=$FORMAT -project $WORK/Example.inform -variable *tout=$TOUT -variable *cout=$COUT -pipeline $PIPELINE >$I7CONSOLE 2>&1
 	or: 'failed with Problem message(s)' $I7CONSOLE
-	show: $I7CONSOLE
 
 	set: $CCCONSOLE = $WORK/Example.inform/Build/cc_output.txt
 	set: $LINKCONSOLE = $WORK/Example.inform/Build/link_output.txt
@@ -264,6 +263,8 @@
 	step: $STORYFILE >$A 2>&1
 	or: 'failed to run C program' $A
 
+	show: $A
+
 	match text: $A $I
 	or: 'C program misbehaved'
 
diff --git a/inter/codegen-module/Chapter 4/Final Targets.w b/inter/codegen-module/Chapter 4/Final Targets.w
index 3459d234c..ccdb85043 100644
--- a/inter/codegen-module/Chapter 4/Final Targets.w	
+++ b/inter/codegen-module/Chapter 4/Final Targets.w	
@@ -205,6 +205,7 @@ void CodeGen::Targets::declare_local_variable(int pass, code_generation *gen, in
 @e DECLARE_INSTANCE_MTID
 @e END_INSTANCE_MTID
 @e ASSIGN_PROPERTY_MTID
+@e PROPERTY_OFFSET_MTID
 
 =
 VOID_METHOD_TYPE(DECLARE_CLASS_MTID, code_generation_target *cgt, code_generation *gen, text_stream *class_name)
@@ -234,6 +235,11 @@ void CodeGen::Targets::assign_mangled_property(code_generation *gen, text_stream
 	DISCARD_TEXT(mangled)
 }
 
+VOID_METHOD_TYPE(PROPERTY_OFFSET_MTID, code_generation_target *cgt, code_generation *gen, text_stream *property_name, int pos, int as_att)
+void CodeGen::Targets::property_offset(code_generation *gen, text_stream *property_name, int pos, int as_att) {
+	VOID_METHOD_CALL(gen->target, PROPERTY_OFFSET_MTID, gen, property_name, pos, as_att);
+}
+
 @
 
 @e OFFER_PRAGMA_MTID
diff --git a/inter/codegen-module/Chapter 4/Instances and Properties.w b/inter/codegen-module/Chapter 4/Instances and Properties.w
index cd75d2f3e..4db6d881d 100644
--- a/inter/codegen-module/Chapter 4/Instances and Properties.w	
+++ b/inter/codegen-module/Chapter 4/Instances and Properties.w	
@@ -756,34 +756,20 @@ though this won't happen for any property created by I7 source text.
 
 @ =
 	if (properties_found) {
-		TEMPORARY_TEXT(pm_writer)
-		WRITE_TO(pm_writer, "[ CreatePropertyOffsets i;\n"); STREAM_INDENT(pm_writer);
-		WRITE_TO(pm_writer, "for (i=0: ii = -1;\n"); STREAM_OUTDENT(pm_writer);
-		WRITE_TO(pm_writer, "for (i=0: ii = -1;\n"); STREAM_OUTDENT(pm_writer);
-
 		CodeGen::Targets::begin_array(gen, I"property_metadata", WORD_ARRAY_FORMAT);
 		int pos = 0;
 		for (int p=0; p%S = %d;\n", CodeGen::CL::name(prop_name), pos);
-
+				CodeGen::Targets::property_offset(gen, CodeGen::CL::name(prop_name), pos, FALSE);
 			@;
 			@;
 			CodeGen::Targets::mangled_array_entry(gen, I"NULL", WORD_ARRAY_FORMAT);
 			pos++;
 		}
 		CodeGen::Targets::end_array(gen, WORD_ARRAY_FORMAT);
-		STREAM_OUTDENT(pm_writer);
-		WRITE_TO(pm_writer, "];\n");
-		WRITE("%S", pm_writer);
-		DISCARD_TEXT(pm_writer)
 	}
 
 @ =
diff --git a/inter/codegen-module/Chapter 5/Final C.w b/inter/codegen-module/Chapter 5/Final C.w
index ce388d674..8dbbe01bd 100644
--- a/inter/codegen-module/Chapter 5/Final C.w	
+++ b/inter/codegen-module/Chapter 5/Final C.w	
@@ -22,6 +22,7 @@ void CodeGen::C::create_target(void) {
 	METHOD_ADD(cgt, COMPILE_LITERAL_TEXT_MTID, CodeGen::C::compile_literal_text);
 	METHOD_ADD(cgt, DECLARE_PROPERTY_MTID, CodeGen::C::declare_property);
 	METHOD_ADD(cgt, DECLARE_ATTRIBUTE_MTID, CodeGen::C::declare_attribute);
+	METHOD_ADD(cgt, PROPERTY_OFFSET_MTID, CodeGen::C::property_offset);
 	METHOD_ADD(cgt, PREPARE_VARIABLE_MTID, CodeGen::C::prepare_variable);
 	METHOD_ADD(cgt, DECLARE_VARIABLE_MTID, CodeGen::C::declare_variable);
 	METHOD_ADD(cgt, DECLARE_CLASS_MTID, CodeGen::C::declare_class);
@@ -93,6 +94,7 @@ int CodeGen::C::begin_generation(code_generation_target *cgt, code_generation *g
 	gen->segments[code_at_eof_I7CGS] = CodeGen::new_segment();
 	gen->segments[verbs_at_eof_I7CGS] = CodeGen::new_segment();
 	gen->segments[stubs_at_eof_I7CGS] = CodeGen::new_segment();
+	gen->segments[property_offset_creator_I7CGS] = CodeGen::new_segment();
 	gen->segments[c_mem_I7CGS] = CodeGen::new_segment();
 	gen->segments[c_initialiser_I7CGS] = CodeGen::new_segment();
 
@@ -153,6 +155,24 @@ int CodeGen::C::begin_generation(code_generation_target *cgt, code_generation *g
 	WRITE("i7val ref = 0;\n");
 	CodeGen::deselect(gen, saved);
 	
+	saved = CodeGen::select(gen, property_offset_creator_I7CGS);
+	OUT = CodeGen::current(gen);
+	WRITE("i7val fn_");
+	CodeGen::C::mangle(cgt, OUT, I"CreatePropertyOffsets");
+	WRITE("(int argc) {\n"); INDENT;
+	WRITE("for (int i=0; i<");
+	CodeGen::C::mangle(cgt, OUT, I"attributed_property_offsets_SIZE");
+	WRITE("; i++)"); INDENT;
+	WRITE("write_i7_lookup(i7mem, ");
+	CodeGen::C::mangle(cgt, OUT, I"attributed_property_offsets");
+	WRITE(", i, -1);\n"); OUTDENT;
+	WRITE("for (int i=0; i<");
+	CodeGen::C::mangle(cgt, OUT, I"valued_property_offsets_SIZE");
+	WRITE("; i++)"); INDENT;
+	WRITE("write_i7_lookup(i7mem, ");
+	CodeGen::C::mangle(cgt, OUT, I"valued_property_offsets");
+	WRITE(", i, -1);\n"); OUTDENT;
+	CodeGen::deselect(gen, saved);
 	return FALSE;
 }
 
@@ -174,6 +194,13 @@ int CodeGen::C::end_generation(code_generation_target *cgt, code_generation *gen
 	WRITE("return ref;\n");
 	WRITE("}\n");
 	CodeGen::deselect(gen, saved);
+
+	saved = CodeGen::select(gen, property_offset_creator_I7CGS);
+	OUT = CodeGen::current(gen);
+	WRITE("return 0;\n");
+	OUTDENT;
+	WRITE("}\n");
+	CodeGen::deselect(gen, saved);
 	return FALSE;
 }
 
@@ -730,6 +757,18 @@ void CodeGen::C::declare_attribute(code_generation_target *cgt, code_generation
 	CodeGen::deselect(gen, saved);
 }
 
+void CodeGen::C::property_offset(code_generation_target *cgt, code_generation *gen, text_stream *prop, int pos, int as_attr) {
+	generated_segment *saved = CodeGen::select(gen, property_offset_creator_I7CGS);
+	text_stream *OUT = CodeGen::current(gen);
+	WRITE("write_i7_lookup(i7mem, ");
+	if (as_attr) CodeGen::C::mangle(cgt, OUT, I"attributed_property_offsets");
+	else CodeGen::C::mangle(cgt, OUT, I"valued_property_offsets");
+	WRITE(", ");
+	CodeGen::C::mangle(cgt, OUT, prop);
+	WRITE(", %d);\n", pos);
+	CodeGen::deselect(gen, saved);
+}
+
 @
 
 =
@@ -844,6 +883,7 @@ void CodeGen::C::begin_function(code_generation_target *cgt, int pass, code_gene
 		WRITE_TO(C_fn_prototype, "(int __argc");
 	}
 	if (pass == 2) {
+		C_fn_being_found = RETRIEVE_POINTER_final_c_function(fn->translation_data);
 		text_stream *OUT = CodeGen::current(gen);
 		WRITE("i7val fn_");
 		CodeGen::C::mangle(cgt, OUT, fn_name);
@@ -854,6 +894,11 @@ void CodeGen::C::begin_function(code_generation_target *cgt, int pass, code_gene
 void CodeGen::C::begin_function_code(code_generation_target *cgt, code_generation *gen) {
 	text_stream *OUT = CodeGen::current(gen);
 	WRITE(") {");
+	if (C_fn_being_found) {
+		if (FALSE) {
+			WRITE("printf(\"called %S\\n\");\n", C_fn_being_found->identifier_as_constant);
+		}
+	}
 }
 
 void CodeGen::C::place_label(code_generation_target *cgt, code_generation *gen, text_stream *label_name) {
@@ -883,6 +928,16 @@ void CodeGen::C::end_function(code_generation_target *cgt, int pass, code_genera
 }
 
 void CodeGen::C::begin_function_call(code_generation_target *cgt, code_generation *gen, inter_symbol *fn, int argc) {
+	inter_tree_node *D = fn->definition;
+	if ((D) && (D->W.data[ID_IFLD] == CONSTANT_IST) && (D->W.data[FORMAT_CONST_IFLD] == CONSTANT_DIRECT)) {
+		inter_ti val1 = D->W.data[DATA_CONST_IFLD];
+		inter_ti val2 = D->W.data[DATA_CONST_IFLD + 1];
+		if (Inter::Symbols::is_stored_in_data(val1, val2)) {
+			inter_symbol *aliased = InterSymbolsTables::symbol_from_data_pair_and_table(val1, val2, Inter::Packages::scope_of(D));
+			if (aliased) fn = aliased;
+		}
+	}
+
 	text_stream *fn_name = CodeGen::CL::name(fn);
 	text_stream *OUT = CodeGen::current(gen);
 	WRITE("fn_");
@@ -932,6 +987,7 @@ void CodeGen::C::end_function_call(code_generation_target *cgt, code_generation
 }
 
 int C_operand_count = 0, C_operand_branches = FALSE; inter_tree_node *C_operand_label = NULL;
+int C_pointer_on_operand = -1;
 void CodeGen::C::begin_opcode(code_generation_target *cgt, code_generation *gen, text_stream *opcode) {
 	text_stream *OUT = CodeGen::current(gen);
 	C_operand_branches = FALSE;
@@ -943,6 +999,9 @@ void CodeGen::C::begin_opcode(code_generation_target *cgt, code_generation *gen,
 		if (Str::get(pos) != '@')
 			PUT(Str::get(pos));
 	WRITE("("); C_operand_count = 0;
+	C_pointer_on_operand = -1;
+	if (Str::eq(opcode, I"@gestalt")) C_pointer_on_operand = 3;
+	if (Str::eq(opcode, I"@glk")) C_pointer_on_operand = 3;
 }
 void CodeGen::C::supply_operand(code_generation_target *cgt, code_generation *gen, inter_tree_node *F, int is_label) {
 	text_stream *OUT = CodeGen::current(gen);
@@ -950,7 +1009,17 @@ void CodeGen::C::supply_operand(code_generation_target *cgt, code_generation *ge
 		C_operand_label = F;
 	} else {
 		if (C_operand_count++ > 0) WRITE(", ");
-		CodeGen::FC::frame(gen, F);
+		if (C_operand_count == C_pointer_on_operand) {
+			TEMPORARY_TEXT(write_to)
+			CodeGen::select_temporary(gen, write_to);
+			CodeGen::FC::frame(gen, F);
+			CodeGen::deselect_temporary(gen);
+			if (Str::eq(write_to, I"0")) WRITE("NULL");
+			else WRITE("&%S", write_to);
+			DISCARD_TEXT(write_to)
+		} else {
+			CodeGen::FC::frame(gen, F);
+		}
 	}
 }
 void CodeGen::C::end_opcode(code_generation_target *cgt, code_generation *gen) {
diff --git a/inter/codegen-module/Chapter 5/Final Inform 6.w b/inter/codegen-module/Chapter 5/Final Inform 6.w
index c88e0e534..0b9c97390 100644
--- a/inter/codegen-module/Chapter 5/Final Inform 6.w	
+++ b/inter/codegen-module/Chapter 5/Final Inform 6.w	
@@ -22,6 +22,7 @@ void CodeGen::I6::create_target(void) {
 	METHOD_ADD(cgt, COMPILE_LITERAL_TEXT_MTID, CodeGen::I6::compile_literal_text);
 	METHOD_ADD(cgt, DECLARE_PROPERTY_MTID, CodeGen::I6::declare_property);
 	METHOD_ADD(cgt, DECLARE_ATTRIBUTE_MTID, CodeGen::I6::declare_attribute);
+	METHOD_ADD(cgt, PROPERTY_OFFSET_MTID, CodeGen::I6::property_offset);
 	METHOD_ADD(cgt, PREPARE_VARIABLE_MTID, CodeGen::I6::prepare_variable);
 	METHOD_ADD(cgt, DECLARE_VARIABLE_MTID, CodeGen::I6::declare_variable);
 	METHOD_ADD(cgt, DECLARE_CLASS_MTID, CodeGen::I6::declare_class);
@@ -46,6 +47,7 @@ void CodeGen::I6::create_target(void) {
 	METHOD_ADD(cgt, ARRAY_ENTRY_MTID, CodeGen::I6::array_entry);
 	METHOD_ADD(cgt, END_ARRAY_MTID, CodeGen::I6::end_array);
 	METHOD_ADD(cgt, OFFER_PRAGMA_MTID, CodeGen::I6::offer_pragma)
+	METHOD_ADD(cgt, END_GENERATION_MTID, CodeGen::I6::end_generation);
 	inform6_target = cgt;
 }
 
@@ -90,6 +92,7 @@ now a bitmap of flags for tracing actions, calls to object routines, and so on.
 @e code_at_eof_I7CGS
 @e verbs_at_eof_I7CGS
 @e stubs_at_eof_I7CGS
+@e property_offset_creator_I7CGS
 
 =
 int CodeGen::I6::begin_generation(code_generation_target *cgt, code_generation *gen) {
@@ -118,13 +121,32 @@ int CodeGen::I6::begin_generation(code_generation_target *cgt, code_generation *
 	gen->segments[code_at_eof_I7CGS] = CodeGen::new_segment();
 	gen->segments[verbs_at_eof_I7CGS] = CodeGen::new_segment();
 	gen->segments[stubs_at_eof_I7CGS] = CodeGen::new_segment();
+	gen->segments[property_offset_creator_I7CGS] = CodeGen::new_segment();
 
 	generated_segment *saved = CodeGen::select(gen, compiler_versioning_matter_I7CGS);
 	text_stream *OUT = CodeGen::current(gen);
 	WRITE("Constant Grammar__Version 2;\n");
 	WRITE("Global debug_flag;\n");
 	CodeGen::deselect(gen, saved);
-	
+
+	saved = CodeGen::select(gen, property_offset_creator_I7CGS);
+	OUT = CodeGen::current(gen);
+	WRITE("[ CreatePropertyOffsets i;\n"); INDENT;
+	WRITE("for (i=0: ii = -1;\n"); OUTDENT;
+	WRITE("for (i=0: ii = -1;\n"); OUTDENT;
+	CodeGen::deselect(gen, saved);
+
+	return FALSE;
+}
+
+int CodeGen::I6::end_generation(code_generation_target *cgt, code_generation *gen) {
+	generated_segment *saved = CodeGen::select(gen, property_offset_creator_I7CGS);
+	text_stream *OUT = CodeGen::current(gen);
+	OUTDENT;
+	WRITE("];\n");
+	CodeGen::deselect(gen, saved);
 	return FALSE;
 }
 
@@ -588,6 +610,15 @@ void CodeGen::I6::declare_attribute(code_generation_target *cgt, code_generation
 	WRITE_TO(CodeGen::current(gen), "Attribute %S;\n", prop_name);
 }
 
+void CodeGen::I6::property_offset(code_generation_target *cgt, code_generation *gen, text_stream *prop, int pos, int as_attr) {
+	generated_segment *saved = CodeGen::select(gen, property_offset_creator_I7CGS);
+	text_stream *OUT = CodeGen::current(gen);
+	if (as_attr) WRITE("attributed_property_offsets");
+	else WRITE("valued_property_offsets");
+	WRITE("-->%S = %d;\n", prop, pos);
+	CodeGen::deselect(gen, saved);
+}
+
 @
 
 =
diff --git a/inter/gitignorescript.txt b/inter/gitignorescript.txt
index d2abf9d1c..e612cf1c3 100644
--- a/inter/gitignorescript.txt
+++ b/inter/gitignorescript.txt
@@ -22,6 +22,7 @@ Tests/Toys/_I6_Object_Code/
 Tests/Toys/_I6_Output_Actual/
 Tests/C/_C/
 Tests/C/_Textual/
+Tests/C/_Results_Actual/
 Tests/Valid/_Binary/
 Tests/Valid/_Console/
 Tests/Valid/_Textual/