diff --git a/cli/ops/bench.rs b/cli/ops/bench.rs index 79a7ddef0e238f..1f4a4bd9b5879d 100644 --- a/cli/ops/bench.rs +++ b/cli/ops/bench.rs @@ -2,7 +2,6 @@ use std::sync::atomic::AtomicUsize; use std::sync::atomic::Ordering; -use std::time; use deno_core::error::generic_error; use deno_core::error::type_error; @@ -13,6 +12,7 @@ use deno_core::ModuleSpecifier; use deno_core::OpState; use deno_runtime::deno_permissions::ChildPermissionsArg; use deno_runtime::deno_permissions::PermissionsContainer; +use deno_runtime::deno_web::StartTime; use tokio::sync::mpsc::UnboundedSender; use uuid::Uuid; @@ -148,7 +148,7 @@ fn op_dispatch_bench_event(state: &mut OpState, #[serde] event: BenchEvent) { #[op2(fast)] #[number] fn op_bench_now(state: &mut OpState) -> Result { - let ns = state.borrow::().elapsed().as_nanos(); + let ns = state.borrow::().elapsed().as_nanos(); let ns_u64 = u64::try_from(ns)?; Ok(ns_u64) } diff --git a/ext/web/02_timers.js b/ext/web/02_timers.js index 89acaca42b4485..6058febd597537 100644 --- a/ext/web/02_timers.js +++ b/ext/web/02_timers.js @@ -1,12 +1,9 @@ // Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. import { core, primordials } from "ext:core/mod.js"; -import { op_defer, op_now } from "ext:core/ops"; +import { op_defer } from "ext:core/ops"; const { - Uint8Array, - Uint32Array, PromisePrototypeThen, - TypedArrayPrototypeGetBuffer, TypeError, indirectEval, ReflectApply, @@ -18,13 +15,6 @@ const { import * as webidl from "ext:deno_webidl/00_webidl.js"; -const hrU8 = new Uint8Array(8); -const hr = new Uint32Array(TypedArrayPrototypeGetBuffer(hrU8)); -function opNow() { - op_now(hrU8); - return (hr[0] * 1000 + hr[1] / 1e6); -} - // --------------------------------------------------------------------------- function checkThis(thisArg) { @@ -151,7 +141,6 @@ export { clearInterval, clearTimeout, defer, - opNow, refTimer, setImmediate, setInterval, diff --git a/ext/web/15_performance.js b/ext/web/15_performance.js index ea5557278138fa..9e0e310a57e4b9 100644 --- a/ext/web/15_performance.js +++ b/ext/web/15_performance.js @@ -1,6 +1,7 @@ // Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. import { primordials } from "ext:core/mod.js"; +import { op_now, op_time_origin } from "ext:core/ops"; const { ArrayPrototypeFilter, ArrayPrototypePush, @@ -10,19 +11,34 @@ const { Symbol, SymbolFor, TypeError, + TypedArrayPrototypeGetBuffer, + Uint8Array, + Uint32Array, } = primordials; import * as webidl from "ext:deno_webidl/00_webidl.js"; import { structuredClone } from "./02_structured_clone.js"; import { createFilteredInspectProxy } from "ext:deno_console/01_console.js"; import { EventTarget } from "./02_event.js"; -import { opNow } from "./02_timers.js"; import { DOMException } from "./01_dom_exception.js"; const illegalConstructorKey = Symbol("illegalConstructorKey"); let performanceEntries = []; let timeOrigin; +const hrU8 = new Uint8Array(8); +const hr = new Uint32Array(TypedArrayPrototypeGetBuffer(hrU8)); + +function setTimeOrigin() { + op_time_origin(hrU8); + timeOrigin = hr[0] * 1000 + hr[1] / 1e6; +} + +function now() { + op_now(hrU8); + return hr[0] * 1000 + hr[1] / 1e6; +} + webidl.converters["PerformanceMarkOptions"] = webidl .createDictionaryConverter( "PerformanceMarkOptions", @@ -90,10 +106,6 @@ webidl.converters["DOMString or PerformanceMeasureOptions"] = ( return webidl.converters.DOMString(V, prefix, context, opts); }; -function setTimeOrigin(origin) { - timeOrigin = origin; -} - function findMostRecent( name, type, @@ -135,8 +147,6 @@ function filterByNameType( ); } -const now = opNow; - const _name = Symbol("[[name]]"); const _entryType = Symbol("[[entryType]]"); const _startTime = Symbol("[[startTime]]"); diff --git a/ext/web/benches/encoding.rs b/ext/web/benches/encoding.rs index d0738c6452bc0d..ce90d30ce0f88c 100644 --- a/ext/web/benches/encoding.rs +++ b/ext/web/benches/encoding.rs @@ -6,15 +6,6 @@ use deno_bench_util::bencher::benchmark_group; use deno_bench_util::bencher::Bencher; use deno_core::Extension; -#[derive(Clone)] -struct Permissions; - -impl deno_web::TimersPermission for Permissions { - fn allow_hrtime(&mut self) -> bool { - false - } -} - fn setup() -> Vec { deno_core::extension!( bench_setup, @@ -26,19 +17,13 @@ fn setup() -> Vec { globalThis.hello12k = Deno.core.encode("hello world\n".repeat(1e3)); "# }], - state = |state| { - state.put(Permissions {}); - }, ); vec![ deno_webidl::deno_webidl::init_ops_and_esm(), deno_url::deno_url::init_ops_and_esm(), deno_console::deno_console::init_ops_and_esm(), - deno_web::deno_web::init_ops_and_esm::( - Default::default(), - None, - ), + deno_web::deno_web::init_ops_and_esm(Default::default(), None), bench_setup::init_ops_and_esm(), ] } diff --git a/ext/web/benches/timers_ops.rs b/ext/web/benches/timers_ops.rs index d39ee4eeae81da..9f1a0e55d5573a 100644 --- a/ext/web/benches/timers_ops.rs +++ b/ext/web/benches/timers_ops.rs @@ -6,15 +6,6 @@ use deno_bench_util::bencher::benchmark_group; use deno_bench_util::bencher::Bencher; use deno_core::Extension; -#[derive(Clone)] -struct Permissions; - -impl deno_web::TimersPermission for Permissions { - fn allow_hrtime(&mut self) -> bool { - true - } -} - fn setup() -> Vec { deno_core::extension!( bench_setup, @@ -25,19 +16,13 @@ fn setup() -> Vec { globalThis.setTimeout = setTimeout; "# }], - state = |state| { - state.put(Permissions {}); - }, ); vec![ deno_webidl::deno_webidl::init_ops_and_esm(), deno_url::deno_url::init_ops_and_esm(), deno_console::deno_console::init_ops_and_esm(), - deno_web::deno_web::init_ops_and_esm::( - Default::default(), - None, - ), + deno_web::deno_web::init_ops_and_esm(Default::default(), None), bench_setup::init_ops_and_esm(), ] } diff --git a/ext/web/lib.rs b/ext/web/lib.rs index 4935af5bd3df93..3eb0891ebe00e8 100644 --- a/ext/web/lib.rs +++ b/ext/web/lib.rs @@ -52,12 +52,11 @@ pub use crate::message_port::Transferable; use crate::timers::op_defer; use crate::timers::op_now; -use crate::timers::StartTime; -pub use crate::timers::TimersPermission; +use crate::timers::op_time_origin; +pub use crate::timers::StartTime; deno_core::extension!(deno_web, deps = [ deno_webidl, deno_console, deno_url ], - parameters = [P: TimersPermission], ops = [ op_base64_decode, op_base64_encode, @@ -83,7 +82,8 @@ deno_core::extension!(deno_web, compression::op_compression_new, compression::op_compression_write, compression::op_compression_finish, - op_now

, + op_now, + op_time_origin, op_defer, stream_resource::op_readable_stream_resource_allocate, stream_resource::op_readable_stream_resource_allocate_sized, @@ -123,7 +123,7 @@ deno_core::extension!(deno_web, if let Some(location) = options.maybe_location { state.put(Location(location)); } - state.put(StartTime::now()); + state.put(StartTime::default()); } ); diff --git a/ext/web/timers.rs b/ext/web/timers.rs index a9ab7c97e4bdbc..97e56fb20b53bf 100644 --- a/ext/web/timers.rs +++ b/ext/web/timers.rs @@ -4,50 +4,51 @@ use deno_core::op2; use deno_core::OpState; +use std::time::Duration; use std::time::Instant; +use std::time::SystemTime; +use std::time::UNIX_EPOCH; -pub trait TimersPermission { - fn allow_hrtime(&mut self) -> bool; +pub struct StartTime(Instant); + +impl Default for StartTime { + fn default() -> Self { + Self(Instant::now()) + } } -impl TimersPermission for deno_permissions::PermissionsContainer { - #[inline(always)] - fn allow_hrtime(&mut self) -> bool { - true +impl std::ops::Deref for StartTime { + type Target = Instant; + + fn deref(&self) -> &Self::Target { + &self.0 } } -pub type StartTime = Instant; +fn expose_time(duration: Duration, out: &mut [u8]) { + let seconds = duration.as_secs() as u32; + let subsec_nanos = duration.subsec_nanos(); + + if out.len() >= 8 { + out[0..4].copy_from_slice(&seconds.to_ne_bytes()); + out[4..8].copy_from_slice(&subsec_nanos.to_ne_bytes()); + } +} -// Returns a milliseconds and nanoseconds subsec -// since the start time of the deno runtime. -// If the High precision flag is not set, the -// nanoseconds are rounded on 2ms. #[op2(fast)] -pub fn op_now(state: &mut OpState, #[buffer] buf: &mut [u8]) -where - TP: TimersPermission + 'static, -{ +pub fn op_now(state: &mut OpState, #[buffer] buf: &mut [u8]) { let start_time = state.borrow::(); let elapsed = start_time.elapsed(); - let seconds = elapsed.as_secs(); - let mut subsec_nanos = elapsed.subsec_nanos(); - - // If the permission is not enabled - // Round the nano result on 2 milliseconds - // see: https://developer.mozilla.org/en-US/docs/Web/API/DOMHighResTimeStamp#Reduced_time_precision - if !state.borrow_mut::().allow_hrtime() { - let reduced_time_precision = 2_000_000; // 2ms in nanoseconds - subsec_nanos -= subsec_nanos % reduced_time_precision; - } - if buf.len() < 8 { - return; - } - let buf: &mut [u32] = - // SAFETY: buffer is at least 8 bytes long. - unsafe { std::slice::from_raw_parts_mut(buf.as_mut_ptr() as _, 2) }; - buf[0] = seconds as u32; - buf[1] = subsec_nanos; + expose_time(elapsed, buf); +} + +#[op2(fast)] +pub fn op_time_origin(state: &mut OpState, #[buffer] buf: &mut [u8]) { + // https://w3c.github.io/hr-time/#dfn-estimated-monotonic-time-of-the-unix-epoch + let wall_time = SystemTime::now(); + let monotonic_time = state.borrow::().elapsed(); + let epoch = wall_time.duration_since(UNIX_EPOCH).unwrap() - monotonic_time; + expose_time(epoch, buf); } #[allow(clippy::unused_async)] diff --git a/runtime/js/99_main.js b/runtime/js/99_main.js index 4d391dcc3ac992..6ddaa1335ecc3d 100644 --- a/runtime/js/99_main.js +++ b/runtime/js/99_main.js @@ -27,7 +27,6 @@ const { ArrayPrototypeForEach, ArrayPrototypeIncludes, ArrayPrototypeMap, - DateNow, Error, ErrorPrototype, FunctionPrototypeBind, @@ -642,7 +641,7 @@ function bootstrapMainRuntime(runtimeOptions, warmup = false) { removeImportedOps(); - performance.setTimeOrigin(DateNow()); + performance.setTimeOrigin(); globalThis_ = globalThis; // Remove bootstrapping data from the global scope @@ -858,7 +857,7 @@ function bootstrapWorkerRuntime( 7: nodeDebug, } = runtimeOptions; - performance.setTimeOrigin(DateNow()); + performance.setTimeOrigin(); globalThis_ = globalThis; // Remove bootstrapping data from the global scope diff --git a/runtime/snapshot.rs b/runtime/snapshot.rs index 251ee5f41ce413..3bbbbbdde91b48 100644 --- a/runtime/snapshot.rs +++ b/runtime/snapshot.rs @@ -31,12 +31,6 @@ impl deno_websocket::WebSocketPermissions for Permissions { } } -impl deno_web::TimersPermission for Permissions { - fn allow_hrtime(&mut self) -> bool { - unreachable!("snapshotting!") - } -} - impl deno_fetch::FetchPermissions for Permissions { fn check_net_url( &mut self, @@ -271,7 +265,7 @@ pub fn create_runtime_snapshot( deno_webidl::deno_webidl::init_ops_and_esm(), deno_console::deno_console::init_ops_and_esm(), deno_url::deno_url::init_ops_and_esm(), - deno_web::deno_web::init_ops_and_esm::( + deno_web::deno_web::init_ops_and_esm( Default::default(), Default::default(), ), diff --git a/runtime/web_worker.rs b/runtime/web_worker.rs index 61e5c770299285..cb80697aec3971 100644 --- a/runtime/web_worker.rs +++ b/runtime/web_worker.rs @@ -434,7 +434,7 @@ impl WebWorker { deno_webidl::deno_webidl::init_ops_and_esm(), deno_console::deno_console::init_ops_and_esm(), deno_url::deno_url::init_ops_and_esm(), - deno_web::deno_web::init_ops_and_esm::( + deno_web::deno_web::init_ops_and_esm( services.blob_store, Some(options.main_module.clone()), ), diff --git a/runtime/worker.rs b/runtime/worker.rs index 88a61fa9389801..423daecab30922 100644 --- a/runtime/worker.rs +++ b/runtime/worker.rs @@ -349,7 +349,7 @@ impl MainWorker { deno_webidl::deno_webidl::init_ops_and_esm(), deno_console::deno_console::init_ops_and_esm(), deno_url::deno_url::init_ops_and_esm(), - deno_web::deno_web::init_ops_and_esm::( + deno_web::deno_web::init_ops_and_esm( services.blob_store.clone(), options.bootstrap.location.clone(), ),