organize
This commit is contained in:
@@ -404,6 +404,72 @@ typedef struct { uint16_t line; uint16_t col; } MachLineEntry;
|
||||
#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) === */
|
||||
|
||||
@@ -549,7 +615,6 @@ typedef enum MachOpcode {
|
||||
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)) */
|
||||
MACH_TYPEOF, /* R(A) = typeof(R(B)) */
|
||||
|
||||
/* Logical (mcode-style) */
|
||||
MACH_NOT, /* R(A) = !R(B) — boolean not (AB) */
|
||||
@@ -702,7 +767,6 @@ static const char *mach_opcode_names[MACH_OP_COUNT] = {
|
||||
[MACH_IS_TEXT] = "is_text",
|
||||
[MACH_IS_BOOL] = "is_bool",
|
||||
[MACH_IS_NULL] = "is_null",
|
||||
[MACH_TYPEOF] = "typeof",
|
||||
[MACH_NOT] = "not",
|
||||
[MACH_AND] = "and",
|
||||
[MACH_OR] = "or",
|
||||
@@ -825,6 +889,38 @@ static inline objhdr_t *chase(JSValue v) {
|
||||
return oh;
|
||||
}
|
||||
|
||||
/* Inline type checks — use these in the VM dispatch loop to avoid
|
||||
function call overhead. The public API (JS_IsArray etc. in quickjs.h)
|
||||
remains non-inline for external callers; those wrappers live in runtime.c. */
|
||||
|
||||
static inline JS_BOOL mist_is_gc_object(JSValue v) {
|
||||
return JS_IsPtr(v);
|
||||
}
|
||||
|
||||
static inline JS_BOOL mist_is_array(JSValue v) {
|
||||
return mist_is_gc_object(v) && objhdr_type(*chase(v)) == OBJ_ARRAY;
|
||||
}
|
||||
|
||||
static inline JS_BOOL mist_is_record(JSValue v) {
|
||||
return mist_is_gc_object(v) && objhdr_type(*chase(v)) == OBJ_RECORD;
|
||||
}
|
||||
|
||||
static inline JS_BOOL mist_is_function(JSValue v) {
|
||||
return mist_is_gc_object(v) && objhdr_type(*chase(v)) == OBJ_FUNCTION;
|
||||
}
|
||||
|
||||
static inline JS_BOOL mist_is_text(JSValue v) {
|
||||
return MIST_IsImmediateASCII(v)
|
||||
|| (mist_is_gc_object(v) && objhdr_type(*chase(v)) == OBJ_TEXT);
|
||||
}
|
||||
|
||||
static inline JS_BOOL mist_is_blob(JSValue v) {
|
||||
return mist_is_gc_object(v) && objhdr_type(*chase(v)) == OBJ_BLOB;
|
||||
}
|
||||
|
||||
static inline JS_BOOL mist_is_stone(JSValue v) {
|
||||
return !mist_is_gc_object(v) || objhdr_s(*chase(v));
|
||||
}
|
||||
|
||||
/* Intrinsic array type - tagged as JS_TAG_PTR with mist_hdr type OBJ_ARRAY */
|
||||
typedef struct JSArray {
|
||||
|
||||
Reference in New Issue
Block a user