/* * qbe_rt.c - Runtime support for QBE-compiled ƿit modules * * Provides non-inline versions of static-inline quickjs functions * (which QBE-generated code calls as external symbols) and stub * implementations of cell_rt_* helper functions. */ #include #include #include typedef uint64_t JSValue; typedef struct JSContext JSContext; #define JS_TAG_SHORT_FLOAT 5 #define JS_TAG_NULL 7 #define JS_VAL_NULL 7 /* ============================================================ Non-inline wrappers for static-inline quickjs functions ============================================================ */ /* * __JS_NewFloat64 — encode double as tagged JSValue * Short float: [sign:1][exp:8][mantissa:52][tag:3] * Returns tagged int if value is an exact integer in int32 range */ JSValue __JS_NewFloat64(JSContext *ctx, double d) { union { double d; uint64_t u; } u; u.d = d; uint64_t sign = u.u >> 63; int exp = (u.u >> 52) & 0x7FF; uint64_t mantissa = u.u & ((1ULL << 52) - 1); /* Zero */ if (exp == 0 && mantissa == 0) return JS_TAG_SHORT_FLOAT; /* NaN/Inf → null */ if (exp == 0x7FF) return JS_VAL_NULL; /* Subnormals → zero */ if (exp == 0) return (sign << 63) | JS_TAG_SHORT_FLOAT; int short_exp = exp - 1023 + 127; if (short_exp < 1 || short_exp > 254) return JS_VAL_NULL; /* Prefer integer if exact */ if (d >= (double)(-2147483647 - 1) && d <= (double)2147483647) { int32_t i = (int32_t)d; if ((double)i == d) return (uint64_t)(uint32_t)i << 1; } return (sign << 63) | ((uint64_t)short_exp << 55) | (mantissa << 3) | JS_TAG_SHORT_FLOAT; } /* * JS_IsNumber — check if value is tagged int or short float */ int JS_IsNumber(JSValue v) { int is_int = (v & 1) == 0; int is_float = (v & 7) == JS_TAG_SHORT_FLOAT; return is_int || is_float; } /* * JS_NewString — create string from C string (wraps JS_NewStringLen) */ extern JSValue JS_NewStringLen(JSContext *ctx, const char *str, size_t len); JSValue JS_NewString(JSContext *ctx, const char *str) { return JS_NewStringLen(ctx, str, strlen(str)); } /* ============================================================ cell_rt_* stubs — error/fallback paths for QBE-compiled code These are called from type-mismatch branches that should not be reached in pure numeric code. ============================================================ */ extern JSValue JS_ThrowTypeError(JSContext *ctx, const char *fmt, ...); void cell_rt_disrupt(JSContext *ctx) { JS_ThrowTypeError(ctx, "type error in native code"); } JSValue cell_rt_lt_text(JSContext *ctx, JSValue a, JSValue b) { return JS_VAL_NULL; } JSValue cell_rt_gt_text(JSContext *ctx, JSValue a, JSValue b) { return JS_VAL_NULL; } JSValue cell_rt_le_text(JSContext *ctx, JSValue a, JSValue b) { return JS_VAL_NULL; } JSValue cell_rt_ge_text(JSContext *ctx, JSValue a, JSValue b) { return JS_VAL_NULL; } JSValue cell_rt_eq_tol(JSContext *ctx, JSValue a, JSValue b) { return JS_VAL_NULL; } JSValue cell_rt_ne_tol(JSContext *ctx, JSValue a, JSValue b) { return JS_VAL_NULL; } JSValue cell_rt_get_intrinsic(JSContext *ctx, const char *name) { return JS_VAL_NULL; } JSValue cell_rt_load_field(JSContext *ctx, JSValue obj, const char *name) { return JS_VAL_NULL; } JSValue cell_rt_load_dynamic(JSContext *ctx, JSValue obj, JSValue key) { return JS_VAL_NULL; } JSValue cell_rt_load_index(JSContext *ctx, JSValue arr, JSValue idx) { return JS_VAL_NULL; } void cell_rt_store_field(JSContext *ctx, JSValue val, JSValue obj, const char *name) {} void cell_rt_store_dynamic(JSContext *ctx, JSValue val, JSValue obj, JSValue key) {} void cell_rt_store_index(JSContext *ctx, JSValue val, JSValue arr, JSValue idx) {} JSValue cell_rt_get_closure(JSContext *ctx, void *fp, int64_t depth, int64_t index) { return JS_VAL_NULL; } void cell_rt_put_closure(JSContext *ctx, void *fp, JSValue val, int64_t depth, int64_t index) {} JSValue cell_rt_frame(JSContext *ctx, JSValue fn, int64_t nargs) { return JS_VAL_NULL; } void cell_rt_setarg(JSValue frame, int64_t idx, JSValue val) {} JSValue cell_rt_invoke(JSContext *ctx, JSValue frame) { return JS_VAL_NULL; } JSValue cell_rt_goframe(JSContext *ctx, JSValue fn, int64_t nargs) { return JS_VAL_NULL; } void cell_rt_goinvoke(JSContext *ctx, JSValue frame) {} JSValue cell_rt_make_function(JSContext *ctx, int64_t fn_idx) { return JS_VAL_NULL; } void cell_rt_push(JSContext *ctx, JSValue arr, JSValue val) {} JSValue cell_rt_pop(JSContext *ctx, JSValue arr) { return JS_VAL_NULL; } JSValue cell_rt_delete(JSContext *ctx, JSValue obj, JSValue key) { return JS_VAL_NULL; } JSValue cell_rt_typeof(JSContext *ctx, JSValue val) { return JS_VAL_NULL; }