From 1a92d3b5b81e195e192d07f407bfbfb52e425b23 Mon Sep 17 00:00:00 2001 From: wangdequan Date: Sun, 30 Aug 2026 14:20:48 +0800 Subject: [PATCH] Dynamically allocate large WASM G-code sources --- wasm-core/CMakeLists.txt | 2 +- wasm-core/include/sim_program.h | 9 +++- wasm-core/src/sim_program.c | 68 +++++++++++++++++++++++++---- web/worker/wasm-program-runtime.mjs | 8 +++- 4 files changed, 75 insertions(+), 12 deletions(-) diff --git a/wasm-core/CMakeLists.txt b/wasm-core/CMakeLists.txt index 382069d..ba4b117 100644 --- a/wasm-core/CMakeLists.txt +++ b/wasm-core/CMakeLists.txt @@ -247,7 +247,7 @@ if(EMSCRIPTEN) ) get_target_property(_sim_module_link_flags sim_core_module LINK_FLAGS) string(REPLACE "_sim_task_recover','_sim_task_restore" "_sim_task_recover','_sim_task_command_gate','_sim_task_restore" _sim_module_link_flags "${_sim_module_link_flags}") - string(REPLACE "_sim_interpreter_size" "_sim_program_size','_sim_program_requires_subroutines','_sim_program_init','_sim_program_reset','_sim_program_load','_sim_program_add_subroutine','_sim_program_set_rapid_velocity','_sim_program_start','_sim_program_pause','_sim_program_resume','_sim_program_abort','_sim_program_step','_sim_program_execute_block','_sim_program_seek','_sim_program_read_motion','_sim_program_clear_motion','_sim_program_canonical','_sim_program_state_hash','_sim_interpreter_size" _sim_module_link_flags "${_sim_module_link_flags}") + string(REPLACE "_sim_interpreter_size" "_sim_program_size','_sim_program_requires_subroutines','_sim_program_init','_sim_program_reset','_sim_program_destroy','_sim_program_load','_sim_program_add_subroutine','_sim_program_set_rapid_velocity','_sim_program_start','_sim_program_pause','_sim_program_resume','_sim_program_abort','_sim_program_step','_sim_program_execute_block','_sim_program_seek','_sim_program_read_motion','_sim_program_clear_motion','_sim_program_canonical','_sim_program_state_hash','_sim_interpreter_size" _sim_module_link_flags "${_sim_module_link_flags}") string(REPLACE "_sim_hal_set_pin" "_sim_hal_set_pin_scalar','_sim_hal_set_pin" _sim_module_link_flags "${_sim_module_link_flags}") string(REPLACE "_sim_hal_set_param" "_sim_hal_set_param_scalar','_sim_hal_set_param" _sim_module_link_flags "${_sim_module_link_flags}") string(REPLACE "_sim_io_init" "_sim_io_size','_sim_io_init" _sim_module_link_flags "${_sim_module_link_flags}") diff --git a/wasm-core/include/sim_program.h b/wasm-core/include/sim_program.h index d4f9a03..c1d0729 100644 --- a/wasm-core/include/sim_program.h +++ b/wasm-core/include/sim_program.h @@ -9,6 +9,8 @@ extern "C" { #define SIM_PROGRAM_SOURCE_CAPACITY 524288u #define SIM_PROGRAM_LINE_CAPACITY 16384u +#define SIM_PROGRAM_MAX_SOURCE_BYTES (64u * 1024u * 1024u) +#define SIM_PROGRAM_MAX_LINE_COUNT 1048576u #define SIM_PROGRAM_CANONICAL_CAPACITY 4096u #define SIM_PROGRAM_SUBROUTINE_CAPACITY 16u #define SIM_PROGRAM_SUBROUTINE_NAME_CAPACITY 48u @@ -48,8 +50,10 @@ typedef struct sim_program_call_frame { typedef struct sim_program { sim_interpreter interpreter; - char source[SIM_PROGRAM_SOURCE_CAPACITY]; - uint32_t line_offsets[SIM_PROGRAM_LINE_CAPACITY + 1u]; + char *source; + uint32_t *line_offsets; + uint32_t source_capacity; + uint32_t line_capacity; uint32_t source_length; uint32_t line_count; uint32_t main_line_count; @@ -72,6 +76,7 @@ uint32_t sim_program_size(void); int32_t sim_program_requires_subroutines(const char *source, uint32_t length); int32_t sim_program_init(sim_program *program); int32_t sim_program_reset(sim_program *program); +void sim_program_destroy(sim_program *program); int32_t sim_program_load(sim_program *program, const char *source, uint32_t length); int32_t sim_program_add_subroutine(sim_program *program, const char *source, uint32_t length); int32_t sim_program_set_rapid_velocity(sim_program *program, double velocity); diff --git a/wasm-core/src/sim_program.c b/wasm-core/src/sim_program.c index 8c7ca20..be633b7 100644 --- a/wasm-core/src/sim_program.c +++ b/wasm-core/src/sim_program.c @@ -60,7 +60,8 @@ static int parse_oword(const char *line, uint32_t length, char *name, size_t nam int32_t sim_program_requires_subroutines(const char *source, uint32_t length) { uint32_t offset = 0; - if (source == NULL || length == 0 || length >= SIM_PROGRAM_SOURCE_CAPACITY) return SIM_PROGRAM_ERR_ARGUMENT; + if (source == NULL || length == 0) return SIM_PROGRAM_ERR_ARGUMENT; + if (length > SIM_PROGRAM_MAX_SOURCE_BYTES) return SIM_PROGRAM_ERR_RANGE; while (offset < length) { uint32_t available = length - offset; uint32_t line_size = line_length(source + offset, available); @@ -74,25 +75,65 @@ int32_t sim_program_requires_subroutines(const char *source, uint32_t length) { return 0; } -static void reindex_source(sim_program *program) { +static int ensure_source_capacity(sim_program *program, uint32_t required) { + uint32_t capacity; + char *source; + if (required <= program->source_capacity) return SIM_PROGRAM_OK; + capacity = program->source_capacity == 0 ? SIM_PROGRAM_SOURCE_CAPACITY : program->source_capacity; + while (capacity < required) { + if (capacity >= SIM_PROGRAM_MAX_SOURCE_BYTES / 2u) { capacity = SIM_PROGRAM_MAX_SOURCE_BYTES; break; } + capacity *= 2u; + } + if (capacity < required || capacity > SIM_PROGRAM_MAX_SOURCE_BYTES) return SIM_PROGRAM_ERR_RANGE; + source = (char *)realloc(program->source, capacity); + if (source == NULL) return SIM_PROGRAM_ERR_RANGE; + program->source = source; + program->source_capacity = capacity; + return SIM_PROGRAM_OK; +} + +static int ensure_line_capacity(sim_program *program, uint32_t required) { + uint32_t capacity; + uint32_t *offsets; + if (required <= program->line_capacity) return SIM_PROGRAM_OK; + capacity = program->line_capacity == 0 ? SIM_PROGRAM_LINE_CAPACITY + 1u : program->line_capacity; + while (capacity < required) { + if (capacity >= SIM_PROGRAM_MAX_LINE_COUNT / 2u) { capacity = SIM_PROGRAM_MAX_LINE_COUNT + 1u; break; } + capacity *= 2u; + } + if (capacity > SIM_PROGRAM_MAX_LINE_COUNT + 1u) return SIM_PROGRAM_ERR_RANGE; + offsets = (uint32_t *)realloc(program->line_offsets, (size_t)capacity * sizeof(*offsets)); + if (offsets == NULL) return SIM_PROGRAM_ERR_RANGE; + program->line_offsets = offsets; + program->line_capacity = capacity; + return SIM_PROGRAM_OK; +} + +static int reindex_source(sim_program *program) { uint32_t index; + if (ensure_line_capacity(program, 2u) != SIM_PROGRAM_OK) return SIM_PROGRAM_ERR_RANGE; program->line_count = program->source_length == 0 ? 0 : 1; program->line_offsets[0] = 0; for (index = 0; index < program->source_length; ++index) if (program->source[index] == '\n' && index + 1u < program->source_length) { - if (program->line_count < SIM_PROGRAM_LINE_CAPACITY) program->line_offsets[program->line_count++] = index + 1u; + if (program->line_count >= SIM_PROGRAM_MAX_LINE_COUNT || ensure_line_capacity(program, program->line_count + 2u) != SIM_PROGRAM_OK) return SIM_PROGRAM_ERR_RANGE; + program->line_offsets[program->line_count++] = index + 1u; } program->line_offsets[program->line_count] = program->source_length; + return SIM_PROGRAM_OK; } static int append_source(sim_program *program, const char *source, uint32_t length) { - uint32_t separator = program->source_length > 0 && program->source[program->source_length - 1u] != '\n' ? 1u : 0u; - if (source == NULL || length == 0 || program->source_length + separator + length >= SIM_PROGRAM_SOURCE_CAPACITY) return SIM_PROGRAM_ERR_RANGE; + uint32_t separator; + uint64_t required; + if (source == NULL || length == 0) return SIM_PROGRAM_ERR_ARGUMENT; + separator = program->source_length > 0 && program->source[program->source_length - 1u] != '\n' ? 1u : 0u; + required = (uint64_t)program->source_length + separator + length + 1u; + if (required > SIM_PROGRAM_MAX_SOURCE_BYTES + 1ull || ensure_source_capacity(program, (uint32_t)required) != SIM_PROGRAM_OK) return SIM_PROGRAM_ERR_RANGE; if (separator) program->source[program->source_length++] = '\n'; memcpy(program->source + program->source_length, source, length); program->source_length += length; program->source[program->source_length] = '\0'; - reindex_source(program); - return SIM_PROGRAM_OK; + return reindex_source(program); } static int scan_subroutines(sim_program *program) { @@ -245,13 +286,24 @@ int32_t sim_program_init(sim_program *program) { int32_t sim_program_reset(sim_program *program) { if (program == NULL) return SIM_PROGRAM_ERR_ARGUMENT; if (sim_interpreter_reset(&program->interpreter) != SIM_INTERP_OK) return SIM_PROGRAM_ERR_INTERPRETER; + free(program->source); + free(program->line_offsets); + program->source = NULL; + program->line_offsets = NULL; + program->source_capacity = 0; + program->line_capacity = 0; reset_runtime(program); return SIM_PROGRAM_OK; } +void sim_program_destroy(sim_program *program) { + if (program == NULL) return; + (void)sim_program_reset(program); +} + int32_t sim_program_load(sim_program *program, const char *source, uint32_t length) { if (program == NULL || source == NULL) return SIM_PROGRAM_ERR_ARGUMENT; - if (length == 0 || length >= SIM_PROGRAM_SOURCE_CAPACITY) return SIM_PROGRAM_ERR_RANGE; + if (length == 0 || length > SIM_PROGRAM_MAX_SOURCE_BYTES) return SIM_PROGRAM_ERR_RANGE; if (sim_program_reset(program) != SIM_PROGRAM_OK) return SIM_PROGRAM_ERR_INTERPRETER; if (append_source(program, source, length) != SIM_PROGRAM_OK) return SIM_PROGRAM_ERR_RANGE; program->main_line_count = program->line_count; diff --git a/web/worker/wasm-program-runtime.mjs b/web/worker/wasm-program-runtime.mjs index 936a910..6cd4ec5 100644 --- a/web/worker/wasm-program-runtime.mjs +++ b/web/worker/wasm-program-runtime.mjs @@ -271,5 +271,11 @@ export class WasmProgramRuntime { } finally { this.core._free(buffer); } } - destroy() { for (const pointer of [this.pointer, this.motionPointer, this.samplePointer, this.samplePosePointer]) if (pointer && typeof this.core?._free === "function") this.core._free(pointer); this.pointer = this.motionPointer = this.samplePointer = this.samplePosePointer = 0; this.executionSource = ""; this.executionLines = []; } + destroy() { + if (this.pointer && (typeof this.core?._sim_program_destroy === "function" || typeof this.core?.sim_program_destroy === "function")) call(this.core, "sim_program_destroy", "number", ["number"], [this.pointer]); + for (const pointer of [this.pointer, this.motionPointer, this.samplePointer, this.samplePosePointer]) if (pointer && typeof this.core?._free === "function") this.core._free(pointer); + this.pointer = this.motionPointer = this.samplePointer = this.samplePosePointer = 0; + this.executionSource = ""; + this.executionLines = []; + } }