use new parser information
This commit is contained in:
261
source/quickjs.c
261
source/quickjs.c
@@ -523,11 +523,10 @@ typedef enum MachOpcode {
|
||||
MACH_GETINDEX, /* R(A) = R(B)[R(C)] — computed property */
|
||||
MACH_SETINDEX, /* R(A)[R(B)] = R(C) — computed property */
|
||||
|
||||
/* Global/environment access (ABx) */
|
||||
MACH_GETGLOBAL, /* R(A) = global[K(Bx)] — post-link */
|
||||
MACH_SETGLOBAL, /* global[K(Bx)] = R(A) — post-link */
|
||||
MACH_GETNAME, /* R(A) = resolve(K(Bx)) — pre-link, patched to GETGLOBAL */
|
||||
MACH_SETNAME, /* resolve(K(Bx)) = R(A) — pre-link, patched to SETGLOBAL */
|
||||
/* Unbound variable access (ABx) */
|
||||
MACH_GETNAME, /* R(A) = resolve(K(Bx)) — compiler placeholder, patched by link */
|
||||
MACH_GETINTRINSIC, /* R(A) = global[K(Bx)] — post-link, intrinsic/built-in */
|
||||
MACH_GETENV, /* R(A) = env[K(Bx)] — post-link, module environment */
|
||||
|
||||
/* Closure access (ABC) */
|
||||
MACH_GETUP, /* R(A) = outer_frame[B].slots[C] */
|
||||
@@ -592,10 +591,9 @@ static const char *mach_opcode_names[MACH_OP_COUNT] = {
|
||||
[MACH_SETFIELD] = "setfield",
|
||||
[MACH_GETINDEX] = "getindex",
|
||||
[MACH_SETINDEX] = "setindex",
|
||||
[MACH_GETGLOBAL] = "getglobal",
|
||||
[MACH_SETGLOBAL] = "setglobal",
|
||||
[MACH_GETNAME] = "getname",
|
||||
[MACH_SETNAME] = "setname",
|
||||
[MACH_GETINTRINSIC] = "getintrinsic",
|
||||
[MACH_GETENV] = "getenv",
|
||||
[MACH_GETUP] = "getup",
|
||||
[MACH_SETUP] = "setup",
|
||||
[MACH_JMP] = "jmp",
|
||||
@@ -30706,6 +30704,10 @@ typedef struct MachCompState {
|
||||
/* Parent for nested function compilation */
|
||||
struct MachCompState *parent;
|
||||
|
||||
/* AST semantic annotations */
|
||||
int function_nr; /* current function number (0=program body) */
|
||||
cJSON *scopes; /* pointer to AST "scopes" array (not owned) */
|
||||
|
||||
/* Error tracking */
|
||||
int has_error;
|
||||
} MachCompState;
|
||||
@@ -30825,38 +30827,34 @@ static int mach_add_function(MachCompState *cs, JSCodeRegister *fn) {
|
||||
return cs->func_count++;
|
||||
}
|
||||
|
||||
/* Scan AST statements for var/def declarations (hoisting) */
|
||||
static void mach_scan_vars(MachCompState *cs, cJSON *stmts) {
|
||||
int count = cJSON_GetArraySize(stmts);
|
||||
/* Find the scope record for a given function_nr in the scopes array */
|
||||
static cJSON *mach_find_scope_record(cJSON *scopes, int function_nr) {
|
||||
if (!scopes) return NULL;
|
||||
int count = cJSON_GetArraySize(scopes);
|
||||
for (int i = 0; i < count; i++) {
|
||||
cJSON *stmt = cJSON_GetArrayItem(stmts, i);
|
||||
const char *kind = cJSON_GetStringValue(cJSON_GetObjectItem(stmt, "kind"));
|
||||
if (!kind) continue;
|
||||
cJSON *scope = cJSON_GetArrayItem(scopes, i);
|
||||
cJSON *fn_nr = cJSON_GetObjectItem(scope, "function_nr");
|
||||
if (fn_nr && (int)cJSON_GetNumberValue(fn_nr) == function_nr)
|
||||
return scope;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (strcmp(kind, "var") == 0 || strcmp(kind, "def") == 0) {
|
||||
cJSON *left = cJSON_GetObjectItem(stmt, "left");
|
||||
const char *name = cJSON_GetStringValue(cJSON_GetObjectItem(left, "name"));
|
||||
if (name && mach_find_var(cs, name) < 0) {
|
||||
int slot = mach_reserve_reg(cs);
|
||||
mach_add_var(cs, name, slot, strcmp(kind, "def") == 0);
|
||||
}
|
||||
}
|
||||
/* Also handle function declarations at top level */
|
||||
if (strcmp(kind, "call") == 0) {
|
||||
cJSON *expr = cJSON_GetObjectItem(stmt, "expression");
|
||||
if (expr) {
|
||||
const char *ek = cJSON_GetStringValue(cJSON_GetObjectItem(expr, "kind"));
|
||||
if (ek && strcmp(ek, "function") == 0) {
|
||||
cJSON *fname = cJSON_GetObjectItem(expr, "name");
|
||||
if (fname && cJSON_IsString(fname)) {
|
||||
const char *fn = cJSON_GetStringValue(fname);
|
||||
if (fn && mach_find_var(cs, fn) < 0) {
|
||||
int slot = mach_reserve_reg(cs);
|
||||
mach_add_var(cs, fn, slot, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/* Scan AST scope record for variable declarations */
|
||||
static void mach_scan_scope(MachCompState *cs) {
|
||||
cJSON *scope = mach_find_scope_record(cs->scopes, cs->function_nr);
|
||||
cJSON *vars = scope ? cJSON_GetObjectItem(scope, "vars") : NULL;
|
||||
if (!vars) return;
|
||||
int vcount = cJSON_GetArraySize(vars);
|
||||
for (int j = 0; j < vcount; j++) {
|
||||
cJSON *v = cJSON_GetArrayItem(vars, j);
|
||||
const char *make = cJSON_GetStringValue(cJSON_GetObjectItem(v, "make"));
|
||||
if (!make || strcmp(make, "input") == 0) continue;
|
||||
const char *name = cJSON_GetStringValue(cJSON_GetObjectItem(v, "name"));
|
||||
if (name && mach_find_var(cs, name) < 0) {
|
||||
int is_const = (strcmp(make, "def") == 0 || strcmp(make, "function") == 0);
|
||||
int slot = mach_reserve_reg(cs);
|
||||
mach_add_var(cs, name, slot, is_const);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -30940,16 +30938,29 @@ static int mach_compile_expr(MachCompState *cs, cJSON *node, int dest) {
|
||||
if (strcmp(kind, "name") == 0) {
|
||||
const char *name = cJSON_GetStringValue(cJSON_GetObjectItem(node, "name"));
|
||||
if (name) {
|
||||
int slot = mach_find_var(cs, name);
|
||||
if (slot >= 0) {
|
||||
/* Local variable — just return its register */
|
||||
if (dest >= 0 && dest != slot) {
|
||||
mach_emit(cs, MACH_ABC(MACH_MOVE, dest, slot, 0));
|
||||
return dest;
|
||||
cJSON *level_node = cJSON_GetObjectItem(node, "level");
|
||||
int level = level_node ? (int)cJSON_GetNumberValue(level_node) : -1;
|
||||
|
||||
if (level == 0) {
|
||||
/* Local variable */
|
||||
int slot = mach_find_var(cs, name);
|
||||
if (slot >= 0) {
|
||||
if (dest >= 0 && dest != slot) {
|
||||
mach_emit(cs, MACH_ABC(MACH_MOVE, dest, slot, 0));
|
||||
return dest;
|
||||
}
|
||||
return slot;
|
||||
}
|
||||
return slot;
|
||||
} else if (level > 0) {
|
||||
/* Closure variable — walk parent compiler states for slot */
|
||||
MachCompState *target = cs;
|
||||
for (int i = 0; i < level; i++) target = target->parent;
|
||||
int slot = mach_find_var(target, name);
|
||||
if (dest < 0) dest = mach_reserve_reg(cs);
|
||||
mach_emit(cs, MACH_ABC(MACH_GETUP, dest, level, slot));
|
||||
return dest;
|
||||
}
|
||||
/* Unbound — emit GETNAME (will be patched to GETGLOBAL at link time) */
|
||||
/* Unbound or fallback — emit placeholder, patched at link time */
|
||||
if (dest < 0) dest = mach_reserve_reg(cs);
|
||||
int ki = mach_cpool_add_str(cs, name);
|
||||
mach_emit(cs, MACH_ABx(MACH_GETNAME, dest, ki));
|
||||
@@ -31127,22 +31138,35 @@ static int mach_compile_expr(MachCompState *cs, cJSON *node, int dest) {
|
||||
|
||||
if (lk && strcmp(lk, "name") == 0) {
|
||||
const char *name = cJSON_GetStringValue(cJSON_GetObjectItem(left, "name"));
|
||||
int slot = name ? mach_find_var(cs, name) : -1;
|
||||
if (slot >= 0) {
|
||||
int r = mach_compile_expr(cs, right, slot);
|
||||
if (r != slot)
|
||||
mach_emit(cs, MACH_ABC(MACH_MOVE, slot, r, 0));
|
||||
if (dest >= 0 && dest != slot)
|
||||
mach_emit(cs, MACH_ABC(MACH_MOVE, dest, slot, 0));
|
||||
return slot;
|
||||
cJSON *level_node = cJSON_GetObjectItem(left, "level");
|
||||
int level = level_node ? (int)cJSON_GetNumberValue(level_node) : -1;
|
||||
|
||||
if (level == 0) {
|
||||
/* Local assignment */
|
||||
int slot = name ? mach_find_var(cs, name) : -1;
|
||||
if (slot >= 0) {
|
||||
int r = mach_compile_expr(cs, right, slot);
|
||||
if (r != slot)
|
||||
mach_emit(cs, MACH_ABC(MACH_MOVE, slot, r, 0));
|
||||
if (dest >= 0 && dest != slot)
|
||||
mach_emit(cs, MACH_ABC(MACH_MOVE, dest, slot, 0));
|
||||
return slot;
|
||||
}
|
||||
} else if (level > 0) {
|
||||
/* Closure assignment — walk parent states for slot */
|
||||
MachCompState *target = cs;
|
||||
for (int i = 0; i < level; i++) target = target->parent;
|
||||
int slot = mach_find_var(target, name);
|
||||
if (dest < 0) dest = mach_reserve_reg(cs);
|
||||
int r = mach_compile_expr(cs, right, dest);
|
||||
if (r != dest)
|
||||
mach_emit(cs, MACH_ABC(MACH_MOVE, dest, r, 0));
|
||||
mach_emit(cs, MACH_ABC(MACH_SETUP, dest, level, slot));
|
||||
return dest;
|
||||
}
|
||||
/* Global assignment */
|
||||
/* Unbound (level -1) — error, AST parser should have rejected this */
|
||||
if (dest < 0) dest = mach_reserve_reg(cs);
|
||||
int r = mach_compile_expr(cs, right, dest);
|
||||
if (r != dest)
|
||||
mach_emit(cs, MACH_ABC(MACH_MOVE, dest, r, 0));
|
||||
int ki = mach_cpool_add_str(cs, name);
|
||||
mach_emit(cs, MACH_ABx(MACH_SETNAME, dest, ki));
|
||||
mach_emit(cs, MACH_ABx(MACH_LOADNULL, dest, 0));
|
||||
return dest;
|
||||
}
|
||||
|
||||
@@ -31308,8 +31332,13 @@ static int mach_compile_expr(MachCompState *cs, cJSON *node, int dest) {
|
||||
MachCompState child = {0};
|
||||
child.ctx = cs->ctx;
|
||||
child.parent = cs;
|
||||
child.scopes = cs->scopes;
|
||||
child.freereg = 1; /* slot 0 = this */
|
||||
|
||||
/* Read function_nr from AST node */
|
||||
cJSON *fn_nr_node = cJSON_GetObjectItem(node, "function_nr");
|
||||
child.function_nr = fn_nr_node ? (int)cJSON_GetNumberValue(fn_nr_node) : 0;
|
||||
|
||||
/* Register parameters */
|
||||
cJSON *params = cJSON_GetObjectItem(node, "params");
|
||||
if (!params) params = cJSON_GetObjectItem(node, "parameters");
|
||||
@@ -31325,15 +31354,14 @@ static int mach_compile_expr(MachCompState *cs, cJSON *node, int dest) {
|
||||
}
|
||||
}
|
||||
|
||||
/* Scan for var/def */
|
||||
/* Scan scope record for var/def declarations */
|
||||
mach_scan_scope(&child);
|
||||
|
||||
/* Compile body */
|
||||
cJSON *body = cJSON_GetObjectItem(node, "body");
|
||||
if (body) {
|
||||
cJSON *stmts = cJSON_GetObjectItem(body, "statements");
|
||||
if (!stmts) stmts = body; /* body might be the statements array directly */
|
||||
if (cJSON_IsArray(stmts))
|
||||
mach_scan_vars(&child, stmts);
|
||||
|
||||
/* Compile body */
|
||||
if (cJSON_IsArray(stmts)) {
|
||||
int count = cJSON_GetArraySize(stmts);
|
||||
for (int i = 0; i < count; i++) {
|
||||
@@ -31346,10 +31374,12 @@ static int mach_compile_expr(MachCompState *cs, cJSON *node, int dest) {
|
||||
mach_emit(&child, MACH_ABC(MACH_RETNIL, 0, 0, 0));
|
||||
|
||||
/* Build JSCodeRegister for the child function */
|
||||
cJSON *fn_scope = mach_find_scope_record(cs->scopes, child.function_nr);
|
||||
cJSON *fn_ncs = fn_scope ? cJSON_GetObjectItem(fn_scope, "nr_close_slots") : NULL;
|
||||
JSCodeRegister *fn_code = js_mallocz_rt(sizeof(JSCodeRegister));
|
||||
fn_code->arity = nparams;
|
||||
fn_code->nr_slots = child.maxreg;
|
||||
fn_code->nr_close_slots = 0;
|
||||
fn_code->nr_close_slots = fn_ncs ? (int)cJSON_GetNumberValue(fn_ncs) : 0;
|
||||
fn_code->entry_point = 0;
|
||||
fn_code->instr_count = child.code_count;
|
||||
fn_code->instructions = child.code;
|
||||
@@ -31615,23 +31645,23 @@ static void mach_compile_stmt(MachCompState *cs, cJSON *stmt) {
|
||||
}
|
||||
}
|
||||
|
||||
/* ---- Link pass: resolve GETNAME/SETNAME to GETGLOBAL/SETGLOBAL ---- */
|
||||
/* ---- Link pass: resolve GETNAME to GETINTRINSIC or GETENV ---- */
|
||||
|
||||
static void mach_link_names(MachCompState *cs, JSValue env) {
|
||||
for (int i = 0; i < cs->code_count; i++) {
|
||||
MachInstr32 instr = cs->code[i];
|
||||
int op = MACH_GET_OP(instr);
|
||||
if (op == MACH_GETNAME) {
|
||||
int a = MACH_GET_A(instr);
|
||||
int bx = MACH_GET_Bx(instr);
|
||||
/* Patch to GETGLOBAL — the VM will look up K(Bx) in global_obj */
|
||||
cs->code[i] = MACH_ABx(MACH_GETGLOBAL, a, bx);
|
||||
} else if (op == MACH_SETNAME) {
|
||||
int a = MACH_GET_A(instr);
|
||||
int bx = MACH_GET_Bx(instr);
|
||||
cs->code[i] = MACH_ABx(MACH_SETGLOBAL, a, bx);
|
||||
static void mach_link_code(JSContext *ctx, JSCodeRegister *code, JSValue env) {
|
||||
for (uint32_t i = 0; i < code->instr_count; i++) {
|
||||
MachInstr32 instr = code->instructions[i];
|
||||
if (MACH_GET_OP(instr) != MACH_GETNAME) continue;
|
||||
int a = MACH_GET_A(instr);
|
||||
int bx = MACH_GET_Bx(instr);
|
||||
int in_env = 0;
|
||||
if (!JS_IsNull(env) && (uint32_t)bx < code->cpool_count) {
|
||||
JSValue val = JS_GetProperty(ctx, env, code->cpool[bx]);
|
||||
in_env = !JS_IsNull(val) && !JS_IsException(val);
|
||||
}
|
||||
code->instructions[i] = MACH_ABx(in_env ? MACH_GETENV : MACH_GETINTRINSIC, a, bx);
|
||||
}
|
||||
for (uint32_t i = 0; i < code->func_count; i++)
|
||||
if (code->functions[i]) mach_link_code(ctx, code->functions[i], env);
|
||||
}
|
||||
|
||||
/* ---- Top-level compiler ---- */
|
||||
@@ -31640,8 +31670,12 @@ static JSCodeRegister *mach_compile_program(MachCompState *cs, cJSON *ast, JSVal
|
||||
cJSON *stmts = cJSON_GetObjectItem(ast, "statements");
|
||||
if (!stmts || !cJSON_IsArray(stmts)) return NULL;
|
||||
|
||||
/* Scan for var/def declarations (hoisting) */
|
||||
mach_scan_vars(cs, stmts);
|
||||
/* Read scopes array from AST */
|
||||
cs->scopes = cJSON_GetObjectItem(ast, "scopes");
|
||||
cs->function_nr = 0;
|
||||
|
||||
/* Scan scope record for declarations */
|
||||
mach_scan_scope(cs);
|
||||
|
||||
/* Compile each statement */
|
||||
int count = cJSON_GetArraySize(stmts);
|
||||
@@ -31652,14 +31686,15 @@ static JSCodeRegister *mach_compile_program(MachCompState *cs, cJSON *ast, JSVal
|
||||
/* Implicit return null */
|
||||
mach_emit(cs, MACH_ABC(MACH_RETNIL, 0, 0, 0));
|
||||
|
||||
/* Link: resolve GETNAME/SETNAME */
|
||||
mach_link_names(cs, env);
|
||||
/* nr_close_slots from scope record */
|
||||
cJSON *prog_scope = mach_find_scope_record(cs->scopes, 0);
|
||||
cJSON *ncs_node = prog_scope ? cJSON_GetObjectItem(prog_scope, "nr_close_slots") : NULL;
|
||||
|
||||
/* Build JSCodeRegister */
|
||||
JSCodeRegister *code = js_mallocz_rt(sizeof(JSCodeRegister));
|
||||
code->arity = 0;
|
||||
code->nr_slots = cs->maxreg;
|
||||
code->nr_close_slots = 0;
|
||||
code->nr_close_slots = ncs_node ? (int)cJSON_GetNumberValue(ncs_node) : 0;
|
||||
code->entry_point = 0;
|
||||
code->instr_count = cs->code_count;
|
||||
code->instructions = cs->code;
|
||||
@@ -31684,6 +31719,9 @@ JSCodeRegister *JS_CompileMach(JSContext *ctx, const char *ast_json, JSValue env
|
||||
|
||||
JSCodeRegister *code = mach_compile_program(&cs, ast, env);
|
||||
|
||||
/* Link: resolve GETNAME to GETINTRINSIC/GETENV */
|
||||
if (code) mach_link_code(ctx, code, env);
|
||||
|
||||
/* Free var table (code/cpool/functions are owned by JSCodeRegister now) */
|
||||
for (int i = 0; i < cs.var_count; i++)
|
||||
sys_free(cs.vars[i].name);
|
||||
@@ -32100,32 +32138,26 @@ static JSValue JS_CallRegisterVM(JSContext *ctx, JSCodeRegister *code,
|
||||
break;
|
||||
}
|
||||
|
||||
case MACH_GETGLOBAL: {
|
||||
case MACH_GETINTRINSIC: {
|
||||
int bx = MACH_GET_Bx(instr);
|
||||
JSValue key = code->cpool[bx];
|
||||
JSValue val = JS_GetProperty(ctx, ctx->global_obj, key);
|
||||
frame = (JSFrameRegister *)JS_VALUE_GET_PTR(frame_ref.val);
|
||||
if (JS_IsNull(val) || JS_IsException(val)) {
|
||||
/* Try env too */
|
||||
if (!JS_IsNull(env)) {
|
||||
val = JS_GetProperty(ctx, env, key);
|
||||
frame = (JSFrameRegister *)JS_VALUE_GET_PTR(frame_ref.val);
|
||||
}
|
||||
}
|
||||
frame->slots[a] = val;
|
||||
break;
|
||||
}
|
||||
|
||||
case MACH_SETGLOBAL: {
|
||||
case MACH_GETENV: {
|
||||
int bx = MACH_GET_Bx(instr);
|
||||
JSValue key = code->cpool[bx];
|
||||
JS_SetProperty(ctx, ctx->global_obj, key, frame->slots[a]);
|
||||
JSValue val = JS_GetProperty(ctx, env, key);
|
||||
frame = (JSFrameRegister *)JS_VALUE_GET_PTR(frame_ref.val);
|
||||
frame->slots[a] = val;
|
||||
break;
|
||||
}
|
||||
|
||||
case MACH_GETNAME: {
|
||||
/* Runtime fallback: try env then global */
|
||||
/* Runtime fallback: try env then global (should not appear in linked code) */
|
||||
int bx = MACH_GET_Bx(instr);
|
||||
JSValue key = code->cpool[bx];
|
||||
JSValue val = JS_NULL;
|
||||
@@ -32141,30 +32173,28 @@ static JSValue JS_CallRegisterVM(JSContext *ctx, JSCodeRegister *code,
|
||||
break;
|
||||
}
|
||||
|
||||
case MACH_SETNAME: {
|
||||
int bx = MACH_GET_Bx(instr);
|
||||
JSValue key = code->cpool[bx];
|
||||
JS_SetProperty(ctx, ctx->global_obj, key, frame->slots[a]);
|
||||
frame = (JSFrameRegister *)JS_VALUE_GET_PTR(frame_ref.val);
|
||||
break;
|
||||
}
|
||||
|
||||
case MACH_GETUP: {
|
||||
/* R(A) = outer_frame[B].slots[C] */
|
||||
/* R(A) = outer_frame[B].slots[C] — walk lexical scope chain */
|
||||
int depth = b;
|
||||
JSFrameRegister *target = frame;
|
||||
for (int d = 0; d < depth && !JS_IsNull(target->caller); d++)
|
||||
target = (JSFrameRegister *)JS_VALUE_GET_PTR(target->caller);
|
||||
JSFunction *fn = JS_VALUE_GET_FUNCTION(frame->function);
|
||||
JSFrameRegister *target = (JSFrameRegister *)JS_VALUE_GET_PTR(fn->u.reg.outer_frame);
|
||||
for (int d = 1; d < depth; d++) {
|
||||
fn = JS_VALUE_GET_FUNCTION(target->function);
|
||||
target = (JSFrameRegister *)JS_VALUE_GET_PTR(fn->u.reg.outer_frame);
|
||||
}
|
||||
frame->slots[a] = target->slots[c];
|
||||
break;
|
||||
}
|
||||
|
||||
case MACH_SETUP: {
|
||||
/* outer_frame[B].slots[C] = R(A) */
|
||||
/* outer_frame[B].slots[C] = R(A) — walk lexical scope chain */
|
||||
int depth = b;
|
||||
JSFrameRegister *target = frame;
|
||||
for (int d = 0; d < depth && !JS_IsNull(target->caller); d++)
|
||||
target = (JSFrameRegister *)JS_VALUE_GET_PTR(target->caller);
|
||||
JSFunction *fn = JS_VALUE_GET_FUNCTION(frame->function);
|
||||
JSFrameRegister *target = (JSFrameRegister *)JS_VALUE_GET_PTR(fn->u.reg.outer_frame);
|
||||
for (int d = 1; d < depth; d++) {
|
||||
fn = JS_VALUE_GET_FUNCTION(target->function);
|
||||
target = (JSFrameRegister *)JS_VALUE_GET_PTR(fn->u.reg.outer_frame);
|
||||
}
|
||||
target->slots[c] = frame->slots[a];
|
||||
break;
|
||||
}
|
||||
@@ -32507,11 +32537,10 @@ static void dump_register_code(JSContext *ctx, JSCodeRegister *code, int indent)
|
||||
printf("r%d, r%d, r%d", a, b, c);
|
||||
break;
|
||||
|
||||
/* ABx: global/name access */
|
||||
case MACH_GETGLOBAL:
|
||||
case MACH_SETGLOBAL:
|
||||
/* ABx: name/intrinsic/env access */
|
||||
case MACH_GETNAME:
|
||||
case MACH_SETNAME: {
|
||||
case MACH_GETINTRINSIC:
|
||||
case MACH_GETENV: {
|
||||
int bx = MACH_GET_Bx(instr);
|
||||
printf("r%d, #%d", a, bx);
|
||||
if ((uint32_t)bx < code->cpool_count) {
|
||||
|
||||
Reference in New Issue
Block a user