summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cli/tests/unit_node/v8_test.ts58
-rw-r--r--ext/node/lib.rs3
-rw-r--r--ext/node/polyfills/v8.ts27
-rw-r--r--ext/node/v8.rs29
-rw-r--r--ops/fast_call.rs5
-rw-r--r--ops/lib.rs37
-rw-r--r--ops/optimizer.rs32
-rw-r--r--ops/optimizer_tests/f64_slice.expected11
-rw-r--r--ops/optimizer_tests/f64_slice.out112
-rw-r--r--ops/optimizer_tests/f64_slice.rs3
10 files changed, 314 insertions, 3 deletions
diff --git a/cli/tests/unit_node/v8_test.ts b/cli/tests/unit_node/v8_test.ts
new file mode 100644
index 000000000..ab1903596
--- /dev/null
+++ b/cli/tests/unit_node/v8_test.ts
@@ -0,0 +1,58 @@
+// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
+import {
+ cachedDataVersionTag,
+ getHeapStatistics,
+ setFlagsFromString,
+} from "node:v8";
+import {
+ assertEquals,
+ assertThrows,
+} from "../../../test_util/std/testing/asserts.ts";
+
+// https://github.com/nodejs/node/blob/a2bbe5ff216bc28f8dac1c36a8750025a93c3827/test/parallel/test-v8-version-tag.js#L6
+Deno.test({
+ name: "cachedDataVersionTag success",
+ fn() {
+ const tag = cachedDataVersionTag();
+ assertEquals(typeof tag, "number");
+ assertEquals(cachedDataVersionTag(), tag);
+ },
+});
+
+// https://github.com/nodejs/node/blob/a2bbe5ff216bc28f8dac1c36a8750025a93c3827/test/parallel/test-v8-stats.js#L6
+Deno.test({
+ name: "getHeapStatistics success",
+ fn() {
+ const s = getHeapStatistics();
+ const keys = [
+ "does_zap_garbage",
+ "external_memory",
+ "heap_size_limit",
+ "malloced_memory",
+ "number_of_detached_contexts",
+ "number_of_native_contexts",
+ "peak_malloced_memory",
+ "total_available_size",
+ "total_global_handles_size",
+ "total_heap_size",
+ "total_heap_size_executable",
+ "total_physical_size",
+ "used_global_handles_size",
+ "used_heap_size",
+ ];
+ assertEquals(Object.keys(s).sort(), keys);
+ for (const k of keys) {
+ assertEquals(
+ typeof (s as unknown as Record<string, unknown>)[k],
+ "number",
+ );
+ }
+ },
+});
+
+Deno.test({
+ name: "setFlagsFromString throws",
+ fn() {
+ assertThrows(() => setFlagsFromString("--allow_natives_syntax"));
+ },
+});
diff --git a/ext/node/lib.rs b/ext/node/lib.rs
index f4c23a16a..cb273ef9e 100644
--- a/ext/node/lib.rs
+++ b/ext/node/lib.rs
@@ -20,6 +20,7 @@ mod package_json;
mod path;
mod polyfill;
mod resolution;
+mod v8;
mod winerror;
pub use package_json::PackageJson;
@@ -413,6 +414,8 @@ pub fn init_polyfill() -> Extension {
crypto::op_node_hash_digest::decl(),
crypto::op_node_hash_clone::decl(),
winerror::op_node_sys_to_uv_error::decl(),
+ v8::op_v8_cached_data_version_tag::decl(),
+ v8::op_v8_get_heap_statistics::decl(),
op_node_build_os::decl(),
])
.build()
diff --git a/ext/node/polyfills/v8.ts b/ext/node/polyfills/v8.ts
index f186ff023..c7875e654 100644
--- a/ext/node/polyfills/v8.ts
+++ b/ext/node/polyfills/v8.ts
@@ -3,8 +3,10 @@
import { notImplemented } from "internal:deno_node/polyfills/_utils.ts";
+const { ops } = globalThis.__bootstrap.core;
+
export function cachedDataVersionTag() {
- notImplemented("v8.cachedDataVersionTag");
+ return ops.op_v8_cached_data_version_tag();
}
export function getHeapCodeStatistics() {
notImplemented("v8.getHeapCodeStatistics");
@@ -15,9 +17,30 @@ export function getHeapSnapshot() {
export function getHeapSpaceStatistics() {
notImplemented("v8.getHeapSpaceStatistics");
}
+
+const buffer = new Float64Array(14);
+
export function getHeapStatistics() {
- notImplemented("v8.getHeapStatistics");
+ ops.op_v8_get_heap_statistics(buffer);
+
+ return {
+ total_heap_size: buffer[0],
+ total_heap_size_executable: buffer[1],
+ total_physical_size: buffer[2],
+ total_available_size: buffer[3],
+ used_heap_size: buffer[4],
+ heap_size_limit: buffer[5],
+ malloced_memory: buffer[6],
+ peak_malloced_memory: buffer[7],
+ does_zap_garbage: buffer[8],
+ number_of_native_contexts: buffer[9],
+ number_of_detached_contexts: buffer[10],
+ total_global_handles_size: buffer[11],
+ used_global_handles_size: buffer[12],
+ external_memory: buffer[13],
+ };
}
+
export function setFlagsFromString() {
notImplemented("v8.setFlagsFromString");
}
diff --git a/ext/node/v8.rs b/ext/node/v8.rs
new file mode 100644
index 000000000..5307f7107
--- /dev/null
+++ b/ext/node/v8.rs
@@ -0,0 +1,29 @@
+// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
+use deno_core::op;
+use deno_core::v8;
+
+#[op]
+fn op_v8_cached_data_version_tag() -> u32 {
+ v8::script_compiler::cached_data_version_tag()
+}
+
+#[op(v8)]
+fn op_v8_get_heap_statistics(scope: &mut v8::HandleScope, buffer: &mut [f64]) {
+ let mut stats = v8::HeapStatistics::default();
+ scope.get_heap_statistics(&mut stats);
+
+ buffer[0] = stats.total_heap_size() as f64;
+ buffer[1] = stats.total_heap_size_executable() as f64;
+ buffer[2] = stats.total_physical_size() as f64;
+ buffer[3] = stats.total_available_size() as f64;
+ buffer[4] = stats.used_heap_size() as f64;
+ buffer[5] = stats.heap_size_limit() as f64;
+ buffer[6] = stats.malloced_memory() as f64;
+ buffer[7] = stats.peak_malloced_memory() as f64;
+ buffer[8] = stats.does_zap_garbage() as f64;
+ buffer[9] = stats.number_of_native_contexts() as f64;
+ buffer[10] = stats.number_of_detached_contexts() as f64;
+ buffer[11] = stats.total_global_handles_size() as f64;
+ buffer[12] = stats.used_global_handles_size() as f64;
+ buffer[13] = stats.external_memory() as f64;
+}
diff --git a/ops/fast_call.rs b/ops/fast_call.rs
index 9093190b2..fe6455f37 100644
--- a/ops/fast_call.rs
+++ b/ops/fast_call.rs
@@ -426,7 +426,9 @@ fn q_fast_ty(v: &FastValue) -> Quote {
FastValue::F64 => q!({ f64 }),
FastValue::Bool => q!({ bool }),
FastValue::V8Value => q!({ v8::Local<v8::Value> }),
- FastValue::Uint8Array | FastValue::Uint32Array => unreachable!(),
+ FastValue::Uint8Array
+ | FastValue::Uint32Array
+ | FastValue::Float64Array => unreachable!(),
}
}
@@ -444,6 +446,7 @@ fn q_fast_ty_variant(v: &FastValue) -> Quote {
FastValue::V8Value => q!({ V8Value }),
FastValue::Uint8Array => q!({ TypedArray(CType::Uint8) }),
FastValue::Uint32Array => q!({ TypedArray(CType::Uint32) }),
+ FastValue::Float64Array => q!({ TypedArray(CType::Float64) }),
}
}
diff --git a/ops/lib.rs b/ops/lib.rs
index 35796d41a..d8f28dd37 100644
--- a/ops/lib.rs
+++ b/ops/lib.rs
@@ -452,6 +452,13 @@ fn codegen_arg(
let #ident = #blck;
};
}
+ Some(SliceType::F64Mut) => {
+ assert!(!asyncness, "Memory slices are not allowed in async ops");
+ let blck = codegen_f64_mut_slice(core, idx);
+ return quote! {
+ let #ident = #blck;
+ };
+ }
Some(_) => {
assert!(!asyncness, "Memory slices are not allowed in async ops");
let blck = codegen_u8_slice(core, idx);
@@ -576,6 +583,28 @@ fn codegen_u32_mut_slice(core: &TokenStream2, idx: usize) -> TokenStream2 {
}
}
+fn codegen_f64_mut_slice(core: &TokenStream2, idx: usize) -> TokenStream2 {
+ quote! {
+ if let Ok(view) = #core::v8::Local::<#core::v8::Float64Array>::try_from(args.get(#idx as i32)) {
+ let (offset, len) = (view.byte_offset(), view.byte_length());
+ let buffer = match view.buffer(scope) {
+ Some(v) => v,
+ None => {
+ return #core::_ops::throw_type_error(scope, format!("Expected Float64Array at position {}", #idx));
+ }
+ };
+ if let Some(data) = buffer.data() {
+ let store = data.cast::<u8>().as_ptr();
+ unsafe { ::std::slice::from_raw_parts_mut(store.add(offset) as *mut f64, len / 8) }
+ } else {
+ &mut []
+ }
+ } else {
+ return #core::_ops::throw_type_error(scope, format!("Expected Float64Array at position {}", #idx));
+ }
+ }
+}
+
fn codegen_sync_ret(
core: &TokenStream2,
output: &syn::ReturnType,
@@ -655,6 +684,7 @@ enum SliceType {
U8,
U8Mut,
U32Mut,
+ F64Mut,
}
fn is_ref_slice(ty: impl ToTokens) -> Option<SliceType> {
@@ -667,6 +697,9 @@ fn is_ref_slice(ty: impl ToTokens) -> Option<SliceType> {
if is_u32_slice_mut(&ty) {
return Some(SliceType::U32Mut);
}
+ if is_f64_slice_mut(&ty) {
+ return Some(SliceType::F64Mut);
+ }
None
}
@@ -682,6 +715,10 @@ fn is_u32_slice_mut(ty: impl ToTokens) -> bool {
tokens(ty) == "& mut [u32]"
}
+fn is_f64_slice_mut(ty: impl ToTokens) -> bool {
+ tokens(ty) == "& mut [f64]"
+}
+
fn is_ptr_u8(ty: impl ToTokens) -> bool {
tokens(ty) == "* const u8"
}
diff --git a/ops/optimizer.rs b/ops/optimizer.rs
index 7c19a7cfd..ae3175511 100644
--- a/ops/optimizer.rs
+++ b/ops/optimizer.rs
@@ -43,6 +43,7 @@ enum TransformKind {
V8Value,
SliceU32(bool),
SliceU8(bool),
+ SliceF64(bool),
PtrU8,
WasmMemory,
}
@@ -69,6 +70,13 @@ impl Transform {
}
}
+ fn slice_f64(index: usize, is_mut: bool) -> Self {
+ Transform {
+ kind: TransformKind::SliceF64(is_mut),
+ index,
+ }
+ }
+
fn wasm_memory(index: usize) -> Self {
Transform {
kind: TransformKind::WasmMemory,
@@ -150,6 +158,20 @@ impl Transform {
unsafe { (&*var).get_storage_if_aligned().unwrap_unchecked() };
})
}
+ TransformKind::SliceF64(_) => {
+ *ty =
+ parse_quote! { *const #core::v8::fast_api::FastApiTypedArray<f64> };
+
+ q!(Vars { var: &ident }, {
+ let var = match unsafe { &*var }.get_storage_if_aligned() {
+ Some(v) => v,
+ None => {
+ unsafe { &mut *fast_api_callback_options }.fallback = true;
+ return Default::default();
+ }
+ };
+ })
+ }
TransformKind::WasmMemory => {
// Note: `ty` is correctly set to __opts by the fast call tier.
// U8 slice is always byte-aligned.
@@ -214,6 +236,7 @@ pub(crate) enum FastValue {
V8Value,
Uint8Array,
Uint32Array,
+ Float64Array,
}
impl Default for FastValue {
@@ -620,6 +643,15 @@ impl Optimizer {
.insert(index, Transform::slice_u32(index, is_mut_ref))
.is_none());
}
+ // Is `T` a f64?
+ PathSegment { ident, .. } if ident == "f64" => {
+ self.needs_fast_callback_option = true;
+ self.fast_parameters.push(FastValue::Float64Array);
+ assert!(self
+ .transforms
+ .insert(index, Transform::slice_f64(index, is_mut_ref))
+ .is_none());
+ }
_ => return Err(BailoutReason::FastUnsupportedParamType),
}
}
diff --git a/ops/optimizer_tests/f64_slice.expected b/ops/optimizer_tests/f64_slice.expected
new file mode 100644
index 000000000..32182b004
--- /dev/null
+++ b/ops/optimizer_tests/f64_slice.expected
@@ -0,0 +1,11 @@
+=== Optimizer Dump ===
+returns_result: false
+has_ref_opstate: false
+has_rc_opstate: false
+has_fast_callback_option: false
+needs_fast_callback_option: true
+fast_result: Some(Void)
+fast_parameters: [V8Value, Float64Array]
+transforms: {0: Transform { kind: SliceF64(true), index: 0 }}
+is_async: false
+fast_compatible: true
diff --git a/ops/optimizer_tests/f64_slice.out b/ops/optimizer_tests/f64_slice.out
new file mode 100644
index 000000000..88ccd232a
--- /dev/null
+++ b/ops/optimizer_tests/f64_slice.out
@@ -0,0 +1,112 @@
+#[allow(non_camel_case_types)]
+///Auto-generated by `deno_ops`, i.e: `#[op]`
+///
+///Use `op_f64_buf::decl()` to get an op-declaration
+///you can include in a `deno_core::Extension`.
+pub struct op_f64_buf;
+#[doc(hidden)]
+impl op_f64_buf {
+ pub fn name() -> &'static str {
+ stringify!(op_f64_buf)
+ }
+ pub fn v8_fn_ptr<'scope>() -> deno_core::v8::FunctionCallback {
+ use deno_core::v8::MapFnTo;
+ Self::v8_func.map_fn_to()
+ }
+ pub fn decl<'scope>() -> deno_core::OpDecl {
+ deno_core::OpDecl {
+ name: Self::name(),
+ v8_fn_ptr: Self::v8_fn_ptr(),
+ enabled: true,
+ fast_fn: Some(
+ Box::new(op_f64_buf_fast {
+ _phantom: ::std::marker::PhantomData,
+ }),
+ ),
+ is_async: false,
+ is_unstable: false,
+ is_v8: false,
+ argc: 1usize,
+ }
+ }
+ #[inline]
+ #[allow(clippy::too_many_arguments)]
+ fn call(buffer: &mut [f64]) {}
+ pub fn v8_func<'scope>(
+ scope: &mut deno_core::v8::HandleScope<'scope>,
+ args: deno_core::v8::FunctionCallbackArguments,
+ mut rv: deno_core::v8::ReturnValue,
+ ) {
+ let ctx = unsafe {
+ &*(deno_core::v8::Local::<deno_core::v8::External>::cast(args.data()).value()
+ as *const deno_core::_ops::OpCtx)
+ };
+ let arg_0 = if let Ok(view)
+ = deno_core::v8::Local::<
+ deno_core::v8::Float64Array,
+ >::try_from(args.get(0usize as i32)) {
+ let (offset, len) = (view.byte_offset(), view.byte_length());
+ let buffer = match view.buffer(scope) {
+ Some(v) => v,
+ None => {
+ return deno_core::_ops::throw_type_error(
+ scope,
+ format!("Expected Float64Array at position {}", 0usize),
+ );
+ }
+ };
+ if let Some(data) = buffer.data() {
+ let store = data.cast::<u8>().as_ptr();
+ unsafe {
+ ::std::slice::from_raw_parts_mut(
+ store.add(offset) as *mut f64,
+ len / 8,
+ )
+ }
+ } else {
+ &mut []
+ }
+ } else {
+ return deno_core::_ops::throw_type_error(
+ scope,
+ format!("Expected Float64Array at position {}", 0usize),
+ );
+ };
+ let result = Self::call(arg_0);
+ let op_state = ::std::cell::RefCell::borrow(&*ctx.state);
+ op_state.tracker.track_sync(ctx.id);
+ }
+}
+struct op_f64_buf_fast {
+ _phantom: ::std::marker::PhantomData<()>,
+}
+impl<'scope> deno_core::v8::fast_api::FastFunction for op_f64_buf_fast {
+ fn function(&self) -> *const ::std::ffi::c_void {
+ op_f64_buf_fast_fn as *const ::std::ffi::c_void
+ }
+ fn args(&self) -> &'static [deno_core::v8::fast_api::Type] {
+ use deno_core::v8::fast_api::Type::*;
+ use deno_core::v8::fast_api::CType;
+ &[V8Value, TypedArray(CType::Float64), CallbackOptions]
+ }
+ fn return_type(&self) -> deno_core::v8::fast_api::CType {
+ deno_core::v8::fast_api::CType::Void
+ }
+}
+fn op_f64_buf_fast_fn<'scope>(
+ _: deno_core::v8::Local<deno_core::v8::Object>,
+ buffer: *const deno_core::v8::fast_api::FastApiTypedArray<f64>,
+ fast_api_callback_options: *mut deno_core::v8::fast_api::FastApiCallbackOptions,
+) -> () {
+ use deno_core::v8;
+ use deno_core::_ops;
+ let buffer = match unsafe { &*buffer }.get_storage_if_aligned() {
+ Some(v) => v,
+ None => {
+ unsafe { &mut *fast_api_callback_options }.fallback = true;
+ return Default::default();
+ }
+ };
+ let result = op_f64_buf::call(buffer);
+ result
+}
diff --git a/ops/optimizer_tests/f64_slice.rs b/ops/optimizer_tests/f64_slice.rs
new file mode 100644
index 000000000..fa2778531
--- /dev/null
+++ b/ops/optimizer_tests/f64_slice.rs
@@ -0,0 +1,3 @@
+fn op_f64_buf(buffer: &mut [f64]) {
+ // @test-attr:fast
+}