summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cli/flags.rs24
-rw-r--r--cli/isolate_state.rs3
-rw-r--r--cli/msg.fbs4
-rw-r--r--cli/ops.rs32
-rw-r--r--cli/permissions.rs12
-rw-r--r--js/performance.ts12
-rw-r--r--js/performance_test.ts4
-rw-r--r--js/permissions.ts5
-rw-r--r--js/permissions_test.ts3
-rw-r--r--js/test_util.ts31
-rw-r--r--tests/025_high_precision.test2
-rw-r--r--tests/025_high_precision.ts3
-rw-r--r--tests/025_high_precision.ts.out2
-rwxr-xr-xtools/unit_tests.py16
14 files changed, 119 insertions, 34 deletions
diff --git a/cli/flags.rs b/cli/flags.rs
index e52e55b5e..9f43b0b80 100644
--- a/cli/flags.rs
+++ b/cli/flags.rs
@@ -19,6 +19,7 @@ pub struct DenoFlags {
pub allow_net: bool,
pub allow_env: bool,
pub allow_run: bool,
+ pub allow_high_precision: bool,
pub no_prompts: bool,
pub types: bool,
pub prefetch: bool,
@@ -54,6 +55,9 @@ impl<'a> From<ArgMatches<'a>> for DenoFlags {
if matches.is_present("allow-run") {
flags.allow_run = true;
}
+ if matches.is_present("allow-high-precision") {
+ flags.allow_high_precision = true;
+ }
if matches.is_present("allow-all") {
flags.allow_read = true;
flags.allow_env = true;
@@ -61,6 +65,7 @@ impl<'a> From<ArgMatches<'a>> for DenoFlags {
flags.allow_run = true;
flags.allow_read = true;
flags.allow_write = true;
+ flags.allow_high_precision = true;
}
if matches.is_present("no-prompt") {
flags.no_prompts = true;
@@ -125,6 +130,10 @@ pub fn set_flags(
.long("allow-run")
.help("Allow running subprocesses"),
).arg(
+ Arg::with_name("allow-high-precision")
+ .long("allow-high-precision")
+ .help("Allow high precision time measurement"),
+ ).arg(
Arg::with_name("allow-all")
.short("A")
.long("allow-all")
@@ -338,6 +347,7 @@ fn test_set_flags_7() {
allow_run: true,
allow_read: true,
allow_write: true,
+ allow_high_precision: true,
..DenoFlags::default()
}
)
@@ -356,3 +366,17 @@ fn test_set_flags_8() {
}
)
}
+
+#[test]
+fn test_set_flags_9() {
+ let (flags, rest) =
+ set_flags(svec!["deno", "--allow-high-precision", "script.ts"]).unwrap();
+ assert_eq!(rest, svec!["deno", "script.ts"]);
+ assert_eq!(
+ flags,
+ DenoFlags {
+ allow_high_precision: true,
+ ..DenoFlags::default()
+ }
+ )
+}
diff --git a/cli/isolate_state.rs b/cli/isolate_state.rs
index 500cdd7d7..313f4f6ce 100644
--- a/cli/isolate_state.rs
+++ b/cli/isolate_state.rs
@@ -17,6 +17,7 @@ use std::env;
use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::Arc;
use std::sync::Mutex;
+use std::time::Instant;
pub type WorkerSender = async_mpsc::Sender<Buf>;
pub type WorkerReceiver = async_mpsc::Receiver<Buf>;
@@ -51,6 +52,7 @@ pub struct IsolateState {
pub global_timer: Mutex<GlobalTimer>,
pub workers: Mutex<UserWorkerTable>,
pub is_worker: bool,
+ pub start_time: Instant,
}
impl IsolateState {
@@ -73,6 +75,7 @@ impl IsolateState {
global_timer: Mutex::new(GlobalTimer::new()),
workers: Mutex::new(UserWorkerTable::new()),
is_worker,
+ start_time: Instant::now(),
}
}
diff --git a/cli/msg.fbs b/cli/msg.fbs
index c515b9add..4eca8dcf8 100644
--- a/cli/msg.fbs
+++ b/cli/msg.fbs
@@ -281,6 +281,7 @@ table PermissionsRes {
write: bool;
net: bool;
env: bool;
+ high_precision: bool;
}
// Note this represents The WHOLE header of an http message, not just the key
@@ -527,7 +528,8 @@ table RunStatusRes {
table Now {}
table NowRes {
- time: uint64;
+ seconds: uint64;
+ subsec_nanos: uint32;
}
table IsTTY {}
diff --git a/cli/ops.rs b/cli/ops.rs
index a0169d6ab..d5656a3b6 100644
--- a/cli/ops.rs
+++ b/cli/ops.rs
@@ -41,7 +41,7 @@ use std::path::Path;
use std::path::PathBuf;
use std::process::Command;
use std::sync::Arc;
-use std::time::{Duration, Instant, SystemTime, UNIX_EPOCH};
+use std::time::{Duration, Instant, UNIX_EPOCH};
use tokio;
use tokio::net::TcpListener;
use tokio::net::TcpStream;
@@ -212,19 +212,35 @@ pub fn op_selector_std(inner_type: msg::Any) -> Option<OpCreator> {
}
}
+// 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.
fn op_now(
- _sc: &IsolateStateContainer,
+ sc: &IsolateStateContainer,
base: &msg::Base<'_>,
data: deno_buf,
) -> Box<OpWithError> {
assert_eq!(data.len(), 0);
- let start = SystemTime::now();
- let since_the_epoch = start.duration_since(UNIX_EPOCH).unwrap();
- let time = since_the_epoch.as_secs() * 1000
- + u64::from(since_the_epoch.subsec_millis());
+ let seconds = sc.state().start_time.elapsed().as_secs();
+ let mut subsec_nanos = sc.state().start_time.elapsed().subsec_nanos();
+ let reduced_time_precision = 2000000; // 2ms in nanoseconds
+
+ // 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 !sc.state().permissions.allows_high_precision() {
+ subsec_nanos -= subsec_nanos % reduced_time_precision
+ }
let builder = &mut FlatBufferBuilder::new();
- let inner = msg::NowRes::create(builder, &msg::NowResArgs { time });
+ let inner = msg::NowRes::create(
+ builder,
+ &msg::NowResArgs {
+ seconds,
+ subsec_nanos,
+ },
+ );
ok_future(serialize_response(
base.cmd_id(),
builder,
@@ -555,6 +571,7 @@ fn op_permissions(
write: sc.state().permissions.allows_write(),
net: sc.state().permissions.allows_net(),
env: sc.state().permissions.allows_env(),
+ high_precision: sc.state().permissions.allows_high_precision(),
},
);
ok_future(serialize_response(
@@ -582,6 +599,7 @@ fn op_revoke_permission(
"write" => sc.state().permissions.revoke_write(),
"net" => sc.state().permissions.revoke_net(),
"env" => sc.state().permissions.revoke_env(),
+ "highPrecision" => sc.state().permissions.revoke_high_precision(),
_ => Ok(()),
};
if let Err(e) = result {
diff --git a/cli/permissions.rs b/cli/permissions.rs
index 2240d94c1..6247cd0d1 100644
--- a/cli/permissions.rs
+++ b/cli/permissions.rs
@@ -131,6 +131,7 @@ pub struct DenoPermissions {
pub allow_net: PermissionAccessor,
pub allow_env: PermissionAccessor,
pub allow_run: PermissionAccessor,
+ pub allow_high_precision: PermissionAccessor,
pub no_prompts: AtomicBool,
}
@@ -142,6 +143,9 @@ impl DenoPermissions {
allow_env: PermissionAccessor::from(flags.allow_env),
allow_net: PermissionAccessor::from(flags.allow_net),
allow_run: PermissionAccessor::from(flags.allow_run),
+ allow_high_precision: PermissionAccessor::from(
+ flags.allow_high_precision,
+ ),
no_prompts: AtomicBool::new(flags.no_prompts),
}
}
@@ -263,6 +267,10 @@ impl DenoPermissions {
self.allow_env.is_allow()
}
+ pub fn allows_high_precision(&self) -> bool {
+ return self.allow_high_precision.is_allow();
+ }
+
pub fn revoke_run(&self) -> DenoResult<()> {
self.allow_run.revoke();
Ok(())
@@ -287,6 +295,10 @@ impl DenoPermissions {
self.allow_env.revoke();
Ok(())
}
+ pub fn revoke_high_precision(&self) -> DenoResult<()> {
+ self.allow_high_precision.revoke();
+ return Ok(());
+ }
}
/// Quad-state value for representing user input on permission prompt
diff --git a/js/performance.ts b/js/performance.ts
index 1af75809b..51e213f0f 100644
--- a/js/performance.ts
+++ b/js/performance.ts
@@ -5,13 +5,9 @@ import * as flatbuffers from "./flatbuffers";
import { assert } from "./util";
export class Performance {
- timeOrigin = 0;
-
- constructor() {
- this.timeOrigin = new Date().getTime();
- }
-
- /** Returns a current time from Deno's start
+ /** Returns a current time from Deno's start.
+ * In milliseconds. Flag --allow-high-precision give
+ * a precise measure.
*
* const t = performance.now();
* console.log(`${t} ms since start!`);
@@ -23,6 +19,6 @@ export class Performance {
assert(msg.Any.NowRes === baseRes.innerType());
const res = new msg.NowRes();
assert(baseRes.inner(res) != null);
- return res.time().toFloat64() - this.timeOrigin;
+ return res.seconds().toFloat64() * 1e3 + res.subsecNanos() / 1e6;
}
}
diff --git a/js/performance_test.ts b/js/performance_test.ts
index 154dadbbe..8f9dbc990 100644
--- a/js/performance_test.ts
+++ b/js/performance_test.ts
@@ -1,7 +1,7 @@
// Copyright 2018-2019 the Deno authors. All rights reserved. MIT license.
-import { test, assert } from "./test_util.ts";
+import { testPerm, assert } from "./test_util.ts";
-test(function now() {
+testPerm({ highPrecision: false }, function now() {
const start = performance.now();
setTimeout(() => {
const end = performance.now();
diff --git a/js/permissions.ts b/js/permissions.ts
index 46c809cf6..d0885ba6a 100644
--- a/js/permissions.ts
+++ b/js/permissions.ts
@@ -11,7 +11,7 @@ export interface Permissions {
net: boolean;
env: boolean;
run: boolean;
-
+ highPrecision: boolean;
// NOTE: Keep in sync with src/permissions.rs
}
@@ -29,7 +29,8 @@ function createPermissions(inner: msg.PermissionsRes): Permissions {
write: inner.write(),
net: inner.net(),
env: inner.env(),
- run: inner.run()
+ run: inner.run(),
+ highPrecision: inner.highPrecision()
};
}
diff --git a/js/permissions_test.ts b/js/permissions_test.ts
index e44be79bb..c49696c01 100644
--- a/js/permissions_test.ts
+++ b/js/permissions_test.ts
@@ -6,7 +6,8 @@ const knownPermissions: Deno.Permission[] = [
"read",
"write",
"net",
- "env"
+ "env",
+ "highPrecision"
];
for (let grant of knownPermissions) {
diff --git a/js/test_util.ts b/js/test_util.ts
index e683d32b1..15bbb521b 100644
--- a/js/test_util.ts
+++ b/js/test_util.ts
@@ -26,6 +26,7 @@ interface DenoPermissions {
net?: boolean;
env?: boolean;
run?: boolean;
+ highPrecision?: boolean;
}
function permToString(perms: DenoPermissions): string {
@@ -34,11 +35,12 @@ function permToString(perms: DenoPermissions): string {
const n = perms.net ? 1 : 0;
const e = perms.env ? 1 : 0;
const u = perms.run ? 1 : 0;
- return `permR${r}W${w}N${n}E${e}U${u}`;
+ const h = perms.highPrecision ? 1 : 0;
+ return `permR${r}W${w}N${n}E${e}U${u}H${h}`;
}
function permFromString(s: string): DenoPermissions {
- const re = /^permR([01])W([01])N([01])E([01])U([01])$/;
+ const re = /^permR([01])W([01])N([01])E([01])U([01])H([01])$/;
const found = s.match(re);
if (!found) {
throw Error("Not a permission string");
@@ -48,7 +50,8 @@ function permFromString(s: string): DenoPermissions {
write: Boolean(Number(found[2])),
net: Boolean(Number(found[3])),
env: Boolean(Number(found[4])),
- run: Boolean(Number(found[5]))
+ run: Boolean(Number(found[5])),
+ highPrecision: Boolean(Number(found[6]))
};
}
@@ -62,7 +65,14 @@ export function testPerm(
export function test(fn: testing.TestFunction): void {
testPerm(
- { read: false, write: false, net: false, env: false, run: false },
+ {
+ read: false,
+ write: false,
+ net: false,
+ env: false,
+ run: false,
+ highPrecision: false
+ },
fn
);
}
@@ -73,8 +83,17 @@ test(function permSerialization() {
for (const env of [true, false]) {
for (const run of [true, false]) {
for (const read of [true, false]) {
- const perms: DenoPermissions = { write, net, env, run, read };
- assertEquals(perms, permFromString(permToString(perms)));
+ for (const highPrecision of [true, false]) {
+ const perms: DenoPermissions = {
+ write,
+ net,
+ env,
+ run,
+ read,
+ highPrecision
+ };
+ assertEquals(perms, permFromString(permToString(perms)));
+ }
}
}
}
diff --git a/tests/025_high_precision.test b/tests/025_high_precision.test
new file mode 100644
index 000000000..2bc460c9b
--- /dev/null
+++ b/tests/025_high_precision.test
@@ -0,0 +1,2 @@
+args: --allow-high-precision --reload tests/025_high_precision.ts
+output: tests/025_high_precision.ts.out
diff --git a/tests/025_high_precision.ts b/tests/025_high_precision.ts
new file mode 100644
index 000000000..85b3c839b
--- /dev/null
+++ b/tests/025_high_precision.ts
@@ -0,0 +1,3 @@
+console.log(performance.now() % 2 !== 0);
+Deno.revokePermission("highPrecision");
+console.log(performance.now() % 2 === 0);
diff --git a/tests/025_high_precision.ts.out b/tests/025_high_precision.ts.out
new file mode 100644
index 000000000..bb101b641
--- /dev/null
+++ b/tests/025_high_precision.ts.out
@@ -0,0 +1,2 @@
+true
+true
diff --git a/tools/unit_tests.py b/tools/unit_tests.py
index c77449759..21fea3231 100755
--- a/tools/unit_tests.py
+++ b/tools/unit_tests.py
@@ -45,14 +45,16 @@ def run_unit_test(deno_exe, permStr, flags=None):
# tests by the special string. permW0N0 means allow-write but not allow-net.
# See js/test_util.ts for more details.
def unit_tests(deno_exe):
- run_unit_test(deno_exe, "permR0W0N0E0U0", ["--reload"])
- run_unit_test(deno_exe, "permR1W0N0E0U0", ["--allow-read"])
- run_unit_test(deno_exe, "permR0W1N0E0U0", ["--allow-write"])
- run_unit_test(deno_exe, "permR1W1N0E0U0",
+ run_unit_test(deno_exe, "permR0W0N0E0U0H0", ["--reload"])
+ run_unit_test(deno_exe, "permR1W0N0E0U0H0", ["--allow-read"])
+ run_unit_test(deno_exe, "permR0W1N0E0U0H0", ["--allow-write"])
+ run_unit_test(deno_exe, "permR1W1N0E0U0H0",
["--allow-read", "--allow-write"])
- run_unit_test(deno_exe, "permR0W0N0E1U0", ["--allow-env"])
- run_unit_test(deno_exe, "permR0W0N0E0U1", ["--allow-run"])
- run_unit_test(deno_exe, "permR0W1N0E0U1", ["--allow-run", "--allow-write"])
+ run_unit_test(deno_exe, "permR0W0N0E1U0H0", ["--allow-env"])
+ run_unit_test(deno_exe, "permR0W0N0E0U0H1", ["--allow-high-precision"])
+ run_unit_test(deno_exe, "permR0W0N0E0U1H0", ["--allow-run"])
+ run_unit_test(deno_exe, "permR0W1N0E0U1H0",
+ ["--allow-run", "--allow-write"])
# TODO We might accidentally miss some. We should be smarter about which we
# run. Maybe we can use the "filtered out" number to check this.