Some internal optimzations and helpers. (0.41.14)
This commit is contained in:
parent
3a838ae3d5
commit
0d6685abcd
4 changed files with 62 additions and 1 deletions
|
|
@ -1,5 +1,5 @@
|
||||||
cmake_minimum_required(VERSION 3.10)
|
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 99)
|
||||||
set(CMAKE_C_STANDARD_REQUIRED ON)
|
set(CMAKE_C_STANDARD_REQUIRED ON)
|
||||||
|
|
|
||||||
36
src/map.c
36
src/map.c
|
|
@ -99,6 +99,42 @@ int map_set(Value *vm, const char *key, Value v) {
|
||||||
return 1;
|
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.
|
* @brief Look up a key and copy the stored value into out.
|
||||||
*
|
*
|
||||||
|
|
|
||||||
|
|
@ -118,6 +118,8 @@ Value array_concat(const Value *a, const Value *b);
|
||||||
Value make_map_empty(void);
|
Value make_map_empty(void);
|
||||||
/** Set key to v (takes ownership); returns 1 on success. */
|
/** Set key to v (takes ownership); returns 1 on success. */
|
||||||
int map_set(Value *m, const char *key, Value v);
|
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. */
|
/** Lookup key; returns 1 and copies value to out on success. */
|
||||||
int map_get_copy(const Value *m, const char *key, Value *out);
|
int map_get_copy(const Value *m, const char *key, Value *out);
|
||||||
/** Test if key exists; returns 1/0. */
|
/** Test if key exists; returns 1/0. */
|
||||||
|
|
|
||||||
23
src/vm.c
23
src/vm.c
|
|
@ -546,6 +546,22 @@ void vm_debug_request_continue(VM *vm) {
|
||||||
vm->debug_stop_requested = 0;
|
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.
|
* @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++];
|
Instruction inst = f->fn->instructions[f->ip++];
|
||||||
vm->instr_count++; /* count each executed instruction */
|
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) {
|
if (vm->trace_enabled) {
|
||||||
const char *opname = (inst.op >= 0 && inst.op < (int)(sizeof(opcode_names) / sizeof(opcode_names[0])))
|
const char *opname = (inst.op >= 0 && inst.op < (int)(sizeof(opcode_names) / sizeof(opcode_names[0])))
|
||||||
? opcode_names[inst.op]
|
? opcode_names[inst.op]
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue