From a69fe713a93239501742cf8a501fb15cfa9692f2 Mon Sep 17 00:00:00 2001 From: Graham Nelson Date: Mon, 25 Oct 2021 23:59:20 +0100 Subject: [PATCH] Improvements to memory model --- docs/final-module/2-cg.html | 6 +- docs/final-module/2-cg2.html | 2 +- docs/final-module/5-cgv.html | 17 + docs/final-module/5-clt.html | 72 +- docs/final-module/5-cmm.html | 773 +++++++++--------- docs/final-module/5-cnm.html | 16 +- docs/final-module/5-com.html | 36 +- docs/final-module/5-cpc.html | 4 +- docs/final-module/5-fnc.html | 16 +- inform7/Figures/timings-diagnostics.txt | 16 +- inform7/Internal/Miscellany/inform7_clib.c | 210 +++-- inform7/Internal/Miscellany/inform7_clib.h | 24 +- .../Chapter 5/C Global Variables.w | 15 + inter/final-module/Chapter 5/C Literals.w | 10 + inter/final-module/Chapter 5/C Memory Model.w | 681 ++++++++------- inter/final-module/Chapter 5/C Namespace.w | 13 +- inter/final-module/Chapter 5/C Object Model.w | 14 +- inter/final-module/Chapter 5/Final C.w | 12 +- 18 files changed, 1007 insertions(+), 930 deletions(-) diff --git a/docs/final-module/2-cg.html b/docs/final-module/2-cg.html index 6f41af25c..c63764d8e 100644 --- a/docs/final-module/2-cg.html +++ b/docs/final-module/2-cg.html @@ -414,7 +414,7 @@ but for now about 10 layers is plenty.

-segmentation_pos CodeGen::select(code_generation *gen, int i) {
+segmentation_pos CodeGen::select(code_generation *gen, int i) {
     return CodeGen::select_layered(gen, i, 1);
 }
 
@@ -431,7 +431,7 @@ but for now about 10 layers is plenty.
     return previous_pos;
 }
 
-void CodeGen::deselect(code_generation *gen, segmentation_pos saved) {
+void CodeGen::deselect(code_generation *gen, segmentation_pos saved) {
     if (gen->segmentation.temporarily_diverted) internal_error("poorly timed deselection");
     gen->segmentation.pos = saved;
 }
@@ -457,7 +457,7 @@ if it has been "temporarily diverted" then the regiular selection is ignored.
 

-text_stream *CodeGen::current(code_generation *gen) {
+text_stream *CodeGen::current(code_generation *gen) {
     if (gen->segmentation.temporarily_diverted)
         return gen->segmentation.temporarily_diverted_to;
     if (gen->segmentation.pos.current_segment == NULL) return NULL;
diff --git a/docs/final-module/2-cg2.html b/docs/final-module/2-cg2.html
index 2c9c27c4f..46937710a 100644
--- a/docs/final-module/2-cg2.html
+++ b/docs/final-module/2-cg2.html
@@ -336,7 +336,7 @@ I6 code. Still, all pragmas are offered to all generators.
 
 VOID_METHOD_TYPE(MANGLE_IDENTIFIER_MTID, code_generator *generator, text_stream *OUT, text_stream *identifier)
-void Generators::mangle(code_generation *gen, text_stream *OUT, text_stream *identifier) {
+void Generators::mangle(code_generation *gen, text_stream *OUT, text_stream *identifier) {
     VOID_METHOD_CALL(gen->generator, MANGLE_IDENTIFIER_MTID, OUT, identifier);
 }
 
diff --git a/docs/final-module/5-cgv.html b/docs/final-module/5-cgv.html index 04be02a16..666772f81 100644 --- a/docs/final-module/5-cgv.html +++ b/docs/final-module/5-cgv.html @@ -21,6 +21,7 @@ function togglePopup(material_id) { + @@ -224,6 +225,22 @@ but has no Inter declaration node. WRITE("]"); }
+

§5. Finally, this function, part of the C library, initialises the variables for a +newly-starting process. +

+ +
+void i7_initialise_variables(i7process_t *proc);
+
+ +
+void i7_initialise_variables(i7process_t *proc) {
+    proc->state.variables = i7_calloc(proc, i7_no_variables, sizeof(i7word_t));
+    for (int i=0; i<i7_no_variables; i++)
+        proc->state.variables[i] = i7_initial_variable_values[i];
+}
+
+ diff --git a/docs/final-module/5-clt.html b/docs/final-module/5-clt.html index 4f0536916..e9f8ba8dd 100644 --- a/docs/final-module/5-clt.html +++ b/docs/final-module/5-clt.html @@ -83,7 +83,8 @@ function togglePopup(material_id) { METHOD_ADD(cgt, COMPILE_DICTIONARY_WORD_MTID, CLiteralsModel::compile_dictionary_word); METHOD_ADD(cgt, COMPILE_LITERAL_NUMBER_MTID, CLiteralsModel::compile_literal_number); METHOD_ADD(cgt, COMPILE_LITERAL_REAL_MTID, CLiteralsModel::compile_literal_real); - METHOD_ADD(cgt, COMPILE_LITERAL_TEXT_MTID, CLiteralsModel::compile_literal_text); + METHOD_ADD(cgt, COMPILE_LITERAL_TEXT_MTID, CLiteralsModel::compile_literal_text); + METHOD_ADD(cgt, COMPILE_LITERAL_SYMBOL_MTID, CLiteralsModel::compile_literal_symbol); METHOD_ADD(cgt, NEW_ACTION_MTID, CLiteralsModel::new_action); } @@ -182,14 +183,14 @@ function togglePopup(material_id) { int dictlen = C_GEN_DATA(litdata.C_dword_count); segmentation_pos saved = CodeGen::select(gen, c_predeclarations_I7CGS); - CMemoryModel::begin_array(NULL, gen, I"#dictionary_table", NULL, NULL, BYTE_ARRAY_FORMAT, NULL); + CMemoryModel::begin_array(NULL, gen, I"#dictionary_table", NULL, NULL, BYTE_ARRAY_FORMAT, NULL); for (int b=0; b<4; b++) { TEMPORARY_TEXT(N) WRITE_TO(N, "I7BYTE_%d(%d)", b, dictlen); - CMemoryModel::array_entry(NULL, gen, N, BYTE_ARRAY_FORMAT); + CMemoryModel::array_entry(NULL, gen, N, BYTE_ARRAY_FORMAT); DISCARD_TEXT(N) } - CMemoryModel::end_array(NULL, gen, BYTE_ARRAY_FORMAT, NULL); + CMemoryModel::end_array(NULL, gen, BYTE_ARRAY_FORMAT, NULL); if (dictlen == 0) return; C_dword **sorted = (C_dword **) @@ -199,10 +200,10 @@ function togglePopup(material_id) { qsort(sorted, (size_t) LinkedLists::len(C_GEN_DATA(litdata.words)), sizeof(C_dword *), CLiteralsModel::compare_dwords); for (int i=0; i<dictlen; i++) { dw = sorted[i]; - CMemoryModel::begin_array(NULL, gen, sorted[i]->identifier, NULL, NULL, BYTE_ARRAY_FORMAT, NULL); + CMemoryModel::begin_array(NULL, gen, sorted[i]->identifier, NULL, NULL, BYTE_ARRAY_FORMAT, NULL); TEMPORARY_TEXT(N) WRITE_TO(N, "0x60"); - CMemoryModel::array_entry(NULL, gen, N, BYTE_ARRAY_FORMAT); + CMemoryModel::array_entry(NULL, gen, N, BYTE_ARRAY_FORMAT); DISCARD_TEXT(N); for (int i=0; i<9; i++) { TEMPORARY_TEXT(N) @@ -211,7 +212,7 @@ function togglePopup(material_id) { else WRITE_TO(N, "'%c'", Str::get_at(dw->text, i)); } else WRITE_TO(N, "0"); - CMemoryModel::array_entry(NULL, gen, N, BYTE_ARRAY_FORMAT); + CMemoryModel::array_entry(NULL, gen, N, BYTE_ARRAY_FORMAT); DISCARD_TEXT(N); } TEMPORARY_TEXT(DP1H) @@ -228,17 +229,17 @@ function togglePopup(material_id) { WRITE_TO(DP1L, "((%d)%%256)", f); WRITE_TO(DP2H, "((%d)/256)", 0xFFFF - dw->verb_number); WRITE_TO(DP2L, "((%d)%%256)", 0xFFFF - dw->verb_number); - CMemoryModel::array_entry(NULL, gen, DP1H, BYTE_ARRAY_FORMAT); - CMemoryModel::array_entry(NULL, gen, DP1L, BYTE_ARRAY_FORMAT); - CMemoryModel::array_entry(NULL, gen, DP2H, BYTE_ARRAY_FORMAT); - CMemoryModel::array_entry(NULL, gen, DP2L, BYTE_ARRAY_FORMAT); - CMemoryModel::array_entry(NULL, gen, I"0", BYTE_ARRAY_FORMAT); - CMemoryModel::array_entry(NULL, gen, I"0", BYTE_ARRAY_FORMAT); + CMemoryModel::array_entry(NULL, gen, DP1H, BYTE_ARRAY_FORMAT); + CMemoryModel::array_entry(NULL, gen, DP1L, BYTE_ARRAY_FORMAT); + CMemoryModel::array_entry(NULL, gen, DP2H, BYTE_ARRAY_FORMAT); + CMemoryModel::array_entry(NULL, gen, DP2L, BYTE_ARRAY_FORMAT); + CMemoryModel::array_entry(NULL, gen, I"0", BYTE_ARRAY_FORMAT); + CMemoryModel::array_entry(NULL, gen, I"0", BYTE_ARRAY_FORMAT); DISCARD_TEXT(DP1H) DISCARD_TEXT(DP1L) DISCARD_TEXT(DP2H) DISCARD_TEXT(DP2L) - CMemoryModel::end_array(NULL, gen, BYTE_ARRAY_FORMAT, NULL); + CMemoryModel::end_array(NULL, gen, BYTE_ARRAY_FORMAT, NULL); } Memory::I7_free(sorted, CODE_GENERATION_MREASON, dictlen); CodeGen::deselect(gen, saved); @@ -258,7 +259,7 @@ function togglePopup(material_id) { CNamespace::mangle(cgt, OUT, dw->identifier); } -void CLiteralsModel::verb_grammar(code_generator *cgt, code_generation *gen, +void CLiteralsModel::verb_grammar(code_generator *cgt, code_generation *gen, inter_symbol *array_s, inter_tree_node *P) { inter_tree *I = gen->from; int verbnum = C_GEN_DATA(litdata.verb_count)++; @@ -492,25 +493,25 @@ function togglePopup(material_id) { } void CLiteralsModel::compile_verb_table(code_generation *gen) { - CMemoryModel::begin_array(NULL, gen, I"#grammar_table", NULL, NULL, WORD_ARRAY_FORMAT, NULL); + CMemoryModel::begin_array(NULL, gen, I"#grammar_table", NULL, NULL, WORD_ARRAY_FORMAT, NULL); TEMPORARY_TEXT(N) WRITE_TO(N, "%d", C_GEN_DATA(litdata.verb_count) - 1); - CMemoryModel::array_entry(NULL, gen, N, WORD_ARRAY_FORMAT); + CMemoryModel::array_entry(NULL, gen, N, WORD_ARRAY_FORMAT); DISCARD_TEXT(N) C_dword *dw; int c = 1; LOOP_OVER_LINKED_LIST(dw, C_dword, C_GEN_DATA(litdata.verbs)) { TEMPORARY_TEXT(N) WRITE_TO(N, "(i7_ss_grammar_table_cont+%d /* %d: %S */ )", dw->grammar_table_offset, c++, dw->text); - CMemoryModel::array_entry(NULL, gen, N, WORD_ARRAY_FORMAT); + CMemoryModel::array_entry(NULL, gen, N, WORD_ARRAY_FORMAT); DISCARD_TEXT(N) } - CMemoryModel::end_array(NULL, gen, WORD_ARRAY_FORMAT, NULL); - CMemoryModel::begin_array(NULL, gen, I"#grammar_table_cont", NULL, NULL, BYTE_ARRAY_FORMAT, NULL); + CMemoryModel::end_array(NULL, gen, WORD_ARRAY_FORMAT, NULL); + CMemoryModel::begin_array(NULL, gen, I"#grammar_table_cont", NULL, NULL, BYTE_ARRAY_FORMAT, NULL); text_stream *entry; LOOP_OVER_LINKED_LIST(entry, text_stream, C_GEN_DATA(litdata.verb_grammar)) { - CMemoryModel::array_entry(NULL, gen, entry, BYTE_ARRAY_FORMAT); + CMemoryModel::array_entry(NULL, gen, entry, BYTE_ARRAY_FORMAT); } - CMemoryModel::end_array(NULL, gen, BYTE_ARRAY_FORMAT, NULL); + CMemoryModel::end_array(NULL, gen, BYTE_ARRAY_FORMAT, NULL); } void CLiteralsModel::new_action(code_generator *cgt, code_generation *gen, text_stream *name, int true_action) { @@ -527,19 +528,19 @@ function togglePopup(material_id) { } void CLiteralsModel::compile_actions_table(code_generation *gen) { - CMemoryModel::begin_array(NULL, gen, I"#actions_table", NULL, NULL, WORD_ARRAY_FORMAT, NULL); + CMemoryModel::begin_array(NULL, gen, I"#actions_table", NULL, NULL, WORD_ARRAY_FORMAT, NULL); TEMPORARY_TEXT(N) WRITE_TO(N, "%d", C_GEN_DATA(litdata.C_action_count)); - CMemoryModel::array_entry(NULL, gen, N, WORD_ARRAY_FORMAT); + CMemoryModel::array_entry(NULL, gen, N, WORD_ARRAY_FORMAT); DISCARD_TEXT(N) text_stream *an; LOOP_OVER_LINKED_LIST(an, text_stream, C_GEN_DATA(litdata.actions)) { TEMPORARY_TEXT(N) WRITE_TO(N, "i7_mgl_%SSub", an); - CMemoryModel::array_entry(NULL, gen, N, WORD_ARRAY_FORMAT); + CMemoryModel::array_entry(NULL, gen, N, WORD_ARRAY_FORMAT); DISCARD_TEXT(N) } - CMemoryModel::end_array(NULL, gen, WORD_ARRAY_FORMAT, NULL); + CMemoryModel::end_array(NULL, gen, WORD_ARRAY_FORMAT, NULL); } @@ -749,6 +750,15 @@ function togglePopup(material_id) {

§5.

+
+void CLiteralsModel::compile_literal_symbol(code_generator *cgt, code_generation *gen, inter_symbol *aliased) {
+    text_stream *OUT = CodeGen::current(gen);
+    text_stream *S = Inter::Symbols::name(aliased);
+    Generators::mangle(gen, OUT, S);
+}
+
+

§6.

+
 int CLiteralsModel::hex_val(wchar_t c) {
     if ((c >= '0') && (c <= '9')) return c - '0';
@@ -756,7 +766,7 @@ function togglePopup(material_id) {
     if ((c >= 'A') && (c <= 'F')) return c - 'A' + 10;
     return -1;
 }
-void CLiteralsModel::compile_literal_text(code_generator *cgt, code_generation *gen,
+void CLiteralsModel::compile_literal_text(code_generator *cgt, code_generation *gen,
     text_stream *S, int escape_mode) {
     text_stream *OUT = CodeGen::current(gen);
 
@@ -780,7 +790,7 @@ function togglePopup(material_id) {
                     } else if (Str::get_at(S, i+1) == '{') {
                         int cc = 0; i++;
                         while ((Str::get_at(S, ++i) != '}') && (Str::get_at(S, i) != 0))
-                            cc = 16*cc + CLiteralsModel::hex_val(Str::get_at(S, i));
+                            cc = 16*cc + CLiteralsModel::hex_val(Str::get_at(S, i));
                         if ((cc == '\n') || (cc == '\"') || (cc == '\\')) PUT('\\');
                         PUT(cc);
                     } else WRITE("@");
@@ -811,11 +821,11 @@ function togglePopup(material_id) {
     if (gen->literal_text_mode != PRINTING_LTM) WRITE(",\n");
 }
 
-int CLiteralsModel::no_strings(code_generation *gen) {
+int CLiteralsModel::no_strings(code_generation *gen) {
     return C_GEN_DATA(litdata.no_double_quoted_C_strings);
 }
 
-int CLiteralsModel::invoke_primitive(code_generation *gen, inter_ti bip, inter_tree_node *P) {
+int CLiteralsModel::invoke_primitive(code_generation *gen, inter_ti bip, inter_tree_node *P) {
     text_stream *OUT = CodeGen::current(gen);
     switch (bip) {
         case PRINTSTRING_BIP: WRITE("i7_print_C_string(proc, dqs["); VNODE_1C; WRITE(" - I7VAL_STRINGS_BASE])"); break;
@@ -825,7 +835,7 @@ function togglePopup(material_id) {
     return FALSE;
 }
 
-

§6.

+

§7.

 void i7_print_dword(i7process_t *proc, i7word_t at);
diff --git a/docs/final-module/5-cmm.html b/docs/final-module/5-cmm.html
index a819ff470..1b689ec28 100644
--- a/docs/final-module/5-cmm.html
+++ b/docs/final-module/5-cmm.html
@@ -74,33 +74,9 @@ function togglePopup(material_id) {
     
 

How arrays of all kinds are stored in C.

-
+
-

§1. Setting up the model.

- -
-void CMemoryModel::initialise(code_generator *cgt) {
-    METHOD_ADD(cgt, BEGIN_ARRAY_MTID, CMemoryModel::begin_array);
-    METHOD_ADD(cgt, ARRAY_ENTRY_MTID, CMemoryModel::array_entry);
-    METHOD_ADD(cgt, COMPILE_LITERAL_SYMBOL_MTID, CMemoryModel::compile_literal_symbol);
-    METHOD_ADD(cgt, ARRAY_ENTRIES_MTID, CMemoryModel::array_entries);
-    METHOD_ADD(cgt, END_ARRAY_MTID, CMemoryModel::end_array);
-}
-
-typedef struct C_generation_memory_model_data {
-    int himem;  high point of memory: 1 more than the largest legal address
-    struct text_stream *array_name;
-    int entry_count;
-} C_generation_memory_model_data;
-
-void CMemoryModel::initialise_data(code_generation *gen) {
-    C_GEN_DATA(memdata.himem) = 0;
-    C_GEN_DATA(memdata.array_name) = Str::new();
-    C_GEN_DATA(memdata.entry_count) = 0;
-}
-
- -

§2. Byte-addressable memory. The Inter semantics require that there be an area of byte-accessible memory: +

§1. Setting up the model. The Inter semantics require that there be an area of byte-accessible memory:

-

We will manage that with a single C array. +

+void CMemoryModel::initialise(code_generator *cgt) {
+    METHOD_ADD(cgt, BEGIN_ARRAY_MTID, CMemoryModel::begin_array);
+    METHOD_ADD(cgt, ARRAY_ENTRY_MTID, CMemoryModel::array_entry);
+    METHOD_ADD(cgt, ARRAY_ENTRIES_MTID, CMemoryModel::array_entries);
+    METHOD_ADD(cgt, END_ARRAY_MTID, CMemoryModel::end_array);
+}
+
+typedef struct C_generation_memory_model_data {
+    int himem;                       1 more than the largest legal byte address
+    struct text_stream *array_name;  of the array currently being compiled
+    int entry_count;                 within the array currently being compiled
+} C_generation_memory_model_data;
+
+void CMemoryModel::initialise_data(code_generation *gen) {
+    C_GEN_DATA(memdata.himem) = 0;
+    C_GEN_DATA(memdata.array_name) = Str::new();
+    C_GEN_DATA(memdata.entry_count) = 0;
+}
+
+ +

§2. For a given process proc, the current contents of byte-addressable memory will +be an array called proc->state.memory; here, we will compile a single static array +i7_initial_memory holding the initial contents of this memory, so that a new +process can be initialised from that.

-

§3. Declaring that array is our main task in this section. +

The first 64 bytes of memory are reserved for the "header". We don't write those +here, and instead blank them out to all 0s.

@@ -134,17 +135,14 @@ of 2 or 4.
     CodeGen::deselect(gen, saved);
 }
 
-

§4. We will end the array with two dummy bytes (which should never be accessed) -just in case, and to ensure that it is never empty, which would be illegal -in C. +

§3. And we must close that array declaration, too:

 void CMemoryModel::end(code_generation *gen) {
     segmentation_pos saved = CodeGen::select(gen, c_mem_I7CGS);
     text_stream *OUT = CodeGen::current(gen);
-    WRITE("0, 0 };\n");
-
+    WRITE("};\n");
     CodeGen::deselect(gen, saved);
 
     saved = CodeGen::select(gen, c_ids_and_maxima_I7CGS);
@@ -153,31 +151,233 @@ in C.
     CodeGen::deselect(gen, saved);
 }
 
-

§5.

+

§4. What goes into memory are arrays: memory is allocated only in the form of +such arrays, which are declared one at a time. See Vanilla Constants. +

+ +
+int CMemoryModel::begin_array(code_generator *cgt, code_generation *gen,
+    text_stream *array_name, inter_symbol *array_s, inter_tree_node *P, int format,
+    segmentation_pos *saved) {
+    Str::clear(C_GEN_DATA(memdata.array_name));
+    WRITE_TO(C_GEN_DATA(memdata.array_name), "%S", array_name);
+    C_GEN_DATA(memdata.entry_count) = 0;
+    if ((array_s) && (Inter::Symbols::read_annotation(array_s, VERBARRAY_IANN) == 1))
+        Short-circuit the usual Vanilla algorithm by compiling the whole array now4.1
+    else
+        Declare this array in concert with the usual Vanilla algorithm4.2;
+}
+
+

§4.1. Command-grammar arrays are handled differently: note the return value FALSE, +which tells Vanilla not to call us again about this array. +

+ +

Short-circuit the usual Vanilla algorithm by compiling the whole array now4.1 = +

+ +
+    if (saved) *saved = CodeGen::select(gen, c_verb_arrays_I7CGS);
+    CLiteralsModel::verb_grammar(cgt, gen, array_s, P);
+    return FALSE;
+
+ +

§4.2. Declare this array in concert with the usual Vanilla algorithm4.2 = +

+ +
+    if (saved) *saved = CodeGen::select(gen, c_arrays_I7CGS);
+    text_stream *format_name = I"unknown";
+    Work out the format name4.2.1;
+    Define a constant for the byte address in memory where the array begins4.2.2;
+    if ((format == TABLE_ARRAY_FORMAT) || (format == BUFFER_ARRAY_FORMAT))
+        Place the extent entry N at index 04.2.3;
+    return TRUE;
+
+ +

§4.2.1. Work out the format name4.2.1 = +

+ +
+    switch (format) {
+        case BYTE_ARRAY_FORMAT: format_name = I"byte"; break;
+        case WORD_ARRAY_FORMAT: format_name = I"word"; break;
+        case BUFFER_ARRAY_FORMAT: format_name = I"buffer"; break;
+        case TABLE_ARRAY_FORMAT: format_name = I"table"; break;
+    }
+
+ +

§4.2.2. Crucially, the array names are #define constants declared up near the top +of the source code: they are not variables with pointer types, or something +like that. This means they can legally be used as values elsewhere in memory, +or as initial values of variables, and so on. +

+ +

Object, class and function names can also legally appear as array entries, +because they too are defined constants, equal to their IDs: see C Object Model. +

+ +

Define a constant for the byte address in memory where the array begins4.2.2 = +

+ +
+    segmentation_pos saved = CodeGen::select(gen, c_predeclarations_I7CGS);
+    text_stream *OUT = CodeGen::current(gen);
+    WRITE("#define ");
+    CNamespace::mangle(cgt, OUT, array_name);
+    WRITE(" %d /* = position in memory of %S array %S */\n",
+        C_GEN_DATA(memdata.himem), format_name, array_name);
+    if (array_s)
+        Inter::Symbols::annotate_i(array_s, C_ARRAY_ADDRESS_IANN,
+            (inter_ti) C_GEN_DATA(memdata.himem));
+    CodeGen::deselect(gen, saved);
+
+ +

§4.2.3. Of course, right now we don't know N, the extent of the array. So we will +refer to this with a constant like i7_mgl_myarray__xt (XT meaning "extent"), +which we will retrospectively predefine when the array ends. +

+ +

Place the extent entry N at index 04.2.3 = +

+ +
+    TEMPORARY_TEXT(extname)
+    CNamespace::mangle(cgt, extname, array_name);
+    WRITE_TO(extname, "__xt");
+    CMemoryModel::array_entry(cgt, gen, extname, format);
+    DISCARD_TEXT(extname)
+
+ +

§5. The call to CMemoryModel::begin_array is then followed by a series of calls to: +

+ +
+void CMemoryModel::array_entry(code_generator *cgt, code_generation *gen,
+    text_stream *entry, int format) {
+    segmentation_pos saved = CodeGen::select(gen, c_mem_I7CGS);
+    text_stream *OUT = CodeGen::current(gen);
+    if ((format == TABLE_ARRAY_FORMAT) || (format == WORD_ARRAY_FORMAT))
+        This is a word entry5.2
+    else
+        This is a byte entry5.1;
+    CodeGen::deselect(gen, saved);
+    C_GEN_DATA(memdata.entry_count)++;
+}
+
+

§5.1. This is a byte entry5.1 = +

+ +
+    WRITE("    (i7byte_t) %S, /* %d */\n", entry, C_GEN_DATA(memdata.himem));
+    C_GEN_DATA(memdata.himem) += 1;
+
+ +

§5.2. Note that I7BYTE_0 and so on are macros and not functions (see below): they +use only arithmetic operations which can be constant-folded by the C compiler, +and therefore if X is a valid constant-context expression in C then so is +I7BYTE_0(X). +

+ +

This is a word entry5.2 = +

+ +
+    WRITE("    I7BYTE_0(%S), I7BYTE_1(%S), I7BYTE_2(%S), I7BYTE_3(%S), /* %d */\n",
+        entry, entry, entry, entry, C_GEN_DATA(memdata.himem));
+    C_GEN_DATA(memdata.himem) += 4;
+
+ +

§6. Alternatively, we can just specify how many entries there will be: they will +then be initialised to 0. +

+ +
+void CMemoryModel::array_entries(code_generator *cgt, code_generation *gen,
+    int how_many, int format) {
+    for (int i=0; i<how_many; i++) CMemoryModel::array_entry(cgt, gen, I"0", format);
+}
+
+

§7. When all the entries have been placed, the following is called. It does nothing +except to predeclare the extent constant. +

+ +
+void CMemoryModel::end_array(code_generator *cgt, code_generation *gen, int format,
+    segmentation_pos *saved) {
+    segmentation_pos x_saved = CodeGen::select(gen, c_predeclarations_I7CGS);
+    text_stream *OUT = CodeGen::current(gen);
+    WRITE("#define ");
+    CNamespace::mangle(cgt, OUT, C_GEN_DATA(memdata.array_name));
+    WRITE("__xt %d\n", C_GEN_DATA(memdata.entry_count)-1);
+    CodeGen::deselect(gen, x_saved);
+    if (saved) CodeGen::deselect(gen, *saved);
+}
+
+

§8. The primitives for byte and word lookup have the signatures: +

+ +
+primitive !lookup val val -> val
+primitive !lookupbyte val val -> val
+
+
+int CMemoryModel::handle_store_by_ref(code_generation *gen, inter_tree_node *ref) {
+    if (Inter::Reference::node_is_ref_to(gen->from, ref, LOOKUP_BIP)) return TRUE;
+    if (Inter::Reference::node_is_ref_to(gen->from, ref, LOOKUPBYTE_BIP)) return TRUE;
+    return FALSE;
+}
+
+int CMemoryModel::invoke_primitive(code_generation *gen, inter_ti bip, inter_tree_node *P) {
+    text_stream *OUT = CodeGen::current(gen);
+    switch (bip) {
+        case LOOKUP_BIP:
+            WRITE("i7_read_word(proc, "); VNODE_1C; WRITE(", "); VNODE_2C; WRITE(")");
+            break;
+        case LOOKUPBYTE_BIP:
+            WRITE("i7_read_byte(proc, "); VNODE_1C; WRITE(" + "); VNODE_2C; WRITE(")");
+            break;
+        default:
+            return NOT_APPLICABLE;
+    }
+    return FALSE;
+}
+
+

§9. So, then, time to write some more of the C library. We are going to need to +define the macros I7BYTE_0 to I7BYTE_3, and also the functions i7_read_word +and i7_read_byte, used just above. But we start with the function which resets +memory to its initial state when a process begins, and with the stack empty. +

+ +

Note that we fill in ten bytes of the 64-byte header block of memory: +

+ + +

We carefully defined those two constants, if they exist, before the inclusion point of +the C library in order that the conditional compilations in i7_initialise_memory_and_stack +will work correctly. See CNamespace::declare_constant. +

+ +

The rest of the header area remains all zeros. +

-void i7_initialise_state(i7process_t *proc);
+void i7_initialise_memory_and_stack(i7process_t *proc);
 
 i7byte_t i7_initial_memory[];
-void i7_initialise_state(i7process_t *proc) {
+void i7_initialise_memory_and_stack(i7process_t *proc) {
     if (proc->state.memory != NULL) free(proc->state.memory);
-    i7byte_t *mem = calloc(i7_static_himem, sizeof(i7byte_t));
-    if (mem == NULL) {
-        printf("Memory allocation failed\n");
-        i7_fatal_exit(proc);
-    }
-    proc->state.memory = mem;
-    proc->state.himem = i7_static_himem;
+
+    i7byte_t *mem = i7_calloc(proc, i7_static_himem, sizeof(i7byte_t));
     for (int i=0; i<i7_static_himem; i++) mem[i] = i7_initial_memory[i];
     #ifdef i7_mgl_Release
-    mem[0x34] = I7BYTE_2(i7_mgl_Release);
-    mem[0x35] = I7BYTE_3(i7_mgl_Release);
+    mem[0x34] = I7BYTE_2(i7_mgl_Release); mem[0x35] = I7BYTE_3(i7_mgl_Release);
     #endif
     #ifndef i7_mgl_Release
-    mem[0x34] = I7BYTE_2(1);
-    mem[0x35] = I7BYTE_3(1);
+    mem[0x34] = I7BYTE_2(1); mem[0x35] = I7BYTE_3(1);
     #endif
     #ifdef i7_mgl_Serial
     char *p = i7_text_of_string(i7_mgl_Serial);
@@ -186,41 +386,156 @@ in C.
     #ifndef i7_mgl_Serial
     for (int i=0; i<6; i++) mem[0x36 + i] = '0';
     #endif
+
+    proc->state.memory = mem;
+    proc->state.himem = i7_static_himem;
     proc->state.stack_pointer = 0;
-
-    proc->state.object_tree_parent  = calloc(i7_max_objects, sizeof(i7word_t));
-    proc->state.object_tree_child   = calloc(i7_max_objects, sizeof(i7word_t));
-    proc->state.object_tree_sibling = calloc(i7_max_objects, sizeof(i7word_t));
-
-    if ((proc->state.object_tree_parent == NULL) ||
-        (proc->state.object_tree_child == NULL) ||
-        (proc->state.object_tree_sibling == NULL)) {
-        printf("Memory allocation failed\n");
-        i7_fatal_exit(proc);
-    }
-    for (int i=0; i<i7_max_objects; i++) {
-        proc->state.object_tree_parent[i] = 0;
-        proc->state.object_tree_child[i] = 0;
-        proc->state.object_tree_sibling[i] = 0;
-    }
-
-    proc->state.variables = calloc(i7_no_variables, sizeof(i7word_t));
-    if (proc->state.variables == NULL) {
-        printf("Memory allocation failed\n");
-        i7_fatal_exit(proc);
-    }
-    for (int i=0; i<i7_no_variables; i++)
-        proc->state.variables[i] = i7_initial_variable_values[i];
 }
 
-

§6. And now some deep copy functions. The above structures are full of pointers +

§10. The array proc->state.memory is of i7byte_t values, so it's easy to read +and write bytes. Words are more challenging since we need to pack and unpack them. +

+ +

The following function reads a word which is in entry array_index (counting +0, 1, 2, ...) in the array which begins at the byte address array_address. +

+ +
+i7byte_t i7_read_byte(i7process_t *proc, i7word_t address);
+i7word_t i7_read_word(i7process_t *proc, i7word_t array_address, i7word_t array_index);
+
+ +
+i7byte_t i7_read_byte(i7process_t *proc, i7word_t address) {
+    return proc->state.memory[address];
+}
+
+i7word_t i7_read_word(i7process_t *proc, i7word_t array_address, i7word_t array_index) {
+    i7byte_t *data = proc->state.memory;
+    int byte_position = array_address + 4*array_index;
+    if ((byte_position < 0) || (byte_position >= i7_static_himem)) {
+        printf("Memory access out of range: %d\n", byte_position);
+        i7_fatal_exit(proc);
+    }
+    return             (i7word_t) data[byte_position + 3]  +
+                0x100*((i7word_t) data[byte_position + 2]) +
+              0x10000*((i7word_t) data[byte_position + 1]) +
+            0x1000000*((i7word_t) data[byte_position + 0]);
+}
+
+ +

§11. Packing, unlike unpacking, is done with macros so that it is possible to express +a packed word in constant context, which we will need later. +

+ +
+#define I7BYTE_0(V) ((V & 0xFF000000) >> 24)
+#define I7BYTE_1(V) ((V & 0x00FF0000) >> 16)
+#define I7BYTE_2(V) ((V & 0x0000FF00) >> 8)
+#define I7BYTE_3(V)  (V & 0x000000FF)
+
+void i7_write_byte(i7process_t *proc, i7word_t address, i7byte_t new_val);
+i7word_t i7_write_word(i7process_t *proc, i7word_t array_address, i7word_t array_index,
+    i7word_t new_val, int way);
+
+ +
+void i7_write_byte(i7process_t *proc, i7word_t address, i7byte_t new_val) {
+    proc->state.memory[address] = new_val;
+}
+
+i7byte_t i7_change_byte(i7process_t *proc, i7word_t address, i7byte_t new_val, int way) {
+    i7byte_t old_val = i7_read_byte(proc, address);
+    i7byte_t return_val = new_val;
+    switch (way) {
+        case i7_lvalue_PREDEC:   return_val = old_val-1;   new_val = old_val-1; break;
+        case i7_lvalue_POSTDEC:  return_val = old_val; new_val = old_val-1; break;
+        case i7_lvalue_PREINC:   return_val = old_val+1;   new_val = old_val+1; break;
+        case i7_lvalue_POSTINC:  return_val = old_val; new_val = old_val+1; break;
+        case i7_lvalue_SETBIT:   new_val = old_val | new_val; return_val = new_val; break;
+        case i7_lvalue_CLEARBIT: new_val = old_val &(~new_val); return_val = new_val; break;
+    }
+    i7_write_byte(proc, address, new_val);
+    return return_val;
+}
+
+i7word_t i7_write_word(i7process_t *proc, i7word_t array_address, i7word_t array_index, i7word_t new_val, int way) {
+    i7byte_t *data = proc->state.memory;
+    i7word_t old_val = i7_read_word(proc, array_address, array_index);
+    i7word_t return_val = new_val;
+    switch (way) {
+        case i7_lvalue_PREDEC:   return_val = old_val-1;   new_val = old_val-1; break;
+        case i7_lvalue_POSTDEC:  return_val = old_val; new_val = old_val-1; break;
+        case i7_lvalue_PREINC:   return_val = old_val+1;   new_val = old_val+1; break;
+        case i7_lvalue_POSTINC:  return_val = old_val; new_val = old_val+1; break;
+        case i7_lvalue_SETBIT:   new_val = old_val | new_val; return_val = new_val; break;
+        case i7_lvalue_CLEARBIT: new_val = old_val &(~new_val); return_val = new_val; break;
+    }
+    int byte_position = array_address + 4*array_index;
+    if ((byte_position < 0) || (byte_position >= i7_static_himem)) {
+        printf("Memory access out of range: %d\n", byte_position);
+        i7_fatal_exit(proc);
+    }
+    data[byte_position]   = I7BYTE_0(new_val);
+    data[byte_position+1] = I7BYTE_1(new_val);
+    data[byte_position+2] = I7BYTE_2(new_val);
+    data[byte_position+3] = I7BYTE_3(new_val);
+    return return_val;
+}
+
+ +

§12. "Short" 16-bit numbers can also be accessed: +

+ +
+void glulx_aloads(i7process_t *proc, i7word_t x, i7word_t y, i7word_t *z);
+
+ +
+void glulx_aloads(i7process_t *proc, i7word_t x, i7word_t y, i7word_t *z) {
+    if (z) *z = 0x100*((i7word_t) i7_read_byte(proc, x+2*y)) + ((i7word_t) i7_read_byte(proc, x+2*y+1));
+}
+
+ +

§13. A Glulx assembly opcode is provided for fast memory copies: +

+ +
+void glulx_mcopy(i7process_t *proc, i7word_t x, i7word_t y, i7word_t z);
+void glulx_malloc(i7process_t *proc, i7word_t x, i7word_t y);
+void glulx_mfree(i7process_t *proc, i7word_t x);
+
+ +
+void glulx_mcopy(i7process_t *proc, i7word_t x, i7word_t y, i7word_t z) {
+    if (z < y)
+        for (i7word_t i=0; i<x; i++)
+            i7_write_byte(proc, z+i, i7_read_byte(proc, y+i));
+    else
+        for (i7word_t i=x-1; i>=0; i--)
+            i7_write_byte(proc, z+i, i7_read_byte(proc, y+i));
+}
+
+void glulx_malloc(i7process_t *proc, i7word_t x, i7word_t y) {
+    printf("Unimplemented: glulx_malloc.\n");
+    i7_fatal_exit(proc);
+}
+
+void glulx_mfree(i7process_t *proc, i7word_t x) {
+    printf("Unimplemented: glulx_mfree.\n");
+    i7_fatal_exit(proc);
+}
+
+ +

§14. And now some deep copy functions. The above structures are full of pointers to arrays, so a simple copy will only duplicate those pointers, not the data in the arrays they point to. Similarly, we can't just throw away an i7state_t value without causing a memory leak, so we need explicit destructors.

+void *i7_calloc(i7process_t *proc, size_t how_many, size_t of_size);
 void i7_copy_state(i7process_t *proc, i7state_t *to, i7state_t *from);
 void i7_destroy_state(i7process_t *proc, i7state_t *s);
 
@@ -326,320 +641,6 @@ value without causing a memory leak, so we need explicit destructors. }
-

§7. Reading and writing memory. Given the above array, it's easy to read and write bytes. Words are more -challenging since we need to pack and unpack them. -

- -

The following function reads a word which is in entry array_index (counting -0, 1, 2, ...) in the array which begins at the byte address array_address. -

- -
-i7byte_t i7_read_byte(i7process_t *proc, i7word_t address);
-i7word_t i7_read_word(i7process_t *proc, i7word_t array_address, i7word_t array_index);
-
- -
-i7byte_t i7_read_byte(i7process_t *proc, i7word_t address) {
-    return proc->state.memory[address];
-}
-
-i7word_t i7_read_word(i7process_t *proc, i7word_t array_address, i7word_t array_index) {
-    i7byte_t *data = proc->state.memory;
-    int byte_position = array_address + 4*array_index;
-    if ((byte_position < 0) || (byte_position >= i7_static_himem)) {
-        printf("Memory access out of range: %d\n", byte_position);
-        i7_fatal_exit(proc);
-    }
-    return             (i7word_t) data[byte_position + 3]      +
-                0x100*((i7word_t) data[byte_position + 2]) +
-              0x10000*((i7word_t) data[byte_position + 1]) +
-            0x1000000*((i7word_t) data[byte_position + 0]);
-}
-
- -

§8. Packing, unlike unpacking, is done with macros so that it is possible to -express a packed word in constant context, which we will need later. -

- -
-#define I7BYTE_0(V) ((V & 0xFF000000) >> 24)
-#define I7BYTE_1(V) ((V & 0x00FF0000) >> 16)
-#define I7BYTE_2(V) ((V & 0x0000FF00) >> 8)
-#define I7BYTE_3(V)  (V & 0x000000FF)
-
-void i7_write_byte(i7process_t *proc, i7word_t address, i7byte_t new_val);
-i7word_t i7_write_word(i7process_t *proc, i7word_t array_address, i7word_t array_index, i7word_t new_val, int way);
-
- -
-void i7_write_byte(i7process_t *proc, i7word_t address, i7byte_t new_val) {
-    proc->state.memory[address] = new_val;
-}
-
-i7byte_t i7_change_byte(i7process_t *proc, i7word_t address, i7byte_t new_val, int way) {
-    i7byte_t old_val = i7_read_byte(proc, address);
-    i7byte_t return_val = new_val;
-    switch (way) {
-        case i7_lvalue_PREDEC:   return_val = old_val-1;   new_val = old_val-1; break;
-        case i7_lvalue_POSTDEC:  return_val = old_val; new_val = old_val-1; break;
-        case i7_lvalue_PREINC:   return_val = old_val+1;   new_val = old_val+1; break;
-        case i7_lvalue_POSTINC:  return_val = old_val; new_val = old_val+1; break;
-        case i7_lvalue_SETBIT:   new_val = old_val | new_val; return_val = new_val; break;
-        case i7_lvalue_CLEARBIT: new_val = old_val &(~new_val); return_val = new_val; break;
-    }
-    i7_write_byte(proc, address, new_val);
-    return return_val;
-}
-
-i7word_t i7_write_word(i7process_t *proc, i7word_t array_address, i7word_t array_index, i7word_t new_val, int way) {
-    i7byte_t *data = proc->state.memory;
-    i7word_t old_val = i7_read_word(proc, array_address, array_index);
-    i7word_t return_val = new_val;
-    switch (way) {
-        case i7_lvalue_PREDEC:   return_val = old_val-1;   new_val = old_val-1; break;
-        case i7_lvalue_POSTDEC:  return_val = old_val; new_val = old_val-1; break;
-        case i7_lvalue_PREINC:   return_val = old_val+1;   new_val = old_val+1; break;
-        case i7_lvalue_POSTINC:  return_val = old_val; new_val = old_val+1; break;
-        case i7_lvalue_SETBIT:   new_val = old_val | new_val; return_val = new_val; break;
-        case i7_lvalue_CLEARBIT: new_val = old_val &(~new_val); return_val = new_val; break;
-    }
-    int byte_position = array_address + 4*array_index;
-    if ((byte_position < 0) || (byte_position >= i7_static_himem)) {
-        printf("Memory access out of range: %d\n", byte_position);
-        i7_fatal_exit(proc);
-    }
-    data[byte_position]   = I7BYTE_0(new_val);
-    data[byte_position+1] = I7BYTE_1(new_val);
-    data[byte_position+2] = I7BYTE_2(new_val);
-    data[byte_position+3] = I7BYTE_3(new_val);
-    return return_val;
-}
-
- -

§9. "Short" 16-bit numbers can also be accessed: -

- -
-void glulx_aloads(i7process_t *proc, i7word_t x, i7word_t y, i7word_t *z);
-
- -
-void glulx_aloads(i7process_t *proc, i7word_t x, i7word_t y, i7word_t *z) {
-    if (z) *z = 0x100*((i7word_t) i7_read_byte(proc, x+2*y)) + ((i7word_t) i7_read_byte(proc, x+2*y+1));
-}
-
- -

§10. A Glulx assembly opcode is provided for fast memory copies: -

- -
-void glulx_mcopy(i7process_t *proc, i7word_t x, i7word_t y, i7word_t z);
-void glulx_malloc(i7process_t *proc, i7word_t x, i7word_t y);
-void glulx_mfree(i7process_t *proc, i7word_t x);
-
- -
-void glulx_mcopy(i7process_t *proc, i7word_t x, i7word_t y, i7word_t z) {
-    if (z < y)
-        for (i7word_t i=0; i<x; i++)
-            i7_write_byte(proc, z+i, i7_read_byte(proc, y+i));
-    else
-        for (i7word_t i=x-1; i>=0; i--)
-            i7_write_byte(proc, z+i, i7_read_byte(proc, y+i));
-}
-
-void glulx_malloc(i7process_t *proc, i7word_t x, i7word_t y) {
-    printf("Unimplemented: glulx_malloc.\n");
-    i7_fatal_exit(proc);
-}
-
-void glulx_mfree(i7process_t *proc, i7word_t x) {
-    printf("Unimplemented: glulx_mfree.\n");
-    i7_fatal_exit(proc);
-}
-
- -

§11. Populating memory with arrays.

- -
-int CMemoryModel::begin_array(code_generator *cgt, code_generation *gen,
-    text_stream *array_name, inter_symbol *array_s, inter_tree_node *P, int format, segmentation_pos *saved) {
-    if (saved) {
-        int choice = c_arrays_at_eof_I7CGS;
-        if ((array_s) && (Inter::Symbols::read_annotation(array_s, VERBARRAY_IANN) == 1))
-            choice = c_verbs_at_eof_I7CGS;
-        *saved = CodeGen::select(gen, choice);
-    }
-    Str::clear(C_GEN_DATA(memdata.array_name));
-    WRITE_TO(C_GEN_DATA(memdata.array_name), "%S", array_name);
-    C_GEN_DATA(memdata.entry_count) = 0;
-
-    if ((array_s) && (Inter::Symbols::read_annotation(array_s, VERBARRAY_IANN) == 1)) {
-        CLiteralsModel::verb_grammar(cgt, gen, array_s, P);
-        return FALSE;
-    }
-
-    text_stream *format_name = I"unknown";
-    Work out the format name11.1;
-    Define a constant for the byte address in memory where the array begins11.2;
-    if ((format == TABLE_ARRAY_FORMAT) || (format == BUFFER_ARRAY_FORMAT))
-        Place the extent entry N at index 011.3;
-    return TRUE;
-}
-
-

§11.1. Work out the format name11.1 = -

- -
-    switch (format) {
-        case BYTE_ARRAY_FORMAT: format_name = I"byte"; break;
-        case WORD_ARRAY_FORMAT: format_name = I"word"; break;
-        case BUFFER_ARRAY_FORMAT: format_name = I"buffer"; break;
-        case TABLE_ARRAY_FORMAT: format_name = I"table"; break;
-    }
-
- -

§11.2. Crucially, the array names are #define constants declared up at the top -of the source code: they are not variables with pointer types, or something -like that. This means they can legally be used as values elsewhere in memory, -or as initial values of variables, and so on. -

- -

Object, class and function names can also legally appear as array entries, -because they too are defined constants, equal to their IDs: see C Object Model. -

- -

Define a constant for the byte address in memory where the array begins11.2 = -

- -
-    segmentation_pos saved = CodeGen::select(gen, c_predeclarations_I7CGS);
-    text_stream *OUT = CodeGen::current(gen);
-    WRITE("#define ");
-    CNamespace::mangle(cgt, OUT, array_name);
-    WRITE(" %d /* = position in memory of %S array %S */\n",
-        C_GEN_DATA(memdata.himem), format_name, array_name);
-    if (array_s)
-        Inter::Symbols::annotate_i(array_s, C_ARRAY_ADDRESS_IANN, (inter_ti) C_GEN_DATA(memdata.himem));
-    CodeGen::deselect(gen, saved);
-
- -

§11.3. Of course, right now we don't know N, the extent of the array. So we will -refer to this with a constant like xt_myarray, which we will retrospectively -predefine when the array ends. -

- -

Place the extent entry N at index 011.3 = -

- -
-    TEMPORARY_TEXT(extname)
-    WRITE_TO(extname, "xt_");
-    CNamespace::mangle(cgt, extname, array_name);
-    CMemoryModel::array_entry(cgt, gen, extname, format);
-    DISCARD_TEXT(extname)
-
- -

§12. The call to CMemoryModel::begin_array is then followed by a series of calls to: -

- -
-void CMemoryModel::array_entry(code_generator *cgt, code_generation *gen,
-    text_stream *entry, int format) {
-    segmentation_pos saved = CodeGen::select(gen, c_mem_I7CGS);
-    text_stream *OUT = CodeGen::current(gen);
-    if ((format == TABLE_ARRAY_FORMAT) || (format == WORD_ARRAY_FORMAT))
-        This is a word entry12.2
-    else
-        This is a byte entry12.1;
-    CodeGen::deselect(gen, saved);
-    C_GEN_DATA(memdata.entry_count)++;
-}
-
-

§12.1. This is a byte entry12.1 = -

- -
-    WRITE("    (i7byte_t) %S, /* %d */\n", entry, C_GEN_DATA(memdata.himem));
-    C_GEN_DATA(memdata.himem) += 1;
-
- -

§12.2. Now we see why it was important for I7BYTE_0 and so on to be macros: they -use only arithmetic operations which can be constant-folded by the C compiler, -and therefore if X is a valid constant-context expression in C then so is -I7BYTE_0(X). -

- -

This is a word entry12.2 = -

- -
-    WRITE("    I7BYTE_0(%S), I7BYTE_1(%S), I7BYTE_2(%S), I7BYTE_3(%S), /* %d */\n",
-        entry, entry, entry, entry, C_GEN_DATA(memdata.himem));
-    C_GEN_DATA(memdata.himem) += 4;
-
- -

§13.

- -
-void CMemoryModel::compile_literal_symbol(code_generator *cgt, code_generation *gen, inter_symbol *aliased) {
-    text_stream *OUT = CodeGen::current(gen);
-    text_stream *S = Inter::Symbols::name(aliased);
-    Generators::mangle(gen, OUT, S);
-}
-
-

§14. Alternatively, we can just specify how many entries there will be: they will -then be initialised to 0. -

- -
-void CMemoryModel::array_entries(code_generator *cgt, code_generation *gen,
-    int how_many, int format) {
-    for (int i=0; i<how_many; i++) CMemoryModel::array_entry(cgt, gen, I"0", format);
-}
-
-

§15. When all the entries have been placed, the following is called. It does nothing -except to predeclare the extent constant, if one was used. -

- -
-void CMemoryModel::end_array(code_generator *cgt, code_generation *gen, int format, segmentation_pos *saved) {
-    segmentation_pos x_saved = CodeGen::select(gen, c_predeclarations_I7CGS);
-    text_stream *OUT = CodeGen::current(gen);
-    WRITE("#define xt_");
-    CNamespace::mangle(cgt, OUT, C_GEN_DATA(memdata.array_name));
-    WRITE(" %d\n", C_GEN_DATA(memdata.entry_count)-1);
-    CodeGen::deselect(gen, x_saved);
-    if (saved) CodeGen::deselect(gen, *saved);
-}
-
-

§16. Primitives for byte and word lookup. The signatures here are: -

- -
-primitive !lookup val val -> val
-primitive !lookupbyte val val -> val
-
-
-int CMemoryModel::handle_store_by_ref(code_generation *gen, inter_tree_node *ref) {
-    if (Inter::Reference::node_is_ref_to(gen->from, ref, LOOKUP_BIP)) return TRUE;
-    if (Inter::Reference::node_is_ref_to(gen->from, ref, LOOKUPBYTE_BIP)) return TRUE;
-    return FALSE;
-}
-
-int CMemoryModel::invoke_primitive(code_generation *gen, inter_ti bip, inter_tree_node *P) {
-    text_stream *OUT = CodeGen::current(gen);
-    switch (bip) {
-        case LOOKUP_BIP:     WRITE("i7_read_word(proc, "); VNODE_1C; WRITE(", "); VNODE_2C; WRITE(")");
-                             break;
-        case LOOKUPBYTE_BIP: WRITE("i7_read_byte(proc, "); VNODE_1C; WRITE(" + "); VNODE_2C; WRITE(")");
-                             break;
-        default:             return NOT_APPLICABLE;
-    }
-    return FALSE;
-}
-
diff --git a/docs/final-module/5-cnm.html b/docs/final-module/5-cnm.html index 4765aeb2d..4e030db17 100644 --- a/docs/final-module/5-cnm.html +++ b/docs/final-module/5-cnm.html @@ -110,7 +110,7 @@ sparingly in Inter, and these can never arise.

-void CNamespace::mangle(code_generator *cgt, OUTPUT_STREAM, text_stream *identifier) {
+void CNamespace::mangle(code_generator *cgt, OUTPUT_STREAM, text_stream *identifier) {
     if (Str::get_first_char(identifier) == '#') {
         WRITE("i7_ss_");
         LOOP_THROUGH_TEXT(pos, identifier)
@@ -207,17 +207,25 @@ to begin with local_}
 

§7. Constants in Inter are indeed directly converted to #defined constants in C, -but with their names of course mangled: +but with their names of course mangled. +

+ +

For the reason why Serial and Release are placed higher-up in the file, see +C Memory Model.

 void CNamespace::declare_constant(code_generator *cgt, code_generation *gen,
     inter_symbol *const_s, int form, text_stream *val) {
-    segmentation_pos saved = CodeGen::select_layered(gen, c_constants_I7CGS,
+    text_stream *name = Inter::Symbols::name(const_s);
+    int seg = c_constants_I7CGS;
+    if (Str::eq(name, I"Serial")) seg = c_ids_and_maxima_I7CGS;
+    if (Str::eq(name, I"Release")) seg = c_ids_and_maxima_I7CGS;
+    segmentation_pos saved = CodeGen::select_layered(gen, seg,
         Inter::Constant::constant_depth(const_s));
     text_stream *OUT = CodeGen::current(gen);
     WRITE("#define ");
-    CNamespace::mangle(cgt, OUT, Inter::Symbols::name(const_s));
+    CNamespace::mangle(cgt, OUT, name);
     WRITE(" ");
     VanillaConstants::definition_value(gen, form, const_s, val);
     WRITE("\n");
diff --git a/docs/final-module/5-com.html b/docs/final-module/5-com.html
index d2f704f20..a9089476b 100644
--- a/docs/final-module/5-com.html
+++ b/docs/final-module/5-com.html
@@ -151,8 +151,8 @@ function togglePopup(material_id) {
 

-    CMemoryModel::begin_array(NULL, gen, I"value_ranges", NULL, NULL, WORD_ARRAY_FORMAT, NULL);
-    CMemoryModel::array_entry(NULL, gen, I"0", WORD_ARRAY_FORMAT);
+    CMemoryModel::begin_array(NULL, gen, I"value_ranges", NULL, NULL, WORD_ARRAY_FORMAT, NULL);
+    CMemoryModel::array_entry(NULL, gen, I"0", WORD_ARRAY_FORMAT);
     inter_symbol *max_weak_id = InterSymbolsTables::url_name_to_symbol(gen->from, NULL,
         I"/main/synoptic/kinds/BASE_KIND_HWM");
     if (max_weak_id) {
@@ -166,23 +166,23 @@ function togglePopup(material_id) {
                         written = TRUE;
                         TEMPORARY_TEXT(N)
                         WRITE_TO(N, "%d", Inter::Kind::instance_count(kind_name));
-                        CMemoryModel::array_entry(NULL, gen, N, WORD_ARRAY_FORMAT);
+                        CMemoryModel::array_entry(NULL, gen, N, WORD_ARRAY_FORMAT);
                         DISCARD_TEXT(N)
                     }
                 }
             }
-            if (written == FALSE) CMemoryModel::array_entry(NULL, gen, I"0", WORD_ARRAY_FORMAT);
+            if (written == FALSE) CMemoryModel::array_entry(NULL, gen, I"0", WORD_ARRAY_FORMAT);
         }
     }
-    CMemoryModel::end_array(NULL, gen, WORD_ARRAY_FORMAT, NULL);
+    CMemoryModel::end_array(NULL, gen, WORD_ARRAY_FORMAT, NULL);
 

§1.2. Make the value property holders1.2 =

-    CMemoryModel::begin_array(NULL, gen, I"value_property_holders", NULL, NULL, WORD_ARRAY_FORMAT, NULL);
-    CMemoryModel::array_entry(NULL, gen, I"0", WORD_ARRAY_FORMAT);
+    CMemoryModel::begin_array(NULL, gen, I"value_property_holders", NULL, NULL, WORD_ARRAY_FORMAT, NULL);
+    CMemoryModel::array_entry(NULL, gen, I"0", WORD_ARRAY_FORMAT);
     inter_symbol *max_weak_id = InterSymbolsTables::url_name_to_symbol(gen->from, NULL,
         I"/main/synoptic/kinds/BASE_KIND_HWM");
     if (max_weak_id) {
@@ -196,15 +196,15 @@ function togglePopup(material_id) {
                         written = TRUE;
                         TEMPORARY_TEXT(N)
                         WRITE_TO(N, "i7_mgl_VPH_%d", w);
-                        CMemoryModel::array_entry(NULL, gen, N, WORD_ARRAY_FORMAT);
+                        CMemoryModel::array_entry(NULL, gen, N, WORD_ARRAY_FORMAT);
                         DISCARD_TEXT(N)
                     }
                 }
             }
-            if (written == FALSE) CMemoryModel::array_entry(NULL, gen, I"0", WORD_ARRAY_FORMAT);
+            if (written == FALSE) CMemoryModel::array_entry(NULL, gen, I"0", WORD_ARRAY_FORMAT);
         }
     }
-    CMemoryModel::end_array(NULL, gen, WORD_ARRAY_FORMAT, NULL);
+    CMemoryModel::end_array(NULL, gen, WORD_ARRAY_FORMAT, NULL);
 

§1.3. Owners. In this model, every class and every instance are represented by one "owner @@ -299,7 +299,7 @@ overlap. WRITE("#define I7VAL_STRINGS_BASE %d\n", C_GEN_DATA(objdata.owner_id_count) + 1); WRITE("#define I7VAL_FUNCTIONS_BASE %d\n", - C_GEN_DATA(objdata.owner_id_count) + 1 + CLiteralsModel::no_strings(gen)); + C_GEN_DATA(objdata.owner_id_count) + 1 + CLiteralsModel::no_strings(gen)); WRITE("#define i7_no_property_ids %d\n", C_GEN_DATA(objdata.property_id_counter)); CodeGen::deselect(gen, saved); @@ -822,7 +822,7 @@ the next owner is declared. CNamespace::mangle(NULL, OUT, owner->name); WRITE("].len[i7_read_word(proc, "); CNamespace::mangle(NULL, OUT, pair->prop->name); - WRITE(", 1)] = xt_%S + 1;\n", pair->val); + WRITE(", 1)] = %S__xt + 1;\n", pair->val); } else { WRITE("i7_properties["); CNamespace::mangle(NULL, OUT, owner->name); @@ -977,6 +977,7 @@ and write them.

§13.

+void i7_initialise_object_tree(i7process_t *proc);
 int i7_has(i7process_t *proc, i7word_t obj, i7word_t attr);
 int i7_provides(i7process_t *proc, i7word_t owner_id, i7word_t prop_id);
 int i7_in(i7process_t *proc, i7word_t obj1, i7word_t obj2);
@@ -1058,6 +1059,17 @@ and write them.
         proc->state.object_tree_child[to] = obj;
     }
 }
+
+void i7_initialise_object_tree(i7process_t *proc) {
+    proc->state.object_tree_parent  = i7_calloc(proc, i7_max_objects, sizeof(i7word_t));
+    proc->state.object_tree_child   = i7_calloc(proc, i7_max_objects, sizeof(i7word_t));
+    proc->state.object_tree_sibling = i7_calloc(proc, i7_max_objects, sizeof(i7word_t));
+    for (int i=0; i<i7_max_objects; i++) {
+        proc->state.object_tree_parent[i] = 0;
+        proc->state.object_tree_child[i] = 0;
+        proc->state.object_tree_sibling[i] = 0;
+    }
+}