1.1 Generic Serialisation
share/lib/rtl/flx_serialisers.hpp
#ifndef __FLX_SERIALISERS_HPP__
#define __FLX_SERIALISERS_HPP__
#include "flx_gc.hpp"
namespace flx { namespace gc { namespace generic {
GC_EXTERN encoder_t string_encoder;
GC_EXTERN decoder_t string_decoder;
GC_EXTERN ::std::string blit (void *, size_t);
GC_EXTERN size_t unblit (void *, size_t, char*, size_t);
GC_EXTERN ::std::string string_blit (::std::string const&);
template<class T>
::std::string tblit(void *p)
{
return blit (p, sizeof(T));
}
template<class T>
size_t tunblit(void *p, char *s, size_t i)
{
return unblit (p, sizeof(T), s, i);
}
}}}
#endif
share/src/gc/flx_serialisers.cpp
#include "flx_serialisers.hpp"
#include <string>
#include <cstring>
#include <cstddef>
namespace flx { namespace gc { namespace generic {
::std::string string_encoder (void *p)
{
return *(::std::string*)p;
}
::std::string string_blit (::std::string const &s)
{
::std::size_t n = s.size();
::std::string b = blit (&n, sizeof(::std::size_t));
b+=s;
return b;
}
::std::string blit (void *p, ::std::size_t n) {
return ::std::string((char*)p,n);
}
::std::size_t string_decoder (void *p, char *s, ::std::size_t i)
{
::std::size_t n;
::std::memcpy (&n,s + i,sizeof(::std::size_t));
new (p) ::std::string(s+i+sizeof(::std::size_t), n);
return i + sizeof(::std::size_t) + n;
}
::std::size_t unblit (void *p, ::std::size_t n, char *s, ::std::size_t i)
{
::std::memcpy (p,s+i,n);
return i + n;
}
}}}
1.2 Judy Serialisers
share/lib/rtl/flx_judy_scanner.hpp
#include "flx_gc.hpp"
namespace flx { namespace gc { namespace generic {
GC_EXTERN scanner_t Judy1_scanner;
GC_EXTERN scanner_t JudyL_scanner;
GC_EXTERN scanner_t JudySL_scanner;
}}}
share/src/gc/flx_judy_scanner.cpp
#include "flx_judy_scanner.hpp"
#include <Judy.h>
namespace flx { namespace gc { namespace generic {
void *Judy1_scanner(collector_t *collector, gc_shape_t *shape, void *pp, size_t dyncount, int reclimit)
{
void *p = *(void**)pp;
JError_t je;
Word_t key = 0;
int res = Judy1First(p, &key, &je);
while(res) {
collector->register_pointer((void*)key,reclimit);
res = Judy1Next(p,&key, &je);
}
return 0;
}
void *JudyL_scanner(collector_t *collector, gc_shape_t *shape, void *pp, size_t dyncount, int reclimit)
{
void *p = *(void**)pp;
JError_t je;
Word_t key = 0;
Word_t *pval = 0;
pval = (Word_t*)JudyLFirst(p, &key, &je);
while(pval) {
collector->register_pointer((void*)key,reclimit);
collector->register_pointer((void*)*pval,reclimit);
pval = (Word_t*)JudyLNext(p, &key, &je);
}
return 0;
}
void *JudySL_scanner(collector_t *collector, gc_shape_t *shape, void *pp, size_t dyncount, int reclimit)
{
void *p = *(void**)pp;
JError_t je;
unsigned char *key = (unsigned char*)::std::malloc(10000); *key = 0;
Word_t *pval = 0;
pval = (Word_t*)JudySLFirst(p, key, &je);
while(pval) {
collector->register_pointer((void*)*pval,reclimit);
pval = (Word_t*)JudySLNext(p, key, &je);
}
::std::free(key);
return 0;
}
}}}
share/lib/std/felix/serialise.flx
class Serialise
{
open Collector;
open Rtti;
open Judy;
fun blit[T] (p: &T) => string ( C_hack::cast[+char] p, C_hack::sizeof[T]);
fun ncode [T] (var v: T) => blit &v;
gen unblit[T] (p: &T, s: +char, i:size) : size =
{
Memory::memcpy(p.address,(s+i).address,C_hack::sizeof[T]);
return i + C_hack::sizeof[T];
}
fun encode_varray (p:address) : string =
{
var pd = Collector::get_pointer_data p;
assert pd.is_felix_pointer;
var shape = pd.shape;
var has_encoder = not shape.encoder.C_hack::cast[address].isNULL;
var has_pointers = shape._unsafe_n_offsets == 0uz;
var out = ncode shape;
out += ncode pd.head;
out += ncode pd.max_elements;
out += ncode pd.used_elements;
assert has_encoder;
var dynamic_slot_size = shape.bytes_per_element * shape.number_of_elements;
for var i:size in 0uz upto pd.used_elements.size - 1uz do
out += shape.encoder (pd.head + i * dynamic_slot_size);
done
return out;
}
fun find_pointers (p:address) : list[address] =
{
var pd = Collector::get_pointer_data p;
if not pd.is_felix_pointer do
return Empty[address];
done
var shape = pd.shape;
var head = pd.head;
var n_offsets = shape.Rtti::n_offsets;
var pointers = Empty[address];
if n_offsets > 0uz do
var offsets = shape.Rtti::offsets;
var repeat_count = pd.used_elements.size * shape.number_of_elements;
var element_size = shape.bytes_per_element;
for var sindex in 0uz upto repeat_count - 1uz do
for var oindex in 0uz upto n_offsets - 1uz do
var bindex = sindex * element_size + (offsets + oindex)*.offset;
var ptr = *((head + bindex).C_hack::cast[&address]);
pointers = Cons (ptr, pointers);
done
done
done
return pointers;
}
struct pclosure
{
processed: J1Array;
waiting: J1Array;
};
ctor pclosure () => pclosure (#J1Array, #J1Array);
proc add_pointer (self: &pclosure) (p:address)
{
var pd = Collector::get_pointer_data p;
if pd.is_felix_pointer do
var je : JError_t;
var ret : int;
var w = pd.head.Judy::word;
if not (w \(\in\) self*.processed or w \(\in\) self*.waiting) do
Judy1Set (self*.waiting, w, &je, &ret);
done
done
}
gen iterator (self: &pclosure) () : opt[address] =
{
var w: word = 0.word;
var je : JError_t;
var ret: int;
Judy1First(self*.waiting,&w,&je,&ret);
if ret == 1 do
Judy1Unset(self*.waiting, w, &je, &ret);
Judy1Set (self*.processed, w, &je, &ret);
return Some w.address;
else
return None[address];
done
}
fun find_closure (p:address) : list[address] =
{
var xpc = #pclosure;
var pd = Collector::get_pointer_data p;
add_pointer &xpc pd.head;
for ptr in &xpc do
iter (add_pointer &xpc) (find_pointers ptr);
done
var lst = list[address] (pd.head);
var a: word = 0.word;
var ret: int;
Judy1First (xpc.processed, &a, &je, &ret);
while ret == 1 do
if a.address != pd.head do
lst = Cons (a.address, lst);
done
Judy1Next(xpc.processed, &a, &je, &ret);
done
var w:word;
var je:JError_t;
Judy1FreeArray (xpc.processed, &je, &w);
return lst;
}
fun encode_closure (alst:list[address]) : string =
{
var b = "";
iter proc (elt:address) { b+=encode_varray elt; } alst;
return b;
}
fun encode_pointer_closure (p:address) =>
p.find_closure.encode_closure
;
gen create_empty_varray : gc_shape_t * size -> address =
"(ptf-> gcp->collector->create_empty_array($1,$2))"
requires property "needs_gc"
;
proc set_used: address * size =
"ptf-> gcp->collector->set_used($1,$2);"
requires property "needs_gc"
;
gen decode_varray (ss:string) : address =
{
var s = ss.cstr;
var i = 0uz;
var shape: gc_shape_t;
var head: address;
var maxslots : size;
var usedslots: size;
i = unblit (&shape, s, i);
i = unblit (&head, s, i);
i = unblit (&maxslots, s, i);
i = unblit (&usedslots, s, i);
assert not shape.decoder.C_hack::cast[address].isNULL;
var dynamic_slot_size = shape.bytes_per_element * shape.number_of_elements;
var p = create_empty_varray (shape, maxslots);
for var slot in 0uz upto usedslots - 1uz do
i = (shape.decoder ( p + slot * dynamic_slot_size, s, i));
done
set_used (p, usedslots);
return p;
}
gen decode_pointer_closure (ss:string) : address =
{
var pmap = #JLArray;
var je : JError_t;
gen create_objects () : address =
{
var s = ss.cstr;
var n = ss.len;
var i = 0uz;
var pnew : &word;
var head: address = NULL;
while i != n do
var shape: gc_shape_t;
var maxslots : size;
var usedslots: size;
i = unblit (&shape, s, i);
i = unblit (&head, s, i);
i = unblit (&maxslots, s, i);
i = unblit (&usedslots, s, i);
assert not shape.decoder.C_hack::cast[address].isNULL;
var dynamic_slot_size = shape.bytes_per_element * shape.number_of_elements;
var p = create_empty_varray (shape, maxslots);
for var slot in 0uz upto usedslots - 1uz do
i = (shape.decoder ( p + slot * dynamic_slot_size, s, i));
done
set_used (p, usedslots);
JudyLIns(pmap,head.word,&je,&pnew);
pnew <- p.word;
done
return head;
}
proc adjust_pointer (pptr:&address)
{
var oldptr = *pptr;
var oldhead = oldptr.word;
var pnew2 : &word;
JudyLLast(pmap,&oldhead,&je,&pnew2);
if not isNULL pnew2 do
var newhead2 = *pnew2;
var pd2 = Collector::get_pointer_data newhead2.address;
var nbytes = pd2.shape.bytes_per_element * pd2.max_elements.size * pd2.shape.number_of_elements;
if oldptr < oldhead.address + nbytes do
pptr <- newhead2.address + (oldptr - oldhead.address);
done
done
}
proc adjust_all_pointers (newhead:address)
{
var pd = Collector::get_pointer_data newhead;
var shape = pd.shape;
var head = pd.head;
var n_offsets = shape.Rtti::n_offsets;
if n_offsets > 0uz do
var offsets = shape.Rtti::offsets;
var repeat_count = pd.used_elements.size * shape.number_of_elements;
var element_size = shape.bytes_per_element;
for var sindex in 0uz upto repeat_count - 1uz do
for var oindex in 0uz upto n_offsets - 1uz do
var bindex = sindex * element_size + (offsets+oindex)*.offset;
var pptr = ((head + bindex).C_hack::cast[&address]);
adjust_pointer (pptr);
done
done
done
}
var rootp = create_objects();
var old : word = 0.word;
var pnew : &word;
JudyLFirst(pmap, &old, &je, &pnew);
while not (isNULL pnew) do
var newhead = (*pnew).address;
adjust_all_pointers (newhead);
JudyLNext(pmap, &old, &je, &pnew);
done
return rootp;
}
}