From 6eca130d8f79557509c44477b5ff47fd6fd77653 Mon Sep 17 00:00:00 2001 From: Sami Vaarala Date: Thu, 3 Aug 2017 23:56:16 +0300 Subject: [PATCH 1/5] Add internal get ecma/monotonic time helpers --- src-input/duk_api_internal.h | 3 +++ src-input/duk_api_time.c | 18 +++++++++++++++++- src-input/duk_bi_date.c | 4 ++-- src-input/duk_heap_alloc.c | 4 ++-- src-input/duk_js_executor.c | 2 +- 5 files changed, 25 insertions(+), 6 deletions(-) diff --git a/src-input/duk_api_internal.h b/src-input/duk_api_internal.h index b1f9033884..9468dcf14a 100644 --- a/src-input/duk_api_internal.h +++ b/src-input/duk_api_internal.h @@ -337,4 +337,7 @@ DUK_INTERNAL_DECL duk_int_t duk_pcall_method_flags(duk_hthread *thr, duk_idx_t n (DUK_ASSERT_EXPR((thr)->valstack_bottom > (thr)->valstack), \ (thr)->valstack_bottom - 1) +DUK_INTERNAL_DECL duk_double_t duk_time_get_ecmascript_time(duk_hthread *thr); +DUK_INTERNAL_DECL duk_double_t duk_time_get_monotonic_time(duk_hthread *thr); + #endif /* DUK_API_INTERNAL_H_INCLUDED */ diff --git a/src-input/duk_api_time.c b/src-input/duk_api_time.c index 0ec757fe9e..481cfabd25 100644 --- a/src-input/duk_api_time.c +++ b/src-input/duk_api_time.c @@ -4,11 +4,27 @@ #include "duk_internal.h" +DUK_INTERNAL duk_double_t duk_time_get_ecmascript_time(duk_hthread *thr) { + return (duk_double_t) DUK_USE_DATE_GET_NOW(thr); +} + +DUK_INTERNAL duk_double_t duk_time_get_monotonic_time(duk_hthread *thr) { + return (duk_double_t) DUK_USE_DATE_GET_NOW(thr); +} + DUK_EXTERNAL duk_double_t duk_get_now(duk_hthread *thr) { DUK_ASSERT_API_ENTRY(thr); - return ((duk_double_t) DUK_USE_DATE_GET_NOW(thr)); + return duk_time_get_ecmascript_time(thr); +} + +#if 0 /* XXX: worth exposing? */ +DUK_EXTERNAL duk_double_t duk_get_monotonic_time(duk_hthread *thr) { + DUK_ASSERT_API_ENTRY(thr); + + return duk_time_get_monotonic_time(thr); } +#endif DUK_EXTERNAL void duk_time_to_components(duk_hthread *thr, duk_double_t timeval, duk_time_components *comp) { duk_int_t parts[DUK_DATE_IDX_NUM_PARTS]; diff --git a/src-input/duk_bi_date.c b/src-input/duk_bi_date.c index b58026fbd0..fa74bb1846 100644 --- a/src-input/duk_bi_date.c +++ b/src-input/duk_bi_date.c @@ -1439,7 +1439,7 @@ DUK_INTERNAL duk_ret_t duk_bi_date_constructor(duk_hthread *thr) { */ if (nargs == 0 || !is_cons) { - d = duk__timeclip(DUK_USE_DATE_GET_NOW(thr)); + d = duk__timeclip(duk_time_get_ecmascript_time(thr)); duk_push_number(thr, d); duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_INT_VALUE, DUK_PROPDESC_FLAGS_W); if (!is_cons) { @@ -1496,7 +1496,7 @@ DUK_INTERNAL duk_ret_t duk_bi_date_constructor_utc(duk_hthread *thr) { DUK_INTERNAL duk_ret_t duk_bi_date_constructor_now(duk_hthread *thr) { duk_double_t d; - d = DUK_USE_DATE_GET_NOW(thr); + d = duk_time_get_ecmascript_time(thr); DUK_ASSERT(duk__timeclip(d) == d); /* TimeClip() should never be necessary */ duk_push_number(thr, d); return 1; diff --git a/src-input/duk_heap_alloc.c b/src-input/duk_heap_alloc.c index 8e3825b1b7..7801e6e438 100644 --- a/src-input/duk_heap_alloc.c +++ b/src-input/duk_heap_alloc.c @@ -1105,10 +1105,10 @@ duk_heap *duk_heap_alloc(duk_alloc_function alloc_func, #if !defined(DUK_USE_GET_RANDOM_DOUBLE) #if defined(DUK_USE_PREFER_SIZE) || !defined(DUK_USE_64BIT_OPS) - res->rnd_state = (duk_uint32_t) DUK_USE_DATE_GET_NOW(res->heap_thread); + res->rnd_state = (duk_uint32_t) duk_time_get_ecmascript_time(res->heap_thread); duk_util_tinyrandom_prepare_seed(res->heap_thread); #else - res->rnd_state[0] = (duk_uint64_t) DUK_USE_DATE_GET_NOW(res->heap_thread); + res->rnd_state[0] = (duk_uint64_t) duk_time_get_ecmascript_time(res->heap_thread); DUK_ASSERT(res->rnd_state[1] == 0); /* Not filled here, filled in by seed preparation. */ #if 0 /* Manual test values matching misc/xoroshiro128plus_test.c. */ res->rnd_state[0] = DUK_U64_CONSTANT(0xdeadbeef12345678); diff --git a/src-input/duk_js_executor.c b/src-input/duk_js_executor.c index 931ff6e558..a9f4488c4c 100644 --- a/src-input/duk_js_executor.c +++ b/src-input/duk_js_executor.c @@ -1800,7 +1800,7 @@ DUK_LOCAL void duk__interrupt_handle_debugger(duk_hthread *thr, duk_bool_t *out_ duk_double_t now, diff_last; thr->heap->dbg_last_counter = thr->heap->dbg_exec_counter; - now = DUK_USE_DATE_GET_NOW(thr); + now = duk_time_get_ecmascript_time(thr); diff_last = now - thr->heap->dbg_last_time; if (diff_last < 0.0 || diff_last >= (duk_double_t) DUK_HEAP_DBG_RATELIMIT_MILLISECS) { From d51fffbb3e24e9e121c410973587bf8ea6030d99 Mon Sep 17 00:00:00 2001 From: Sami Vaarala Date: Fri, 4 Aug 2017 00:05:03 +0300 Subject: [PATCH 2/5] Add DUK_USE_GET_MONOTONIC_TIME config option --- .../config-options/DUK_USE_DATE_GET_NOW.yaml | 4 ++++ .../DUK_USE_GET_MONOTONIC_TIME.yaml | 21 +++++++++++++++++++ 2 files changed, 25 insertions(+) create mode 100644 config/config-options/DUK_USE_GET_MONOTONIC_TIME.yaml diff --git a/config/config-options/DUK_USE_DATE_GET_NOW.yaml b/config/config-options/DUK_USE_DATE_GET_NOW.yaml index e69ccc3e16..e862e1e457 100644 --- a/config/config-options/DUK_USE_DATE_GET_NOW.yaml +++ b/config/config-options/DUK_USE_DATE_GET_NOW.yaml @@ -6,3 +6,7 @@ tags: - portability description: > Mandatory macro for getting the current time, see datetime.rst. + + If the time provided experiences time jumps or doesn't advance in realtime + (which is useful in some time virtualization scenarios), consider defining + DUK_USE_GET_MONOTONIC_TIME. diff --git a/config/config-options/DUK_USE_GET_MONOTONIC_TIME.yaml b/config/config-options/DUK_USE_GET_MONOTONIC_TIME.yaml new file mode 100644 index 0000000000..afafba28d7 --- /dev/null +++ b/config/config-options/DUK_USE_GET_MONOTONIC_TIME.yaml @@ -0,0 +1,21 @@ +define: DUK_USE_GET_MONOTONIC_TIME +introduced: 2.2.0 +default: false +tags: + - date + - portability +description: > + Optional macro for getting monotonic time starting from an arbitrary + starting point (device startup, program startup, script startup, etc). + The time returned must increase monotonically, and must not jump + discontinuously even if system date/time is reset. The semantics are + similar to POSIX clock_gettime() CLOCK_MONOTONIC. + + Monotonic time is used by Duktape for its internal needs, such as rate + limiting debugger transport peek callbacks. If this option is not provided, + Duktape falls back to using DUK_USE_DATE_GET_NOW() which is usually fine. + + If DUK_USE_DATE_GET_NOW() experiences time jumps or doesn't run in realtime + (which may be useful for some time virtualization cases) it's recommended + to provide this config option so that internals which need a reliable + realtime rate have a reliable time basis. From 26b09707f438fa1f848bc0b8526ace8d5c2eefdd Mon Sep 17 00:00:00 2001 From: Sami Vaarala Date: Fri, 4 Aug 2017 00:05:14 +0300 Subject: [PATCH 3/5] Use DUK_USE_GET_MONOTONIC_TIME when available --- src-input/duk_api_time.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src-input/duk_api_time.c b/src-input/duk_api_time.c index 481cfabd25..498cf76024 100644 --- a/src-input/duk_api_time.c +++ b/src-input/duk_api_time.c @@ -9,7 +9,11 @@ DUK_INTERNAL duk_double_t duk_time_get_ecmascript_time(duk_hthread *thr) { } DUK_INTERNAL duk_double_t duk_time_get_monotonic_time(duk_hthread *thr) { +#if defined(DUK_USE_GET_MONOTONIC_TIME) + return (duk_double_t) DUK_USE_GET_MONOTONIC_TIME(thr); +#else return (duk_double_t) DUK_USE_DATE_GET_NOW(thr); +#endif } DUK_EXTERNAL duk_double_t duk_get_now(duk_hthread *thr) { From 6efac9431c0e5c1d0639e85105e62574447879f3 Mon Sep 17 00:00:00 2001 From: Sami Vaarala Date: Fri, 4 Aug 2017 00:07:09 +0300 Subject: [PATCH 4/5] Use monotonic time for debugger rate limiting --- src-input/duk_js_executor.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src-input/duk_js_executor.c b/src-input/duk_js_executor.c index a9f4488c4c..8e39f51d45 100644 --- a/src-input/duk_js_executor.c +++ b/src-input/duk_js_executor.c @@ -1800,12 +1800,14 @@ DUK_LOCAL void duk__interrupt_handle_debugger(duk_hthread *thr, duk_bool_t *out_ duk_double_t now, diff_last; thr->heap->dbg_last_counter = thr->heap->dbg_exec_counter; - now = duk_time_get_ecmascript_time(thr); + now = duk_time_get_monotonic_time(thr); diff_last = now - thr->heap->dbg_last_time; if (diff_last < 0.0 || diff_last >= (duk_double_t) DUK_HEAP_DBG_RATELIMIT_MILLISECS) { - /* Negative value checked so that a "time jump" works - * reasonably. + /* Monotonic time should not experience time jumps, + * but the provider may be missing and we're actually + * using Ecmascript time. So, tolerate negative values + * so that a time jump works reasonably. * * Same interval is now used for status sending and * peeking. From 5d8f5c05dae236adf68c66ac427c8d815e50e206 Mon Sep 17 00:00:00 2001 From: Sami Vaarala Date: Fri, 4 Aug 2017 01:18:20 +0300 Subject: [PATCH 5/5] Releases: DUK_USE_GET_MONOTONIC_TIME --- RELEASES.rst | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/RELEASES.rst b/RELEASES.rst index f95cbe6ba4..f403fe9807 100644 --- a/RELEASES.rst +++ b/RELEASES.rst @@ -2983,6 +2983,16 @@ Planned * Make error message summary strings longer (32 -> 96 character) to better capture error messages for e.g. uncaught errors (GH-1653) +* Add DUK_USE_GET_MONOTONIC_TIME() to allow an application to provide a + monotonic time source (similar to clock_gettime() CLOCK_MONOTONIC) which + Duktape will then use for performance.now() and internal rate limiting + mechanisms; if absent (default), monotonic time defaults to + DUK_USE_DATE_GET_NOW() (GH-1659) + +* Use monotonic time (if available) for debugger transport peeking, so that + the peek callback is called with the same realtime rate even if the + Ecmascript time source jumps or doesn't advance in realtime (GH-1659) + * Fix incorrect handling of register bound unary operation target for unary minus, unary plus, and bitwise NOT (GH-1623, GH-1624)