1 /***********************************************************************/
5 /* Xavier Leroy, projet Cristal, INRIA Rocquencourt */
7 /* Copyright 1996 Institut National de Recherche en Informatique et */
8 /* en Automatique. All rights reserved. This file is distributed */
9 /* under the terms of the GNU Library General Public License, with */
10 /* the special exception on linking described in file ../LICENSE. */
12 /***********************************************************************/
14 /* $Id: intern.c 8768 2008-01-11 16:13:18Z doligez $ */
16 /* Structured input, compact format */
18 /* The interface of this file is "intext.h" */
32 static unsigned char * intern_src;
33 /* Reading pointer in block holding input data. */
35 static unsigned char * intern_input;
36 /* Pointer to beginning of block holding input data.
37 Meaningful only if intern_input_malloced = 1. */
39 static int intern_input_malloced;
40 /* 1 if intern_input was allocated by caml_stat_alloc()
41 and needs caml_stat_free() on error, 0 otherwise. */
43 static header_t * intern_dest;
44 /* Writing pointer in destination block */
46 static char * intern_extra_block;
47 /* If non-NULL, point to new heap chunk allocated with caml_alloc_for_heap. */
49 static asize_t obj_counter;
50 /* Count how many objects seen so far */
52 static value * intern_obj_table;
53 /* The pointers to objects already seen */
55 static unsigned int intern_color;
56 /* Color to assign to newly created headers */
58 static header_t intern_header;
59 /* Original header of the destination block.
60 Meaningful only if intern_extra_block is NULL. */
62 static value intern_block;
63 /* Point to the heap block allocated as destination block.
64 Meaningful only if intern_extra_block is NULL. */
66 #define Sign_extend_shift ((sizeof(intnat) - 1) * 8)
67 #define Sign_extend(x) (((intnat)(x) << Sign_extend_shift) >> Sign_extend_shift)
69 #define read8u() (*intern_src++)
70 #define read8s() Sign_extend(*intern_src++)
73 (intern_src[-2] << 8) + intern_src[-1])
76 (Sign_extend(intern_src[-2]) << 8) + intern_src[-1])
79 ((uintnat)(intern_src[-4]) << 24) + (intern_src[-3] << 16) + \
80 (intern_src[-2] << 8) + intern_src[-1])
83 (Sign_extend(intern_src[-4]) << 24) + (intern_src[-3] << 16) + \
84 (intern_src[-2] << 8) + intern_src[-1])
87 static intnat read64s(void)
92 for (i = 0; i < 8; i++) res = (res << 8) + intern_src[i];
98 #define readblock(dest,len) \
99 (memmove((dest), intern_src, (len)), intern_src += (len))
101 static void intern_cleanup(void)
103 if (intern_input_malloced) caml_stat_free(intern_input);
104 if (intern_obj_table != NULL) caml_stat_free(intern_obj_table);
105 if (intern_extra_block != NULL) {
106 /* free newly allocated heap chunk */
107 caml_free_for_heap(intern_extra_block);
108 } else if (intern_block != 0) {
109 /* restore original header for heap block, otherwise GC is confused */
110 Hd_val(intern_block) = intern_header;
114 static void intern_rec(value *dest)
118 mlsize_t size, len, ofs_ind;
123 struct custom_operations * ops;
127 if (code >= PREFIX_SMALL_INT) {
128 if (code >= PREFIX_SMALL_BLOCK) {
131 size = (code >> 4) & 0x7;
136 v = Val_hp(intern_dest);
138 if (intern_obj_table != NULL) intern_obj_table[obj_counter++] = v;
139 dest = (value *) (intern_dest + 1);
140 *intern_dest = Make_header(size, tag, intern_color);
141 intern_dest += 1 + size;
142 for(/*nothing*/; size > 1; size--, dest++)
148 v = Val_int(code & 0x3F);
151 if (code >= PREFIX_SMALL_STRING) {
155 size = (len + sizeof(value)) / sizeof(value);
156 v = Val_hp(intern_dest);
157 if (intern_obj_table != NULL) intern_obj_table[obj_counter++] = v;
158 *intern_dest = Make_header(size, String_tag, intern_color);
159 intern_dest += 1 + size;
160 Field(v, size - 1) = 0;
161 ofs_ind = Bsize_wsize(size) - 1;
162 Byte(v, ofs_ind) = ofs_ind - len;
163 readblock(String_val(v), len);
167 v = Val_long(read8s());
170 v = Val_long(read16s());
173 v = Val_long(read32s());
176 #ifdef ARCH_SIXTYFOUR
177 v = Val_long(read64s());
181 caml_failwith("input_value: integer too large");
188 Assert (ofs <= obj_counter);
189 Assert (intern_obj_table != NULL);
190 v = intern_obj_table[obj_counter - ofs];
199 header = (header_t) read32u();
200 tag = Tag_hd(header);
201 size = Wosize_hd(header);
204 #ifdef ARCH_SIXTYFOUR
205 header = (header_t) read64s();
206 tag = Tag_hd(header);
207 size = Wosize_hd(header);
211 caml_failwith("input_value: data block too large");
220 case CODE_DOUBLE_LITTLE:
221 case CODE_DOUBLE_BIG:
222 if (sizeof(double) != 8) {
224 caml_invalid_argument("input_value: non-standard floats");
226 v = Val_hp(intern_dest);
227 if (intern_obj_table != NULL) intern_obj_table[obj_counter++] = v;
228 *intern_dest = Make_header(Double_wosize, Double_tag, intern_color);
229 intern_dest += 1 + Double_wosize;
230 readblock((char *) v, 8);
231 #if ARCH_FLOAT_ENDIANNESS == 0x76543210
232 if (code != CODE_DOUBLE_BIG) Reverse_64(v, v);
233 #elif ARCH_FLOAT_ENDIANNESS == 0x01234567
234 if (code != CODE_DOUBLE_LITTLE) Reverse_64(v, v);
236 if (code == CODE_DOUBLE_LITTLE)
237 Permute_64(v, ARCH_FLOAT_ENDIANNESS, v, 0x01234567)
239 Permute_64(v, ARCH_FLOAT_ENDIANNESS, v, 0x76543210);
242 case CODE_DOUBLE_ARRAY8_LITTLE:
243 case CODE_DOUBLE_ARRAY8_BIG:
246 if (sizeof(double) != 8) {
248 caml_invalid_argument("input_value: non-standard floats");
250 size = len * Double_wosize;
251 v = Val_hp(intern_dest);
252 if (intern_obj_table != NULL) intern_obj_table[obj_counter++] = v;
253 *intern_dest = Make_header(size, Double_array_tag, intern_color);
254 intern_dest += 1 + size;
255 readblock((char *) v, len * 8);
256 #if ARCH_FLOAT_ENDIANNESS == 0x76543210
257 if (code != CODE_DOUBLE_ARRAY8_BIG &&
258 code != CODE_DOUBLE_ARRAY32_BIG) {
260 for (i = 0; i < len; i++) Reverse_64((value)((double *)v + i),
261 (value)((double *)v + i));
263 #elif ARCH_FLOAT_ENDIANNESS == 0x01234567
264 if (code != CODE_DOUBLE_ARRAY8_LITTLE &&
265 code != CODE_DOUBLE_ARRAY32_LITTLE) {
267 for (i = 0; i < len; i++) Reverse_64((value)((double *)v + i),
268 (value)((double *)v + i));
271 if (code == CODE_DOUBLE_ARRAY8_LITTLE ||
272 code == CODE_DOUBLE_ARRAY32_LITTLE) {
274 for (i = 0; i < len; i++)
275 Permute_64((value)((double *)v + i), ARCH_FLOAT_ENDIANNESS,
276 (value)((double *)v + i), 0x01234567);
279 for (i = 0; i < len; i++)
280 Permute_64((value)((double *)v + i), ARCH_FLOAT_ENDIANNESS,
281 (value)((double *)v + i), 0x76543210);
285 case CODE_DOUBLE_ARRAY32_LITTLE:
286 case CODE_DOUBLE_ARRAY32_BIG:
288 goto read_double_array;
289 case CODE_CODEPOINTER:
291 readblock(cksum, 16);
292 if (memcmp(cksum, caml_code_checksum(), 16) != 0) {
294 caml_failwith("input_value: code mismatch");
296 v = (value) (caml_code_area_start + ofs);
298 case CODE_INFIXPOINTER:
304 ops = caml_find_custom_operations((char *) intern_src);
307 caml_failwith("input_value: unknown custom block identifier");
309 while (*intern_src++ != 0) /*nothing*/; /*skip identifier*/
310 size = ops->deserialize((void *) (intern_dest + 2));
311 size = 1 + (size + sizeof(value) - 1) / sizeof(value);
312 v = Val_hp(intern_dest);
313 if (intern_obj_table != NULL) intern_obj_table[obj_counter++] = v;
314 *intern_dest = Make_header(size, Custom_tag, intern_color);
315 Custom_ops_val(v) = ops;
316 intern_dest += 1 + size;
320 caml_failwith("input_value: ill-formed message");
327 static void intern_alloc(mlsize_t whsize, mlsize_t num_objects)
332 intern_obj_table = NULL;
333 intern_extra_block = NULL;
337 wosize = Wosize_whsize(whsize);
338 if (wosize > Max_wosize) {
339 /* Round desired size up to next page */
341 ((Bsize_wsize(whsize) + Page_size - 1) >> Page_log) << Page_log;
342 intern_extra_block = caml_alloc_for_heap(request);
343 if (intern_extra_block == NULL) caml_raise_out_of_memory();
344 intern_color = caml_allocation_color(intern_extra_block);
345 intern_dest = (header_t *) intern_extra_block;
347 /* this is a specialised version of caml_alloc from alloc.c */
349 intern_block = Atom (String_tag);
350 }else if (wosize <= Max_young_wosize){
351 intern_block = caml_alloc_small (wosize, String_tag);
353 intern_block = caml_alloc_shr (wosize, String_tag);
354 /* do not do the urgent_gc check here because it might darken
355 intern_block into gray and break the Assert 3 lines down */
357 intern_header = Hd_val(intern_block);
358 intern_color = Color_hd(intern_header);
359 Assert (intern_color == Caml_white || intern_color == Caml_black);
360 intern_dest = (header_t *) Hp_val(intern_block);
361 intern_extra_block = NULL;
365 intern_obj_table = (value *) caml_stat_alloc(num_objects * sizeof(value));
367 intern_obj_table = NULL;
370 static void intern_add_to_heap(mlsize_t whsize)
372 /* Add new heap chunk to heap if needed */
373 if (intern_extra_block != NULL) {
374 /* If heap chunk not filled totally, build free block at end */
376 ((Bsize_wsize(whsize) + Page_size - 1) >> Page_log) << Page_log;
377 header_t * end_extra_block =
378 (header_t *) intern_extra_block + Wsize_bsize(request);
379 Assert(intern_dest <= end_extra_block);
380 if (intern_dest < end_extra_block){
381 caml_make_free_blocks ((value *) intern_dest,
382 end_extra_block - intern_dest, 0);
384 caml_allocated_words +=
385 Wsize_bsize ((char *) intern_dest - intern_extra_block);
386 caml_add_to_heap(intern_extra_block);
390 value caml_input_val(struct channel *chan)
393 mlsize_t block_len, num_objects, size_32, size_64, whsize;
397 if (! caml_channel_binary_mode(chan))
398 caml_failwith("input_value: not a binary channel");
399 magic = caml_getword(chan);
400 if (magic != Intext_magic_number) caml_failwith("input_value: bad object");
401 block_len = caml_getword(chan);
402 num_objects = caml_getword(chan);
403 size_32 = caml_getword(chan);
404 size_64 = caml_getword(chan);
405 /* Read block from channel */
406 block = caml_stat_alloc(block_len);
407 /* During [caml_really_getblock], concurrent [caml_input_val] operations
408 can take place (via signal handlers or context switching in systhreads),
409 and [intern_input] may change. So, wait until [caml_really_getblock]
410 is over before using [intern_input] and the other global vars. */
411 if (caml_really_getblock(chan, block, block_len) == 0) {
412 caml_stat_free(block);
413 caml_failwith("input_value: truncated object");
415 intern_input = (unsigned char *) block;
416 intern_input_malloced = 1;
417 intern_src = intern_input;
418 /* Allocate result */
419 #ifdef ARCH_SIXTYFOUR
424 intern_alloc(whsize, num_objects);
427 intern_add_to_heap(whsize);
428 /* Free everything */
429 caml_stat_free(intern_input);
430 if (intern_obj_table != NULL) caml_stat_free(intern_obj_table);
434 CAMLprim value caml_input_value(value vchan)
437 struct channel * chan = Channel(vchan);
441 res = caml_input_val(chan);
446 CAMLexport value caml_input_val_from_string(value str, intnat ofs)
449 mlsize_t num_objects, size_32, size_64, whsize;
452 intern_src = &Byte_u(str, ofs + 2*4);
453 intern_input_malloced = 0;
454 num_objects = read32u();
457 /* Allocate result */
458 #ifdef ARCH_SIXTYFOUR
463 intern_alloc(whsize, num_objects);
464 intern_src = &Byte_u(str, ofs + 5*4); /* If a GC occurred */
467 intern_add_to_heap(whsize);
468 /* Free everything */
469 if (intern_obj_table != NULL) caml_stat_free(intern_obj_table);
473 CAMLprim value caml_input_value_from_string(value str, value ofs)
475 return caml_input_val_from_string(str, Long_val(ofs));
478 static value input_val_from_block(void)
480 mlsize_t num_objects, size_32, size_64, whsize;
483 num_objects = read32u();
486 /* Allocate result */
487 #ifdef ARCH_SIXTYFOUR
492 intern_alloc(whsize, num_objects);
495 intern_add_to_heap(whsize);
496 /* Free internal data structures */
497 if (intern_obj_table != NULL) caml_stat_free(intern_obj_table);
501 CAMLexport value caml_input_value_from_malloc(char * data, intnat ofs)
507 intern_input = (unsigned char *) data;
508 intern_src = intern_input + ofs;
509 intern_input_malloced = 1;
511 if (magic != Intext_magic_number)
512 caml_failwith("input_value_from_malloc: bad object");
513 block_len = read32u();
514 obj = input_val_from_block();
516 caml_stat_free(intern_input);
520 CAMLexport value caml_input_value_from_block(char * data, intnat len)
526 intern_input = (unsigned char *) data;
527 intern_src = intern_input;
528 intern_input_malloced = 0;
530 if (magic != Intext_magic_number)
531 caml_failwith("input_value_from_block: bad object");
532 block_len = read32u();
533 if (5*4 + block_len > len)
534 caml_failwith("input_value_from_block: bad block length");
535 obj = input_val_from_block();
539 CAMLprim value caml_marshal_data_size(value buff, value ofs)
544 intern_src = &Byte_u(buff, Long_val(ofs));
545 intern_input_malloced = 0;
547 if (magic != Intext_magic_number){
548 caml_failwith("Marshal.data_size: bad object");
550 block_len = read32u();
551 return Val_long(block_len);
554 /* Return an MD5 checksum of the code area */
560 unsigned char * caml_code_checksum(void)
562 static unsigned char checksum[16];
563 static int checksum_computed = 0;
565 if (! checksum_computed) {
566 struct MD5Context ctx;
569 (unsigned char *) caml_code_area_start,
570 caml_code_area_end - caml_code_area_start);
571 caml_MD5Final(checksum, &ctx);
572 checksum_computed = 1;
579 #include "fix_code.h"
581 unsigned char * caml_code_checksum(void)
583 return caml_code_md5;
588 /* Functions for writing user-defined marshallers */
590 CAMLexport int caml_deserialize_uint_1(void)
595 CAMLexport int caml_deserialize_sint_1(void)
600 CAMLexport int caml_deserialize_uint_2(void)
605 CAMLexport int caml_deserialize_sint_2(void)
610 CAMLexport uint32 caml_deserialize_uint_4(void)
615 CAMLexport int32 caml_deserialize_sint_4(void)
620 CAMLexport uint64 caml_deserialize_uint_8(void)
623 caml_deserialize_block_8(&i, 1);
627 CAMLexport int64 caml_deserialize_sint_8(void)
630 caml_deserialize_block_8(&i, 1);
634 CAMLexport float caml_deserialize_float_4(void)
637 caml_deserialize_block_4(&f, 1);
641 CAMLexport double caml_deserialize_float_8(void)
644 caml_deserialize_block_float_8(&f, 1);
648 CAMLexport void caml_deserialize_block_1(void * data, intnat len)
650 memmove(data, intern_src, len);
654 CAMLexport void caml_deserialize_block_2(void * data, intnat len)
656 #ifndef ARCH_BIG_ENDIAN
657 unsigned char * p, * q;
658 for (p = intern_src, q = data; len > 0; len--, p += 2, q += 2)
662 memmove(data, intern_src, len * 2);
663 intern_src += len * 2;
667 CAMLexport void caml_deserialize_block_4(void * data, intnat len)
669 #ifndef ARCH_BIG_ENDIAN
670 unsigned char * p, * q;
671 for (p = intern_src, q = data; len > 0; len--, p += 4, q += 4)
675 memmove(data, intern_src, len * 4);
676 intern_src += len * 4;
680 CAMLexport void caml_deserialize_block_8(void * data, intnat len)
682 #ifndef ARCH_BIG_ENDIAN
683 unsigned char * p, * q;
684 for (p = intern_src, q = data; len > 0; len--, p += 8, q += 8)
688 memmove(data, intern_src, len * 8);
689 intern_src += len * 8;
693 CAMLexport void caml_deserialize_block_float_8(void * data, intnat len)
695 #if ARCH_FLOAT_ENDIANNESS == 0x01234567
696 memmove(data, intern_src, len * 8);
697 intern_src += len * 8;
698 #elif ARCH_FLOAT_ENDIANNESS == 0x76543210
699 unsigned char * p, * q;
700 for (p = intern_src, q = data; len > 0; len--, p += 8, q += 8)
704 unsigned char * p, * q;
705 for (p = intern_src, q = data; len > 0; len--, p += 8, q += 8)
706 Permute_64(q, ARCH_FLOAT_ENDIANNESS, p, 0x01234567);
711 CAMLexport void caml_deserialize_error(char * msg)