Merge pull request #9649 from xavierleroy/marshal-new-closure-repr
Marshaling for the new closure representationmaster
commit
38d2f5a92a
4
Changes
4
Changes
|
@ -40,6 +40,10 @@ Working version
|
|||
- #9634: Allow initial and repeated commas in `OCAMLRUNPARAM`.
|
||||
(Nicolás Ojeda Bär, review by Gabriel Scherer)
|
||||
|
||||
- #9649: Update the marshaler (output_value) to take advantage
|
||||
of the new representation for function closures
|
||||
(Xavier Leroy, review by Damien Doligez)
|
||||
|
||||
- #9654: More efficient management of code fragments.
|
||||
(Xavier Leroy, review by Jacques-Henri Jourdan, Damien Doligez, and
|
||||
Stephen Dolan)
|
||||
|
|
391
runtime/extern.c
391
runtime/extern.c
|
@ -480,13 +480,211 @@ static void writecode64(int code, intnat val)
|
|||
}
|
||||
#endif
|
||||
|
||||
/* Marshaling integers */
|
||||
|
||||
Caml_inline void extern_int(intnat n)
|
||||
{
|
||||
if (n >= 0 && n < 0x40) {
|
||||
write(PREFIX_SMALL_INT + n);
|
||||
} else if (n >= -(1 << 7) && n < (1 << 7)) {
|
||||
writecode8(CODE_INT8, n);
|
||||
} else if (n >= -(1 << 15) && n < (1 << 15)) {
|
||||
writecode16(CODE_INT16, n);
|
||||
#ifdef ARCH_SIXTYFOUR
|
||||
} else if (n < -((intnat)1 << 30) || n >= ((intnat)1 << 30)) {
|
||||
if (extern_flags & COMPAT_32)
|
||||
extern_failwith("output_value: integer cannot be read back on "
|
||||
"32-bit platform");
|
||||
writecode64(CODE_INT64, n);
|
||||
#endif
|
||||
} else {
|
||||
writecode32(CODE_INT32, n);
|
||||
}
|
||||
}
|
||||
|
||||
/* Marshaling references to previously-marshaled blocks */
|
||||
|
||||
Caml_inline void extern_shared_reference(uintnat d)
|
||||
{
|
||||
if (d < 0x100) {
|
||||
writecode8(CODE_SHARED8, d);
|
||||
} else if (d < 0x10000) {
|
||||
writecode16(CODE_SHARED16, d);
|
||||
#ifdef ARCH_SIXTYFOUR
|
||||
} else if (d >= (uintnat)1 << 32) {
|
||||
writecode64(CODE_SHARED64, d);
|
||||
#endif
|
||||
} else {
|
||||
writecode32(CODE_SHARED32, d);
|
||||
}
|
||||
}
|
||||
|
||||
/* Marshaling block headers */
|
||||
|
||||
Caml_inline void extern_header(mlsize_t sz, tag_t tag)
|
||||
{
|
||||
if (tag < 16 && sz < 8) {
|
||||
write(PREFIX_SMALL_BLOCK + tag + (sz << 4));
|
||||
} else {
|
||||
header_t hd = Make_header(sz, tag, Caml_white);
|
||||
#ifdef ARCH_SIXTYFOUR
|
||||
if (sz > 0x3FFFFF && (extern_flags & COMPAT_32))
|
||||
extern_failwith("output_value: array cannot be read back on "
|
||||
"32-bit platform");
|
||||
if (hd < (uintnat)1 << 32)
|
||||
writecode32(CODE_BLOCK32, hd);
|
||||
else
|
||||
writecode64(CODE_BLOCK64, hd);
|
||||
#else
|
||||
writecode32(CODE_BLOCK32, hd);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
/* Marshaling strings */
|
||||
|
||||
Caml_inline void extern_string(value v, mlsize_t len)
|
||||
{
|
||||
if (len < 0x20) {
|
||||
write(PREFIX_SMALL_STRING + len);
|
||||
} else if (len < 0x100) {
|
||||
writecode8(CODE_STRING8, len);
|
||||
} else {
|
||||
#ifdef ARCH_SIXTYFOUR
|
||||
if (len > 0xFFFFFB && (extern_flags & COMPAT_32))
|
||||
extern_failwith("output_value: string cannot be read back on "
|
||||
"32-bit platform");
|
||||
if (len < (uintnat)1 << 32)
|
||||
writecode32(CODE_STRING32, len);
|
||||
else
|
||||
writecode64(CODE_STRING64, len);
|
||||
#else
|
||||
writecode32(CODE_STRING32, len);
|
||||
#endif
|
||||
}
|
||||
writeblock(String_val(v), len);
|
||||
}
|
||||
|
||||
/* Marshaling FP numbers */
|
||||
|
||||
Caml_inline void extern_double(value v)
|
||||
{
|
||||
write(CODE_DOUBLE_NATIVE);
|
||||
writeblock_float8((double *) v, 1);
|
||||
}
|
||||
|
||||
/* Marshaling FP arrays */
|
||||
|
||||
Caml_inline void extern_double_array(value v, mlsize_t nfloats)
|
||||
{
|
||||
if (nfloats < 0x100) {
|
||||
writecode8(CODE_DOUBLE_ARRAY8_NATIVE, nfloats);
|
||||
} else {
|
||||
#ifdef ARCH_SIXTYFOUR
|
||||
if (nfloats > 0x1FFFFF && (extern_flags & COMPAT_32))
|
||||
extern_failwith("output_value: float array cannot be read back on "
|
||||
"32-bit platform");
|
||||
if (nfloats < (uintnat) 1 << 32)
|
||||
writecode32(CODE_DOUBLE_ARRAY32_NATIVE, nfloats);
|
||||
else
|
||||
writecode64(CODE_DOUBLE_ARRAY64_NATIVE, nfloats);
|
||||
#else
|
||||
writecode32(CODE_DOUBLE_ARRAY32_NATIVE, nfloats);
|
||||
#endif
|
||||
}
|
||||
writeblock_float8((double *) v, nfloats);
|
||||
}
|
||||
|
||||
/* Marshaling custom blocks */
|
||||
|
||||
Caml_inline void extern_custom(value v,
|
||||
/*out*/ uintnat * sz_32,
|
||||
/*out*/ uintnat * sz_64)
|
||||
{
|
||||
char * size_header;
|
||||
char const * ident = Custom_ops_val(v)->identifier;
|
||||
void (*serialize)(value v, uintnat * bsize_32, uintnat * bsize_64)
|
||||
= Custom_ops_val(v)->serialize;
|
||||
const struct custom_fixed_length* fixed_length
|
||||
= Custom_ops_val(v)->fixed_length;
|
||||
if (serialize == NULL)
|
||||
extern_invalid_argument("output_value: abstract value (Custom)");
|
||||
if (fixed_length == NULL) {
|
||||
write(CODE_CUSTOM_LEN);
|
||||
writeblock(ident, strlen(ident) + 1);
|
||||
/* Reserve 12 bytes for the lengths (sz_32 and sz_64). */
|
||||
if (extern_ptr + 12 >= extern_limit) grow_extern_output(12);
|
||||
size_header = extern_ptr;
|
||||
extern_ptr += 12;
|
||||
serialize(v, sz_32, sz_64);
|
||||
/* Store length before serialized block */
|
||||
store32(size_header, *sz_32);
|
||||
store64(size_header + 4, *sz_64);
|
||||
} else {
|
||||
write(CODE_CUSTOM_FIXED);
|
||||
writeblock(ident, strlen(ident) + 1);
|
||||
serialize(v, sz_32, sz_64);
|
||||
if (*sz_32 != fixed_length->bsize_32 ||
|
||||
*sz_64 != fixed_length->bsize_64)
|
||||
caml_fatal_error(
|
||||
"output_value: incorrect fixed sizes specified by %s",
|
||||
ident);
|
||||
}
|
||||
}
|
||||
|
||||
/* Marshaling code pointers */
|
||||
|
||||
static void extern_code_pointer(char * codeptr)
|
||||
{
|
||||
struct code_fragment * cf;
|
||||
const char * digest;
|
||||
|
||||
cf = caml_find_code_fragment_by_pc(codeptr);
|
||||
if (cf != NULL) {
|
||||
if ((extern_flags & CLOSURES) == 0)
|
||||
extern_invalid_argument("output_value: functional value");
|
||||
digest = (const char *) caml_digest_of_code_fragment(cf);
|
||||
if (digest == NULL)
|
||||
extern_invalid_argument("output_value: private function");
|
||||
writecode32(CODE_CODEPOINTER, codeptr - cf->code_start);
|
||||
writeblock(digest, 16);
|
||||
} else {
|
||||
extern_invalid_argument("output_value: abstract value (outside heap)");
|
||||
}
|
||||
}
|
||||
|
||||
/* Marshaling the non-environment part of closures */
|
||||
|
||||
Caml_inline mlsize_t extern_closure_up_to_env(value v)
|
||||
{
|
||||
mlsize_t startenv, i;
|
||||
value info;
|
||||
|
||||
startenv = Start_env_closinfo(Closinfo_val(v));
|
||||
i = 0;
|
||||
do {
|
||||
/* The infix header */
|
||||
if (i > 0) extern_int(Long_val(Field(v, i++)));
|
||||
/* The default entry point */
|
||||
extern_code_pointer((char *) Field(v, i++));
|
||||
/* The closure info. */
|
||||
info = Field(v, i++);
|
||||
extern_int(Long_val(info));
|
||||
/* The direct entry point if arity is neither 0 nor 1 */
|
||||
if (Arity_closinfo(info) != 0 && Arity_closinfo(info) != 1) {
|
||||
extern_code_pointer((char *) Field(v, i++));
|
||||
}
|
||||
} while (i < startenv);
|
||||
CAMLassert(i == startenv);
|
||||
return startenv;
|
||||
}
|
||||
|
||||
/* Marshal the given value in the output buffer */
|
||||
|
||||
int caml_extern_allow_out_of_heap = 0;
|
||||
|
||||
static void extern_rec(value v)
|
||||
{
|
||||
struct code_fragment * cf;
|
||||
struct extern_item * sp;
|
||||
uintnat h = 0;
|
||||
uintnat pos = 0;
|
||||
|
@ -496,25 +694,16 @@ static void extern_rec(value v)
|
|||
|
||||
while(1) {
|
||||
if (Is_long(v)) {
|
||||
intnat n = Long_val(v);
|
||||
if (n >= 0 && n < 0x40) {
|
||||
write(PREFIX_SMALL_INT + n);
|
||||
} else if (n >= -(1 << 7) && n < (1 << 7)) {
|
||||
writecode8(CODE_INT8, n);
|
||||
} else if (n >= -(1 << 15) && n < (1 << 15)) {
|
||||
writecode16(CODE_INT16, n);
|
||||
#ifdef ARCH_SIXTYFOUR
|
||||
} else if (n < -((intnat)1 << 30) || n >= ((intnat)1 << 30)) {
|
||||
if (extern_flags & COMPAT_32)
|
||||
extern_failwith("output_value: integer cannot be read back on "
|
||||
"32-bit platform");
|
||||
writecode64(CODE_INT64, n);
|
||||
#endif
|
||||
} else
|
||||
writecode32(CODE_INT32, n);
|
||||
goto next_item;
|
||||
extern_int(Long_val(v));
|
||||
}
|
||||
if (Is_in_value_area(v) || caml_extern_allow_out_of_heap) {
|
||||
#ifndef NO_NAKED_POINTERS
|
||||
else if (! (Is_in_value_area(v) || caml_extern_allow_out_of_heap)) {
|
||||
/* Naked pointer outside the heap: try to marshal it as a code pointer,
|
||||
otherwise fail. */
|
||||
extern_code_pointer((char *) v);
|
||||
}
|
||||
#endif
|
||||
else {
|
||||
header_t hd = Hd_val(v);
|
||||
tag_t tag = Tag_hd(hd);
|
||||
mlsize_t sz = Wosize_hd(hd);
|
||||
|
@ -537,68 +726,29 @@ static void extern_rec(value v)
|
|||
/* Atoms are treated specially for two reasons: they are not allocated
|
||||
in the externed block, and they are automatically shared. */
|
||||
if (sz == 0) {
|
||||
if (tag < 16) {
|
||||
write(PREFIX_SMALL_BLOCK + tag);
|
||||
} else {
|
||||
#ifdef WITH_PROFINFO
|
||||
writecode32(CODE_BLOCK32, Hd_no_profinfo(hd));
|
||||
#else
|
||||
writecode32(CODE_BLOCK32, hd);
|
||||
#endif
|
||||
}
|
||||
extern_header(0, tag);
|
||||
goto next_item;
|
||||
}
|
||||
/* Check if object already seen */
|
||||
if (! (extern_flags & NO_SHARING)) {
|
||||
if (extern_lookup_position(v, &pos, &h)) {
|
||||
uintnat d = obj_counter - pos;
|
||||
if (d < 0x100) {
|
||||
writecode8(CODE_SHARED8, d);
|
||||
} else if (d < 0x10000) {
|
||||
writecode16(CODE_SHARED16, d);
|
||||
#ifdef ARCH_SIXTYFOUR
|
||||
} else if (d >= (uintnat)1 << 32) {
|
||||
writecode64(CODE_SHARED64, d);
|
||||
#endif
|
||||
} else {
|
||||
writecode32(CODE_SHARED32, d);
|
||||
}
|
||||
extern_shared_reference(obj_counter - pos);
|
||||
goto next_item;
|
||||
}
|
||||
}
|
||||
|
||||
/* Output the contents of the object */
|
||||
switch(tag) {
|
||||
case String_tag: {
|
||||
mlsize_t len = caml_string_length(v);
|
||||
if (len < 0x20) {
|
||||
write(PREFIX_SMALL_STRING + len);
|
||||
} else if (len < 0x100) {
|
||||
writecode8(CODE_STRING8, len);
|
||||
} else {
|
||||
#ifdef ARCH_SIXTYFOUR
|
||||
if (len > 0xFFFFFB && (extern_flags & COMPAT_32))
|
||||
extern_failwith("output_value: string cannot be read back on "
|
||||
"32-bit platform");
|
||||
if (len < (uintnat)1 << 32)
|
||||
writecode32(CODE_STRING32, len);
|
||||
else
|
||||
writecode64(CODE_STRING64, len);
|
||||
#else
|
||||
writecode32(CODE_STRING32, len);
|
||||
#endif
|
||||
}
|
||||
writeblock(String_val(v), len);
|
||||
extern_string(v, len);
|
||||
size_32 += 1 + (len + 4) / 4;
|
||||
size_64 += 1 + (len + 8) / 8;
|
||||
extern_record_location(v, h);
|
||||
break;
|
||||
}
|
||||
case Double_tag: {
|
||||
if (sizeof(double) != 8)
|
||||
extern_invalid_argument("output_value: non-standard floats");
|
||||
write(CODE_DOUBLE_NATIVE);
|
||||
writeblock_float8((double *) v, 1);
|
||||
CAMLassert(sizeof(double) == 8);
|
||||
extern_double(v);
|
||||
size_32 += 1 + 2;
|
||||
size_64 += 1 + 1;
|
||||
extern_record_location(v, h);
|
||||
|
@ -606,25 +756,9 @@ static void extern_rec(value v)
|
|||
}
|
||||
case Double_array_tag: {
|
||||
mlsize_t nfloats;
|
||||
if (sizeof(double) != 8)
|
||||
extern_invalid_argument("output_value: non-standard floats");
|
||||
CAMLassert(sizeof(double) == 8);
|
||||
nfloats = Wosize_val(v) / Double_wosize;
|
||||
if (nfloats < 0x100) {
|
||||
writecode8(CODE_DOUBLE_ARRAY8_NATIVE, nfloats);
|
||||
} else {
|
||||
#ifdef ARCH_SIXTYFOUR
|
||||
if (nfloats > 0x1FFFFF && (extern_flags & COMPAT_32))
|
||||
extern_failwith("output_value: float array cannot be read back on "
|
||||
"32-bit platform");
|
||||
if (nfloats < (uintnat) 1 << 32)
|
||||
writecode32(CODE_DOUBLE_ARRAY32_NATIVE, nfloats);
|
||||
else
|
||||
writecode64(CODE_DOUBLE_ARRAY64_NATIVE, nfloats);
|
||||
#else
|
||||
writecode32(CODE_DOUBLE_ARRAY32_NATIVE, nfloats);
|
||||
#endif
|
||||
}
|
||||
writeblock_float8((double *) v, nfloats);
|
||||
extern_double_array(v, nfloats);
|
||||
size_32 += 1 + nfloats * 2;
|
||||
size_64 += 1 + nfloats;
|
||||
extern_record_location(v, h);
|
||||
|
@ -639,92 +773,51 @@ static void extern_rec(value v)
|
|||
continue;
|
||||
case Custom_tag: {
|
||||
uintnat sz_32, sz_64;
|
||||
char * size_header;
|
||||
char const * ident = Custom_ops_val(v)->identifier;
|
||||
void (*serialize)(value v, uintnat * bsize_32,
|
||||
uintnat * bsize_64)
|
||||
= Custom_ops_val(v)->serialize;
|
||||
const struct custom_fixed_length* fixed_length
|
||||
= Custom_ops_val(v)->fixed_length;
|
||||
if (serialize == NULL)
|
||||
extern_invalid_argument("output_value: abstract value (Custom)");
|
||||
if (fixed_length == NULL) {
|
||||
write(CODE_CUSTOM_LEN);
|
||||
writeblock(ident, strlen(ident) + 1);
|
||||
/* Reserve 12 bytes for the lengths (sz_32 and sz_64). */
|
||||
if (extern_ptr + 12 >= extern_limit) grow_extern_output(12);
|
||||
size_header = extern_ptr;
|
||||
extern_ptr += 12;
|
||||
serialize(v, &sz_32, &sz_64);
|
||||
/* Store length before serialized block */
|
||||
store32(size_header, sz_32);
|
||||
store64(size_header + 4, sz_64);
|
||||
} else {
|
||||
write(CODE_CUSTOM_FIXED);
|
||||
writeblock(ident, strlen(ident) + 1);
|
||||
serialize(v, &sz_32, &sz_64);
|
||||
if (sz_32 != fixed_length->bsize_32 ||
|
||||
sz_64 != fixed_length->bsize_64)
|
||||
caml_fatal_error(
|
||||
"output_value: incorrect fixed sizes specified by %s",
|
||||
ident);
|
||||
}
|
||||
extern_custom(v, &sz_32, &sz_64);
|
||||
size_32 += 2 + ((sz_32 + 3) >> 2); /* header + ops + data */
|
||||
size_64 += 2 + ((sz_64 + 7) >> 3);
|
||||
extern_record_location(v, h);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
value field0;
|
||||
if (tag < 16 && sz < 8) {
|
||||
write(PREFIX_SMALL_BLOCK + tag + (sz << 4));
|
||||
} else {
|
||||
#ifdef ARCH_SIXTYFOUR
|
||||
#ifdef WITH_PROFINFO
|
||||
header_t hd_erased = Hd_no_profinfo(hd);
|
||||
#else
|
||||
header_t hd_erased = hd;
|
||||
#endif
|
||||
if (sz > 0x3FFFFF && (extern_flags & COMPAT_32))
|
||||
extern_failwith("output_value: array cannot be read back on "
|
||||
"32-bit platform");
|
||||
if (hd_erased < (uintnat)1 << 32)
|
||||
writecode32(CODE_BLOCK32, Whitehd_hd (hd_erased));
|
||||
else
|
||||
writecode64(CODE_BLOCK64, Whitehd_hd (hd_erased));
|
||||
#else
|
||||
writecode32(CODE_BLOCK32, Whitehd_hd (hd));
|
||||
#endif
|
||||
}
|
||||
#ifdef NO_NAKED_POINTERS
|
||||
case Closure_tag: {
|
||||
mlsize_t i;
|
||||
extern_header(sz, tag);
|
||||
size_32 += 1 + sz;
|
||||
size_64 += 1 + sz;
|
||||
extern_record_location(v, h);
|
||||
i = extern_closure_up_to_env(v);
|
||||
if (i >= sz) goto next_item;
|
||||
/* Remember that we still have to serialize fields i + 1 ... sz - 1 */
|
||||
if (i < sz - 1) {
|
||||
sp++;
|
||||
if (sp >= extern_stack_limit) sp = extern_resize_stack(sp);
|
||||
sp->v = &Field(v, i + 1);
|
||||
sp->count = sz - i - 1;
|
||||
}
|
||||
/* Continue serialization with the first environment field */
|
||||
v = Field(v, i);
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
default: {
|
||||
extern_header(sz, tag);
|
||||
size_32 += 1 + sz;
|
||||
size_64 += 1 + sz;
|
||||
field0 = Field(v, 0);
|
||||
extern_record_location(v, h);
|
||||
/* Remember that we still have to serialize fields 1 ... sz - 1 */
|
||||
if (sz > 1) {
|
||||
sp++;
|
||||
if (sp >= extern_stack_limit) sp = extern_resize_stack(sp);
|
||||
sp->v = &Field(v,1);
|
||||
sp->count = sz-1;
|
||||
sp->v = &Field(v, 1);
|
||||
sp->count = sz - 1;
|
||||
}
|
||||
/* Continue serialization with the first field */
|
||||
v = field0;
|
||||
v = Field(v, 0);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if ((cf = caml_find_code_fragment_by_pc((char*) v)) != NULL) {
|
||||
const char * digest;
|
||||
if ((extern_flags & CLOSURES) == 0)
|
||||
extern_invalid_argument("output_value: functional value");
|
||||
digest = (const char *) caml_digest_of_code_fragment(cf);
|
||||
if (digest == NULL)
|
||||
extern_invalid_argument("output_value: private function");
|
||||
writecode32(CODE_CODEPOINTER, (char *) v - cf->code_start);
|
||||
writeblock(digest, 16);
|
||||
} else {
|
||||
extern_invalid_argument("output_value: abstract value (outside heap)");
|
||||
}
|
||||
next_item:
|
||||
/* Pop one more item to marshal, if any */
|
||||
if (sp == extern_stack) {
|
||||
|
|
Loading…
Reference in New Issue