Skip to content
This repository has been archived by the owner on Sep 11, 2024. It is now read-only.

对 QuickJS 的修改

huliangjie edited this page Apr 15, 2021 · 1 revision

在32位平台禁止 JS_NAN_BOXING

// quickjs.h
#ifndef JS_PTR64
// #define JS_NAN_BOXING
#endif

Disable stack check

因为部分平台的行为不正确

// quickjs.c
// 添加 || defined(CONFIG_DISABLE_STACK_CHECK)

#if !defined(CONFIG_STACK_CHECK) || defined(CONFIG_DISABLE_STACK_CHECK)
/* no stack limitation */
static inline uint8_t *js_get_stack_pointer(void)
{
    return NULL;
}

Expose JS_GetActiveFunction

用于在 module_require 中得到自身信息.

// quickjs.c
// make JS_GetActiveFunction extern

JSValueConst JS_GetActiveFunction(JSContext *ctx) { }

Expose js_string_compare

预留, 用于直接比较JSString, 以避免不必要的类型转换.

// quickjs.c
// make js_string_compare extern 

/* return < 0, 0 or > 0 */
int js_string_compare(JSContext *ctx,
                             const JSString *p1, const JSString *p2)

js_def_malloc_usable_size (return 0 on Android)

// quickjs.c
// add #elif defined(__ANDROID__)
// change to 'return 0;'

/* default memory allocation functions with memory limitation */
static inline size_t js_def_malloc_usable_size(void *ptr)
{
#if defined(__APPLE__)
    return malloc_size(ptr);
#elif defined(_WIN32)
    return _msize(ptr);
#elif defined(EMSCRIPTEN)
    return 0;
#elif defined(__ANDROID__)
    return 0;
#elif defined(__linux__)
    return malloc_usable_size(ptr);
#else
    /* change this to `return 0;` if compilation fails */
    return 0;
#endif
}
static const JSMallocFunctions def_malloc_funcs = {
    js_def_malloc,
    js_def_free,
    js_def_realloc,
#if defined(__APPLE__)
    malloc_size,
#elif defined(_WIN32)
    (size_t (*)(const void *))_msize,
#elif defined(EMSCRIPTEN)
    NULL,
#elif defined(__ANDROID__)
    NULL, 
#elif defined(__linux__)
    (size_t (*)(const void *))malloc_usable_size,
#else
    /* change this to `NULL,` if compilation fails */
    malloc_usable_size,
#endif
};

clock_gettime (for ios)

See stackoverflow

// quickjs.c
// insert before static int JS_InitAtoms(JSRuntime *rt)

#if defined(__APPLE__)
// not best solution
#include <mach/mach_time.h>
#ifndef CLOCK_REALTIME
#define CLOCK_REALTIME 0
int clock_gettime(int clk_id, struct timespec *t){
    mach_timebase_info_data_t timebase;
    mach_timebase_info(&timebase);
    uint64_t time;
    time = mach_absolute_time();
    double nseconds = ((double)time * (double)timebase.numer)/((double)timebase.denom);
    double seconds = ((double)time * (double)timebase.numer)/((double)timebase.denom * 1e9);
    t->tv_sec = seconds;
    t->tv_nsec = nseconds;
    return 0;
}
#endif
#endif

Disable typed array oob error

此修改用于忽略TypedArray越界赋值异常.

let x = new Uint8Array(4);
x[20] = 1;

上述代码在 nodejs 等环境中默认不会抛越界异常. 部分 js 库 (如 xlsx) 依赖于此特性.

See MDN TypedArray - Property access

// quickjs.c
// in JS_SetPropertyInternal()
// ...
    typed_array_oob:
        val = JS_ToNumberFree(ctx, val);
        JS_FreeValue(ctx, val);
        if (JS_IsException(val))
            return -1;
        if (typed_array_is_detached(ctx, p1)) {
            JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
            return -1;
        }
#ifdef JSB_TYPED_ARRAY_NO_THROW
        return TRUE;
#else
        return JS_ThrowTypeErrorOrFalse(ctx, flags, "out-of-bound numeric index");
#endif
// ...
// in JS_SetPropertyValue()
// ...
ta_out_of_bound:
    if (typed_array_is_detached(ctx, p)) {
        JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
        return -1;
    } else {
#ifdef JSB_TYPED_ARRAY_NO_THROW
        break;
#else
        return JS_ThrowTypeErrorOrFalse(ctx, flags, "out-of-bound numeric index");
#endif
// ...

log2 (only for Android)

用于部分情况下数学库中没有 log2 时提供替代.

// quickjs.c
// 在不存在log2的情况下提供替代的 log2 

#if defined(JSB_DEF_LOG2)
static double log2(double v) { return log(v) / log(2.0); }
#endif

JSB_ThrowError

用于在 C# 中产生字符串, 绕过 vsprintf

// quickjs.c

static JSValue JSB_ThrowError2(JSContext *ctx, JSErrorEnum error_num,
                              const char *buf, size_t buf_len, BOOL add_backtrace)
{
    JSValue obj, ret;

    obj = JS_NewObjectProtoClass(ctx, ctx->native_error_proto[error_num],
                                 JS_CLASS_ERROR);
    if (unlikely(JS_IsException(obj))) {
        /* out of memory: throw JS_NULL to avoid recursing */
        obj = JS_NULL;
    } else {
        JS_DefinePropertyValue(ctx, obj, JS_ATOM_message,
                               JS_NewStringLen(ctx, buf, buf_len),
                               JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
    }
    if (add_backtrace) {
        build_backtrace(ctx, obj, NULL, 0, 0);
    }
    ret = JS_Throw(ctx, obj);
    return ret;
}

JSValue JSB_ThrowError(JSContext *ctx, const char *buf, size_t buf_len)
{
    JSRuntime *rt = ctx->rt;
    JSStackFrame *sf;
    BOOL add_backtrace;

    /* the backtrace is added later if called from a bytecode function */
    sf = rt->current_stack_frame;
    add_backtrace = !rt->in_out_of_memory &&
        (!sf || (JS_GetFunctionBytecode(sf->cur_func) == NULL));
    return JSB_ThrowError2(ctx, JS_INTERNAL_ERROR, buf, buf_len, add_backtrace);
}