static Val mkList (Task* task, int ngrps, gid gidset[]) { // ====== // // Convert array of gid_t into a list of gid_t Val w; // NOTE: We should do something about possible cleaning!!! XXX BUGGO FIXME Val p = LIST_NIL; while (ngrps-- > 0) { // WORD_ALLOC (task, w, (Val_Sized_Unt)(gidset[ngrps])); LIST_CONS(task, p, w, p); } return p; }
Val raise_error__may_heapclean ( //========================== // Task* task, const char* altMsg, const char* at, // C sourcefile and line number raising this error: "<foo.c:37>" Roots* extra_roots ) { // Raise the Mythryl exception RUNTIME_EXCEPTION, which is defined as: // // exception RUNTIME_EXCEPTION (String, Null_Or(System_Error) ); // // We normally get invoked via either the // RAISE_SYSERR__MAY_HEAPCLEAN or RAISE_ERROR__MAY_HEAPCLEAN macro from // // src/c/lib/raise-error.h // // For the time being, we use the errno value as the System_Error; eventually that // will be represented by an (Int, String) pair. If alt_msg is non-zero, // then use it as the error string and use NULL for the System_Error. int error_number = errno; // Various calls can trash this value so preserve it early. const char* msg; char buf[32]; Val null_or_errno; if (altMsg != NULL) { // msg = altMsg; null_or_errno = OPTION_NULL; } else if ((msg = strerror(error_number)) != NULL) { null_or_errno = OPTION_THE( task, TAGGED_INT_FROM_C_INT(error_number) ); } else { sprintf(buf, "<unknown error %d>", error_number); msg = buf; null_or_errno = OPTION_THE( task, TAGGED_INT_FROM_C_INT(error_number) ); } #if (defined(DEBUG_OS_INTERFACE) || defined(DEBUG_TRACE_CCALL)) debug_say ("RaiseSysError: errno = %d, msg = \"%s\"\n", (altMsg != NULL) ? -1 : error_number, msg); #endif Roots roots1 = { &null_or_errno, extra_roots }; Val errno_string = make_ascii_string_from_c_string__may_heapclean (task, msg, &roots1 ); Val at_list; // [] or [ "<foo.c:187>" ]. // if (at != NULL) { // Roots roots2 = { &errno_string, &roots1 }; Val at_cstring = make_ascii_string_from_c_string__may_heapclean (task, at, &roots2 ); at_list = LIST_CONS(task, at_cstring, LIST_NIL); } else { at_list = LIST_NIL; } Val arg = make_two_slot_record( task, errno_string, null_or_errno); Val syserr_exception = MAKE_EXCEPTION(task, PTR_CAST( Val, RUNTIME_EXCEPTION__GLOBAL), arg, at_list); // Modify the task state so that 'syserr_exception' // will be raised when Mythryl execution resumes: // raise_mythryl_exception( task, syserr_exception ); // raise_mythryl_exception is from src/c/main/run-mythryl-code-and-runtime-eventloop.c return syserr_exception; } // fun raise_error__may_heapclean
static Val read_in_compiled_file_list__may_heapclean ( // ========================================= // Task* task, const char* compiled_files_to_load_filename, int* return_max_boot_path_len, Roots* extra_roots ){ // Open given file and read from it the list of // filenames of compiled_files to be later loaded. // Return them as a Mythryl list of Mythryl strings: #define BUF_LEN 1024 // "This should be plenty for two numbers." "640K should be enough for anyone." char buf[ BUF_LEN ]; // Val* file_names = NULL; char* name_buf = NULL; int max_num_boot_files = MAX_NUMBER_OF_BOOT_FILES; int max_boot_path_len = MAX_LENGTH_FOR_A_BOOTFILE_PATHNAME; int file_count = 0; FILE* list_fd = open_file( compiled_files_to_load_filename, FALSE ); fprintf ( stderr, " load-compiledfiles.c: Reading file %s\n", compiled_files_to_load_filename ); if (log_fd) { // fprintf ( log_fd, " load-compiledfiles.c: Reading file %s\n", compiled_files_to_load_filename ); } Val file_list = LIST_NIL; Roots roots1 = { &file_list, extra_roots }; if (list_fd) { // Read header: // for (;;) { // if (!fgets (buf, BUF_LEN, list_fd)) { die ( "compiled_files_to_load file \"%s\" ends before end-of-header (first empty line)", compiled_files_to_load_filename ); } { char* p = buf; while (*p == ' ' || *p == '\t') ++p; // Skip leading whitespace. if (p[0] == '\n') break; // Header ends at first empty line. if (p[0] == '#') continue; // Ignore comment lines. if (strstr( p,"FILES=") == p) { // max_num_boot_files = strtoul(p+6, NULL, 0); continue; } if (strstr(p,"MAX_LINE_LENGTH=") == p) { // max_boot_path_len = strtoul(p+16, NULL, 0) +2; continue; } die ( "compiled_files_to_load file \"%s\" contains unrecognized header line \"%s\"", compiled_files_to_load_filename, p ); } } if (max_num_boot_files < 0) { // die("compiled_files_to_load file \"%s\" contains negative files count?! (%d)", compiled_files_to_load_filename, max_num_boot_files ); } if (max_boot_path_len < 0) { // die("compiled_file_to_load file \"%s\" contains negative boot path len?! (%d)", compiled_files_to_load_filename, max_boot_path_len ); } *return_max_boot_path_len = max_boot_path_len; // Tell the calling function. if (!(name_buf = MALLOC( max_boot_path_len ))) { // die ("unable to allocate space for .compiled file filenames"); } // if (!(file_names = MALLOC( max_num_boot_files * sizeof(char*) ))) { // // // die ("Unable to allocate space for compiledfiles-to-load name table"); // } // Read in the file names, converting them to // Mythryl strings and saving them in a list: // while (fgets( name_buf, max_boot_path_len, list_fd )) { // Skip leading whitespace: // char* p = name_buf; while (*p == ' ' || *p == '\t') ++p; // Ignore empty lines and comment lines: // if (*p == '\n') continue; if (*p == '#') continue; // Strip any trailing newline: // { int j = strlen(p)-1; // if (p[j] == '\n') p[j] = '\0'; } if (file_count >= max_num_boot_files) die ("too many files\n"); // If our agegroup0 buffer is more than half full, // empty it by doing a heapcleaning. This is very // conservative -- which is the way I like it. *grin* // if (agegroup0_freespace_in_bytes( task ) < agegroup0_usedspace_in_bytes( task ) ){ call_heapcleaner_with_extra_roots( task, 0, &roots1 ); } Val file_name = make_ascii_string_from_c_string__may_heapclean(task, p, &roots1 ); file_list = LIST_CONS(task, file_name, file_list); } if (name_buf) FREE( name_buf ); fclose( list_fd ); } // Reverse filename list (to restore // original order) and return it: // { Val file_list2 = LIST_NIL; Roots roots2 = { &file_list2, &roots1 }; // for (; file_list != LIST_NIL; file_list = LIST_TAIL(file_list)) { // Val file_name = LIST_HEAD(file_list); // file_list2 = LIST_CONS(task, file_name, file_list2); // Again, if our agegroup0 buffer is more than // half full, empty it by doing a heapcleaning: // if (agegroup0_freespace_in_bytes( task ) < agegroup0_usedspace_in_bytes( task ) ){ call_heapcleaner_with_extra_roots( task, 0, &roots2 ); } } return file_list2; } }
Val make_package_literals_via_bytecode_interpreter (Task* task, Unt8* bytecode_vector, int bytecode_vector_length_in_bytes) { //============== // // NOTE: We allocate all of the chunks in agegroup 1, // but allocate the vector of literals in agegroup0. // // This fn gets exported to the Mythryl level as // // make_package_literals_via_bytecode_interpreter // in // src/lib/compiler/execution/code-segments/code-segment.pkg // via // src/c/lib/heap/make-package-literals-via-bytecode-interpreter.c // // Our ultimate invocation is in // // src/lib/compiler/execution/main/execute.pkg int pc = 0; // Check that sufficient space is available for the // literal chunk that we are about to allocate. // Note that the cons cell has already been accounted // for in space_available (but not in space_needed). // #define GC_CHECK \ do { \ if (space_needed > space_available \ && need_to_call_heapcleaner( task, space_needed + LIST_CONS_CELL_BYTESIZE) \ ){ \ call_heapcleaner_with_extra_roots (task, 0, (Val *)&bytecode_vector, &stk, NULL); \ space_available = 0; \ \ } else { \ \ space_available -= space_needed; \ } \ } while (0) #ifdef DEBUG_LITERALS debug_say("make_package_literals_via_bytecode_interpreter: bytecode_vector = %#x, bytecode_vector_length_in_bytes = %d\n", bytecode_vector, bytecode_vector_length_in_bytes); #endif if (bytecode_vector_length_in_bytes <= 8) return HEAP_NIL; Val_Sized_Unt magic = GET32(bytecode_vector); pc += 4; Val_Sized_Unt max_depth /* This variable is currently unused, so suppress 'unused var' compiler warning: */ __attribute__((unused)) = GET32(bytecode_vector); pc += 4; if (magic != V1_MAGIC) { die("bogus literal magic number %#x", magic); } Val stk = HEAP_NIL; int space_available = 0; for (;;) { // ASSERT(pc < bytecode_vector_length_in_bytes); space_available -= LIST_CONS_CELL_BYTESIZE; // Space for stack cons cell. if (space_available < ONE_K_BINARY) { // if (need_to_call_heapcleaner(task, 64*ONE_K_BINARY)) { // call_heapcleaner_with_extra_roots (task, 0, (Val *)&bytecode_vector, &stk, NULL); } space_available = 64*ONE_K_BINARY; } switch (bytecode_vector[ pc++ ]) { // case I_INT: { int i = GET32(bytecode_vector); pc += 4; #ifdef DEBUG_LITERALS debug_say("[%2d]: INT(%d)\n", pc-5, i); #endif LIST_CONS(task, stk, TAGGED_INT_FROM_C_INT(i), stk); } break; case I_RAW32: { int i = GET32(bytecode_vector); pc += 4; #ifdef DEBUG_LITERALS debug_say("[%2d]: RAW32[%d]\n", pc-5, i); #endif Val result; INT1_ALLOC(task, result, i); LIST_CONS(task, stk, result, stk); space_available -= 2*WORD_BYTESIZE; } break; case I_RAW32L: { int n = GET32(bytecode_vector); pc += 4; #ifdef DEBUG_LITERALS debug_say("[%2d]: RAW32L(%d) [...]\n", pc-5, n); #endif ASSERT(n > 0); int space_needed = 4*(n+1); GC_CHECK; LIB7_AllocWrite (task, 0, MAKE_TAGWORD(n, FOUR_BYTE_ALIGNED_NONPOINTER_DATA_BTAG)); for (int j = 1; j <= n; j++) { // int i = GET32(bytecode_vector); pc += 4; LIB7_AllocWrite (task, j, (Val)i); } Val result = LIB7_Alloc(task, n ); LIST_CONS(task, stk, result, stk); } break; case I_RAW64: { double d = get_double(&(bytecode_vector[pc])); pc += 8; Val result; REAL64_ALLOC(task, result, d); #ifdef DEBUG_LITERALS debug_say("[%2d]: RAW64[%f] @ %#x\n", pc-5, d, result); #endif LIST_CONS(task, stk, result, stk); space_available -= 4*WORD_BYTESIZE; // Extra 4 bytes for alignment padding. } break; case I_RAW64L: { int n = GET32(bytecode_vector); pc += 4; #ifdef DEBUG_LITERALS debug_say("[%2d]: RAW64L(%d) [...]\n", pc-5, n); #endif ASSERT(n > 0); int space_needed = 8*(n+1); GC_CHECK; #ifdef ALIGN_FLOAT64S // Force FLOAT64_BYTESIZE alignment (descriptor is off by one word) // task->heap_allocation_pointer = (Val*)((Punt)(task->heap_allocation_pointer) | WORD_BYTESIZE); #endif int j = 2*n; // Number of words. LIB7_AllocWrite (task, 0, MAKE_TAGWORD(j, EIGHT_BYTE_ALIGNED_NONPOINTER_DATA_BTAG)); Val result = LIB7_Alloc(task, j ); for (int j = 0; j < n; j++) { // PTR_CAST(double*, result)[j] = get_double(&(bytecode_vector[pc])); pc += 8; } LIST_CONS(task, stk, result, stk); } break; case I_STR: { int n = GET32(bytecode_vector); pc += 4; #ifdef DEBUG_LITERALS debug_say("[%2d]: STR(%d) [...]", pc-5, n); #endif if (n == 0) { #ifdef DEBUG_LITERALS debug_say("\n"); #endif LIST_CONS(task, stk, ZERO_LENGTH_STRING__GLOBAL, stk); break; } int j = BYTES_TO_WORDS(n+1); // '+1' to include space for '\0'. // The space request includes space for the data-chunk header word and // the sequence header chunk. // int space_needed = WORD_BYTESIZE*(j+1+3); GC_CHECK; // Allocate the data chunk: // LIB7_AllocWrite(task, 0, MAKE_TAGWORD(j, FOUR_BYTE_ALIGNED_NONPOINTER_DATA_BTAG)); LIB7_AllocWrite (task, j, 0); // So word-by-word string equality works. Val result = LIB7_Alloc (task, j); #ifdef DEBUG_LITERALS debug_say(" @ %#x (%d words)\n", result, j); #endif memcpy (PTR_CAST(void*, result), &bytecode_vector[pc], n); pc += n; // Allocate the header chunk: // SEQHDR_ALLOC(task, result, STRING_TAGWORD, result, n); // Push on stack: // LIST_CONS(task, stk, result, stk); } break; case I_LIT: { int n = GET32(bytecode_vector); pc += 4; Val result = stk; for (int j = 0; j < n; j++) { // result = LIST_TAIL(result); } #ifdef DEBUG_LITERALS debug_say("[%2d]: LIT(%d) = %#x\n", pc-5, n, LIST_HEAD(result)); #endif LIST_CONS(task, stk, LIST_HEAD(result), stk); } break; case I_VECTOR: { int n = GET32(bytecode_vector); pc += 4; #ifdef DEBUG_LITERALS debug_say("[%2d]: VECTOR(%d) [", pc-5, n); #endif if (n == 0) { #ifdef DEBUG_LITERALS debug_say("]\n"); #endif LIST_CONS(task, stk, ZERO_LENGTH_VECTOR__GLOBAL, stk); break; } // The space request includes space // for the data-chunk header word and // the sequence header chunk. // int space_needed = WORD_BYTESIZE*(n+1+3); GC_CHECK; // Allocate the data chunk: // LIB7_AllocWrite(task, 0, MAKE_TAGWORD(n, RO_VECTOR_DATA_BTAG)); // Top of stack is last element in vector: // for (int j = n; j > 0; j--) { // LIB7_AllocWrite(task, j, LIST_HEAD(stk)); stk = LIST_TAIL(stk); } Val result = LIB7_Alloc(task, n ); // Allocate the header chunk: // SEQHDR_ALLOC(task, result, TYPEAGNOSTIC_RO_VECTOR_TAGWORD, result, n); #ifdef DEBUG_LITERALS debug_say("...] @ %#x\n", result); #endif LIST_CONS(task, stk, result, stk); } break; case I_RECORD: { int n = GET32(bytecode_vector); pc += 4; #ifdef DEBUG_LITERALS debug_say("[%2d]: RECORD(%d) [", pc-5, n); #endif if (n == 0) { #ifdef DEBUG_LITERALS debug_say("]\n"); #endif LIST_CONS(task, stk, HEAP_VOID, stk); break; } else { int space_needed = 4*(n+1); GC_CHECK; LIB7_AllocWrite(task, 0, MAKE_TAGWORD(n, PAIRS_AND_RECORDS_BTAG)); } // Top of stack is last element in record: // for (int j = n; j > 0; j--) { // LIB7_AllocWrite(task, j, LIST_HEAD(stk)); stk = LIST_TAIL(stk); } Val result = LIB7_Alloc(task, n ); #ifdef DEBUG_LITERALS debug_say("...] @ %#x\n", result); #endif LIST_CONS(task, stk, result, stk); } break; case I_RETURN: ASSERT(pc == bytecode_vector_length_in_bytes); #ifdef DEBUG_LITERALS debug_say("[%2d]: RETURN(%#x)\n", pc-5, LIST_HEAD(stk)); #endif return LIST_HEAD( stk ); break; default: die ("bogus literal opcode #%x @ %d", bytecode_vector[pc-1], pc-1); } // switch } // while } // fun make_package_literals_via_bytecode_interpreter