/* StarForth — Steady-State Virtual Machine Runtime Copyright (c) 2023–2025 Robert A. James All rights reserved. This file is part of the StarForth project. Licensed under the StarForth License, Version 1.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at: https://github.com/star.4th@proton.me/StarForth/LICENSE.txt This software is provided "AS IS", WITHOUT WARRANTY OF ANY KIND, express or implied, including but not limited to the warranties of merchantability, fitness for a particular purpose, and noninfringement. See the License for the specific language governing permissions and limitations under the License. StarForth — Steady-State Virtual Machine Runtime Copyright (c) 2023–2025 Robert A. James All rights reserved. This file is part of the StarForth project. Licensed under the StarForth License, Version 1.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at: https://github.com/star.4th@proton.me/StarForth/LICENSE.txt This software is provided "AS IS", WITHOUT WARRANTY OF ANY KIND, express or implied, including but not limited to the warranties of merchantability, fitness for a particular purpose, and noninfringement. See the License for the specific language governing permissions and limitations under the License. */ /* * vm_bootstrap.c - VM initialization and bootstrap logic */ #include "../include/vm.h" #include "../include/log.h" #include "../include/word_registry.h" #include "../include/vm_debug.h" #include "../include/physics_hotwords_cache.h" #include "../include/rolling_window_of_truth.h" #include "../include/dictionary_heat_optimization.h" #include "../include/ssm_jacquard.h" #include "word_source/include/vocabulary_words.h" #include "vm_internal.h" #ifdef __STARKERNEL__ #include "starkernel/vm/arena.h" #include "starkernel/console.h" #endif #include #include #if defined(__STARKERNEL__) && SK_PARITY_DEBUG static void vm_bootstrap_print_hex(uint64_t value) { char buf[19]; buf[0] = '0'; buf[1] = 'x'; buf[18] = '\0'; for (int i = 0; i < 16; ++i) { uint8_t nibble = (uint8_t)((value >> ((15 - i) * 4)) & 0xF); buf[i + 2] = (nibble < 10) ? (char)('0' + nibble) : (char)('a' + nibble - 10); } console_puts(buf); } #endif static void vm_bootstrap_scr(VM *vm) { vm_align(vm); void* p = vm_allot(vm, sizeof(cell_t)); if (!p) { vm->error = 1; log_message(LOG_ERROR, "vm_bootstrap_scr: SCR allot failed"); return; } vm->scr_addr = (vaddr_t)((uint8_t*)p - vm->memory); vm_store_cell(vm, vm->scr_addr, 0); } void vm_bootstrap_root_vocabulary(VM *vm, const char *name) { if (!vm || !name) { return; } #if defined(__STARKERNEL__) && SK_PARITY_DEBUG console_println("[VM_BOOTSTRAP] root vocabulary entry"); #endif #ifdef __STARKERNEL__ sk_vm_arena_assert_guards("vm_bootstrap_root_vocabulary:entry"); #endif vocabulary_create_vocabulary_direct(vm, name); size_t len = strlen(name); #if defined(__STARKERNEL__) && SK_PARITY_DEBUG console_println("[VM_BOOTSTRAP] before vm_find_word"); #endif DictEntry *entry = vm_find_word(vm, name, len); #if defined(__STARKERNEL__) && SK_PARITY_DEBUG console_println("[VM_BOOTSTRAP] after vm_find_word"); #endif if (!entry || !entry->func) { vm->error = 1; log_message(LOG_ERROR, "bootstrap: missing vocabulary '%s'", name); return; } #if defined(__STARKERNEL__) && SK_PARITY_DEBUG console_puts("[VOC] "); console_puts(name); console_puts(" entry="); vm_bootstrap_print_hex((uint64_t)(uintptr_t)entry); console_puts(" xt="); vm_bootstrap_print_hex((uint64_t)(uintptr_t)entry->func); console_println(""); const VMHostServices *host = vm_host(vm); if (host && host->is_executable_ptr && !host->is_executable_ptr((const void *)entry->func)) { console_puts("[VOC] invalid XT for "); console_puts(name); console_puts(" func="); vm_bootstrap_print_hex((uint64_t)(uintptr_t)entry->func); console_println(""); if (host->panic) { host->panic("bootstrap vocabulary XT invalid"); } } #endif entry->func(vm); vocabulary_word_definitions(vm); #ifdef __STARKERNEL__ sk_vm_arena_assert_guards("vm_bootstrap_root_vocabulary:exit"); #endif } void vm_init(VM* vm) { vm_init_with_host(vm, NULL); } void vm_init_with_host(VM* vm, const VMHostServices *host) { if (!vm) return; *vm = (VM){0}; vm->host = host ? host : vm_default_host_services(); #ifndef __STARKERNEL__ vm_reset_hosted_fake_ns(vm); #endif vm->interpreter_enabled = 0; vm->next_word_id = 0; vm->recycled_word_id_count = 0; if (sf_mutex_init(&vm->dict_lock) != 0) { log_message(LOG_ERROR, "vm_init: dict_lock init failed"); vm->error = 1; return; } if (sf_mutex_init(&vm->tuning_lock) != 0) { log_message(LOG_ERROR, "vm_init: tuning_lock init failed"); sf_mutex_destroy(&vm->dict_lock); vm->error = 1; return; } vm->memory = (uint8_t*)vm_host_alloc(vm, VM_MEMORY_SIZE, sizeof(void*)); if (!vm->memory) { log_message(LOG_ERROR, "vm_init: out of host memory"); vm->error = 1; return; } vm->dsp = -1; vm->rsp = -1; vm->here = 0; vm->exit_colon = 0; /* Control-flow bookkeeping sentinels (-1/-999 mean "empty"; the * `*vm = (VM){0}` above already zeroed the arrays themselves) */ vm->cf.cf_sp = -1; vm->cf.cf_last_mode = -999; vm->cf.leave_sp = -1; vm->cf.leave_mark_sp = -1; vm->cf.endof_sp = -1; vm->cf.endof_mark_sp = -1; vm->abort_requested = 0; log_message(LOG_DEBUG, "vm_init: memory=%p here=%zu", (void*)vm->memory, vm->here); vm_bootstrap_scr(vm); /* STATE (0=interpret, -1=compile) */ { void* p = vm_allot(vm, sizeof(cell_t)); if (!p) { vm->error = 1; log_message(LOG_ERROR, "vm_init: STATE allot failed"); return; } vm->state_addr = (vaddr_t)((uint8_t*)p - vm->memory); vm_store_cell(vm, vm->state_addr, 0); vm->state_var = 0; } /* BASE (default 10) */ { void* p = vm_allot(vm, sizeof(cell_t)); if (!p) { vm->error = 1; log_message(LOG_ERROR, "vm_init: BASE allot failed"); return; } vm->base_addr = (vaddr_t)((uint8_t*)p - vm->memory); vm_set_base(vm, 10); } /* Pictured-number hold buffer (64 bytes, per-VM so child VMs are independent) */ { void* p = vm_allot(vm, 64); if (!p) { vm->error = 1; log_message(LOG_ERROR, "vm_init: hold buffer allot failed"); return; } vm->hold_addr = (vaddr_t)((uint8_t*)p - vm->memory); vm->hold_pos = 0; memset(p, 0, 64); } vm->mode = MODE_INTERPRET; vm->compiling_word = NULL; vm->latest = NULL; vm->error = 0; vm->halted = 0; vm->input_length = 0; vm->input_pos = 0; vm->current_executing_entry = NULL; vm_debug_set_current_vm(vm); vm_debug_install_signal_handlers(); /* Register Forth-79 wordset */ register_forth79_words(vm); #ifdef __STARKERNEL__ #if SK_PARITY_DEBUG console_println("[VM_BOOTSTRAP] register_forth79_words complete"); #endif #endif /* Interpreter may be enabled only after parity check passes (in sk_vm_bootstrap.c) */ /* Set FORGET fence to post-boot */ vm->dict_fence_latest = vm->latest; vm->dict_fence_here = vm->here; /* Initialize hot-words cache */ vm->hotwords_cache = (HotwordsCache*)vm_host_alloc(vm, sizeof(HotwordsCache), sizeof(void*)); if (!vm->hotwords_cache) { log_message(LOG_ERROR, "vm_init: hotwords cache malloc failed"); vm->error = 1; return; } hotwords_cache_init(vm->hotwords_cache); /* Initialize rolling window */ if (rolling_window_init(&vm->rolling_window) != 0) { log_message(LOG_ERROR, "vm_init: rolling window malloc failed"); vm->error = 1; return; } /* Initialize VM heartbeat */ vm->heartbeat.tick_count = 0; vm->heartbeat.last_inference_tick = 0; vm->heartbeat.check_counter = 0; vm->heartbeat.heartbeat_enabled = 1; vm->heartbeat.tick_target_ns = HEARTBEAT_TICK_NS; vm->heartbeat.snapshot_index = 0; vm->heartbeat.worker = NULL; vm->heartbeat_decay_cursor_id = WORD_ID_INVALID; vm->pipeline_metrics.prefetch_attempts = 0; vm->pipeline_metrics.prefetch_hits = 0; vm->pipeline_metrics.window_tuning_checks = 0; vm->pipeline_metrics.last_checked_window_size = vm->rolling_window.effective_window_size; vm->pipeline_metrics.last_checked_accuracy = 0.0; vm->pipeline_metrics.suggested_next_size = vm->rolling_window.effective_window_size; heartbeat_publish_snapshot(vm); #if HEARTBEAT_HAS_THREADS vm->heartbeat.worker = vm_host_calloc(vm, 1, sizeof(HeartbeatWorker)); if (vm->heartbeat.worker) { vm->heartbeat.worker->tick_ns = HEARTBEAT_TICK_NS; if (pthread_create(&vm->heartbeat.worker->thread, NULL, heartbeat_thread_main, vm) != 0) { log_message(LOG_WARN, "heartbeat: pthread_create failed (%d), falling back to inline mode", errno); vm_host_free(vm, vm->heartbeat.worker); vm->heartbeat.worker = NULL; } } else { log_message(LOG_WARN, "heartbeat: worker allocation failed, using inline heartbeat"); } #endif vm->decay_slope_q48 = (1ULL << 16) / 3; vm->last_decay_check_ns = 0; vm->total_heat_at_last_check = 0; vm->stale_word_count_at_check = 0; vm->decay_slope_direction = 0; vm->lookup_strategy = 0; vm->last_bucket_reorg_ns = 0; dict_update_heat_percentiles(vm); vm->ssm_l8_state = vm_host_alloc(vm, sizeof(ssm_l8_state_t), sizeof(void*)); if (!vm->ssm_l8_state) { log_message(LOG_ERROR, "vm_init: SSM L8 state malloc failed"); vm->error = 1; return; } ssm_l8_init((ssm_l8_state_t*)vm->ssm_l8_state, SSM_MODE_C0); ssm_l8_init_table((ssm_l8_state_t*)vm->ssm_l8_state); vm->ssm_config = vm_host_alloc(vm, sizeof(ssm_config_t), sizeof(void*)); if (!vm->ssm_config) { log_message(LOG_ERROR, "vm_init: SSM config malloc failed"); vm->error = 1; return; } ((ssm_config_t*)vm->ssm_config)->L1_heat_tracking = 0; ((ssm_config_t*)vm->ssm_config)->L2_rolling_window = 0; ((ssm_config_t*)vm->ssm_config)->L3_linear_decay = 0; ((ssm_config_t*)vm->ssm_config)->L4_pipelining = 0; ((ssm_config_t*)vm->ssm_config)->L5_window_inference = 0; ((ssm_config_t*)vm->ssm_config)->L6_decay_inference = 0; ((ssm_config_t*)vm->ssm_config)->L7_adaptive_heartrate = 0; }