summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNayeem Rahman <nayeemrmn99@gmail.com>2022-08-11 10:57:20 +0100
committerGitHub <noreply@github.com>2022-08-11 11:57:20 +0200
commit25a1cc1b28ee2f37deb6305c0feb66d4eec50804 (patch)
tree4ddbedaaeb9fe30845e1e617df73a677d0d196c3
parent321a42d1fbab8dd8869749b44b560bbbc4f5872a (diff)
refactor(core): unwrap sync ops in rust (#15449)
-rw-r--r--core/01_core.js15
-rw-r--r--core/error.rs26
-rw-r--r--core/ops_builtin_v8.rs3
-rw-r--r--core/runtime.rs19
-rw-r--r--ops/lib.rs4
5 files changed, 60 insertions, 7 deletions
diff --git a/core/01_core.js b/core/01_core.js
index 0e823f54a..1dfb88c99 100644
--- a/core/01_core.js
+++ b/core/01_core.js
@@ -127,6 +127,18 @@
errorMap[className] = errorBuilder;
}
+ function buildCustomError(className, message, code) {
+ const error = errorMap[className]?.(message);
+ // Strip buildCustomError() calls from stack trace
+ if (typeof error == "object") {
+ ErrorCaptureStackTrace(error, buildCustomError);
+ if (code) {
+ error.code = code;
+ }
+ }
+ return error;
+ }
+
function unwrapOpResult(res) {
// .$err_class_name is a special key that should only exist on errors
if (res?.$err_class_name) {
@@ -168,7 +180,7 @@
}
function opSync(opName, ...args) {
- return unwrapOpResult(ops[opName](...args));
+ return ops[opName](...args);
}
function refOp(promiseId) {
@@ -229,6 +241,7 @@
metrics,
registerErrorBuilder,
registerErrorClass,
+ buildCustomError,
opresolve,
BadResource,
BadResourcePrototype,
diff --git a/core/error.rs b/core/error.rs
index 664cb5c0b..bc8a3195b 100644
--- a/core/error.rs
+++ b/core/error.rs
@@ -1,5 +1,7 @@
// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license.
+use crate::runtime::GetErrorClassFn;
+use crate::runtime::JsRealm;
use crate::runtime::JsRuntime;
use crate::source_map::apply_source_map;
use crate::source_map::get_source_line;
@@ -91,6 +93,30 @@ pub fn get_custom_error_class(error: &Error) -> Option<&'static str> {
error.downcast_ref::<CustomError>().map(|e| e.class)
}
+pub fn to_v8_error<'a>(
+ scope: &mut v8::HandleScope<'a>,
+ get_class: GetErrorClassFn,
+ error: &Error,
+) -> v8::Local<'a, v8::Value> {
+ let cb = JsRealm::state_from_scope(scope)
+ .borrow()
+ .js_build_custom_error_cb
+ .clone()
+ .expect("Custom error builder must be set");
+ let cb = cb.open(scope);
+ let this = v8::undefined(scope).into();
+ let class = v8::String::new(scope, get_class(error)).unwrap();
+ let message = v8::String::new(scope, &error.to_string()).unwrap();
+ let mut args = vec![class.into(), message.into()];
+ if let Some(code) = crate::error_codes::get_error_code(error) {
+ args.push(v8::String::new(scope, code).unwrap().into());
+ }
+ let exception = cb
+ .call(scope, this, &args)
+ .expect("Custom error class must have a builder registered");
+ exception
+}
+
/// A `JsError` represents an exception coming from V8, with stack frames and
/// line numbers. The deno_cli crate defines another `JsError` type, which wraps
/// the one defined here, that adds source map support and colorful formatting.
diff --git a/core/ops_builtin_v8.rs b/core/ops_builtin_v8.rs
index f2d28346e..b828f908d 100644
--- a/core/ops_builtin_v8.rs
+++ b/core/ops_builtin_v8.rs
@@ -473,7 +473,8 @@ fn op_serialize(
value_serializer.write_value(scope.get_current_context(), value.v8_value);
if scope.has_caught() || scope.has_terminated() {
scope.rethrow();
- Err(type_error("unreachable"))
+ // Dummy value, this result will be discarded because an error was thrown.
+ Ok(ZeroCopyBuf::empty())
} else if let Some(true) = ret {
let vector = value_serializer.release();
Ok(vector.into())
diff --git a/core/runtime.rs b/core/runtime.rs
index b13ed0b7e..3f3caac5e 100644
--- a/core/runtime.rs
+++ b/core/runtime.rs
@@ -150,6 +150,7 @@ pub type CompiledWasmModuleStore = CrossIsolateStore<v8::CompiledWasmModule>;
#[derive(Default)]
pub(crate) struct ContextState {
js_recv_cb: Option<v8::Global<v8::Function>>,
+ pub(crate) js_build_custom_error_cb: Option<v8::Global<v8::Function>>,
// TODO(andreubotella): Move the rest of Option<Global<Function>> fields from
// JsRuntimeState to this struct.
pub(crate) unrefed_ops: HashSet<i32>,
@@ -653,16 +654,25 @@ impl JsRuntime {
/// Grabs a reference to core.js' opresolve & syncOpsCache()
fn init_cbs(&mut self, realm: &JsRealm) {
- let recv_cb = {
+ let (recv_cb, build_custom_error_cb) = {
let scope = &mut realm.handle_scope(self.v8_isolate());
let recv_cb =
Self::grab_global::<v8::Function>(scope, "Deno.core.opresolve")
.expect("Deno.core.opresolve is undefined in the realm");
- v8::Global::new(scope, recv_cb)
+ let recv_cb = v8::Global::new(scope, recv_cb);
+ let build_custom_error_cb =
+ Self::grab_global::<v8::Function>(scope, "Deno.core.buildCustomError")
+ .expect("Deno.core.buildCustomError is undefined in the realm");
+ let build_custom_error_cb = v8::Global::new(scope, build_custom_error_cb);
+ (recv_cb, build_custom_error_cb)
};
// Put global handle in callback state
let state = realm.state(self.v8_isolate());
state.borrow_mut().js_recv_cb.replace(recv_cb);
+ state
+ .borrow_mut()
+ .js_build_custom_error_cb
+ .replace(build_custom_error_cb);
}
/// Returns the runtime's op state, which can be used to maintain ops
@@ -737,6 +747,9 @@ impl JsRuntime {
let realm = JsRealm::new(context.clone());
let realm_state = realm.state(self.v8_isolate());
std::mem::take(&mut realm_state.borrow_mut().js_recv_cb);
+ std::mem::take(
+ &mut realm_state.borrow_mut().js_build_custom_error_cb,
+ );
context
.open(self.v8_isolate())
.clear_all_slots(self.v8_isolate());
@@ -3424,7 +3437,7 @@ assertEquals(1, notify_return_value);
Deno.core.opSync("op_set_promise_reject_callback", (type, promise, reason) => {
Deno.core.opSync("op_promise_reject");
});
-
+
throw new Error('top level throw');
"#;
diff --git a/ops/lib.rs b/ops/lib.rs
index fdafca165..42913160b 100644
--- a/ops/lib.rs
+++ b/ops/lib.rs
@@ -399,8 +399,8 @@ fn codegen_sync_ret(
#ok_block
},
Err(err) => {
- let err = #core::OpError::new(op_state.get_error_class_fn, err);
- rv.set(#core::serde_v8::to_v8(scope, err).unwrap());
+ let exception = #core::error::to_v8_error(scope, op_state.get_error_class_fn, &err);
+ scope.throw_exception(exception);
},
};
}