summaryrefslogtreecommitdiff
path: root/runtime
diff options
context:
space:
mode:
Diffstat (limited to 'runtime')
-rw-r--r--runtime/js/10_dispatch_buffer.js150
-rw-r--r--runtime/js/11_timers.js3
-rw-r--r--runtime/js/12_io.js10
-rw-r--r--runtime/ops/io.rs8
-rw-r--r--runtime/ops/mod.rs20
-rw-r--r--runtime/ops/ops_buffer.rs377
-rw-r--r--runtime/ops/timers.rs2
7 files changed, 19 insertions, 551 deletions
diff --git a/runtime/js/10_dispatch_buffer.js b/runtime/js/10_dispatch_buffer.js
deleted file mode 100644
index 091fce504..000000000
--- a/runtime/js/10_dispatch_buffer.js
+++ /dev/null
@@ -1,150 +0,0 @@
-// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license.
-"use strict";
-
-((window) => {
- const core = window.Deno.core;
-
- function assert(cond) {
- if (!cond) {
- throw Error("assert");
- }
- }
-
- ////////////////////////////////////////////////////////////////////////////////////////////
- ////////////////////////////// General async handling //////////////////////////////////////
- ////////////////////////////////////////////////////////////////////////////////////////////
-
- // General Async response handling
- let nextRequestId = 1;
- const promiseTable = {};
-
- function opAsync(opName, opRequestBuilder, opResultParser) {
- // Make sure requests of this type are handled by the asyncHandler
- // The asyncHandler's role is to call the "promiseTable[requestId]" function
- core.setAsyncHandlerByName(opName, (bufUi8, _) => {
- const [requestId, result, error] = opResultParser(bufUi8, true);
- if (error !== null) {
- promiseTable[requestId][1](error);
- } else {
- promiseTable[requestId][0](result);
- }
- delete promiseTable[requestId];
- });
-
- const requestId = nextRequestId++;
-
- // Create and store promise
- const promise = new Promise((resolve, reject) => {
- promiseTable[requestId] = [resolve, reject];
- });
-
- // Synchronously dispatch async request
- core.dispatchByName(opName, ...opRequestBuilder(requestId));
-
- // Wait for async response
- return promise;
- }
-
- function opSync(opName, opRequestBuilder, opResultParser) {
- const rawResult = core.dispatchByName(opName, ...opRequestBuilder());
-
- const [_, result, error] = opResultParser(rawResult, false);
- if (error !== null) throw error;
- return result;
- }
-
- ////////////////////////////////////////////////////////////////////////////////////////////
- /////////////////////////////////// Error handling /////////////////////////////////////////
- ////////////////////////////////////////////////////////////////////////////////////////////
-
- function handleError(className, message) {
- const [ErrorClass, args] = core.getErrorClassAndArgs(className);
- if (!ErrorClass) {
- return new Error(
- `Unregistered error class: "${className}"\n` +
- ` ${message}\n` +
- ` Classes of errors returned from ops should be registered via Deno.core.registerErrorClass().`,
- );
- }
- return new ErrorClass(message, ...args);
- }
-
- ////////////////////////////////////////////////////////////////////////////////////////////
- ///////////////////////////////// Buffer ops handling //////////////////////////////////////
- ////////////////////////////////////////////////////////////////////////////////////////////
-
- const scratchBytes = new ArrayBuffer(3 * 4);
- const scratchView = new DataView(
- scratchBytes,
- scratchBytes.byteOffset,
- scratchBytes.byteLength,
- );
-
- function bufferOpBuildRequest(requestId, argument, zeroCopy) {
- scratchView.setBigUint64(0, BigInt(requestId), true);
- scratchView.setUint32(8, argument, true);
- return [scratchView, ...zeroCopy];
- }
-
- function bufferOpParseResult(bufUi8, isCopyNeeded) {
- // Decode header value from ui8 buffer
- const headerByteLength = 4 * 4;
- assert(bufUi8.byteLength >= headerByteLength);
- assert(bufUi8.byteLength % 4 == 0);
- const view = new DataView(
- bufUi8.buffer,
- bufUi8.byteOffset + bufUi8.byteLength - headerByteLength,
- headerByteLength,
- );
-
- const requestId = Number(view.getBigUint64(0, true));
- const status = view.getUint32(8, true);
- const result = view.getUint32(12, true);
-
- // Error handling
- if (status !== 0) {
- const className = core.decode(bufUi8.subarray(0, result));
- const message = core.decode(bufUi8.subarray(result, -headerByteLength))
- .trim();
-
- return [requestId, null, handleError(className, message)];
- }
-
- if (bufUi8.byteLength === headerByteLength) {
- return [requestId, result, null];
- }
-
- // Rest of response buffer is passed as reference or as a copy
- let respBuffer = null;
- if (isCopyNeeded) {
- // Copy part of the response array (if sent through shared array buf)
- respBuffer = bufUi8.slice(0, result);
- } else {
- // Create view on existing array (if sent through overflow)
- respBuffer = bufUi8.subarray(0, result);
- }
-
- return [requestId, respBuffer, null];
- }
-
- function bufferOpAsync(opName, argument = 0, ...zeroCopy) {
- return opAsync(
- opName,
- (requestId) => bufferOpBuildRequest(requestId, argument, zeroCopy),
- bufferOpParseResult,
- );
- }
-
- function bufferOpSync(opName, argument = 0, ...zeroCopy) {
- return opSync(
- opName,
- () => bufferOpBuildRequest(0, argument, zeroCopy),
- bufferOpParseResult,
- );
- }
-
- window.__bootstrap.dispatchBuffer = {
- bufferOpSync,
- bufferOpAsync,
- };
-})(this);
diff --git a/runtime/js/11_timers.js b/runtime/js/11_timers.js
index f07622388..7a0307c06 100644
--- a/runtime/js/11_timers.js
+++ b/runtime/js/11_timers.js
@@ -4,7 +4,6 @@
((window) => {
const assert = window.__bootstrap.util.assert;
const core = window.Deno.core;
- const { bufferOpSync } = window.__bootstrap.dispatchBuffer;
function opStopGlobalTimer() {
core.jsonOpSync("op_global_timer_stop");
@@ -20,7 +19,7 @@
const nowBytes = new Uint8Array(8);
function opNow() {
- bufferOpSync("op_now", 0, nowBytes);
+ core.binOpSync("op_now", 0, nowBytes);
return new DataView(nowBytes.buffer).getFloat64();
}
diff --git a/runtime/js/12_io.js b/runtime/js/12_io.js
index 09e87f990..fe815c7ed 100644
--- a/runtime/js/12_io.js
+++ b/runtime/js/12_io.js
@@ -6,8 +6,8 @@
"use strict";
((window) => {
+ const core = window.Deno.core;
const DEFAULT_BUFFER_SIZE = 32 * 1024;
- const { bufferOpSync, bufferOpAsync } = window.__bootstrap.dispatchBuffer;
// Seek whence values.
// https://golang.org/pkg/io/#pkg-constants
const SeekMode = {
@@ -81,7 +81,7 @@
return 0;
}
- const nread = bufferOpSync("op_read_sync", rid, buffer);
+ const nread = core.binOpSync("op_read_sync", rid, buffer);
if (nread < 0) {
throw new Error("read error");
}
@@ -97,7 +97,7 @@
return 0;
}
- const nread = await bufferOpAsync("op_read_async", rid, buffer);
+ const nread = await core.binOpAsync("op_read_async", rid, buffer);
if (nread < 0) {
throw new Error("read error");
}
@@ -106,7 +106,7 @@
}
function writeSync(rid, data) {
- const result = bufferOpSync("op_write_sync", rid, data);
+ const result = core.binOpSync("op_write_sync", rid, data);
if (result < 0) {
throw new Error("write error");
}
@@ -115,7 +115,7 @@
}
async function write(rid, data) {
- const result = await bufferOpAsync("op_write_async", rid, data);
+ const result = await core.binOpAsync("op_write_async", rid, data);
if (result < 0) {
throw new Error("write error");
}
diff --git a/runtime/ops/io.rs b/runtime/ops/io.rs
index e1520b2c5..1260452b6 100644
--- a/runtime/ops/io.rs
+++ b/runtime/ops/io.rs
@@ -99,11 +99,11 @@ lazy_static! {
}
pub fn init(rt: &mut JsRuntime) {
- super::reg_buffer_async(rt, "op_read_async", op_read_async);
- super::reg_buffer_async(rt, "op_write_async", op_write_async);
+ super::reg_bin_async(rt, "op_read_async", op_read_async);
+ super::reg_bin_async(rt, "op_write_async", op_write_async);
- super::reg_buffer_sync(rt, "op_read_sync", op_read_sync);
- super::reg_buffer_sync(rt, "op_write_sync", op_write_sync);
+ super::reg_bin_sync(rt, "op_read_sync", op_read_sync);
+ super::reg_bin_sync(rt, "op_write_sync", op_write_sync);
super::reg_json_async(rt, "op_shutdown", op_shutdown);
}
diff --git a/runtime/ops/mod.rs b/runtime/ops/mod.rs
index e082c5d3a..2e94d99f5 100644
--- a/runtime/ops/mod.rs
+++ b/runtime/ops/mod.rs
@@ -8,7 +8,6 @@ pub mod io;
pub mod net;
#[cfg(unix)]
mod net_unix;
-mod ops_buffer;
pub mod os;
pub mod permissions;
pub mod plugin;
@@ -25,6 +24,8 @@ pub mod websocket;
pub mod worker_host;
use crate::metrics::metrics_op;
+use deno_core::bin_op_async;
+use deno_core::bin_op_sync;
use deno_core::error::AnyError;
use deno_core::json_op_async;
use deno_core::json_op_sync;
@@ -33,10 +34,8 @@ use deno_core::serde::Serialize;
use deno_core::BufVec;
use deno_core::JsRuntime;
use deno_core::OpState;
+use deno_core::ValueOrVector;
use deno_core::ZeroCopyBuf;
-use ops_buffer::buffer_op_async;
-use ops_buffer::buffer_op_sync;
-use ops_buffer::ValueOrVector;
use std::cell::RefCell;
use std::future::Future;
use std::rc::Rc;
@@ -63,24 +62,21 @@ where
rt.register_op(name, metrics_op(name, json_op_sync(op_fn)));
}
-pub fn reg_buffer_async<F, R, RV>(
- rt: &mut JsRuntime,
- name: &'static str,
- op_fn: F,
-) where
+pub fn reg_bin_async<F, R, RV>(rt: &mut JsRuntime, name: &'static str, op_fn: F)
+where
F: Fn(Rc<RefCell<OpState>>, u32, BufVec) -> R + 'static,
R: Future<Output = Result<RV, AnyError>> + 'static,
RV: ValueOrVector,
{
- rt.register_op(name, metrics_op(name, buffer_op_async(op_fn)));
+ rt.register_op(name, metrics_op(name, bin_op_async(op_fn)));
}
-pub fn reg_buffer_sync<F, R>(rt: &mut JsRuntime, name: &'static str, op_fn: F)
+pub fn reg_bin_sync<F, R>(rt: &mut JsRuntime, name: &'static str, op_fn: F)
where
F: Fn(&mut OpState, u32, &mut [ZeroCopyBuf]) -> Result<R, AnyError> + 'static,
R: ValueOrVector,
{
- rt.register_op(name, metrics_op(name, buffer_op_sync(op_fn)));
+ rt.register_op(name, metrics_op(name, bin_op_sync(op_fn)));
}
/// `UnstableChecker` is a struct so it can be placed inside `GothamState`;
diff --git a/runtime/ops/ops_buffer.rs b/runtime/ops/ops_buffer.rs
deleted file mode 100644
index 6998144cf..000000000
--- a/runtime/ops/ops_buffer.rs
+++ /dev/null
@@ -1,377 +0,0 @@
-// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license.
-
-use deno_core::error::AnyError;
-use deno_core::futures::future::FutureExt;
-use deno_core::BufVec;
-use deno_core::Op;
-use deno_core::OpFn;
-use deno_core::OpState;
-use deno_core::ZeroCopyBuf;
-use std::boxed::Box;
-use std::cell::RefCell;
-use std::convert::TryInto;
-use std::future::Future;
-use std::rc::Rc;
-
-#[derive(Copy, Clone, Debug, PartialEq)]
-pub struct RequestHeader {
- pub request_id: u64,
- pub argument: u32,
-}
-
-impl RequestHeader {
- pub fn from_raw(bytes: &[u8]) -> Option<Self> {
- if bytes.len() < 3 * 4 {
- return None;
- }
-
- Some(Self {
- request_id: u64::from_le_bytes(bytes[0..8].try_into().unwrap()),
- argument: u32::from_le_bytes(bytes[8..12].try_into().unwrap()),
- })
- }
-}
-
-#[derive(Copy, Clone, Debug, PartialEq)]
-pub struct ResponseHeader {
- pub request_id: u64,
- pub status: u32,
- pub result: u32,
-}
-
-impl Into<[u8; 16]> for ResponseHeader {
- fn into(self) -> [u8; 16] {
- let mut resp_header = [0u8; 16];
- resp_header[0..8].copy_from_slice(&self.request_id.to_le_bytes());
- resp_header[8..12].copy_from_slice(&self.status.to_le_bytes());
- resp_header[12..16].copy_from_slice(&self.result.to_le_bytes());
- resp_header
- }
-}
-
-pub trait ValueOrVector {
- fn value(&self) -> u32;
- fn vector(self) -> Option<Vec<u8>>;
-}
-
-impl ValueOrVector for Vec<u8> {
- fn value(&self) -> u32 {
- self.len() as u32
- }
- fn vector(self) -> Option<Vec<u8>> {
- Some(self)
- }
-}
-
-impl ValueOrVector for u32 {
- fn value(&self) -> u32 {
- *self
- }
- fn vector(self) -> Option<Vec<u8>> {
- None
- }
-}
-
-fn gen_padding_32bit(len: usize) -> &'static [u8] {
- &[b' ', b' ', b' '][0..(4 - (len & 3)) & 3]
-}
-
-/// Creates an op that passes data synchronously using raw ui8 buffer.
-///
-/// The provided function `op_fn` has the following parameters:
-/// * `&mut OpState`: the op state, can be used to read/write resources in the runtime from an op.
-/// * `argument`: the i32 value that is passed to the Rust function.
-/// * `&mut [ZeroCopyBuf]`: raw bytes passed along.
-///
-/// `op_fn` returns an array buffer value, which is directly returned to JavaScript.
-///
-/// When registering an op like this...
-/// ```ignore
-/// let mut runtime = JsRuntime::new(...);
-/// runtime.register_op("hello", deno_core::buffer_op_sync(Self::hello_op));
-/// ```
-///
-/// ...it can be invoked from JS using the provided name, for example:
-/// ```js
-/// Deno.core.ops();
-/// let result = Deno.core.bufferOpSync("function_name", args);
-/// ```
-///
-/// The `Deno.core.ops()` statement is needed once before any op calls, for initialization.
-/// A more complete example is available in the examples directory.
-pub fn buffer_op_sync<F, R>(op_fn: F) -> Box<OpFn>
-where
- F: Fn(&mut OpState, u32, &mut [ZeroCopyBuf]) -> Result<R, AnyError> + 'static,
- R: ValueOrVector,
-{
- Box::new(move |state: Rc<RefCell<OpState>>, bufs: BufVec| -> Op {
- let mut bufs_iter = bufs.into_iter();
- let record_buf = bufs_iter.next().expect("Expected record at position 0");
- let mut zero_copy = bufs_iter.collect::<BufVec>();
-
- let req_header = match RequestHeader::from_raw(&record_buf) {
- Some(r) => r,
- None => {
- let error_class = b"TypeError";
- let error_message = b"Unparsable control buffer";
- let len = error_class.len() + error_message.len();
- let padding = gen_padding_32bit(len);
- let resp_header = ResponseHeader {
- request_id: 0,
- status: 1,
- result: error_class.len() as u32,
- };
- return Op::Sync(
- error_class
- .iter()
- .chain(error_message.iter())
- .chain(padding)
- .chain(&Into::<[u8; 16]>::into(resp_header))
- .cloned()
- .collect(),
- );
- }
- };
-
- match op_fn(&mut state.borrow_mut(), req_header.argument, &mut zero_copy) {
- Ok(possibly_vector) => {
- let resp_header = ResponseHeader {
- request_id: req_header.request_id,
- status: 0,
- result: possibly_vector.value(),
- };
- let resp_encoded_header = Into::<[u8; 16]>::into(resp_header);
-
- let resp_vector = match possibly_vector.vector() {
- Some(mut vector) => {
- let padding = gen_padding_32bit(vector.len());
- vector.extend(padding);
- vector.extend(&resp_encoded_header);
- vector
- }
- None => resp_encoded_header.to_vec(),
- };
- Op::Sync(resp_vector.into_boxed_slice())
- }
- Err(error) => {
- let error_class =
- (state.borrow().get_error_class_fn)(&error).as_bytes();
- let error_message = error.to_string().as_bytes().to_owned();
- let len = error_class.len() + error_message.len();
- let padding = gen_padding_32bit(len);
- let resp_header = ResponseHeader {
- request_id: req_header.request_id,
- status: 1,
- result: error_class.len() as u32,
- };
- return Op::Sync(
- error_class
- .iter()
- .chain(error_message.iter())
- .chain(padding)
- .chain(&Into::<[u8; 16]>::into(resp_header))
- .cloned()
- .collect(),
- );
- }
- }
- })
-}
-
-/// Creates an op that passes data asynchronously using raw ui8 buffer.
-///
-/// The provided function `op_fn` has the following parameters:
-/// * `Rc<RefCell<OpState>>`: the op state, can be used to read/write resources in the runtime from an op.
-/// * `argument`: the i32 value that is passed to the Rust function.
-/// * `BufVec`: raw bytes passed along, usually not needed if the JSON value is used.
-///
-/// `op_fn` returns a future, whose output is a JSON value. This value will be asynchronously
-/// returned to JavaScript.
-///
-/// When registering an op like this...
-/// ```ignore
-/// let mut runtime = JsRuntime::new(...);
-/// runtime.register_op("hello", deno_core::json_op_async(Self::hello_op));
-/// ```
-///
-/// ...it can be invoked from JS using the provided name, for example:
-/// ```js
-/// Deno.core.ops();
-/// let future = Deno.core.jsonOpAsync("function_name", args);
-/// ```
-///
-/// The `Deno.core.ops()` statement is needed once before any op calls, for initialization.
-/// A more complete example is available in the examples directory.
-pub fn buffer_op_async<F, R, RV>(op_fn: F) -> Box<OpFn>
-where
- F: Fn(Rc<RefCell<OpState>>, u32, BufVec) -> R + 'static,
- R: Future<Output = Result<RV, AnyError>> + 'static,
- RV: ValueOrVector,
-{
- Box::new(move |state: Rc<RefCell<OpState>>, bufs: BufVec| -> Op {
- let mut bufs_iter = bufs.into_iter();
- let record_buf = bufs_iter.next().expect("Expected record at position 0");
- let zero_copy = bufs_iter.collect::<BufVec>();
-
- let req_header = match RequestHeader::from_raw(&record_buf) {
- Some(r) => r,
- None => {
- let error_class = b"TypeError";
- let error_message = b"Unparsable control buffer";
- let len = error_class.len() + error_message.len();
- let padding = gen_padding_32bit(len);
- let resp_header = ResponseHeader {
- request_id: 0,
- status: 1,
- result: error_class.len() as u32,
- };
- return Op::Sync(
- error_class
- .iter()
- .chain(error_message.iter())
- .chain(padding)
- .chain(&Into::<[u8; 16]>::into(resp_header))
- .cloned()
- .collect(),
- );
- }
- };
-
- let fut =
- op_fn(state.clone(), req_header.argument, zero_copy).map(move |result| {
- match result {
- Ok(possibly_vector) => {
- let resp_header = ResponseHeader {
- request_id: req_header.request_id,
- status: 0,
- result: possibly_vector.value(),
- };
- let resp_encoded_header = Into::<[u8; 16]>::into(resp_header);
-
- let resp_vector = match possibly_vector.vector() {
- Some(mut vector) => {
- let padding = gen_padding_32bit(vector.len());
- vector.extend(padding);
- vector.extend(&resp_encoded_header);
- vector
- }
- None => resp_encoded_header.to_vec(),
- };
- resp_vector.into_boxed_slice()
- }
- Err(error) => {
- let error_class =
- (state.borrow().get_error_class_fn)(&error).as_bytes();
- let error_message = error.to_string().as_bytes().to_owned();
- let len = error_class.len() + error_message.len();
- let padding = gen_padding_32bit(len);
- let resp_header = ResponseHeader {
- request_id: req_header.request_id,
- status: 1,
- result: error_class.len() as u32,
- };
-
- error_class
- .iter()
- .chain(error_message.iter())
- .chain(padding)
- .chain(&Into::<[u8; 16]>::into(resp_header))
- .cloned()
- .collect()
- }
- }
- });
- let temp = Box::pin(fut);
- Op::Async(temp)
- })
-}
-
-#[cfg(test)]
-mod tests {
- use super::*;
-
- #[test]
- fn padding() {
- assert_eq!(gen_padding_32bit(0), &[] as &[u8]);
- assert_eq!(gen_padding_32bit(1), &[b' ', b' ', b' ']);
- assert_eq!(gen_padding_32bit(2), &[b' ', b' ']);
- assert_eq!(gen_padding_32bit(3), &[b' ']);
- assert_eq!(gen_padding_32bit(4), &[] as &[u8]);
- assert_eq!(gen_padding_32bit(5), &[b' ', b' ', b' ']);
- }
-
- #[test]
- fn response_header_to_bytes() {
- // Max size of an js Number is 1^53 - 1, so use this value as max for 64bit ´request_id´
- let resp_header = ResponseHeader {
- request_id: 0x0102030405060708u64,
- status: 0x090A0B0Cu32,
- result: 0x0D0E0F10u32,
- };
-
- // All numbers are always little-endian encoded, as the js side also wants this to be fixed
- assert_eq!(
- &Into::<[u8; 16]>::into(resp_header),
- &[8, 7, 6, 5, 4, 3, 2, 1, 12, 11, 10, 9, 16, 15, 14, 13]
- );
- }
-
- #[test]
- fn response_header_to_bytes_max_value() {
- // Max size of an js Number is 1^53 - 1, so use this value as max for 64bit ´request_id´
- let resp_header = ResponseHeader {
- request_id: (1u64 << 53u64) - 1u64,
- status: 0xFFFFFFFFu32,
- result: 0xFFFFFFFFu32,
- };
-
- // All numbers are always little-endian encoded, as the js side also wants this to be fixed
- assert_eq!(
- &Into::<[u8; 16]>::into(resp_header),
- &[
- 255, 255, 255, 255, 255, 255, 31, 0, 255, 255, 255, 255, 255, 255, 255,
- 255
- ]
- );
- }
-
- #[test]
- fn request_header_from_bytes() {
- let req_header =
- RequestHeader::from_raw(&[8, 7, 6, 5, 4, 3, 2, 1, 12, 11, 10, 9])
- .unwrap();
-
- assert_eq!(req_header.request_id, 0x0102030405060708u64);
- assert_eq!(req_header.argument, 0x090A0B0Cu32);
- }
-
- #[test]
- fn request_header_from_bytes_max_value() {
- let req_header = RequestHeader::from_raw(&[
- 255, 255, 255, 255, 255, 255, 31, 0, 255, 255, 255, 255,
- ])
- .unwrap();
-
- assert_eq!(req_header.request_id, (1u64 << 53u64) - 1u64);
- assert_eq!(req_header.argument, 0xFFFFFFFFu32);
- }
-
- #[test]
- fn request_header_from_bytes_too_short() {
- let req_header =
- RequestHeader::from_raw(&[8, 7, 6, 5, 4, 3, 2, 1, 12, 11, 10]);
-
- assert_eq!(req_header, None);
- }
-
- #[test]
- fn request_header_from_bytes_long() {
- let req_header = RequestHeader::from_raw(&[
- 8, 7, 6, 5, 4, 3, 2, 1, 12, 11, 10, 9, 13, 14, 15, 16, 17, 18, 19, 20, 21,
- ])
- .unwrap();
-
- assert_eq!(req_header.request_id, 0x0102030405060708u64);
- assert_eq!(req_header.argument, 0x090A0B0Cu32);
- }
-}
diff --git a/runtime/ops/timers.rs b/runtime/ops/timers.rs
index 445b7366c..4395b4885 100644
--- a/runtime/ops/timers.rs
+++ b/runtime/ops/timers.rs
@@ -77,7 +77,7 @@ pub fn init(rt: &mut deno_core::JsRuntime) {
super::reg_json_sync(rt, "op_global_timer_stop", op_global_timer_stop);
super::reg_json_sync(rt, "op_global_timer_start", op_global_timer_start);
super::reg_json_async(rt, "op_global_timer", op_global_timer);
- super::reg_buffer_sync(rt, "op_now", op_now);
+ super::reg_bin_sync(rt, "op_now", op_now);
super::reg_json_sync(rt, "op_sleep_sync", op_sleep_sync);
}