static void check_ro_ptrpair_sib (Sib* ap) { // ==================== // Val* p; Val* stop; Val w; int gen = GET_AGE_FROM_SIBID(ap->id); if (*sib_is_active(ap)) return; // sib_is_active def in src/c/h/heap.h debug_say (" pairs [%d]: [%#x..%#x:%#x)\n", gen, ap->tospace, ap->tospace.first_free, ap->tospace.limit); p = ap->tospace + 2; stop = ap->tospace.first_free; while (p < stop) { w = *p++; if (IS_TAGWORD(w)) { ERROR; debug_say ( "** @%#x: unexpected tagword %#x in pair sib\n", p-1, w); return; } else if (IS_POINTER(w)) { check_pointer(p, w, gen, RO_CONSCELL_KIND, CHUNKC_any); } } }
static void read_heap ( // ========= // Inbuf* bp, Heap_Header* header, Task* task, Val* externs ){ Heap* heap = task->heap; Sib_Header* sib_headers; Sib_Header* p; Sib_Header* q; int sib_headers_bytesize; int i, j, k; long prevSzB[MAX_PLAIN_SIBS], size; Sibid* oldBOOK2SIBID; Punt addrOffset[MAX_AGEGROUPS][MAX_PLAIN_SIBS]; Hugechunk_Quire_Relocation_Info* boRelocInfo; Addresstable* boRegionTable; // Allocate a book_to_sibid__global for the imported // heap image's address space: // #ifdef TWO_LEVEL_MAP #error two level map not supported #else oldBOOK2SIBID = MALLOC_VEC (Sibid, BOOK2SIBID_TABLE_SIZE_IN_SLOTS); #endif // Read in the hugechunk region descriptors // for the old address space: // { int size; Hugechunk_Quire_Header* boRgnHdr; boRegionTable = make_address_hashtable(LOG2_BOOK_BYTESIZE+1, header->hugechunk_quire_count); size = header->hugechunk_quire_count * sizeof(Hugechunk_Quire_Header); boRgnHdr = (Hugechunk_Quire_Header*) MALLOC (size); heapio__read_block( bp, boRgnHdr, size ); boRelocInfo = MALLOC_VEC(Hugechunk_Quire_Relocation_Info, header->hugechunk_quire_count); for (i = 0; i < header->hugechunk_quire_count; i++) { set_book2sibid_entries_for_range(oldBOOK2SIBID, (Val*)(boRgnHdr[i].base_address), BOOKROUNDED_BYTESIZE(boRgnHdr[i].bytesize), HUGECHUNK_DATA_SIBID(1) ); oldBOOK2SIBID[GET_BOOK_CONTAINING_POINTEE(boRgnHdr[i].base_address)] = HUGECHUNK_RECORD_SIBID(MAX_AGEGROUPS); boRelocInfo[i].first_ram_quantum = boRgnHdr[i].first_ram_quantum; boRelocInfo[i].page_count = (boRgnHdr[i].bytesize - (boRgnHdr[i].first_ram_quantum - boRgnHdr[i].base_address)) >> LOG2_HUGECHUNK_RAM_QUANTUM_IN_BYTES; boRelocInfo[i].hugechunk_page_to_hugechunk = MALLOC_VEC(Hugechunk_Relocation_Info*, boRelocInfo[i].page_count); for (j = 0; j < boRelocInfo[i].page_count; j++) { // boRelocInfo[i].hugechunk_page_to_hugechunk[j] = NULL; } addresstable_insert (boRegionTable, boRgnHdr[i].base_address, &(boRelocInfo[i])); } FREE (boRgnHdr); } // Read the sib headers: // sib_headers_bytesize = header->active_agegroups * TOTAL_SIBS * sizeof( Sib_Header ); // sib_headers = (Sib_Header*) MALLOC( sib_headers_bytesize ); // heapio__read_block( bp, sib_headers, sib_headers_bytesize ); for (i = 0; i < MAX_PLAIN_SIBS; i++) { // prevSzB[i] = task->heap_allocation_buffer_bytesize; } // Allocate the sib buffers and read in the heap image: // for (p = sib_headers, i = 0; i < header->active_agegroups; i++) { // Agegroup* age = heap->agegroup[ i ]; // Compute the space required for this agegroup, // and mark the oldBOOK2SIBID to reflect the old address space: // for (q = p, j = 0; j < MAX_PLAIN_SIBS; j++) { set_book2sibid_entries_for_range ( // oldBOOK2SIBID, (Val*) q->info.o.base_address, BOOKROUNDED_BYTESIZE( q->info.o.bytesize ), age->sib[ j ]->id ); size = q->info.o.bytesize + prevSzB[j]; if (j == RO_CONSCELL_SIB && size > 0 ){ size += 2*WORD_BYTESIZE; } age->sib[ j ]->tospace.bytesize = BOOKROUNDED_BYTESIZE( size ); prevSzB[ j ] = q->info.o.bytesize; q++; } if (set_up_tospace_sib_buffers_for_agegroup(age) == FALSE) { die ("unable to allocated space for agegroup %d\n", i+1); } if (sib_is_active( age->sib[ RW_POINTERS_SIB ] )) { // sib_is_active def in src/c/h/heap.h // make_new_coarse_inter_agegroup_pointers_map_for_agegroup (age); } // Read in the sib buffers for this agegroup // and initialize the address offset table: // for (int j = 0; j < MAX_PLAIN_SIBS; j++) { // Sib* ap = age->sib[ j ]; if (p->info.o.bytesize > 0) { addrOffset[i][j] = (Punt)(ap->tospace.start) - (Punt)(p->info.o.base_address); heapio__seek( bp, (long) p->offset ); heapio__read_block( bp, (ap->tospace.start), p->info.o.bytesize ); ap->tospace.used_end = (Val *)((Punt)(ap->tospace.start) + p->info.o.bytesize); ap->fromspace.seniorchunks_end = ap->tospace.start; } else if (sib_is_active(ap)) { ap->fromspace.seniorchunks_end = ap->tospace.start; } if (verbosity__global > 0) say("."); p++; } // Read in the hugechunk sib buffers (currently just codechunks): // for (int ilk = 0; ilk < MAX_HUGE_SIBS; ilk++) { // MAX_HUGE_SIBS def in src/c/h/sibid.h // Punt totSizeB; Hugechunk* free_chunk; Hugechunk* bdp = NULL; // Without this initialization, gcc -Wall gives a 'possible uninitialized use' warning. Hugechunk_Quire* free_quire; Hugechunk_Header* boHdrs; int boHdrSizeB; int index; Hugechunk_Quire_Relocation_Info* region; if (p->info.bo.hugechunk_quanta_count > 0) { // totSizeB = p->info.bo.hugechunk_quanta_count << LOG2_HUGECHUNK_RAM_QUANTUM_IN_BYTES; free_chunk = allocate_hugechunk_quire( heap, totSizeB ); free_quire = free_chunk->hugechunk_quire; free_quire->age_of_youngest_live_chunk_in_quire = i; set_book2sibid_entries_for_range ( // book_to_sibid__global, (Val*) free_quire, BYTESIZE_OF_QUIRE( free_quire->quire ), HUGECHUNK_DATA_SIBID( i ) ); book_to_sibid__global[ GET_BOOK_CONTAINING_POINTEE( free_quire ) ] = HUGECHUNK_RECORD_SIBID( i ); // Read in the hugechunk headers: // boHdrSizeB = p->info.bo.hugechunk_count * sizeof(Hugechunk_Header); // boHdrs = (Hugechunk_Header*) MALLOC (boHdrSizeB); // heapio__read_block (bp, boHdrs, boHdrSizeB); // Read in the hugechunks: // heapio__read_block( bp, (void *)(free_chunk->chunk), totSizeB ); // if (ilk == CODE__HUGE_SIB) { // ilk = 0 == CODE__HUGE_SIB def in src/c/h/sibid.h // flush_instruction_cache ((void *)(free_chunk->chunk), totSizeB); } // Set up the hugechunk descriptors // and per-chunk relocation info: // for (k = 0; k < p->info.bo.hugechunk_count; k++) { // // Find the region relocation info for the // chunk's region in the exported heap: // for (index = GET_BOOK_CONTAINING_POINTEE(boHdrs[k].base_address); !SIBID_ID_IS_BIGCHUNK_RECORD(oldBOOK2SIBID[index]); index--) continue; region = LOOK_UP_HUGECHUNK_REGION (boRegionTable, index); // Allocate the hugechunk record for // the chunk and link it into the list // of hugechunks for its agegroup. // bdp = allocate_a_hugechunk( free_chunk, &(boHdrs[k]), region ); bdp->next = age->hugechunks[ ilk ]; age->hugechunks[ ilk ] = bdp; ASSERT( bdp->gen == i+1 ); if (codechunk_comment_display_is_enabled__global && ilk == CODE__HUGE_SIB ){ // Dump the comment string of the code chunk. Unt8* namestring; // if ((namestring = get_codechunk_comment_string_else_null( bdp ))) { debug_say ("[%6d bytes] %s\n", bdp->bytesize, (char*)namestring); } } } if (free_chunk != bdp) { // if p->info.bo.hugechunk_count can be zero, 'bdp' value here may be bogus. XXX BUGGO FIXME. // // There was some extra space left in the region: // insert_hugechunk_in_doubly_linked_list( heap->hugechunk_freelist, free_chunk); // insert_hugechunk_in_doubly_linked_list def in src/c/h/heap.h } FREE (boHdrs); } if (verbosity__global > 0) say("."); p++; } } repair_heap (heap, oldBOOK2SIBID, addrOffset, boRegionTable, externs); // Adjust the run-time globals // that point into the heap: // *PTR_CAST( Val*, PERVASIVE_PACKAGE_PICKLE_LIST_REFCELL__GLOBAL ) = repair_word( *PTR_CAST( Val*, PERVASIVE_PACKAGE_PICKLE_LIST_REFCELL__GLOBAL ), oldBOOK2SIBID, addrOffset, boRegionTable, externs ); runtime_package__global = repair_word( runtime_package__global, oldBOOK2SIBID, addrOffset, boRegionTable, externs ); #ifdef ASM_MATH mathvec__global = repair_word (mathvec__global, oldBOOK2SIBID, addrOffset, boRegionTable, externs); #endif // Adjust the Mythryl registers // to the new address space: // ASSIGN( POSIX_INTERPROCESS_SIGNAL_HANDLER_REFCELL__GLOBAL, // repair_word ( // DEREF( POSIX_INTERPROCESS_SIGNAL_HANDLER_REFCELL__GLOBAL ), oldBOOK2SIBID, addrOffset, boRegionTable, externs ) ); task->argument = repair_word( task->argument, oldBOOK2SIBID, addrOffset, boRegionTable, externs ); task->fate = repair_word( task->fate, oldBOOK2SIBID, addrOffset, boRegionTable, externs ); task->current_closure = repair_word( task->current_closure, oldBOOK2SIBID, addrOffset, boRegionTable, externs ); task->program_counter = repair_word( task->program_counter, oldBOOK2SIBID, addrOffset, boRegionTable, externs ); task->link_register = repair_word (task->link_register, oldBOOK2SIBID, addrOffset, boRegionTable, externs ); task->exception_fate = repair_word( task->exception_fate, oldBOOK2SIBID, addrOffset, boRegionTable, externs ); task->current_thread = repair_word( task->current_thread, oldBOOK2SIBID, addrOffset, boRegionTable, externs ); task->callee_saved_registers[0] = repair_word( task->callee_saved_registers[0], oldBOOK2SIBID, addrOffset, boRegionTable, externs ); task->callee_saved_registers[1] = repair_word( task->callee_saved_registers[1], oldBOOK2SIBID, addrOffset, boRegionTable, externs ); task->callee_saved_registers[2] = repair_word( task->callee_saved_registers[2], oldBOOK2SIBID, addrOffset, boRegionTable, externs ); // Release storage: // for (i = 0; i < header->hugechunk_quire_count; i++) { // Hugechunk_Relocation_Info* p; for (p = NULL, j = 0; j < boRelocInfo[i].page_count; j++) { if ((boRelocInfo[i].hugechunk_page_to_hugechunk[j] != NULL) && (boRelocInfo[i].hugechunk_page_to_hugechunk[j] != p)) { FREE (boRelocInfo[i].hugechunk_page_to_hugechunk[j]); p = boRelocInfo[i].hugechunk_page_to_hugechunk[j]; } } } free_address_table( boRegionTable, FALSE ); FREE( boRelocInfo ); FREE( sib_headers ); FREE( oldBOOK2SIBID ); // Reset the tospace.swept_end pointers: // for (int i = 0; i < heap->active_agegroups; i++) { // Agegroup* age = heap->agegroup[i]; // for (int j = 0; j < MAX_PLAIN_SIBS; j++) { // Sib* ap = age->sib[ j ]; // if (sib_is_active(ap)) { // sib_is_active def in src/c/h/heap.h // ap->tospace.swept_end = ap->tospace.used_end; } } } } // fun read_heap
static void check_ro_pointer_sib (Sib* ap) { // ==================== Val* p; Val* stop; Val tagword; Val w; int i; int len; int gen = GET_AGE_FROM_SIBID( ap->id ); if (*sib_is_active(ap)) return; // sib_is_active def in src/c/h/heap.h debug_say (" records [%d]: [%#x..%#x:%#x)\n", // gen, ap->tospace, ap->tospace.first_free, ap->tospace.limit ); p = ap->tospace; stop = ap->tospace.first_free; while (p < stop) { // tagword = *p++; if (*IS_TAGWORD(tagword)) { ERROR; debug_say ( "** @%#x: expected tagword, but found %#x in record sib\n", p-1, tagword); return; } switch (GET_BTAG_FROM_TAGWORD tagword) { // case PAIRS_AND_RECORDS_BTAG: # len = GET_LENGTH_IN_WORDS_FROM_TAGWORD( tagword ); // Length excludes tagword. # for (i = 0; i < len; i++, p++) { w = *p; if (IS_TAGWORD(w)) { ERROR; debug_say ( "** @%#x: unexpected tagword %#x in slot %d of %d\n", p, w, i, GET_LENGTH_IN_WORDS_FROM_TAGWORD(tagword)); return; } else if (IS_POINTER(w)) { check_pointer(p, w, gen, RO_POINTERS_KIND, CHUNKC_any); } } break; case RW_VECTOR_HEADER_BTAG: case RO_VECTOR_HEADER_BTAG: // switch (GET_LENGTH_IN_WORDS_FROM_TAGWORD(tagword)) { // case TYPEAGNOSTIC_VECTOR_CTAG: if (GET_BTAG_FROM_TAGWORD(tagword) == RW_VECTOR_HEADER_BTAG) check_pointer (p, *p, gen, RO_POINTERS_KIND, CHUNKC__IS_RW_POINTERS); else check_pointer (p, *p, gen, RO_POINTERS_KIND, CHUNKC__IS_RO_POINTERS|CHUNKC__IS_RO_CONSCELL); break; case VECTOR_OF_ONE_BYTE_UNTS_CTAG: case UNT16_VECTOR_CTAG: case TAGGED_INT_VECTOR_CTAG: case INT1_VECTOR_CTAG: case VECTOR_OF_FOUR_BYTE_FLOATS_CTAG: case VECTOR_OF_EIGHT_BYTE_FLOATS_CTAG: check_pointer (p, *p, gen, RO_POINTERS_KIND, CHUNKC__IS_NONPTR_DATA); break; default: ERROR; debug_say ("** @%#x: strange sequence kind %d in record sib\n", p-1, GET_LENGTH_IN_WORDS_FROM_TAGWORD(tagword)); return; } if (*IS_TAGGED_INT(p[1])) { ERROR; debug_say ("** @%#x: sequence header length field not an in (%#x)\n", p+1, p[1]); } p += 2; break; default: ERROR; debug_say ("** @%#x: strange tag (%#x) in record sib\n", p-1, GET_BTAG_FROM_TAGWORD(tagword)); return; } } } // fun check_ro_pointer_sib
static void check_rw_pointer_sib (Sib* ap, Coarse_Inter_Agegroup_Pointers_Map* map) { // 'map' is nowhere used in the code?! Should be deleted or used. XXX BUGGO FIXME // ==================== // Val* p; Val* stop; Val tagword; Val w; int i, j; int len; int gen = GET_AGE_FROM_SIBID(ap->id); if (*sib_is_active(ap)) return; // sib_is_active def in src/c/h/heap.h debug_say (" arrays [%d]: [%#x..%#x:%#x)\n", // gen, ap->tospace, ap->tospace.first_free, ap->tospace.limit ); p = ap->tospace; stop = ap->tospace.first_free; while (p < stop) { tagword = *p++; if (*IS_TAGWORD(tagword)) { ERROR; debug_say ( "** @%#x: expected tagword, but found %#x in vector sib\n", p-1, tagword); return; } switch (GET_BTAG_FROM_TAGWORD(tagword)) { // case RW_VECTOR_DATA_BTAG: len = GET_LENGTH_IN_WORDS_FROM_TAGWORD(tagword); break; case WEAK_POINTER_OR_SUSPENSION_BTAG: len = 1; break; default: ERROR; debug_say ("** @%#x: strange tag (%#x) in vector sib\n", p-1, GET_BTAG_FROM_TAGWORD(tagword)); return; } for (int i = 0; i < len; i++, p++) { // w = *p; if (IS_TAGWORD(w)) { ERROR; debug_say ( "** @%#x: Unexpected tagword %#x in rw_vector slot %d of %d\n", p, w, i, GET_LENGTH_IN_WORDS_FROM_TAGWORD(tagword)); for (p -= (i+1), j = 0; j <= len; j++, p++) { debug_say (" %#x: %#10x\n", p, *p); } return; } else if (IS_POINTER(w)) { check_pointer(p, w, gen, RW_POINTERS_KIND, CHUNKC_any); } } } } // fun check_rw_pointer_sib
static void check_nonpointer_sib (Sib* ap) { // ================ // // Check a string sib for consistency. Val* p; Val* stop; Val* prevTagword; Val tagword; Val next; int len; int gen = GET_AGE_FROM_SIBID( ap->id ); if (*sib_is_active(ap)) return; // sib_is_active def in src/c/h/heap.h debug_say (" strings [%d]: [%#x..%#x:%#x)\n", // gen, ap->tospace, ap->tospace.first_free, ap->tospace.limit ); p = ap->tospace; stop = ap->tospace.first_free; prevTagword = NULL; while (p < stop) { tagword = *p++; if (IS_TAGWORD(tagword)) { // switch (GET_BTAG_FROM_TAGWORD(tagword)) { // case FOUR_BYTE_ALIGNED_NONPOINTER_DATA_BTAG: case EIGHT_BYTE_ALIGNED_NONPOINTER_DATA_BTAG: len = GET_LENGTH_IN_WORDS_FROM_TAGWORD(tagword); break; default: ERROR; debug_say ("** @%#x: strange tag (%#x) in string sib\n", p-1, GET_BTAG_FROM_TAGWORD(tagword)); if (prevTagword != NULL) debug_say (" previous string started @ %#x\n", prevTagword); return; } prevTagword = p-1; p += len; } #ifdef ALIGN_FLOAT64S else if ((tagword == 0) && (((Vunt)p & WORD_BYTESIZE) != 0)) continue; // Assume this is alignment padding. #endif else { ERROR; debug_say ("** @%#x: expected tagword, but found %#x in string sib\n", p-1, tagword); if (prevTagword != NULL) debug_say (" previous string started @ %#x\n", prevTagword); return; } } } // fun check_nonpointer_sib
static Status read_image (Task* task, Inbuf* bp, Val* chunk_ref) { // ========== // Pickle_Header pickle_header; Val* externs; Sib_Header* sib_headers[ TOTAL_SIBS ]; Sib_Header* sib_headers_buffer; int sib_headers_size; Agegroup* age1 = task->heap->agegroup[ 0 ]; if (heapio__read_block( bp, &pickle_header, sizeof(pickle_header) ) == FALSE || pickle_header.smallchunk_sibs_count > MAX_PLAIN_SIBS // MAX_PLAIN_SIBS def in src/c/h/sibid.h || pickle_header.hugechunk_sibs_count > MAX_HUGE_SIBS // MAX_HUGE_SIBS def in src/c/h/sibid.h ){ return FALSE; // XXX BUGGO FIXME we gotta do better than this. } // Read the externals table: // externs = heapio__read_externs_table( bp ); // Read the sib headers: // sib_headers_size = (pickle_header.smallchunk_sibs_count + pickle_header.hugechunk_sibs_count) * sizeof( Sib_Header ); // sib_headers_buffer = (Sib_Header*) MALLOC (sib_headers_size); // if (heapio__read_block( bp, sib_headers_buffer, sib_headers_size ) == FALSE) { // FREE( sib_headers_buffer ); return FALSE; } // for (int ilk = 0; ilk < TOTAL_SIBS; ilk++) { // sib_headers[ ilk ] = NULL; } // for (int sib = 0; sib < pickle_header.smallchunk_sibs_count; sib++) { // Sib_Header* p = &sib_headers_buffer[ sib ]; // sib_headers[ p->chunk_ilk ] = p; } // DO BIG CHUNK HEADERS TOO // Check the heap to see if there is // enough free space in agegroup 1: // { Punt agegroup0_buffer_bytesize = agegroup0_buffer_size_in_bytes( task ); // Bool needs_cleaning = FALSE; for (int ilk = 0; ilk < MAX_PLAIN_SIBS; ilk++) { // Sib* sib = age1->sib[ ilk ]; if (sib_headers[ilk] != NULL && (!sib_is_active(sib) // sib_is_active def in src/c/h/heap.h || sib_freespace_in_bytes(sib) < sib_headers[ ilk ]->info.o.bytesize // sib_freespace_in_bytes def in src/c/h/heap.h + agegroup0_buffer_bytesize ) ){ needs_cleaning = TRUE; sib->requested_extra_free_bytes = sib_headers[ ilk ]->info.o.bytesize; } } if (needs_cleaning) { // if (bp->nbytes <= 0) { // call_heapcleaner( task, 1 ); // call_heapcleaner def in /src/c/heapcleaner/call-heapcleaner.c } else { // // The cleaning may move the buffer, so: Val buffer = PTR_CAST( Val, bp->base ); { Roots extra_roots = { &buffer, NULL }; // call_heapcleaner_with_extra_roots (task, 1, &extra_roots ); } if (buffer != PTR_CAST( Val, bp->base )) { // // The buffer moved, so adjust the buffer pointers: Unt8* new_base = PTR_CAST( Unt8*, buffer ); bp->buf = new_base + (bp->buf - bp->base); bp->base = new_base; } } } }
static Val pickle_heap_datastructure (Task *task, Val root_chunk, Pickler_Result* result) { // ========================= // Heap* heap = task->heap; int max_age = result->oldest_agegroup_included_in_pickle; Vunt total_sib_buffer_bytesize[ MAX_PLAIN_SIBS ]; Vunt total_bytesize; struct { Vunt base; // Base address of the sib buffer in the heap. Vunt offset; // Relative position in the merged sib buffer. // } adjust[ MAX_AGEGROUPS ][ MAX_PLAIN_SIBS ]; Sib_Header* p; // Sib_Header def in src/c/heapcleaner/runtime-heap-image.h Sib_Header* sib_headers[ TOTAL_SIBS ]; Sib_Header* sib_header_buffer; int sib_header_bytesize; int smallchunk_sibs_count; Val pickle; Writer* wr; // Compute the sib offsets in the heap image: // for (int ilk = 0; ilk < MAX_PLAIN_SIBS; ilk++) { // total_sib_buffer_bytesize[ ilk ] = 0; } // The embedded literals go first: // total_sib_buffer_bytesize[ NONPTR_DATA_SIB ] // pickler__relocate_embedded_literals def in src/c/heapcleaner/datastructure-pickler-cleaner.c = pickler__relocate_embedded_literals( result, NONPTR_DATA_SIB, 0 ); // DEBUG debug_say("%d bytes of string literals\n", total_sib_buffer_bytesize[NONPTR_DATA_SIB]); for (int age = 0; age < max_age; age++) { for (int ilk = 0; ilk < MAX_PLAIN_SIBS; ilk++) { // Sib* sib = heap->agegroup[ age ]->sib[ ilk ]; adjust[ age ][ ilk ].offset = total_sib_buffer_bytesize[ ilk ]; if (!sib_is_active(sib)) { // sib_is_active def in src/c/h/heap.h // adjust[ age ][ ilk ].base = 0; // } else { // total_sib_buffer_bytesize[ ilk ] += (Vunt) sib->tospace.first_free - (Vunt) sib->tospace.start; adjust[ age ][ ilk ].base = (Vunt) sib->tospace.start; } } } // DEBUG for (ilk = 0; ilk < MAX_PLAIN_SIBS; ilk++) debug_say ("sib %d: %d bytes\n", ilk+1, total_sib_buffer_bytesize[ilk]); // WHAT ABOUT THE BIG CHUNKS??? XXX BUGGO FIXME // Compute the total size of the pickled datastructure: // smallchunk_sibs_count = 0; total_bytesize = 0; // for (int ilk = 0; ilk < MAX_PLAIN_SIBS; ilk++) { // if (total_sib_buffer_bytesize[ilk] > 0) { smallchunk_sibs_count++; total_bytesize += total_sib_buffer_bytesize[ilk]; } } total_bytesize += sizeof( Heapfile_Header ) + sizeof( Pickle_Header ) + (smallchunk_sibs_count * sizeof( Sib_Header )); // COUNT SPACE FOR BIG CHUNKS total_bytesize += sizeof(Externs_Header) + heapfile_cfun_table_bytesize( result->cfun_table ); // Include the space for the external symbols (i.e., runtime C functions referenced within the heapgraph). // Allocate the heap bytevector for the pickled // datastructure representation and initialize // the bytevector-writer. // pickle = allocate_heap_ram_for_pickle( task, total_bytesize ); // wr = WR_OpenMem( PTR_CAST(Unt8*, pickle), total_bytesize ); // WR_OpenMem def in src/c/heapcleaner/mem-writer.c // Initialize the sib headers: // sib_header_bytesize = smallchunk_sibs_count * sizeof(Sib_Header); // sib_header_buffer = (Sib_Header*) MALLOC (sib_header_bytesize); // p = sib_header_buffer; // for (int ilk = 0; ilk < MAX_PLAIN_SIBS; ilk++) { // if (total_sib_buffer_bytesize[ ilk ] <= 0) { // sib_headers[ilk] = NULL; // } else { // p->age = 0; p->chunk_ilk = ilk; // p->info.o.base_address = 0; // Not used. p->info.o.bytesize = total_sib_buffer_bytesize[ ilk ]; p->info.o.rounded_bytesize = -1; // Not used. // p->offset = -1; // Not used. sib_headers[ ilk ] = p; p++; } } // What about big chunks? XXX BUGGO FIXME // Write the pickle image header: // if (heapio__write_image_header (wr, NORMAL_DATASTRUCTURE_PICKLE) == FALSE) { // heapio__write_image_header def in src/c/heapcleaner/export-heap-stuff.c // FREE( sib_header_buffer ); return PICKLER_ERROR; } // Write the pickle header: // { Pickle_Header header; header.smallchunk_sibs_count = smallchunk_sibs_count; header.hugechunk_sibs_count = 0; // FIX THIS XXX BUGGO FIXME header.hugechunk_quire_count = 0; // FIX THIS XXX BUGGO FIXME if (!IS_EXTERNAL_TAG( root_chunk )) { Sibid sibid = SIBID_FOR_POINTER( book_to_sibid__global, root_chunk ); if (!SIBID_KIND_IS_CODE(sibid)) { // This is the normal case -- // we're saving a vanilla heap value. Vunt addr = HEAP_POINTER_AS_UNT( root_chunk ); int age = GET_AGE_FROM_SIBID( sibid) - 1; int kind = GET_KIND_FROM_SIBID(sibid) - 1; // GET_KIND_FROM_SIBID def in src/c/h/sibid.h addr -= adjust[ age ][ kind ].base; addr += adjust[ age ][ kind ].offset; header.root_chunk = HIO_TAG_PTR(kind, addr); // HIO_TAG_PTR def in src/c/heapcleaner/runtime-heap-image.h } else { // Embedded_Chunk_Info* p = FIND_EMBEDDED_CHUNK( result->embedded_chunk_table, root_chunk ); if ((p == NULL) || (p->kind == USED_CODE)) { // say_error( "Pickling compiled Mythryl code not implemented\n" ); FREE (sib_header_buffer); return PICKLER_ERROR; } else { header.root_chunk = p->relocated_address; } } } else { // IS_EXTERNAL_TAG( root_chunk ) // ASSERT( smallchunk_sibs_count == 0 ); header.root_chunk = root_chunk; } WR_WRITE(wr, &header, sizeof(header)); // WR_WRITE def in src/c/heapcleaner/writer.h // if (WR_ERROR(wr)) { FREE (sib_header_buffer); return PICKLER_ERROR; } } // Record in the pickle the table of heap-referenced // runtime C functions. May also include // a handful of assembly fns, exceptions // and refcells: // { int bytes_written = heapio__write_cfun_table( wr, result->cfun_table ); // heapio__write_cfun_table def in src/c/heapcleaner/export-heap-stuff.c if (bytes_written == -1) { FREE( sib_header_buffer ); return PICKLER_ERROR; } } // Write the pickle sib headers: // WR_WRITE (wr, sib_header_buffer, sib_header_bytesize); // if (WR_ERROR(wr)) { FREE (sib_header_buffer); return PICKLER_ERROR; } // Write the pickled datastructure proper: // for (int ilk = 0; ilk < MAX_PLAIN_SIBS; ilk++) { // if (ilk == NONPTR_DATA_SIB) { // Write into the pickle the required embedded literals: // pickler__pickle_embedded_literals( wr ); // pickler__pickle_embedded_literals def in src/c/heapcleaner/datastructure-pickler-cleaner.c // Write into the pickle remaining required strings: // for (int age = 0; age < max_age; age++) { // Sib* sib = heap->agegroup[ age ]->sib[ ilk ]; if (sib_is_active(sib)) { // sib_is_active def in src/c/h/heap.h // WR_WRITE( wr, sib->tospace.start, (Vunt) sib->tospace.first_free -(Vunt) sib->tospace.start ); } } } else { for (int age = 0; age < max_age; age++) { // Sib* sib = heap->agegroup[ age ]->sib[ ilk ]; if (sib_is_active( sib )) { // Val* top = sib->tospace.first_free; // for (Val* p = sib->tospace.start; p < top; p++ ){ Val w = *p; if (IS_POINTER(w)) { // Sibid sibid = SIBID_FOR_POINTER( book_to_sibid__global, w ); if (BOOK_IS_UNMAPPED(sibid)) { // w = add_cfun_to_heapfile_cfun_table( result->cfun_table, w); ASSERT (w != HEAP_VOID); } else if (SIBID_KIND_IS_CODE(sibid)) { Embedded_Chunk_Info* chunk_info = FIND_EMBEDDED_CHUNK( result->embedded_chunk_table, w ); if (chunk_info == NULL || chunk_info->kind == USED_CODE ){ die("Pickling of Mythryl compiled code not implemented"); } else { w = chunk_info->relocated_address; } } else { // Adjust the pointer: // int age = GET_AGE_FROM_SIBID( sibid)-1; int kind = GET_KIND_FROM_SIBID(sibid)-1; Vunt addr = HEAP_POINTER_AS_UNT(w); addr -= adjust[ age ][ kind ].base; addr += adjust[ age ][ kind ].offset; w = HIO_TAG_PTR( kind, addr ); } } // if (IS_POINTER(w)) WR_PUT(wr, (Vunt)w); } // for } } } } FREE( sib_header_buffer ); if (WR_ERROR(wr)) return PICKLER_ERROR; return make_vector_header(task, STRING_TAGWORD, pickle, total_bytesize); } // fun pickle_heap_datastructure