diff options
Diffstat (limited to 'byterun/extern.c')
-rw-r--r-- | byterun/extern.c | 206 |
1 files changed, 124 insertions, 82 deletions
diff --git a/byterun/extern.c b/byterun/extern.c index 94a930d0a..12530c1c3 100644 --- a/byterun/extern.c +++ b/byterun/extern.c @@ -34,9 +34,10 @@ struct extern_obj { value obj; }; -static byteoffset_t initial_ofs = 1; +static byteoffset_t initial_ofs = 1; /* Initial value of object offsets */ static struct extern_obj * extern_table = NULL; static unsigned long extern_table_size; +static byteoffset_t obj_counter; /* Number of objects emitted so far */ #ifdef ARCH_SIXTYFOUR #define Hash(v) (((unsigned long) ((v) >> 3)) % extern_table_size) @@ -97,12 +98,14 @@ static void free_extern_table() /* To buffer the output */ static char * extern_block, * extern_ptr, * extern_limit; +static int extern_block_malloced; static void alloc_extern_block() { extern_block = stat_alloc(INITIAL_EXTERN_BLOCK_SIZE); extern_limit = extern_block + INITIAL_EXTERN_BLOCK_SIZE; extern_ptr = extern_block; + extern_block_malloced = 1; } static void resize_extern_block(required) @@ -110,6 +113,11 @@ static void resize_extern_block(required) { long curr_pos, size, reqd_size; + if (! extern_block_malloced) { + initial_ofs += obj_counter; + free_extern_table(); + failwith("Marshal.to_buffer: buffer overflow"); + } curr_pos = extern_ptr - extern_block; size = extern_limit - extern_block; reqd_size = curr_pos + required; @@ -119,12 +127,12 @@ static void resize_extern_block(required) extern_ptr = extern_block + curr_pos; } +/* Write characters, integers, and blocks in the output buffer */ + #define Write(c) \ if (extern_ptr >= extern_limit) resize_extern_block(1); \ *extern_ptr++ = (c) -/* Write integers and blocks in the output buffer */ - static void writeblock(data, len) char * data; long len; @@ -193,14 +201,16 @@ static void writecode64(code, val) /* Marshal the given value in the output buffer */ -static byteoffset_t obj_counter; /* Number of objects emitted so far */ static unsigned long size_32; /* Size in words of 32-bit block for struct. */ static unsigned long size_64; /* Size in words of 64-bit block for struct. */ +static int extern_ignore_sharing; /* Flag to ignore sharing */ +static int extern_closures; /* Flag to allow externing code pointers */ + static void extern_invalid_argument(msg) char * msg; { - stat_free(extern_block); + if (extern_block_malloced) stat_free(extern_block); initial_ofs += obj_counter; free_extern_table(); invalid_argument(msg); @@ -224,9 +234,9 @@ static void extern_rec(v) #endif } else writecode32(CODE_INT32, n); - } else if (!Is_atom(v) && !Is_young(v) && !Is_in_heap(v)) { - extern_invalid_argument("output_value: abstract value"); - } else { + return; + } + if (Is_young(v) || Is_in_heap(v) || Is_atom(v)) { header_t hd = Hd_val(v); tag_t tag = Tag_hd(hd); mlsize_t sz = Wosize_hd(hd); @@ -239,8 +249,10 @@ static void extern_rec(v) } else { writecode32(CODE_BLOCK32, hd); } - } else { - /* Check if already seen */ + return; + } + /* Check if already seen */ + if (! extern_ignore_sharing) { if (2 * obj_counter >= extern_table_size) resize_extern_table(); h = Hash(v); while (extern_table[h].ofs >= initial_ofs) { @@ -258,85 +270,100 @@ static void extern_rec(v) h++; if (h >= extern_table_size) h = 0; } - /* Not seen yet. Record the object and output its contents. */ + /* Not seen yet. Record the object */ extern_table[h].ofs = initial_ofs + obj_counter; extern_table[h].obj = v; obj_counter++; - switch(tag) { - case String_tag: { - mlsize_t len = string_length(v); - if (len < 0x20) { - Write(PREFIX_SMALL_STRING + len); - } else if (len < 0x100) { - writecode8(CODE_STRING8, len); - } else { - writecode32(CODE_STRING32, len); - } - writeblock(String_val(v), len); - size_32 += 1 + (len + 4) / 4; - size_64 += 1 + (len + 8) / 8; - break; - } - case Double_tag: { - if (sizeof(double) != 8) - extern_invalid_argument("output_value: non-standard floats"); - Write(CODE_DOUBLE_NATIVE); - writeblock((char *) v, 8); - size_32 += 1 + 2; - size_64 += 1 + 1; - break; + } + /* Output the contents of the object */ + switch(tag) { + case String_tag: { + mlsize_t len = string_length(v); + if (len < 0x20) { + Write(PREFIX_SMALL_STRING + len); + } else if (len < 0x100) { + writecode8(CODE_STRING8, len); + } else { + writecode32(CODE_STRING32, len); } - case Double_array_tag: { - mlsize_t nfloats; - if (sizeof(double) != 8) - extern_invalid_argument("output_value: non-standard floats"); - nfloats = Wosize_val(v) / Double_wosize; - if (nfloats < 0x100) { - writecode8(CODE_DOUBLE_ARRAY8_NATIVE, nfloats); - } else { - writecode32(CODE_DOUBLE_ARRAY32_NATIVE, nfloats); - } - writeblock((char *) v, Bosize_val(v)); - size_32 += 1 + nfloats * 2; - size_64 += 1 + nfloats; - break; + writeblock(String_val(v), len); + size_32 += 1 + (len + 4) / 4; + size_64 += 1 + (len + 8) / 8; + break; + } + case Double_tag: { + if (sizeof(double) != 8) + extern_invalid_argument("output_value: non-standard floats"); + Write(CODE_DOUBLE_NATIVE); + writeblock((char *) v, 8); + size_32 += 1 + 2; + size_64 += 1 + 1; + break; + } + case Double_array_tag: { + mlsize_t nfloats; + if (sizeof(double) != 8) + extern_invalid_argument("output_value: non-standard floats"); + nfloats = Wosize_val(v) / Double_wosize; + if (nfloats < 0x100) { + writecode8(CODE_DOUBLE_ARRAY8_NATIVE, nfloats); + } else { + writecode32(CODE_DOUBLE_ARRAY32_NATIVE, nfloats); } - case Abstract_tag: - case Final_tag: - extern_invalid_argument("output_value: abstract value"); - break; - case Closure_tag: - case Infix_tag: - extern_invalid_argument("output_value: functional value"); - break; - case Object_tag: - extern_invalid_argument("output_value: object value"); - break; - default: { - mlsize_t i; - if (tag < 16 && sz < 8) { - Write(PREFIX_SMALL_BLOCK + tag + (sz << 4)); - } else { - writecode32(CODE_BLOCK32, hd & ~Black); - } - size_32 += 1 + sz; - size_64 += 1 + sz; - for (i = 0; i < sz - 1; i++) extern_rec(Field(v, i)); - v = Field(v, i); - goto tailcall; + writeblock((char *) v, Bosize_val(v)); + size_32 += 1 + nfloats * 2; + size_64 += 1 + nfloats; + break; + } + case Abstract_tag: + case Final_tag: + extern_invalid_argument("output_value: abstract value"); + break; + case Infix_tag: + writecode32(CODE_INFIXPOINTER, Infix_offset_hd(hd)); + extern_rec(v - Infix_offset_hd(hd)); + break; + case Object_tag: + extern_invalid_argument("output_value: object value"); + break; + default: { + mlsize_t i; + if (tag < 16 && sz < 8) { + Write(PREFIX_SMALL_BLOCK + tag + (sz << 4)); + } else { + writecode32(CODE_BLOCK32, hd & ~Black); } + size_32 += 1 + sz; + size_64 += 1 + sz; + for (i = 0; i < sz - 1; i++) extern_rec(Field(v, i)); + v = Field(v, i); + goto tailcall; } } + return; } + if ((char *) v >= code_area_start && (char *) v < code_area_end) { + if (!extern_closures) + extern_invalid_argument("output_value: functional value"); + writecode32(CODE_CODEPOINTER, (char *) v - code_area_start); + writeblock(code_checksum(), 16); + return; + } + extern_invalid_argument("output_value: abstract value"); } -static long extern_value(v) - value v; +enum { NO_SHARING = 1, CLOSURES = 2 }; +static int extern_flags[] = { NO_SHARING, CLOSURES }; + +static long extern_value(v, flags) + value v, flags; { long res_len; - - /* Allocate buffer for holding the result */ - alloc_extern_block(); + int fl; + /* Parse flag list */ + fl = convert_flag_list(flags, extern_flags); + extern_ignore_sharing = fl & NO_SHARING; + extern_closures = fl & CLOSURES; /* Allocate hashtable of objects already seen, if needed */ extern_table_size = INITIAL_EXTERN_TABLE_SIZE; if (extern_table == NULL) { @@ -376,25 +403,40 @@ static long extern_value(v) return res_len; } -value output_value(chan, v) /* ML */ +value output_value(chan, v, flags) /* ML */ struct channel * chan; - value v; + value v, flags; { long len; - len = extern_value(v); + alloc_extern_block(); + len = extern_value(v, flags); really_putblock(chan, extern_block, len); stat_free(extern_block); return Val_unit; } -value output_value_to_string(v) /* ML */ - value v; +value output_value_to_string(v, flags) /* ML */ + value v, flags; { long len; value res; - len = extern_value(v); + alloc_extern_block(); + len = extern_value(v, flags); res = alloc_string(len); bcopy(extern_block, String_val(res), len); stat_free(extern_block); return res; } + +value output_value_to_buffer(buf, ofs, len, v, flags) /* ML */ + value buf, ofs, len, v, flags; +{ + long len_res; + extern_block = &Byte(buf, Long_val(ofs)); + extern_limit = extern_block + Long_val(len); + extern_ptr = extern_block; + extern_block_malloced = 0; + len_res = extern_value(v, flags); + return Val_long(len_res); +} + |