thin out quickjs-internal
This commit is contained in:
402
source/mach.c
402
source/mach.c
@@ -25,7 +25,409 @@
|
||||
|
||||
#include "quickjs-internal.h"
|
||||
|
||||
/* ============================================================
|
||||
Mach VM instruction definitions (private to mach.c)
|
||||
============================================================ */
|
||||
|
||||
/* Encoding macros */
|
||||
#define MACH_ABC(op, a, b, c) ((uint32_t)(op) | ((uint32_t)(a)<<8) | ((uint32_t)(b)<<16) | ((uint32_t)(c)<<24))
|
||||
#define MACH_ABx(op, a, bx) ((uint32_t)(op) | ((uint32_t)(a)<<8) | ((uint32_t)(bx)<<16))
|
||||
#define MACH_AsBx(op, a, sbx) ((uint32_t)(op) | ((uint32_t)(a)<<8) | ((uint32_t)(uint16_t)(sbx)<<16))
|
||||
#define MACH_sJ(op, sj) ((uint32_t)(op) | (((uint32_t)(sj) & 0xFFFFFF) << 8))
|
||||
|
||||
/* Decoding macros */
|
||||
#define MACH_GET_OP(i) ((i) & 0xFF)
|
||||
#define MACH_GET_A(i) (((i) >> 8) & 0xFF)
|
||||
#define MACH_GET_B(i) (((i) >> 16) & 0xFF)
|
||||
#define MACH_GET_C(i) (((i) >> 24) & 0xFF)
|
||||
#define MACH_GET_Bx(i) ((i) >> 16)
|
||||
#define MACH_GET_sBx(i) ((int16_t)((i) >> 16))
|
||||
#define MACH_GET_sJ(i) ((int32_t)((i) & 0xFFFFFF00) >> 8)
|
||||
|
||||
/* ============================================================
|
||||
GC Safepoint Classification for the MACH VM Dispatch Loop
|
||||
============================================================
|
||||
|
||||
Every opcode falls into one of three categories:
|
||||
|
||||
[P] Pure inline — never calls C, never allocates. No GC possible.
|
||||
No frame re-derivation needed after execution.
|
||||
|
||||
[N] Non-allocating C call — calls a C function that is guaranteed
|
||||
to never allocate (e.g. JS_ToBool, js_string_compare_value).
|
||||
No frame re-derivation needed.
|
||||
|
||||
[G] GC safepoint — calls C that may allocate, triggering GC.
|
||||
After the call, all heap pointers (including `frame`) MUST be
|
||||
re-derived via: frame = (JSFrameRegister *)JS_VALUE_GET_PTR(frame_ref.val);
|
||||
|
||||
The 18 C entry points that can allocate (GC safepoints):
|
||||
1. JS_GetProperty — key interning for string keys >7 chars
|
||||
2. JS_SetProperty — rec_resize when record grows
|
||||
3. JS_GetPropertyNumber — text substring extraction
|
||||
4. JS_SetPropertyNumber — array grow
|
||||
5. JS_NewObject — allocates record
|
||||
6. JS_NewArray / JS_NewArrayLen — allocates array
|
||||
7. js_new_register_function — allocates function object (closure)
|
||||
8. alloc_frame_register — allocates frame via js_mallocz
|
||||
9. js_call_c_function — arbitrary C code
|
||||
10. JS_CallInternal — arbitrary bytecode
|
||||
11. JS_Call — arbitrary call
|
||||
12. JS_ConcatString — allocates new string
|
||||
13. JS_ArrayPush — array grow
|
||||
14. JS_ArrayPop — reads, but frame refresh needed
|
||||
15. JS_DeleteProperty — mutates record
|
||||
16. JS_HasProperty — complex traversal
|
||||
17. js_regexp_constructor — allocates regex
|
||||
18. reg_vm_binop — polymorphic dispatch (legacy opcodes)
|
||||
|
||||
Opcode-level classification:
|
||||
[P] LOADK, LOADI, LOADNULL, LOADTRUE, LOADFALSE, MOVE, NOP
|
||||
[P] ADD_INT..MOD_INT, NEG_INT, ADD_FLOAT..MOD_FLOAT, NEG_FLOAT
|
||||
[P] EQ_INT..GE_INT, EQ_FLOAT..GE_FLOAT, EQ_BOOL, NE_BOOL
|
||||
[P] IS_IDENTICAL, IS_INT, IS_NUM, IS_TEXT, IS_BOOL, IS_NULL
|
||||
[P] IS_ARRAY, IS_FUNC, IS_RECORD, IS_STONE, IS_PROXY
|
||||
[P] NOT, AND, OR, BITNOT, BITAND, BITOR, BITXOR
|
||||
[P] JMP, JMPTRUE, JMPFALSE, JMPNULL, JMPNOTNULL
|
||||
[P] RETURN, RETNIL, SETARG, GETUP, SETUP, DISRUPT, THROW
|
||||
[P] LENGTH (array + imm-ASCII fast path only; text/blob fallback is [G])
|
||||
[N] EQ_TEXT..GE_TEXT (js_string_compare_value — no allocation)
|
||||
[N] LNOT (JS_ToBool — no allocation)
|
||||
[G] ADD..USHR, NEG, INC, DEC, EQ..GE (legacy: reg_vm_binop)
|
||||
[G] EQ_TOL, NEQ_TOL (tolerance comparison, may fall back)
|
||||
[G] CONCAT (JS_ConcatString)
|
||||
[G] GETFIELD, SETFIELD, GETINDEX, SETINDEX (property access)
|
||||
[G] LOAD_FIELD, STORE_FIELD, LOAD_INDEX, STORE_INDEX
|
||||
[G] LOAD_DYNAMIC, STORE_DYNAMIC
|
||||
[G] GETNAME, GETINTRINSIC, GETENV, SET_VAR
|
||||
[G] NEWOBJECT, NEWRECORD, NEWARRAY (object/array creation)
|
||||
[G] CLOSURE (js_new_register_function)
|
||||
[G] FRAME, GOFRAME (alloc_frame_register)
|
||||
[G] INVOKE, GOINVOKE (function calls)
|
||||
[G] PUSH (JS_ArrayPush), POP (JS_ArrayPop)
|
||||
[G] DELETE, DELETEINDEX (JS_DeleteProperty)
|
||||
[G] HASPROP, IN (JS_HasProperty)
|
||||
[G] REGEXP (js_regexp_constructor)
|
||||
============================================================ */
|
||||
|
||||
typedef enum MachOpcode {
|
||||
/* === Legacy opcodes (used by existing .mach files) === */
|
||||
|
||||
/* Constants & Loading */
|
||||
MACH_LOADK, /* R(A) = K(Bx) — load from constant pool (ABx) */
|
||||
MACH_LOADI, /* R(A) = (int16_t)sBx — load small integer (AsBx) */
|
||||
MACH_LOADNULL, /* R(A) = null (A only) */
|
||||
MACH_LOADTRUE, /* R(A) = true (A only) */
|
||||
MACH_LOADFALSE, /* R(A) = false (A only) */
|
||||
|
||||
/* Movement */
|
||||
MACH_MOVE, /* R(A) = R(B) */
|
||||
|
||||
/* Generic arithmetic (ABC) — used by legacy .mach */
|
||||
MACH_ADD, /* R(A) = R(B) + R(C) */
|
||||
MACH_SUB, /* R(A) = R(B) - R(C) */
|
||||
MACH_MUL, /* R(A) = R(B) * R(C) */
|
||||
MACH_DIV, /* R(A) = R(B) / R(C) */
|
||||
MACH_MOD, /* R(A) = R(B) % R(C) */
|
||||
MACH_POW, /* R(A) = R(B) ** R(C) */
|
||||
MACH_NEG, /* R(A) = -R(B) */
|
||||
MACH_REMAINDER, /* R(A) = remainder(R(B), R(C)) */
|
||||
MACH_MAX, /* R(A) = max(R(B), R(C)) */
|
||||
MACH_MIN, /* R(A) = min(R(B), R(C)) */
|
||||
MACH_ABS, /* R(A) = abs(R(B)) */
|
||||
MACH_SIGN, /* R(A) = sign(R(B)) */
|
||||
MACH_FRACTION, /* R(A) = fraction(R(B)) */
|
||||
MACH_INTEGER, /* R(A) = integer(R(B)) */
|
||||
MACH_FLOOR, /* R(A) = floor(R(B), R(C)) */
|
||||
MACH_CEILING, /* R(A) = ceiling(R(B), R(C)) */
|
||||
MACH_ROUND, /* R(A) = round(R(B), R(C)) */
|
||||
MACH_TRUNC, /* R(A) = trunc(R(B), R(C)) */
|
||||
MACH__DEAD_INC, /* reserved — was MACH_INC, never emitted */
|
||||
MACH__DEAD_DEC, /* reserved — was MACH_DEC, never emitted */
|
||||
|
||||
/* Generic comparison (ABC) — used by legacy .mach */
|
||||
MACH_EQ, /* R(A) = (R(B) == R(C)) */
|
||||
MACH_NEQ, /* R(A) = (R(B) != R(C)) */
|
||||
MACH_LT, /* R(A) = (R(B) < R(C)) */
|
||||
MACH_LE, /* R(A) = (R(B) <= R(C)) */
|
||||
MACH_GT, /* R(A) = (R(B) > R(C)) */
|
||||
MACH_GE, /* R(A) = (R(B) >= R(C)) */
|
||||
|
||||
/* Logical/Bitwise — used by legacy .mach */
|
||||
MACH_LNOT, /* R(A) = !R(B) */
|
||||
MACH_BNOT, /* R(A) = ~R(B) */
|
||||
MACH_BAND, /* R(A) = R(B) & R(C) */
|
||||
MACH_BOR, /* R(A) = R(B) | R(C) */
|
||||
MACH_BXOR, /* R(A) = R(B) ^ R(C) */
|
||||
MACH_SHL, /* R(A) = R(B) << R(C) */
|
||||
MACH_SHR, /* R(A) = R(B) >> R(C) */
|
||||
MACH_USHR, /* R(A) = R(B) >>> R(C) */
|
||||
|
||||
/* Property access — used by legacy .mach */
|
||||
MACH_GETFIELD, /* R(A) = R(B)[K(C)] — named property */
|
||||
MACH_SETFIELD, /* R(A)[K(B)] = R(C) — named property */
|
||||
MACH_GETINDEX, /* R(A) = R(B)[R(C)] — computed property */
|
||||
MACH_SETINDEX, /* R(A)[R(B)] = R(C) — computed property */
|
||||
|
||||
/* 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] */
|
||||
MACH_SETUP, /* outer_frame[B].slots[C] = R(A) */
|
||||
|
||||
/* Control flow */
|
||||
MACH_JMP, /* pc += sJ — unconditional (isJ format) */
|
||||
MACH_JMPTRUE, /* if R(A): pc += sBx — (iAsBx format) */
|
||||
MACH_JMPFALSE, /* if !R(A): pc += sBx — (iAsBx format) */
|
||||
MACH_JMPNULL, /* if R(A)==null: pc += sBx */
|
||||
|
||||
/* Function calls — Lua-style consecutive registers (legacy .mach) */
|
||||
MACH_RETURN, /* Return R(A) */
|
||||
MACH_RETNIL, /* Return null */
|
||||
|
||||
/* Object/array creation — legacy .mach */
|
||||
MACH_NEWOBJECT, /* R(A) = {} */
|
||||
MACH_NEWARRAY, /* R(A) = new array, B = element count in R(A+1)..R(A+B) */
|
||||
MACH_CLOSURE, /* R(A) = closure(functions[Bx]) (ABx) */
|
||||
|
||||
MACH_THROW, /* disrupt — trigger disruption */
|
||||
|
||||
MACH_PUSH, /* push R(B) onto array R(A) */
|
||||
MACH_POP, /* R(A) = pop last element from array R(B) */
|
||||
|
||||
MACH_DELETE, /* R(A) = delete R(B)[K(C)] — named property delete */
|
||||
MACH_DELETEINDEX, /* R(A) = delete R(B)[R(C)] — computed property delete */
|
||||
MACH_HASPROP, /* R(A) = R(C) in R(B) — has property check */
|
||||
MACH_REGEXP, /* R(A) = regexp(K(B), K(C)) — regex literal */
|
||||
|
||||
MACH_EQ_TOL, /* R(A) = eq_tol(R(B), R(B+1), R(B+2)), C=3 */
|
||||
MACH_NEQ_TOL, /* R(A) = ne_tol(R(B), R(B+1), R(B+2)), C=3 */
|
||||
|
||||
MACH_NOP,
|
||||
|
||||
/* === New mcode-derived opcodes (1:1 mapping to mcode IR) === */
|
||||
|
||||
/* Text */
|
||||
MACH_CONCAT, /* R(A) = R(B) ++ R(C) — string concatenation */
|
||||
|
||||
/* Typed integer comparisons (ABC) */
|
||||
MACH_EQ_INT, /* R(A) = (R(B) == R(C)) — int */
|
||||
MACH_NE_INT, /* R(A) = (R(B) != R(C)) — int */
|
||||
MACH_LT_INT, /* R(A) = (R(B) < R(C)) — int */
|
||||
MACH_LE_INT, /* R(A) = (R(B) <= R(C)) — int */
|
||||
MACH_GT_INT, /* R(A) = (R(B) > R(C)) — int */
|
||||
MACH_GE_INT, /* R(A) = (R(B) >= R(C)) — int */
|
||||
|
||||
/* Typed float comparisons (ABC) */
|
||||
MACH_EQ_FLOAT, /* R(A) = (R(B) == R(C)) — float */
|
||||
MACH_NE_FLOAT, /* R(A) = (R(B) != R(C)) — float */
|
||||
MACH_LT_FLOAT, /* R(A) = (R(B) < R(C)) — float */
|
||||
MACH_LE_FLOAT, /* R(A) = (R(B) <= R(C)) — float */
|
||||
MACH_GT_FLOAT, /* R(A) = (R(B) > R(C)) — float */
|
||||
MACH_GE_FLOAT, /* R(A) = (R(B) >= R(C)) — float */
|
||||
|
||||
/* Typed text comparisons (ABC) */
|
||||
MACH_EQ_TEXT, /* R(A) = (R(B) == R(C)) — text */
|
||||
MACH_NE_TEXT, /* R(A) = (R(B) != R(C)) — text */
|
||||
MACH_LT_TEXT, /* R(A) = (R(B) < R(C)) — text */
|
||||
MACH_LE_TEXT, /* R(A) = (R(B) <= R(C)) — text */
|
||||
MACH_GT_TEXT, /* R(A) = (R(B) > R(C)) — text */
|
||||
MACH_GE_TEXT, /* R(A) = (R(B) >= R(C)) — text */
|
||||
|
||||
/* Typed bool comparisons (ABC) */
|
||||
MACH_EQ_BOOL, /* R(A) = (R(B) == R(C)) — bool */
|
||||
MACH_NE_BOOL, /* R(A) = (R(B) != R(C)) — bool */
|
||||
|
||||
/* Special comparisons */
|
||||
MACH_IS_IDENTICAL, /* R(A) = (R(B) === R(C)) — identity check (ABC) */
|
||||
|
||||
/* Type checks (AB) */
|
||||
MACH_IS_INT, /* R(A) = is_int(R(B)) */
|
||||
MACH_IS_NUM, /* R(A) = is_num(R(B)) */
|
||||
MACH_IS_TEXT, /* R(A) = is_text(R(B)) */
|
||||
MACH_IS_BOOL, /* R(A) = is_bool(R(B)) */
|
||||
MACH_IS_NULL, /* R(A) = is_null(R(B)) */
|
||||
|
||||
/* Logical (mcode-style) */
|
||||
MACH_NOT, /* R(A) = !R(B) — boolean not (AB) */
|
||||
MACH_AND, /* R(A) = R(B) && R(C) (ABC) */
|
||||
MACH_OR, /* R(A) = R(B) || R(C) (ABC) */
|
||||
|
||||
/* Bitwise (mcode names) */
|
||||
MACH_BITNOT, /* R(A) = ~R(B) (AB) */
|
||||
MACH_BITAND, /* R(A) = R(B) & R(C) (ABC) */
|
||||
MACH_BITOR, /* R(A) = R(B) | R(C) (ABC) */
|
||||
MACH_BITXOR, /* R(A) = R(B) ^ R(C) (ABC) */
|
||||
|
||||
/* Property access (mcode names) */
|
||||
MACH_LOAD_FIELD, /* R(A) = R(B).K(C) — named property (ABC) */
|
||||
MACH_STORE_FIELD, /* R(A).K(B) = R(C) — named property (ABC) */
|
||||
MACH_LOAD_INDEX, /* R(A) = R(B)[R(C)] — integer index (ABC) */
|
||||
MACH_STORE_INDEX, /* R(A)[R(B)] = R(C) — integer index (ABC) */
|
||||
MACH_LOAD_DYNAMIC, /* R(A) = R(B)[R(C)] — dynamic key (ABC) */
|
||||
MACH_STORE_DYNAMIC, /* R(A)[R(B)] = R(C) — dynamic key (ABC) */
|
||||
|
||||
/* Object/Array creation (mcode names) */
|
||||
MACH_NEWRECORD, /* R(A) = {} — new empty record (A only) */
|
||||
|
||||
/* Decomposed function calls (mcode-style) */
|
||||
MACH_FRAME, /* R(A) = frame(R(B), C) — alloc call frame (ABC) */
|
||||
MACH_SETARG, /* frame R(A)[B] = R(C) — set arg in frame (ABC) */
|
||||
MACH_INVOKE, /* R(B) = invoke(R(A)) — call frame, result in R(B) (AB) */
|
||||
MACH_GOFRAME, /* R(A) = goframe(R(B), C) — async frame (ABC) */
|
||||
MACH_GOINVOKE, /* goinvoke(R(A)) — async invoke, no result (A only) */
|
||||
|
||||
/* Control flow */
|
||||
MACH_JMPNOTNULL, /* if R(A)!=null: pc += sBx (iAsBx) */
|
||||
|
||||
/* Error handling */
|
||||
MACH_DISRUPT, /* trigger disruption (A only) */
|
||||
|
||||
/* Misc */
|
||||
MACH_IN, /* R(A) = (R(B) in R(C)) — has property (ABC) */
|
||||
|
||||
/* Extended type checks (AB) */
|
||||
MACH_IS_ARRAY, /* R(A) = is_array(R(B)) */
|
||||
MACH_IS_FUNC, /* R(A) = is_function(R(B)) */
|
||||
MACH_IS_RECORD, /* R(A) = is_object(R(B)) */
|
||||
MACH_IS_STONE, /* R(A) = is_stone(R(B)) */
|
||||
MACH_LENGTH, /* R(A) = length(R(B)) — array/text/blob length */
|
||||
MACH_IS_PROXY, /* R(A) = is_function(R(B)) && R(B).length == 2 */
|
||||
|
||||
MACH_OP_COUNT
|
||||
} MachOpcode;
|
||||
|
||||
static const char *mach_opcode_names[MACH_OP_COUNT] = {
|
||||
/* Legacy */
|
||||
[MACH_LOADK] = "loadk",
|
||||
[MACH_LOADI] = "loadi",
|
||||
[MACH_LOADNULL] = "loadnull",
|
||||
[MACH_LOADTRUE] = "loadtrue",
|
||||
[MACH_LOADFALSE] = "loadfalse",
|
||||
[MACH_MOVE] = "move",
|
||||
[MACH_ADD] = "add",
|
||||
[MACH_SUB] = "sub",
|
||||
[MACH_MUL] = "mul",
|
||||
[MACH_DIV] = "div",
|
||||
[MACH_MOD] = "mod",
|
||||
[MACH_POW] = "pow",
|
||||
[MACH_NEG] = "neg",
|
||||
[MACH_REMAINDER] = "remainder",
|
||||
[MACH_MAX] = "max",
|
||||
[MACH_MIN] = "min",
|
||||
[MACH_ABS] = "abs",
|
||||
[MACH_SIGN] = "sign",
|
||||
[MACH_FRACTION] = "fraction",
|
||||
[MACH_INTEGER] = "integer",
|
||||
[MACH_FLOOR] = "floor",
|
||||
[MACH_CEILING] = "ceiling",
|
||||
[MACH_ROUND] = "round",
|
||||
[MACH_TRUNC] = "trunc",
|
||||
[MACH__DEAD_INC] = "dead_inc",
|
||||
[MACH__DEAD_DEC] = "dead_dec",
|
||||
[MACH_EQ] = "eq",
|
||||
[MACH_NEQ] = "neq",
|
||||
[MACH_LT] = "lt",
|
||||
[MACH_LE] = "le",
|
||||
[MACH_GT] = "gt",
|
||||
[MACH_GE] = "ge",
|
||||
[MACH_LNOT] = "lnot",
|
||||
[MACH_BNOT] = "bnot",
|
||||
[MACH_BAND] = "band",
|
||||
[MACH_BOR] = "bor",
|
||||
[MACH_BXOR] = "bxor",
|
||||
[MACH_SHL] = "shl",
|
||||
[MACH_SHR] = "shr",
|
||||
[MACH_USHR] = "ushr",
|
||||
[MACH_GETFIELD] = "getfield",
|
||||
[MACH_SETFIELD] = "setfield",
|
||||
[MACH_GETINDEX] = "getindex",
|
||||
[MACH_SETINDEX] = "setindex",
|
||||
[MACH_GETNAME] = "getname",
|
||||
[MACH_GETINTRINSIC] = "getintrinsic",
|
||||
[MACH_GETENV] = "getenv",
|
||||
[MACH_GETUP] = "getup",
|
||||
[MACH_SETUP] = "setup",
|
||||
[MACH_JMP] = "jmp",
|
||||
[MACH_JMPTRUE] = "jmptrue",
|
||||
[MACH_JMPFALSE] = "jmpfalse",
|
||||
[MACH_JMPNULL] = "jmpnull",
|
||||
[MACH_RETURN] = "return",
|
||||
[MACH_RETNIL] = "retnil",
|
||||
[MACH_NEWOBJECT] = "newobject",
|
||||
[MACH_NEWARRAY] = "newarray",
|
||||
[MACH_CLOSURE] = "closure",
|
||||
[MACH_THROW] = "throw",
|
||||
[MACH_PUSH] = "push",
|
||||
[MACH_POP] = "pop",
|
||||
[MACH_DELETE] = "delete",
|
||||
[MACH_DELETEINDEX] = "deleteindex",
|
||||
[MACH_HASPROP] = "hasprop",
|
||||
[MACH_REGEXP] = "regexp",
|
||||
[MACH_EQ_TOL] = "eq_tol",
|
||||
[MACH_NEQ_TOL] = "neq_tol",
|
||||
[MACH_NOP] = "nop",
|
||||
/* Mcode-derived */
|
||||
[MACH_CONCAT] = "concat",
|
||||
[MACH_EQ_INT] = "eq_int",
|
||||
[MACH_NE_INT] = "ne_int",
|
||||
[MACH_LT_INT] = "lt_int",
|
||||
[MACH_LE_INT] = "le_int",
|
||||
[MACH_GT_INT] = "gt_int",
|
||||
[MACH_GE_INT] = "ge_int",
|
||||
[MACH_EQ_FLOAT] = "eq_float",
|
||||
[MACH_NE_FLOAT] = "ne_float",
|
||||
[MACH_LT_FLOAT] = "lt_float",
|
||||
[MACH_LE_FLOAT] = "le_float",
|
||||
[MACH_GT_FLOAT] = "gt_float",
|
||||
[MACH_GE_FLOAT] = "ge_float",
|
||||
[MACH_EQ_TEXT] = "eq_text",
|
||||
[MACH_NE_TEXT] = "ne_text",
|
||||
[MACH_LT_TEXT] = "lt_text",
|
||||
[MACH_LE_TEXT] = "le_text",
|
||||
[MACH_GT_TEXT] = "gt_text",
|
||||
[MACH_GE_TEXT] = "ge_text",
|
||||
[MACH_EQ_BOOL] = "eq_bool",
|
||||
[MACH_NE_BOOL] = "ne_bool",
|
||||
[MACH_IS_IDENTICAL] = "is_identical",
|
||||
[MACH_IS_INT] = "is_int",
|
||||
[MACH_IS_NUM] = "is_num",
|
||||
[MACH_IS_TEXT] = "is_text",
|
||||
[MACH_IS_BOOL] = "is_bool",
|
||||
[MACH_IS_NULL] = "is_null",
|
||||
[MACH_NOT] = "not",
|
||||
[MACH_AND] = "and",
|
||||
[MACH_OR] = "or",
|
||||
[MACH_BITNOT] = "bitnot",
|
||||
[MACH_BITAND] = "bitand",
|
||||
[MACH_BITOR] = "bitor",
|
||||
[MACH_BITXOR] = "bitxor",
|
||||
[MACH_LOAD_FIELD] = "load_field",
|
||||
[MACH_STORE_FIELD] = "store_field",
|
||||
[MACH_LOAD_INDEX] = "load_index",
|
||||
[MACH_STORE_INDEX] = "store_index",
|
||||
[MACH_LOAD_DYNAMIC] = "load_dynamic",
|
||||
[MACH_STORE_DYNAMIC] = "store_dynamic",
|
||||
[MACH_NEWRECORD] = "newrecord",
|
||||
[MACH_FRAME] = "frame",
|
||||
[MACH_SETARG] = "setarg",
|
||||
[MACH_INVOKE] = "invoke",
|
||||
[MACH_GOFRAME] = "goframe",
|
||||
[MACH_GOINVOKE] = "goinvoke",
|
||||
[MACH_JMPNOTNULL] = "jmpnotnull",
|
||||
[MACH_DISRUPT] = "disrupt",
|
||||
[MACH_IN] = "in",
|
||||
/* Extended type checks */
|
||||
[MACH_IS_ARRAY] = "is_array",
|
||||
[MACH_IS_FUNC] = "is_func",
|
||||
[MACH_IS_RECORD] = "is_record",
|
||||
[MACH_IS_STONE] = "is_stone",
|
||||
[MACH_LENGTH] = "length",
|
||||
[MACH_IS_PROXY] = "is_proxy",
|
||||
};
|
||||
|
||||
/* ---- Compile-time constant pool entry ---- */
|
||||
/* Stores raw data during compilation; converted to JSValues when loading into context */
|
||||
|
||||
@@ -384,406 +384,6 @@ typedef uint32_t MachInstr32;
|
||||
|
||||
typedef struct { uint16_t line; uint16_t col; } MachLineEntry;
|
||||
|
||||
/* Encoding macros */
|
||||
#define MACH_ABC(op, a, b, c) ((uint32_t)(op) | ((uint32_t)(a)<<8) | ((uint32_t)(b)<<16) | ((uint32_t)(c)<<24))
|
||||
#define MACH_ABx(op, a, bx) ((uint32_t)(op) | ((uint32_t)(a)<<8) | ((uint32_t)(bx)<<16))
|
||||
#define MACH_AsBx(op, a, sbx) ((uint32_t)(op) | ((uint32_t)(a)<<8) | ((uint32_t)(uint16_t)(sbx)<<16))
|
||||
#define MACH_sJ(op, sj) ((uint32_t)(op) | (((uint32_t)(sj) & 0xFFFFFF) << 8))
|
||||
|
||||
/* Decoding macros */
|
||||
#define MACH_GET_OP(i) ((i) & 0xFF)
|
||||
#define MACH_GET_A(i) (((i) >> 8) & 0xFF)
|
||||
#define MACH_GET_B(i) (((i) >> 16) & 0xFF)
|
||||
#define MACH_GET_C(i) (((i) >> 24) & 0xFF)
|
||||
#define MACH_GET_Bx(i) ((i) >> 16)
|
||||
#define MACH_GET_sBx(i) ((int16_t)((i) >> 16))
|
||||
#define MACH_GET_sJ(i) ((int32_t)((i) & 0xFFFFFF00) >> 8)
|
||||
|
||||
/* ============================================================
|
||||
GC Safepoint Classification for the MACH VM Dispatch Loop
|
||||
============================================================
|
||||
|
||||
Every opcode falls into one of three categories:
|
||||
|
||||
[P] Pure inline — never calls C, never allocates. No GC possible.
|
||||
No frame re-derivation needed after execution.
|
||||
|
||||
[N] Non-allocating C call — calls a C function that is guaranteed
|
||||
to never allocate (e.g. JS_ToBool, js_string_compare_value).
|
||||
No frame re-derivation needed.
|
||||
|
||||
[G] GC safepoint — calls C that may allocate, triggering GC.
|
||||
After the call, all heap pointers (including `frame`) MUST be
|
||||
re-derived via: frame = (JSFrameRegister *)JS_VALUE_GET_PTR(frame_ref.val);
|
||||
|
||||
The 18 C entry points that can allocate (GC safepoints):
|
||||
1. JS_GetProperty — key interning for string keys >7 chars
|
||||
2. JS_SetProperty — rec_resize when record grows
|
||||
3. JS_GetPropertyNumber — text substring extraction
|
||||
4. JS_SetPropertyNumber — array grow
|
||||
5. JS_NewObject — allocates record
|
||||
6. JS_NewArray / JS_NewArrayLen — allocates array
|
||||
7. js_new_register_function — allocates function object (closure)
|
||||
8. alloc_frame_register — allocates frame via js_mallocz
|
||||
9. js_call_c_function — arbitrary C code
|
||||
10. JS_CallInternal — arbitrary bytecode
|
||||
11. JS_Call — arbitrary call
|
||||
12. JS_ConcatString — allocates new string
|
||||
13. JS_ArrayPush — array grow
|
||||
14. JS_ArrayPop — reads, but frame refresh needed
|
||||
15. JS_DeleteProperty — mutates record
|
||||
16. JS_HasProperty — complex traversal
|
||||
17. js_regexp_constructor — allocates regex
|
||||
18. reg_vm_binop — polymorphic dispatch (legacy opcodes)
|
||||
|
||||
Opcode-level classification:
|
||||
[P] LOADK, LOADI, LOADNULL, LOADTRUE, LOADFALSE, MOVE, NOP
|
||||
[P] ADD_INT..MOD_INT, NEG_INT, ADD_FLOAT..MOD_FLOAT, NEG_FLOAT
|
||||
[P] EQ_INT..GE_INT, EQ_FLOAT..GE_FLOAT, EQ_BOOL, NE_BOOL
|
||||
[P] IS_IDENTICAL, IS_INT, IS_NUM, IS_TEXT, IS_BOOL, IS_NULL
|
||||
[P] IS_ARRAY, IS_FUNC, IS_RECORD, IS_STONE, IS_PROXY
|
||||
[P] NOT, AND, OR, BITNOT, BITAND, BITOR, BITXOR
|
||||
[P] JMP, JMPTRUE, JMPFALSE, JMPNULL, JMPNOTNULL
|
||||
[P] RETURN, RETNIL, SETARG, GETUP, SETUP, DISRUPT, THROW
|
||||
[P] LENGTH (array + imm-ASCII fast path only; text/blob fallback is [G])
|
||||
[N] EQ_TEXT..GE_TEXT (js_string_compare_value — no allocation)
|
||||
[N] LNOT (JS_ToBool — no allocation)
|
||||
[G] ADD..USHR, NEG, INC, DEC, EQ..GE (legacy: reg_vm_binop)
|
||||
[G] EQ_TOL, NEQ_TOL (tolerance comparison, may fall back)
|
||||
[G] CONCAT (JS_ConcatString)
|
||||
[G] GETFIELD, SETFIELD, GETINDEX, SETINDEX (property access)
|
||||
[G] LOAD_FIELD, STORE_FIELD, LOAD_INDEX, STORE_INDEX
|
||||
[G] LOAD_DYNAMIC, STORE_DYNAMIC
|
||||
[G] GETNAME, GETINTRINSIC, GETENV, SET_VAR
|
||||
[G] NEWOBJECT, NEWRECORD, NEWARRAY (object/array creation)
|
||||
[G] CLOSURE (js_new_register_function)
|
||||
[G] FRAME, GOFRAME (alloc_frame_register)
|
||||
[G] INVOKE, GOINVOKE (function calls)
|
||||
[G] PUSH (JS_ArrayPush), POP (JS_ArrayPop)
|
||||
[G] DELETE, DELETEINDEX (JS_DeleteProperty)
|
||||
[G] HASPROP, IN (JS_HasProperty)
|
||||
[G] REGEXP (js_regexp_constructor)
|
||||
============================================================ */
|
||||
|
||||
typedef enum MachOpcode {
|
||||
/* === Legacy opcodes (used by existing .mach files) === */
|
||||
|
||||
/* Constants & Loading */
|
||||
MACH_LOADK, /* R(A) = K(Bx) — load from constant pool (ABx) */
|
||||
MACH_LOADI, /* R(A) = (int16_t)sBx — load small integer (AsBx) */
|
||||
MACH_LOADNULL, /* R(A) = null (A only) */
|
||||
MACH_LOADTRUE, /* R(A) = true (A only) */
|
||||
MACH_LOADFALSE, /* R(A) = false (A only) */
|
||||
|
||||
/* Movement */
|
||||
MACH_MOVE, /* R(A) = R(B) */
|
||||
|
||||
/* Generic arithmetic (ABC) — used by legacy .mach */
|
||||
MACH_ADD, /* R(A) = R(B) + R(C) */
|
||||
MACH_SUB, /* R(A) = R(B) - R(C) */
|
||||
MACH_MUL, /* R(A) = R(B) * R(C) */
|
||||
MACH_DIV, /* R(A) = R(B) / R(C) */
|
||||
MACH_MOD, /* R(A) = R(B) % R(C) */
|
||||
MACH_POW, /* R(A) = R(B) ** R(C) */
|
||||
MACH_NEG, /* R(A) = -R(B) */
|
||||
MACH_REMAINDER, /* R(A) = remainder(R(B), R(C)) */
|
||||
MACH_MAX, /* R(A) = max(R(B), R(C)) */
|
||||
MACH_MIN, /* R(A) = min(R(B), R(C)) */
|
||||
MACH_ABS, /* R(A) = abs(R(B)) */
|
||||
MACH_SIGN, /* R(A) = sign(R(B)) */
|
||||
MACH_FRACTION, /* R(A) = fraction(R(B)) */
|
||||
MACH_INTEGER, /* R(A) = integer(R(B)) */
|
||||
MACH_FLOOR, /* R(A) = floor(R(B), R(C)) */
|
||||
MACH_CEILING, /* R(A) = ceiling(R(B), R(C)) */
|
||||
MACH_ROUND, /* R(A) = round(R(B), R(C)) */
|
||||
MACH_TRUNC, /* R(A) = trunc(R(B), R(C)) */
|
||||
MACH__DEAD_INC, /* reserved — was MACH_INC, never emitted */
|
||||
MACH__DEAD_DEC, /* reserved — was MACH_DEC, never emitted */
|
||||
|
||||
/* Generic comparison (ABC) — used by legacy .mach */
|
||||
MACH_EQ, /* R(A) = (R(B) == R(C)) */
|
||||
MACH_NEQ, /* R(A) = (R(B) != R(C)) */
|
||||
MACH_LT, /* R(A) = (R(B) < R(C)) */
|
||||
MACH_LE, /* R(A) = (R(B) <= R(C)) */
|
||||
MACH_GT, /* R(A) = (R(B) > R(C)) */
|
||||
MACH_GE, /* R(A) = (R(B) >= R(C)) */
|
||||
|
||||
/* Logical/Bitwise — used by legacy .mach */
|
||||
MACH_LNOT, /* R(A) = !R(B) */
|
||||
MACH_BNOT, /* R(A) = ~R(B) */
|
||||
MACH_BAND, /* R(A) = R(B) & R(C) */
|
||||
MACH_BOR, /* R(A) = R(B) | R(C) */
|
||||
MACH_BXOR, /* R(A) = R(B) ^ R(C) */
|
||||
MACH_SHL, /* R(A) = R(B) << R(C) */
|
||||
MACH_SHR, /* R(A) = R(B) >> R(C) */
|
||||
MACH_USHR, /* R(A) = R(B) >>> R(C) */
|
||||
|
||||
/* Property access — used by legacy .mach */
|
||||
MACH_GETFIELD, /* R(A) = R(B)[K(C)] — named property */
|
||||
MACH_SETFIELD, /* R(A)[K(B)] = R(C) — named property */
|
||||
MACH_GETINDEX, /* R(A) = R(B)[R(C)] — computed property */
|
||||
MACH_SETINDEX, /* R(A)[R(B)] = R(C) — computed property */
|
||||
|
||||
/* 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] */
|
||||
MACH_SETUP, /* outer_frame[B].slots[C] = R(A) */
|
||||
|
||||
/* Control flow */
|
||||
MACH_JMP, /* pc += sJ — unconditional (isJ format) */
|
||||
MACH_JMPTRUE, /* if R(A): pc += sBx — (iAsBx format) */
|
||||
MACH_JMPFALSE, /* if !R(A): pc += sBx — (iAsBx format) */
|
||||
MACH_JMPNULL, /* if R(A)==null: pc += sBx */
|
||||
|
||||
/* Function calls — Lua-style consecutive registers (legacy .mach) */
|
||||
MACH_RETURN, /* Return R(A) */
|
||||
MACH_RETNIL, /* Return null */
|
||||
|
||||
/* Object/array creation — legacy .mach */
|
||||
MACH_NEWOBJECT, /* R(A) = {} */
|
||||
MACH_NEWARRAY, /* R(A) = new array, B = element count in R(A+1)..R(A+B) */
|
||||
MACH_CLOSURE, /* R(A) = closure(functions[Bx]) (ABx) */
|
||||
|
||||
MACH_THROW, /* disrupt — trigger disruption */
|
||||
|
||||
MACH_PUSH, /* push R(B) onto array R(A) */
|
||||
MACH_POP, /* R(A) = pop last element from array R(B) */
|
||||
|
||||
MACH_DELETE, /* R(A) = delete R(B)[K(C)] — named property delete */
|
||||
MACH_DELETEINDEX, /* R(A) = delete R(B)[R(C)] — computed property delete */
|
||||
MACH_HASPROP, /* R(A) = R(C) in R(B) — has property check */
|
||||
MACH_REGEXP, /* R(A) = regexp(K(B), K(C)) — regex literal */
|
||||
|
||||
MACH_EQ_TOL, /* R(A) = eq_tol(R(B), R(B+1), R(B+2)), C=3 */
|
||||
MACH_NEQ_TOL, /* R(A) = ne_tol(R(B), R(B+1), R(B+2)), C=3 */
|
||||
|
||||
MACH_NOP,
|
||||
|
||||
/* === New mcode-derived opcodes (1:1 mapping to mcode IR) === */
|
||||
|
||||
/* Text */
|
||||
MACH_CONCAT, /* R(A) = R(B) ++ R(C) — string concatenation */
|
||||
|
||||
/* Typed integer comparisons (ABC) */
|
||||
MACH_EQ_INT, /* R(A) = (R(B) == R(C)) — int */
|
||||
MACH_NE_INT, /* R(A) = (R(B) != R(C)) — int */
|
||||
MACH_LT_INT, /* R(A) = (R(B) < R(C)) — int */
|
||||
MACH_LE_INT, /* R(A) = (R(B) <= R(C)) — int */
|
||||
MACH_GT_INT, /* R(A) = (R(B) > R(C)) — int */
|
||||
MACH_GE_INT, /* R(A) = (R(B) >= R(C)) — int */
|
||||
|
||||
/* Typed float comparisons (ABC) */
|
||||
MACH_EQ_FLOAT, /* R(A) = (R(B) == R(C)) — float */
|
||||
MACH_NE_FLOAT, /* R(A) = (R(B) != R(C)) — float */
|
||||
MACH_LT_FLOAT, /* R(A) = (R(B) < R(C)) — float */
|
||||
MACH_LE_FLOAT, /* R(A) = (R(B) <= R(C)) — float */
|
||||
MACH_GT_FLOAT, /* R(A) = (R(B) > R(C)) — float */
|
||||
MACH_GE_FLOAT, /* R(A) = (R(B) >= R(C)) — float */
|
||||
|
||||
/* Typed text comparisons (ABC) */
|
||||
MACH_EQ_TEXT, /* R(A) = (R(B) == R(C)) — text */
|
||||
MACH_NE_TEXT, /* R(A) = (R(B) != R(C)) — text */
|
||||
MACH_LT_TEXT, /* R(A) = (R(B) < R(C)) — text */
|
||||
MACH_LE_TEXT, /* R(A) = (R(B) <= R(C)) — text */
|
||||
MACH_GT_TEXT, /* R(A) = (R(B) > R(C)) — text */
|
||||
MACH_GE_TEXT, /* R(A) = (R(B) >= R(C)) — text */
|
||||
|
||||
/* Typed bool comparisons (ABC) */
|
||||
MACH_EQ_BOOL, /* R(A) = (R(B) == R(C)) — bool */
|
||||
MACH_NE_BOOL, /* R(A) = (R(B) != R(C)) — bool */
|
||||
|
||||
/* Special comparisons */
|
||||
MACH_IS_IDENTICAL, /* R(A) = (R(B) === R(C)) — identity check (ABC) */
|
||||
|
||||
/* Type checks (AB) */
|
||||
MACH_IS_INT, /* R(A) = is_int(R(B)) */
|
||||
MACH_IS_NUM, /* R(A) = is_num(R(B)) */
|
||||
MACH_IS_TEXT, /* R(A) = is_text(R(B)) */
|
||||
MACH_IS_BOOL, /* R(A) = is_bool(R(B)) */
|
||||
MACH_IS_NULL, /* R(A) = is_null(R(B)) */
|
||||
|
||||
/* Logical (mcode-style) */
|
||||
MACH_NOT, /* R(A) = !R(B) — boolean not (AB) */
|
||||
MACH_AND, /* R(A) = R(B) && R(C) (ABC) */
|
||||
MACH_OR, /* R(A) = R(B) || R(C) (ABC) */
|
||||
|
||||
/* Bitwise (mcode names) */
|
||||
MACH_BITNOT, /* R(A) = ~R(B) (AB) */
|
||||
MACH_BITAND, /* R(A) = R(B) & R(C) (ABC) */
|
||||
MACH_BITOR, /* R(A) = R(B) | R(C) (ABC) */
|
||||
MACH_BITXOR, /* R(A) = R(B) ^ R(C) (ABC) */
|
||||
|
||||
/* Property access (mcode names) */
|
||||
MACH_LOAD_FIELD, /* R(A) = R(B).K(C) — named property (ABC) */
|
||||
MACH_STORE_FIELD, /* R(A).K(B) = R(C) — named property (ABC) */
|
||||
MACH_LOAD_INDEX, /* R(A) = R(B)[R(C)] — integer index (ABC) */
|
||||
MACH_STORE_INDEX, /* R(A)[R(B)] = R(C) — integer index (ABC) */
|
||||
MACH_LOAD_DYNAMIC, /* R(A) = R(B)[R(C)] — dynamic key (ABC) */
|
||||
MACH_STORE_DYNAMIC, /* R(A)[R(B)] = R(C) — dynamic key (ABC) */
|
||||
|
||||
/* Object/Array creation (mcode names) */
|
||||
MACH_NEWRECORD, /* R(A) = {} — new empty record (A only) */
|
||||
|
||||
/* Decomposed function calls (mcode-style) */
|
||||
MACH_FRAME, /* R(A) = frame(R(B), C) — alloc call frame (ABC) */
|
||||
MACH_SETARG, /* frame R(A)[B] = R(C) — set arg in frame (ABC) */
|
||||
MACH_INVOKE, /* R(B) = invoke(R(A)) — call frame, result in R(B) (AB) */
|
||||
MACH_GOFRAME, /* R(A) = goframe(R(B), C) — async frame (ABC) */
|
||||
MACH_GOINVOKE, /* goinvoke(R(A)) — async invoke, no result (A only) */
|
||||
|
||||
/* Control flow */
|
||||
MACH_JMPNOTNULL, /* if R(A)!=null: pc += sBx (iAsBx) */
|
||||
|
||||
/* Error handling */
|
||||
MACH_DISRUPT, /* trigger disruption (A only) */
|
||||
|
||||
/* Misc */
|
||||
MACH_IN, /* R(A) = (R(B) in R(C)) — has property (ABC) */
|
||||
|
||||
/* Extended type checks (AB) */
|
||||
MACH_IS_ARRAY, /* R(A) = is_array(R(B)) */
|
||||
MACH_IS_FUNC, /* R(A) = is_function(R(B)) */
|
||||
MACH_IS_RECORD, /* R(A) = is_object(R(B)) */
|
||||
MACH_IS_STONE, /* R(A) = is_stone(R(B)) */
|
||||
MACH_LENGTH, /* R(A) = length(R(B)) — array/text/blob length */
|
||||
MACH_IS_PROXY, /* R(A) = is_function(R(B)) && R(B).length == 2 */
|
||||
|
||||
MACH_OP_COUNT
|
||||
} MachOpcode;
|
||||
|
||||
static const char *mach_opcode_names[MACH_OP_COUNT] = {
|
||||
/* Legacy */
|
||||
[MACH_LOADK] = "loadk",
|
||||
[MACH_LOADI] = "loadi",
|
||||
[MACH_LOADNULL] = "loadnull",
|
||||
[MACH_LOADTRUE] = "loadtrue",
|
||||
[MACH_LOADFALSE] = "loadfalse",
|
||||
[MACH_MOVE] = "move",
|
||||
[MACH_ADD] = "add",
|
||||
[MACH_SUB] = "sub",
|
||||
[MACH_MUL] = "mul",
|
||||
[MACH_DIV] = "div",
|
||||
[MACH_MOD] = "mod",
|
||||
[MACH_POW] = "pow",
|
||||
[MACH_NEG] = "neg",
|
||||
[MACH_REMAINDER] = "remainder",
|
||||
[MACH_MAX] = "max",
|
||||
[MACH_MIN] = "min",
|
||||
[MACH_ABS] = "abs",
|
||||
[MACH_SIGN] = "sign",
|
||||
[MACH_FRACTION] = "fraction",
|
||||
[MACH_INTEGER] = "integer",
|
||||
[MACH_FLOOR] = "floor",
|
||||
[MACH_CEILING] = "ceiling",
|
||||
[MACH_ROUND] = "round",
|
||||
[MACH_TRUNC] = "trunc",
|
||||
[MACH__DEAD_INC] = "dead_inc",
|
||||
[MACH__DEAD_DEC] = "dead_dec",
|
||||
[MACH_EQ] = "eq",
|
||||
[MACH_NEQ] = "neq",
|
||||
[MACH_LT] = "lt",
|
||||
[MACH_LE] = "le",
|
||||
[MACH_GT] = "gt",
|
||||
[MACH_GE] = "ge",
|
||||
[MACH_LNOT] = "lnot",
|
||||
[MACH_BNOT] = "bnot",
|
||||
[MACH_BAND] = "band",
|
||||
[MACH_BOR] = "bor",
|
||||
[MACH_BXOR] = "bxor",
|
||||
[MACH_SHL] = "shl",
|
||||
[MACH_SHR] = "shr",
|
||||
[MACH_USHR] = "ushr",
|
||||
[MACH_GETFIELD] = "getfield",
|
||||
[MACH_SETFIELD] = "setfield",
|
||||
[MACH_GETINDEX] = "getindex",
|
||||
[MACH_SETINDEX] = "setindex",
|
||||
[MACH_GETNAME] = "getname",
|
||||
[MACH_GETINTRINSIC] = "getintrinsic",
|
||||
[MACH_GETENV] = "getenv",
|
||||
[MACH_GETUP] = "getup",
|
||||
[MACH_SETUP] = "setup",
|
||||
[MACH_JMP] = "jmp",
|
||||
[MACH_JMPTRUE] = "jmptrue",
|
||||
[MACH_JMPFALSE] = "jmpfalse",
|
||||
[MACH_JMPNULL] = "jmpnull",
|
||||
[MACH_RETURN] = "return",
|
||||
[MACH_RETNIL] = "retnil",
|
||||
[MACH_NEWOBJECT] = "newobject",
|
||||
[MACH_NEWARRAY] = "newarray",
|
||||
[MACH_CLOSURE] = "closure",
|
||||
[MACH_THROW] = "throw",
|
||||
[MACH_PUSH] = "push",
|
||||
[MACH_POP] = "pop",
|
||||
[MACH_DELETE] = "delete",
|
||||
[MACH_DELETEINDEX] = "deleteindex",
|
||||
[MACH_HASPROP] = "hasprop",
|
||||
[MACH_REGEXP] = "regexp",
|
||||
[MACH_EQ_TOL] = "eq_tol",
|
||||
[MACH_NEQ_TOL] = "neq_tol",
|
||||
[MACH_NOP] = "nop",
|
||||
/* Mcode-derived */
|
||||
[MACH_CONCAT] = "concat",
|
||||
[MACH_EQ_INT] = "eq_int",
|
||||
[MACH_NE_INT] = "ne_int",
|
||||
[MACH_LT_INT] = "lt_int",
|
||||
[MACH_LE_INT] = "le_int",
|
||||
[MACH_GT_INT] = "gt_int",
|
||||
[MACH_GE_INT] = "ge_int",
|
||||
[MACH_EQ_FLOAT] = "eq_float",
|
||||
[MACH_NE_FLOAT] = "ne_float",
|
||||
[MACH_LT_FLOAT] = "lt_float",
|
||||
[MACH_LE_FLOAT] = "le_float",
|
||||
[MACH_GT_FLOAT] = "gt_float",
|
||||
[MACH_GE_FLOAT] = "ge_float",
|
||||
[MACH_EQ_TEXT] = "eq_text",
|
||||
[MACH_NE_TEXT] = "ne_text",
|
||||
[MACH_LT_TEXT] = "lt_text",
|
||||
[MACH_LE_TEXT] = "le_text",
|
||||
[MACH_GT_TEXT] = "gt_text",
|
||||
[MACH_GE_TEXT] = "ge_text",
|
||||
[MACH_EQ_BOOL] = "eq_bool",
|
||||
[MACH_NE_BOOL] = "ne_bool",
|
||||
[MACH_IS_IDENTICAL] = "is_identical",
|
||||
[MACH_IS_INT] = "is_int",
|
||||
[MACH_IS_NUM] = "is_num",
|
||||
[MACH_IS_TEXT] = "is_text",
|
||||
[MACH_IS_BOOL] = "is_bool",
|
||||
[MACH_IS_NULL] = "is_null",
|
||||
[MACH_NOT] = "not",
|
||||
[MACH_AND] = "and",
|
||||
[MACH_OR] = "or",
|
||||
[MACH_BITNOT] = "bitnot",
|
||||
[MACH_BITAND] = "bitand",
|
||||
[MACH_BITOR] = "bitor",
|
||||
[MACH_BITXOR] = "bitxor",
|
||||
[MACH_LOAD_FIELD] = "load_field",
|
||||
[MACH_STORE_FIELD] = "store_field",
|
||||
[MACH_LOAD_INDEX] = "load_index",
|
||||
[MACH_STORE_INDEX] = "store_index",
|
||||
[MACH_LOAD_DYNAMIC] = "load_dynamic",
|
||||
[MACH_STORE_DYNAMIC] = "store_dynamic",
|
||||
[MACH_NEWRECORD] = "newrecord",
|
||||
[MACH_FRAME] = "frame",
|
||||
[MACH_SETARG] = "setarg",
|
||||
[MACH_INVOKE] = "invoke",
|
||||
[MACH_GOFRAME] = "goframe",
|
||||
[MACH_GOINVOKE] = "goinvoke",
|
||||
[MACH_JMPNOTNULL] = "jmpnotnull",
|
||||
[MACH_DISRUPT] = "disrupt",
|
||||
[MACH_IN] = "in",
|
||||
/* Extended type checks */
|
||||
[MACH_IS_ARRAY] = "is_array",
|
||||
[MACH_IS_FUNC] = "is_func",
|
||||
[MACH_IS_RECORD] = "is_record",
|
||||
[MACH_IS_STONE] = "is_stone",
|
||||
[MACH_LENGTH] = "length",
|
||||
[MACH_IS_PROXY] = "is_proxy",
|
||||
};
|
||||
|
||||
/* Compiled register-based code (off-heap, never GC'd).
|
||||
Created by JS_CompileMach from AST JSON. */
|
||||
typedef struct JSCodeRegister {
|
||||
|
||||
Reference in New Issue
Block a user