1
0
Fork 0
forked from fun/fun

Some internal optimzations and helpers. (0.41.14)

This commit is contained in:
Johannes Findeisen 2026-05-26 04:43:11 +02:00
commit 0d6685abcd
4 changed files with 62 additions and 1 deletions

View file

@ -1,5 +1,5 @@
cmake_minimum_required(VERSION 3.10)
project(fun VERSION 0.41.13 LANGUAGES C)
project(fun VERSION 0.41.14 LANGUAGES C)
set(CMAKE_C_STANDARD 99)
set(CMAKE_C_STANDARD_REQUIRED ON)

View file

@ -99,6 +99,42 @@ int map_set(Value *vm, const char *key, Value v) {
return 1;
}
/**
* @brief Insert or replace a key in the map with a copy of the provided value.
*
* Unlike map_set(), this function does NOT take ownership of @p v. The value is
* copied according to copy_value() semantics, and the caller retains ownership
* of the original.
*
* @param vm Target Value of type VAL_MAP.
* @param key NUL-terminated key string (copied into the map).
* @param v Pointer to Value to copy from; not consumed.
* @return 1 on success, 0 on error (type mismatch, OOM, or NULL params).
*/
int map_set_copy(Value *vm, const char *key, const Value *v) {
if (!vm || vm->type != VAL_MAP || !vm->map || !key || !v) {
return 0;
}
/* make a defensive copy first so we can reuse map_set path semantics */
Value cv = copy_value(v);
Map *m = (Map *)vm->map;
for (int i = 0; i < m->count; ++i) {
if (strcmp(m->keys[i], key) == 0) {
free_value(m->vals[i]);
m->vals[i] = cv;
return 1;
}
}
if (!map_ensure_cap(m, m->count + 1)) {
free_value(cv);
return 0;
}
m->keys[m->count] = strdup(key);
m->vals[m->count] = cv;
m->count++;
return 1;
}
/**
* @brief Look up a key and copy the stored value into out.
*

View file

@ -118,6 +118,8 @@ Value array_concat(const Value *a, const Value *b);
Value make_map_empty(void);
/** Set key to v (takes ownership); returns 1 on success. */
int map_set(Value *m, const char *key, Value v);
/** Set key to a copy of v (caller retains ownership); returns 1 on success. */
int map_set_copy(Value *m, const char *key, const Value *v);
/** Lookup key; returns 1 and copies value to out on success. */
int map_get_copy(const Value *m, const char *key, Value *out);
/** Test if key exists; returns 1/0. */

View file

@ -546,6 +546,22 @@ void vm_debug_request_continue(VM *vm) {
vm->debug_stop_requested = 0;
}
/* --- Centralized operand stack safety helpers --- */
/** Return current number of values on the stack. */
static inline int vm_stack_count(const VM *vm) { return vm->sp + 1; }
/** Return available space left on the stack (in Values). */
static inline int vm_stack_space(const VM *vm) { return STACK_SIZE - (vm->sp + 1); }
/** Ensure at least n values are available to pop; aborts on underflow. */
static inline void vm_require_stack(VM *vm, int n) {
if (n < 0) n = 0;
if (vm_stack_count(vm) < n) {
fprintf(stderr, "Runtime error: stack underflow (need %d, have %d)\n", n, vm_stack_count(vm));
exit(1);
}
}
/**
* @brief Push a Value onto the VM operand stack.
*
@ -868,6 +884,13 @@ void vm_run(VM *vm, Bytecode *entry) {
Instruction inst = f->fn->instructions[f->ip++];
vm->instr_count++; /* count each executed instruction */
/* Validate opcode defensively */
if (!opcode_is_valid(inst.op)) {
fprintf(stderr, "Runtime error: invalid opcode %d at ip=%d\n", inst.op, f->ip - 1);
vm_raise_error(vm, "Invalid opcode");
break;
}
if (vm->trace_enabled) {
const char *opname = (inst.op >= 0 && inst.op < (int)(sizeof(opcode_names) / sizeof(opcode_names[0])))
? opcode_names[inst.op]