From ea068d9a70d99fb31e7b84abe5e3302141826ded Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sa=C3=BAl=20Ibarra=20Corretg=C3=A9?= Date: Fri, 17 Nov 2023 23:56:46 +0100 Subject: [PATCH] Add performance.{now,timeOrigin} Ref: https://github.com/quickjs-ng/quickjs/issues/16 --- quickjs.c | 39 +++++++++++++++++++++++++++++++++++++++ quickjs.h | 2 ++ 2 files changed, 41 insertions(+) diff --git a/quickjs.c b/quickjs.c index 4a3f472..8e45547 100644 --- a/quickjs.c +++ b/quickjs.c @@ -392,6 +392,8 @@ struct JSContext { JSValue global_obj; /* global object */ JSValue global_var_obj; /* contains the global let/const definitions */ + uint64_t time_origin; + uint64_t random_state; bf_context_t *bf_ctx; /* points to rt->bf_ctx, shared by all contexts */ /* when the counter reaches zero, JSRutime.interrupt_handler is called */ @@ -1979,6 +1981,9 @@ JSContext *JS_NewContext(JSRuntime *rt) JS_AddIntrinsicTypedArrays(ctx); JS_AddIntrinsicPromise(ctx); JS_AddIntrinsicBigInt(ctx); + + JS_AddPerformance(ctx); + return ctx; } @@ -50219,3 +50224,37 @@ void JS_AddIntrinsicTypedArrays(JSContext *ctx) JS_AddIntrinsicAtomics(ctx); #endif } + +/* Performance */ + +static uint64_t js__now_ms(void) +{ + // TODO(saghul) Windows support. + struct timespec ts; + clock_gettime(CLOCK_MONOTONIC, &ts); + return (((uint64_t) ts.tv_sec) * 1000 + ts.tv_nsec / 1e6); +} + +static JSValue js_perf_now(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) +{ + return JS_NewFloat64(ctx, js__now_ms() - ctx->time_origin); +} + +static const JSCFunctionListEntry js_perf_proto_funcs[] = { + JS_CFUNC_DEF2("now", 0, js_perf_now, JS_PROP_ENUMERABLE), +}; + +void JS_AddPerformance(JSContext *ctx) +{ + ctx->time_origin = js__now_ms(); + + JSValue performance = JS_NewObject(ctx); + JS_SetPropertyFunctionList(ctx, performance, js_perf_proto_funcs, countof(js_perf_proto_funcs)); + JS_DefinePropertyValueStr(ctx, performance, "timeOrigin", + JS_NewFloat64(ctx, ctx->time_origin), + JS_PROP_ENUMERABLE); + JS_DefinePropertyValueStr(ctx, ctx->global_obj, "performance", + JS_DupValue(ctx, performance), + JS_PROP_ENUMERABLE); + JS_FreeValue(ctx, performance); +} diff --git a/quickjs.h b/quickjs.h index 188abd3..488295e 100644 --- a/quickjs.h +++ b/quickjs.h @@ -365,6 +365,7 @@ void JS_AddIntrinsicMapSet(JSContext *ctx); void JS_AddIntrinsicTypedArrays(JSContext *ctx); void JS_AddIntrinsicPromise(JSContext *ctx); void JS_AddIntrinsicBigInt(JSContext *ctx); +void JS_AddPerformance(JSContext *ctx); JSValue js_string_codePointRange(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv); @@ -960,6 +961,7 @@ typedef struct JSCFunctionListEntry { /* Note: c++ does not like nested designators */ #define JS_CFUNC_DEF(name, length, func1) { name, JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE, JS_DEF_CFUNC, 0, .u = { .func = { length, JS_CFUNC_generic, { .generic = func1 } } } } +#define JS_CFUNC_DEF2(name, length, func1, prop_flags) { name, prop_flags, JS_DEF_CFUNC, 0, .u = { .func = { length, JS_CFUNC_generic, { .generic = func1 } } } } #define JS_CFUNC_MAGIC_DEF(name, length, func1, magic) { name, JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE, JS_DEF_CFUNC, magic, .u = { .func = { length, JS_CFUNC_generic_magic, { .generic_magic = func1 } } } } #define JS_CFUNC_SPECIAL_DEF(name, length, cproto, func1) { name, JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE, JS_DEF_CFUNC, 0, .u = { .func = { length, JS_CFUNC_ ## cproto, { .cproto = func1 } } } } #define JS_ITERATOR_NEXT_DEF(name, length, func1, magic) { name, JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE, JS_DEF_CFUNC, magic, .u = { .func = { length, JS_CFUNC_iterator_next, { .iterator_next = func1 } } } }