Compare commits
1 Commits
console
...
simplify_c
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a08ee50f84 |
@@ -205,6 +205,7 @@ DEF( set_up, 4, 1, 0, u8_u16) /* value, depth:u8, slot:u16 -> */
|
||||
/* Name resolution with bytecode patching */
|
||||
DEF( get_name, 5, 0, 1, const) /* cpool_idx -> value, patches itself */
|
||||
DEF( get_env_slot, 3, 0, 1, u16) /* slot -> value (patched from get_name) */
|
||||
DEF( set_env_slot, 3, 1, 0, u16) /* value -> slot (patched from put_var) */
|
||||
DEF(get_global_slot, 3, 0, 1, u16) /* slot -> value (patched from get_var) */
|
||||
DEF(set_global_slot, 3, 1, 0, u16) /* value -> slot (patched from put_var) */
|
||||
|
||||
|
||||
1552
source/quickjs.c
1552
source/quickjs.c
File diff suppressed because it is too large
Load Diff
123
source/quickjs.h
123
source/quickjs.h
@@ -92,6 +92,7 @@ static inline int objhdr_s (objhdr_t h) { return (h & OBJHDR_S_MASK) != 0; }
|
||||
typedef struct JSRuntime JSRuntime; // the entire VM
|
||||
typedef struct JSContext JSContext; // Each actor
|
||||
typedef struct JSClass JSClass;
|
||||
typedef struct JSFunctionBytecode JSFunctionBytecode;
|
||||
typedef uint32_t JSClassID;
|
||||
|
||||
/* Forward declaration - JSGCRef moved after JSValue definition */
|
||||
@@ -1099,6 +1100,128 @@ void *js_malloc_rt (size_t size);
|
||||
void *js_mallocz_rt (size_t size);
|
||||
void js_free_rt (void *ptr);
|
||||
|
||||
/* ============================================================================
|
||||
Context-Neutral Module Format (CellModule)
|
||||
============================================================================ */
|
||||
|
||||
/* Capture descriptor - what a nested function closes over */
|
||||
typedef enum {
|
||||
CAP_FROM_PARENT_LOCAL = 1, /* capture local from parent function */
|
||||
CAP_FROM_PARENT_UPVALUE = 2 /* forward upvalue from parent's upvalues */
|
||||
} CellCapKind;
|
||||
|
||||
typedef struct CellCapDesc {
|
||||
uint8_t kind; /* CAP_FROM_PARENT_LOCAL or CAP_FROM_PARENT_UPVALUE */
|
||||
uint16_t index; /* local index in parent, or upvalue index in parent */
|
||||
} CellCapDesc;
|
||||
|
||||
/* External relocation - for integrate-time patching */
|
||||
typedef enum {
|
||||
EXT_GET = 1, /* OP_get_var -> OP_get_env_slot or OP_get_global_slot */
|
||||
EXT_SET = 2 /* OP_put_var -> OP_set_env_slot or OP_set_global_slot */
|
||||
} CellExtKind;
|
||||
|
||||
typedef struct CellExternalReloc {
|
||||
uint32_t pc_offset; /* where operand lives in bytecode */
|
||||
uint32_t name_sid; /* string id of the external name */
|
||||
uint8_t kind; /* EXT_GET or EXT_SET */
|
||||
} CellExternalReloc;
|
||||
|
||||
/* Constant types in cpool */
|
||||
typedef enum {
|
||||
CELL_CONST_NULL = 0,
|
||||
CELL_CONST_INT = 1,
|
||||
CELL_CONST_FLOAT = 2,
|
||||
CELL_CONST_STRING = 3, /* string_sid into module string table */
|
||||
CELL_CONST_UNIT = 4 /* unit_id for nested function */
|
||||
} CellConstType;
|
||||
|
||||
typedef struct CellConst {
|
||||
uint8_t type; /* CellConstType */
|
||||
union {
|
||||
int32_t i32;
|
||||
double f64;
|
||||
uint32_t string_sid;
|
||||
uint32_t unit_id;
|
||||
};
|
||||
} CellConst;
|
||||
|
||||
/* Per-unit structure (context-neutral, flattened) */
|
||||
typedef struct CellUnit {
|
||||
/* Constant pool */
|
||||
uint32_t const_count;
|
||||
CellConst *constants;
|
||||
|
||||
/* Bytecode */
|
||||
uint32_t bytecode_len;
|
||||
uint8_t *bytecode;
|
||||
|
||||
/* Stack requirements */
|
||||
uint16_t arg_count;
|
||||
uint16_t var_count;
|
||||
uint16_t stack_size;
|
||||
|
||||
/* Upvalue (capture) descriptors */
|
||||
uint16_t upvalue_count;
|
||||
CellCapDesc *upvalues;
|
||||
|
||||
/* External relocations */
|
||||
uint32_t external_count;
|
||||
CellExternalReloc *externals;
|
||||
|
||||
/* Debug info (optional) */
|
||||
uint32_t pc2line_len;
|
||||
uint8_t *pc2line;
|
||||
uint32_t name_sid; /* unit name for stack traces */
|
||||
} CellUnit;
|
||||
|
||||
/* Module-level structure (context-neutral) */
|
||||
#define CELL_MODULE_MAGIC 0x4C4C4543 /* "CELL" */
|
||||
#define CELL_MODULE_VERSION 1
|
||||
|
||||
typedef struct CellModule {
|
||||
uint32_t magic; /* CELL_MODULE_MAGIC */
|
||||
uint8_t version; /* CELL_MODULE_VERSION */
|
||||
uint8_t flags;
|
||||
|
||||
/* Shared string table (module-global) */
|
||||
uint32_t string_count;
|
||||
uint32_t string_data_size;
|
||||
uint8_t *string_data; /* concatenated UTF-8 strings */
|
||||
uint32_t *string_offsets; /* offset for each string */
|
||||
|
||||
/* Unit table (entry 0 is the main/entry unit) */
|
||||
uint32_t unit_count;
|
||||
CellUnit *units;
|
||||
|
||||
/* Debug: source stored once at module level */
|
||||
uint32_t source_len;
|
||||
char *source;
|
||||
} CellModule;
|
||||
|
||||
/* Free a CellModule and all its contents */
|
||||
void cell_module_free (CellModule *mod);
|
||||
|
||||
/* Write a CellModule to a byte buffer.
|
||||
Returns allocated buffer (caller must free with pjs_free), or NULL on error. */
|
||||
uint8_t *cell_module_write (CellModule *mod, size_t *out_len);
|
||||
|
||||
/* Read a CellModule from a byte buffer.
|
||||
Returns allocated CellModule (caller must free with cell_module_free), or NULL on error. */
|
||||
CellModule *cell_module_read (const uint8_t *buf, size_t buf_len);
|
||||
|
||||
/* Convert compiled JSFunctionBytecode to CellModule.
|
||||
Returns allocated CellModule (caller must free with cell_module_free), or NULL on error. */
|
||||
CellModule *cell_module_from_bytecode (JSContext *ctx, JSFunctionBytecode *main_func);
|
||||
|
||||
/* Compile source code directly to CellModule.
|
||||
Returns allocated CellModule (caller must free with cell_module_free), or NULL on error. */
|
||||
CellModule *JS_CompileModule (JSContext *ctx, const char *input, size_t input_len, const char *filename);
|
||||
|
||||
/* Integrate a CellModule with an environment and execute.
|
||||
Returns callable function value, or JS_EXCEPTION on error. */
|
||||
JSValue cell_module_integrate (JSContext *ctx, CellModule *mod, JSValue env);
|
||||
|
||||
#undef js_unlikely
|
||||
#undef inline
|
||||
|
||||
|
||||
139
source/suite.c
139
source/suite.c
@@ -2000,6 +2000,138 @@ TEST(wota_encode_blob) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* ============================================================================
|
||||
CELL MODULE TESTS - Serialize/Deserialize bytecode
|
||||
============================================================================ */
|
||||
|
||||
TEST(cell_module_compile_basic) {
|
||||
/* Compile simple source to CellModule */
|
||||
const char *source = "1 + 2";
|
||||
CellModule *mod = JS_CompileModule(ctx, source, strlen(source), "<test>");
|
||||
ASSERT_MSG(mod != NULL, "JS_CompileModule returned NULL");
|
||||
|
||||
/* Check module has units */
|
||||
ASSERT_MSG(mod->unit_count > 0, "Module has no units");
|
||||
ASSERT_MSG(mod->units[0].bytecode_len > 0, "Unit has no bytecode");
|
||||
|
||||
cell_module_free(mod);
|
||||
return 1;
|
||||
}
|
||||
|
||||
TEST(cell_module_write_read) {
|
||||
/* Compile, serialize, deserialize */
|
||||
const char *source = "var x = 10; x * 2";
|
||||
CellModule *mod = JS_CompileModule(ctx, source, strlen(source), "<test>");
|
||||
ASSERT_MSG(mod != NULL, "JS_CompileModule returned NULL");
|
||||
|
||||
/* Serialize */
|
||||
size_t len;
|
||||
uint8_t *buf = cell_module_write(mod, &len);
|
||||
ASSERT_MSG(buf != NULL, "cell_module_write returned NULL");
|
||||
ASSERT_MSG(len > 0, "cell_module_write produced empty buffer");
|
||||
|
||||
/* Deserialize */
|
||||
CellModule *mod2 = cell_module_read(buf, len);
|
||||
free(buf);
|
||||
ASSERT_MSG(mod2 != NULL, "cell_module_read returned NULL");
|
||||
|
||||
/* Verify structure matches */
|
||||
ASSERT_MSG(mod2->unit_count == mod->unit_count, "unit_count mismatch");
|
||||
ASSERT_MSG(mod2->string_count == mod->string_count, "string_count mismatch");
|
||||
|
||||
cell_module_free(mod);
|
||||
cell_module_free(mod2);
|
||||
return 1;
|
||||
}
|
||||
|
||||
TEST(cell_module_integrate_basic) {
|
||||
/* Compile, then integrate and execute */
|
||||
const char *source = "3 + 4";
|
||||
CellModule *mod = JS_CompileModule(ctx, source, strlen(source), "<test>");
|
||||
ASSERT_MSG(mod != NULL, "JS_CompileModule returned NULL");
|
||||
|
||||
/* Integrate into context */
|
||||
JSValue func = cell_module_integrate(ctx, mod, JS_NULL);
|
||||
if (JS_IsException(func)) {
|
||||
cell_module_free(mod);
|
||||
ASSERT_MSG(0, "cell_module_integrate threw exception");
|
||||
}
|
||||
|
||||
/* Execute */
|
||||
JSValue result = JS_Call(ctx, func, JS_NULL, 0, NULL);
|
||||
JS_FreeValue(ctx, func);
|
||||
cell_module_free(mod);
|
||||
|
||||
if (JS_IsException(result)) {
|
||||
ASSERT_MSG(0, "JS_Call threw exception");
|
||||
}
|
||||
|
||||
ASSERT_INT(result, 7);
|
||||
return 1;
|
||||
}
|
||||
|
||||
TEST(cell_module_roundtrip_execute) {
|
||||
/* Full round-trip: compile -> write -> read -> integrate -> execute */
|
||||
const char *source = "var a = 5; var b = 3; a * b";
|
||||
CellModule *mod = JS_CompileModule(ctx, source, strlen(source), "<test>");
|
||||
ASSERT_MSG(mod != NULL, "JS_CompileModule returned NULL");
|
||||
|
||||
/* Serialize */
|
||||
size_t len;
|
||||
uint8_t *buf = cell_module_write(mod, &len);
|
||||
cell_module_free(mod);
|
||||
ASSERT_MSG(buf != NULL, "cell_module_write returned NULL");
|
||||
|
||||
/* Deserialize */
|
||||
CellModule *mod2 = cell_module_read(buf, len);
|
||||
free(buf);
|
||||
ASSERT_MSG(mod2 != NULL, "cell_module_read returned NULL");
|
||||
|
||||
/* Integrate and execute */
|
||||
JSValue func = cell_module_integrate(ctx, mod2, JS_NULL);
|
||||
cell_module_free(mod2);
|
||||
if (JS_IsException(func)) {
|
||||
ASSERT_MSG(0, "cell_module_integrate threw exception");
|
||||
}
|
||||
|
||||
JSValue result = JS_Call(ctx, func, JS_NULL, 0, NULL);
|
||||
JS_FreeValue(ctx, func);
|
||||
|
||||
if (JS_IsException(result)) {
|
||||
ASSERT_MSG(0, "JS_Call threw exception");
|
||||
}
|
||||
|
||||
ASSERT_INT(result, 15);
|
||||
return 1;
|
||||
}
|
||||
|
||||
TEST(cell_module_string_constant) {
|
||||
/* Test string constant handling */
|
||||
const char *source = "'hello' + ' world'";
|
||||
CellModule *mod = JS_CompileModule(ctx, source, strlen(source), "<test>");
|
||||
ASSERT_MSG(mod != NULL, "JS_CompileModule returned NULL");
|
||||
|
||||
/* Verify string table has entries */
|
||||
ASSERT_MSG(mod->string_count > 0, "Module has no strings");
|
||||
|
||||
/* Integrate and execute */
|
||||
JSValue func = cell_module_integrate(ctx, mod, JS_NULL);
|
||||
cell_module_free(mod);
|
||||
if (JS_IsException(func)) {
|
||||
ASSERT_MSG(0, "cell_module_integrate threw exception");
|
||||
}
|
||||
|
||||
JSValue result = JS_Call(ctx, func, JS_NULL, 0, NULL);
|
||||
JS_FreeValue(ctx, func);
|
||||
|
||||
if (JS_IsException(result)) {
|
||||
ASSERT_MSG(0, "JS_Call threw exception");
|
||||
}
|
||||
|
||||
ASSERT_STR(result, "hello world");
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* ============================================================================
|
||||
MAIN TEST RUNNER
|
||||
============================================================================ */
|
||||
@@ -2209,6 +2341,13 @@ int run_c_test_suite(JSContext *ctx)
|
||||
RUN_TEST(wota_encode_nested_array);
|
||||
RUN_TEST(wota_encode_blob);
|
||||
|
||||
// CellModule tests
|
||||
RUN_TEST(cell_module_compile_basic);
|
||||
RUN_TEST(cell_module_write_read);
|
||||
RUN_TEST(cell_module_integrate_basic);
|
||||
RUN_TEST(cell_module_roundtrip_execute);
|
||||
RUN_TEST(cell_module_string_constant);
|
||||
|
||||
printf("\n=================================\n");
|
||||
printf("Results: %d passed, %d failed\n", tests_passed, tests_failed);
|
||||
printf("=================================\n\n");
|
||||
|
||||
Reference in New Issue
Block a user