summaryrefslogtreecommitdiff
path: root/byterun/intern.c
diff options
context:
space:
mode:
Diffstat (limited to 'byterun/intern.c')
-rw-r--r--byterun/intern.c376
1 files changed, 258 insertions, 118 deletions
diff --git a/byterun/intern.c b/byterun/intern.c
index 6411be74da..bea32b4027 100644
--- a/byterun/intern.c
+++ b/byterun/intern.c
@@ -18,6 +18,7 @@
/* The interface of this file is "intext.h" */
#include <string.h>
+#include <stdio.h>
#include "alloc.h"
#include "callback.h"
#include "custom.h"
@@ -25,6 +26,7 @@
#include "gc.h"
#include "intext.h"
#include "io.h"
+#include "md5.h"
#include "memory.h"
#include "mlvalues.h"
#include "misc.h"
@@ -68,6 +70,12 @@ static value * camlinternaloo_last_id = NULL;
/* Pointer to a reference holding the last object id.
-1 means not available (CamlinternalOO not loaded). */
+static char * intern_resolve_code_pointer(unsigned char digest[16],
+ asize_t offset);
+static void intern_bad_code_pointer(unsigned char digest[16]) Noreturn;
+
+static void intern_free_stack(void);
+
#define Sign_extend_shift ((sizeof(intnat) - 1) * 8)
#define Sign_extend(x) (((intnat)(x) << Sign_extend_shift) >> Sign_extend_shift)
@@ -114,27 +122,201 @@ static void intern_cleanup(void)
/* restore original header for heap block, otherwise GC is confused */
Hd_val(intern_block) = intern_header;
}
+ /* free the recursion stack */
+ intern_free_stack();
+}
+
+static void readfloat(double * dest, unsigned int code)
+{
+ if (sizeof(double) != 8) {
+ intern_cleanup();
+ caml_invalid_argument("input_value: non-standard floats");
+ }
+ readblock((char *) dest, 8);
+ /* Fix up endianness, if needed */
+#if ARCH_FLOAT_ENDIANNESS == 0x76543210
+ /* Host is big-endian; fix up if data read is little-endian */
+ if (code != CODE_DOUBLE_BIG) Reverse_64(dest, dest);
+#elif ARCH_FLOAT_ENDIANNESS == 0x01234567
+ /* Host is little-endian; fix up if data read is big-endian */
+ if (code != CODE_DOUBLE_LITTLE) Reverse_64(dest, dest);
+#else
+ /* Host is neither big nor little; permute as appropriate */
+ if (code == CODE_DOUBLE_LITTLE)
+ Permute_64(dest, ARCH_FLOAT_ENDIANNESS, dest, 0x01234567)
+ else
+ Permute_64(dest, ARCH_FLOAT_ENDIANNESS, dest, 0x76543210);
+#endif
+}
+
+static void readfloats(double * dest, mlsize_t len, unsigned int code)
+{
+ mlsize_t i;
+ if (sizeof(double) != 8) {
+ intern_cleanup();
+ caml_invalid_argument("input_value: non-standard floats");
+ }
+ readblock((char *) dest, len * 8);
+ /* Fix up endianness, if needed */
+#if ARCH_FLOAT_ENDIANNESS == 0x76543210
+ /* Host is big-endian; fix up if data read is little-endian */
+ if (code != CODE_DOUBLE_ARRAY8_BIG &&
+ code != CODE_DOUBLE_ARRAY32_BIG) {
+ for (i = 0; i < len; i++) Reverse_64(dest + i, dest + i);
+ }
+#elif ARCH_FLOAT_ENDIANNESS == 0x01234567
+ /* Host is little-endian; fix up if data read is big-endian */
+ if (code != CODE_DOUBLE_ARRAY8_LITTLE &&
+ code != CODE_DOUBLE_ARRAY32_LITTLE) {
+ for (i = 0; i < len; i++) Reverse_64(dest + i, dest + i);
+ }
+#else
+ /* Host is neither big nor little; permute as appropriate */
+ if (code == CODE_DOUBLE_ARRAY8_LITTLE ||
+ code == CODE_DOUBLE_ARRAY32_LITTLE) {
+ for (i = 0; i < len; i++)
+ Permute_64(dest + i, ARCH_FLOAT_ENDIANNESS, dest + i, 0x01234567);
+ } else {
+ for (i = 0; i < len; i++)
+ Permute_64(dest + i, ARCH_FLOAT_ENDIANNESS, dest + i, 0x76543210);
+ }
+#endif
}
-void caml_intern_cleanup(void) {
- intern_cleanup() ;
+/* Item on the stack with defined operation */
+struct intern_item {
+ value * dest;
+ intnat arg;
+ enum {
+ OReadItems, /* read arg items and store them in dest[0], dest[1], ... */
+ OFreshOID, /* generate a fresh OID and store it in *dest */
+ OShift /* offset *dest by arg */
+ } op;
+};
+
+/* FIXME: This is duplicated in two other places, with the only difference of
+ the type of elements stored in the stack. Possible solution in C would
+ be to instantiate stack these function via. C preprocessor macro.
+ */
+
+#define INTERN_STACK_INIT_SIZE 256
+#define INTERN_STACK_MAX_SIZE (1024*1024*100)
+
+static struct intern_item intern_stack_init[INTERN_STACK_INIT_SIZE];
+
+static struct intern_item * intern_stack = intern_stack_init;
+static struct intern_item * intern_stack_limit = intern_stack_init
+ + INTERN_STACK_INIT_SIZE;
+
+/* Free the recursion stack if needed */
+static void intern_free_stack(void)
+{
+ if (intern_stack != intern_stack_init) {
+ free(intern_stack);
+ /* Reinitialize the globals for next time around */
+ intern_stack = intern_stack_init;
+ intern_stack_limit = intern_stack + INTERN_STACK_INIT_SIZE;
+ }
}
+/* Same, then raise Out_of_memory */
+static void intern_stack_overflow(void)
+{
+ caml_gc_message (0x04, "Stack overflow in un-marshaling value\n", 0);
+ intern_free_stack();
+ caml_raise_out_of_memory();
+}
+
+static struct intern_item * intern_resize_stack(struct intern_item * sp)
+{
+ asize_t newsize = 2 * (intern_stack_limit - intern_stack);
+ asize_t sp_offset = sp - intern_stack;
+ struct intern_item * newstack;
+
+ if (newsize >= INTERN_STACK_MAX_SIZE) intern_stack_overflow();
+ if (intern_stack == intern_stack_init) {
+ newstack = malloc(sizeof(struct intern_item) * newsize);
+ if (newstack == NULL) intern_stack_overflow();
+ memcpy(newstack, intern_stack_init,
+ sizeof(struct intern_item) * INTERN_STACK_INIT_SIZE);
+ } else {
+ newstack =
+ realloc(intern_stack, sizeof(struct intern_item) * newsize);
+ if (newstack == NULL) intern_stack_overflow();
+ }
+ intern_stack = newstack;
+ intern_stack_limit = newstack + newsize;
+ return newstack + sp_offset;
+}
+
+/* Convenience macros for requesting operation on the stack */
+#define PushItem() \
+ do { \
+ sp++; \
+ if (sp >= intern_stack_limit) sp = intern_resize_stack(sp); \
+ } while(0)
+
+#define ReadItems(_dest,_n) \
+ do { \
+ if (_n > 0) { \
+ PushItem(); \
+ sp->op = OReadItems; \
+ sp->dest = _dest; \
+ sp->arg = _n; \
+ } \
+ } while(0)
+
+
static void intern_rec(value *dest)
{
unsigned int code;
tag_t tag;
mlsize_t size, len, ofs_ind;
- value v, clos;
+ value v;
asize_t ofs;
header_t header;
- char cksum[16];
+ unsigned char digest[16];
struct custom_operations * ops;
- value * function_placeholder;
- int get_function_placeholder;
-
- get_function_placeholder = 1;
- tailcall:
+ char * codeptr;
+ struct intern_item * sp;
+
+ sp = intern_stack;
+
+ /* Initially let's try to read the first object from the stream */
+ ReadItems(dest, 1);
+
+ /* The un-marshaler loop, the recursion is unrolled */
+ while(sp != intern_stack) {
+
+ /* Interpret next item on the stack */
+ dest = sp->dest;
+ switch (sp->op) {
+ case OFreshOID:
+ /* Refresh the object ID */
+ if (camlinternaloo_last_id == NULL) {
+ camlinternaloo_last_id = caml_named_value("CamlinternalOO.last_id");
+ if (camlinternaloo_last_id == NULL)
+ camlinternaloo_last_id = (value*) (-1);
+ }
+ if (camlinternaloo_last_id != (value*) (-1)) {
+ value id = Field(*camlinternaloo_last_id,0);
+ Field(dest, 0) = id;
+ Field(*camlinternaloo_last_id,0) = id + 2;
+ }
+ /* Pop item and iterate */
+ sp--;
+ break;
+ case OShift:
+ /* Shift value by an offset */
+ *dest += sp->arg;
+ /* Pop item and iterate */
+ sp--;
+ break;
+ case OReadItems:
+ /* Pop item */
+ sp->dest++;
+ if (--(sp->arg) == 0) sp--;
+ /* Read a value and set v to this value */
code = read8u();
if (code >= PREFIX_SMALL_INT) {
if (code >= PREFIX_SMALL_BLOCK) {
@@ -146,30 +328,24 @@ static void intern_rec(value *dest)
v = Atom(tag);
} else {
v = Val_hp(intern_dest);
- *dest = v;
if (intern_obj_table != NULL) intern_obj_table[obj_counter++] = v;
- dest = (value *) (intern_dest + 1);
*intern_dest = Make_header(size, tag, intern_color);
intern_dest += 1 + size;
/* For objects, we need to freshen the oid */
- if (tag == Object_tag && camlinternaloo_last_id != (value*)-1) {
- intern_rec(dest++);
- intern_rec(dest++);
- if (camlinternaloo_last_id == NULL)
- camlinternaloo_last_id = caml_named_value("CamlinternalOO.last_id");
- if (camlinternaloo_last_id == NULL)
- camlinternaloo_last_id = (value*)-1;
- else {
- value id = Field(*camlinternaloo_last_id,0);
- Field(dest,-1) = id;
- Field(*camlinternaloo_last_id,0) = id + 2;
- }
- size -= 2;
- if (size == 0) return;
- }
- for(/*nothing*/; size > 1; size--, dest++)
- intern_rec(dest);
- goto tailcall;
+ if (tag == Object_tag) {
+ Assert(size >= 2);
+ /* Request to read rest of the elements of the block */
+ ReadItems(&Field(v, 2), size - 2);
+ /* Request freshing OID */
+ PushItem();
+ sp->op = OFreshOID;
+ sp->dest = &Field(v, 1);
+ sp->arg = 1;
+ /* Finally read first two block elements: method table and old OID */
+ ReadItems(&Field(v, 0), 2);
+ } else
+ /* If it's not an object then read the contents of the block */
+ ReadItems(&Field(v, 0), size);
}
} else {
/* Small integer */
@@ -248,68 +424,22 @@ static void intern_rec(value *dest)
goto read_string;
case CODE_DOUBLE_LITTLE:
case CODE_DOUBLE_BIG:
- if (sizeof(double) != 8) {
- intern_cleanup();
- caml_invalid_argument("input_value: non-standard floats");
- }
v = Val_hp(intern_dest);
if (intern_obj_table != NULL) intern_obj_table[obj_counter++] = v;
*intern_dest = Make_header(Double_wosize, Double_tag, intern_color);
intern_dest += 1 + Double_wosize;
- readblock((char *) v, 8);
-#if ARCH_FLOAT_ENDIANNESS == 0x76543210
- if (code != CODE_DOUBLE_BIG) Reverse_64(v, v);
-#elif ARCH_FLOAT_ENDIANNESS == 0x01234567
- if (code != CODE_DOUBLE_LITTLE) Reverse_64(v, v);
-#else
- if (code == CODE_DOUBLE_LITTLE)
- Permute_64(v, ARCH_FLOAT_ENDIANNESS, v, 0x01234567)
- else
- Permute_64(v, ARCH_FLOAT_ENDIANNESS, v, 0x76543210);
-#endif
+ readfloat((double *) v, code);
break;
case CODE_DOUBLE_ARRAY8_LITTLE:
case CODE_DOUBLE_ARRAY8_BIG:
len = read8u();
read_double_array:
- if (sizeof(double) != 8) {
- intern_cleanup();
- caml_invalid_argument("input_value: non-standard floats");
- }
size = len * Double_wosize;
v = Val_hp(intern_dest);
if (intern_obj_table != NULL) intern_obj_table[obj_counter++] = v;
*intern_dest = Make_header(size, Double_array_tag, intern_color);
intern_dest += 1 + size;
- readblock((char *) v, len * 8);
-#if ARCH_FLOAT_ENDIANNESS == 0x76543210
- if (code != CODE_DOUBLE_ARRAY8_BIG &&
- code != CODE_DOUBLE_ARRAY32_BIG) {
- mlsize_t i;
- for (i = 0; i < len; i++) Reverse_64((value)((double *)v + i),
- (value)((double *)v + i));
- }
-#elif ARCH_FLOAT_ENDIANNESS == 0x01234567
- if (code != CODE_DOUBLE_ARRAY8_LITTLE &&
- code != CODE_DOUBLE_ARRAY32_LITTLE) {
- mlsize_t i;
- for (i = 0; i < len; i++) Reverse_64((value)((double *)v + i),
- (value)((double *)v + i));
- }
-#else
- if (code == CODE_DOUBLE_ARRAY8_LITTLE ||
- code == CODE_DOUBLE_ARRAY32_LITTLE) {
- mlsize_t i;
- for (i = 0; i < len; i++)
- Permute_64((value)((double *)v + i), ARCH_FLOAT_ENDIANNESS,
- (value)((double *)v + i), 0x01234567);
- } else {
- mlsize_t i;
- for (i = 0; i < len; i++)
- Permute_64((value)((double *)v + i), ARCH_FLOAT_ENDIANNESS,
- (value)((double *)v + i), 0x76543210);
- }
-#endif
+ readfloats((double *) v, len, code);
break;
case CODE_DOUBLE_ARRAY32_LITTLE:
case CODE_DOUBLE_ARRAY32_BIG:
@@ -317,21 +447,20 @@ static void intern_rec(value *dest)
goto read_double_array;
case CODE_CODEPOINTER:
ofs = read32u();
- readblock(cksum, 16);
- if (memcmp(cksum, caml_code_checksum(), 16) != 0) {
- if (get_function_placeholder) {
- function_placeholder =
- caml_named_value ("Debugger.function_placeholder");
- get_function_placeholder = 0;
- }
+ readblock(digest, 16);
+ codeptr = intern_resolve_code_pointer(digest, ofs);
+ if (codeptr != NULL) {
+ v = (value) codeptr;
+ } else {
+ value * function_placeholder =
+ caml_named_value ("Debugger.function_placeholder");
if (function_placeholder != NULL) {
v = *function_placeholder;
- break;
+ } else {
+ intern_cleanup();
+ intern_bad_code_pointer(digest);
}
- intern_cleanup();
- caml_failwith("input_value: code mismatch");
}
- v = (value) (caml_code_area_start + ofs);
break;
/*>JOCAML*/
case CODE_SAVEDCODE:
@@ -356,9 +485,13 @@ static void intern_rec(value *dest)
/*<JOCAML*/
case CODE_INFIXPOINTER:
ofs = read32u();
- intern_rec(&clos);
- v = clos + ofs;
- break;
+ /* Read a value to *dest, then offset *dest by ofs */
+ PushItem();
+ sp->dest = dest;
+ sp->op = OShift;
+ sp->arg = ofs;
+ ReadItems(dest, 1);
+ continue; /* with next iteration of main loop, skipping *dest = v */
case CODE_CUSTOM:
/*>JOCAML*/
custom_tag = Custom_tag ;
@@ -386,8 +519,16 @@ static void intern_rec(value *dest)
caml_failwith("input_value: ill-formed message");
}
}
- }
+ }
+ /* end of case OReadItems */
*dest = v;
+ break;
+ default:
+ Assert(0);
+ }
+ }
+ /* We are done. Cleanup the stack and leave the function */
+ intern_free_stack();
}
static void intern_alloc(mlsize_t whsize, mlsize_t num_objects)
@@ -619,40 +760,39 @@ CAMLprim value caml_marshal_data_size(value buff, value ofs)
return Val_long(block_len);
}
-/* Return an MD5 checksum of the code area */
-
-#ifdef NATIVE_CODE
-
-#include "md5.h"
+/* Resolution of code pointers */
-unsigned char * caml_code_checksum(void)
+static char * intern_resolve_code_pointer(unsigned char digest[16],
+ asize_t offset)
{
- static unsigned char checksum[16];
- static int checksum_computed = 0;
-
- if (! checksum_computed) {
- struct MD5Context ctx;
- caml_MD5Init(&ctx);
- caml_MD5Update(&ctx,
- (unsigned char *) caml_code_area_start,
- caml_code_area_end - caml_code_area_start);
- caml_MD5Final(checksum, &ctx);
- checksum_computed = 1;
+ int i;
+ for (i = caml_code_fragments_table.size - 1; i >= 0; i--) {
+ struct code_fragment * cf = caml_code_fragments_table.contents[i];
+ if (! cf->digest_computed) {
+ caml_md5_block(cf->digest, cf->code_start, cf->code_end - cf->code_start);
+ cf->digest_computed = 1;
+ }
+ if (memcmp(digest, cf->digest, 16) == 0) {
+ if (cf->code_start + offset < cf->code_end)
+ return cf->code_start + offset;
+ else
+ return NULL;
+ }
}
- return checksum;
+ return NULL;
}
-#else
-
-#include "fix_code.h"
-
-unsigned char * caml_code_checksum(void)
+static void intern_bad_code_pointer(unsigned char digest[16])
{
- return caml_code_md5;
+ char msg[256];
+ sprintf(msg, "input_value: unknown code module %02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X",
+ digest[0], digest[1], digest[2], digest[3],
+ digest[4], digest[5], digest[6], digest[7],
+ digest[8], digest[9], digest[10], digest[11],
+ digest[12], digest[13], digest[14], digest[15]);
+ caml_failwith(msg);
}
-#endif
-
/* Functions for writing user-defined marshallers */
CAMLexport int caml_deserialize_uint_1(void)