diff --git a/cli/op_error.rs b/cli/op_error.rs index 3cbe27a06b..2633631221 100644 --- a/cli/op_error.rs +++ b/cli/op_error.rs @@ -54,15 +54,75 @@ pub enum ErrorKind { Busy = 23, } +impl From for String { + fn from(kind: ErrorKind) -> Self { + let s = match kind { + ErrorKind::NotFound => "NotFound", + ErrorKind::PermissionDenied => "PermissionDenied", + ErrorKind::ConnectionRefused => "ConnectionRefused", + ErrorKind::ConnectionReset => "ConnectionReset", + ErrorKind::ConnectionAborted => "ConnectionAborted", + ErrorKind::NotConnected => "NotConnected", + ErrorKind::AddrInUse => "AddrInUse", + ErrorKind::AddrNotAvailable => "AddrNotAvailable", + ErrorKind::BrokenPipe => "BrokenPipe", + ErrorKind::AlreadyExists => "AlreadyExists", + ErrorKind::InvalidData => "InvalidData", + ErrorKind::TimedOut => "TimedOut", + ErrorKind::Interrupted => "Interrupted", + ErrorKind::WriteZero => "WriteZero", + ErrorKind::UnexpectedEof => "UnexpectedEof", + ErrorKind::BadResource => "BadResource", + ErrorKind::Http => "Http", + ErrorKind::URIError => "URIError", + ErrorKind::TypeError => "TypeError", + ErrorKind::Other => "Other", + ErrorKind::Busy => "Busy", + }; + + s.to_string() + } +} + +fn error_str_to_kind(kind_str: &str) -> ErrorKind { + match kind_str { + "NotFound" => ErrorKind::NotFound, + "PermissionDenied" => ErrorKind::PermissionDenied, + "ConnectionRefused" => ErrorKind::ConnectionRefused, + "ConnectionReset" => ErrorKind::ConnectionReset, + "ConnectionAborted" => ErrorKind::ConnectionAborted, + "NotConnected" => ErrorKind::NotConnected, + "AddrInUse" => ErrorKind::AddrInUse, + "AddrNotAvailable" => ErrorKind::AddrNotAvailable, + "BrokenPipe" => ErrorKind::BrokenPipe, + "AlreadyExists" => ErrorKind::AlreadyExists, + "InvalidData" => ErrorKind::InvalidData, + "TimedOut" => ErrorKind::TimedOut, + "Interrupted" => ErrorKind::Interrupted, + "WriteZero" => ErrorKind::WriteZero, + "UnexpectedEof" => ErrorKind::UnexpectedEof, + "BadResource" => ErrorKind::BadResource, + "Http" => ErrorKind::Http, + "URIError" => ErrorKind::URIError, + "TypeError" => ErrorKind::TypeError, + "Other" => ErrorKind::Other, + "Busy" => ErrorKind::Busy, + _ => panic!("unknown error kind"), + } +} + #[derive(Debug)] pub struct OpError { - pub kind: ErrorKind, + pub kind_str: String, pub msg: String, } impl OpError { fn new(kind: ErrorKind, msg: String) -> Self { - Self { kind, msg } + Self { + kind_str: kind.into(), + msg, + } } pub fn not_found(msg: String) -> Self { @@ -112,6 +172,10 @@ impl OpError { "resource is unavailable because it is in use by a promise".to_string(), ) } + + pub fn invalid_domain_error() -> OpError { + OpError::new(ErrorKind::TypeError, "Invalid domain.".to_string()) + } } impl Error for OpError {} @@ -130,10 +194,7 @@ impl From for OpError { impl From<&ImportMapError> for OpError { fn from(error: &ImportMapError) -> Self { - Self { - kind: ErrorKind::Other, - msg: error.to_string(), - } + Self::new(ErrorKind::Other, error.to_string()) } } @@ -145,10 +206,7 @@ impl From for OpError { impl From<&ModuleResolutionError> for OpError { fn from(error: &ModuleResolutionError) -> Self { - Self { - kind: ErrorKind::URIError, - msg: error.to_string(), - } + Self::new(ErrorKind::URIError, error.to_string()) } } @@ -166,10 +224,7 @@ impl From<&VarError> for OpError { NotUnicode(..) => ErrorKind::InvalidData, }; - Self { - kind, - msg: error.to_string(), - } + Self::new(kind, error.to_string()) } } @@ -206,10 +261,7 @@ impl From<&io::Error> for OpError { _ => unreachable!(), }; - Self { - kind, - msg: error.to_string(), - } + Self::new(kind, error.to_string()) } } @@ -221,10 +273,7 @@ impl From for OpError { impl From<&url::ParseError> for OpError { fn from(error: &url::ParseError) -> Self { - Self { - kind: ErrorKind::URIError, - msg: error.to_string(), - } + Self::new(ErrorKind::URIError, error.to_string()) } } impl From for OpError { @@ -252,14 +301,8 @@ impl From<&reqwest::Error> for OpError { .downcast_ref::() .map(|e| e.into()) }) - .unwrap_or_else(|| Self { - kind: ErrorKind::Http, - msg: error.to_string(), - }), - None => Self { - kind: ErrorKind::Http, - msg: error.to_string(), - }, + .unwrap_or_else(|| Self::new(ErrorKind::Http, error.to_string())), + None => Self::new(ErrorKind::Http, error.to_string()), } } } @@ -282,10 +325,7 @@ impl From<&ReadlineError> for OpError { _ => unimplemented!(), }; - Self { - kind, - msg: error.to_string(), - } + Self::new(kind, error.to_string()) } } @@ -305,10 +345,7 @@ impl From<&serde_json::error::Error> for OpError { Category::Eof => ErrorKind::UnexpectedEof, }; - Self { - kind, - msg: error.to_string(), - } + Self::new(kind, error.to_string()) } } @@ -328,10 +365,7 @@ impl From for OpError { nix::Error::UnsupportedOperation => unreachable!(), }; - Self { - kind, - msg: error.to_string(), - } + Self::new(kind, error.to_string()) } } @@ -352,10 +386,7 @@ impl From<&dlopen::Error> for OpError { NullSymbol => ErrorKind::Other, }; - Self { - kind, - msg: error.to_string(), - } + Self::new(kind, error.to_string()) } } @@ -376,10 +407,7 @@ impl From<¬ify::Error> for OpError { InvalidConfig(_) => ErrorKind::InvalidData, }; - Self { - kind, - msg: error.to_string(), - } + Self::new(kind, error.to_string()) } } @@ -391,10 +419,7 @@ impl From for OpError { impl From<&SwcDiagnosticBuffer> for OpError { fn from(error: &SwcDiagnosticBuffer) -> Self { - Self { - kind: ErrorKind::Other, - msg: error.diagnostics.join(", "), - } + Self::new(ErrorKind::Other, error.diagnostics.join(", ")) } } @@ -412,9 +437,9 @@ impl From for OpError { None .or_else(|| { - error - .downcast_ref::() - .map(|e| OpError::new(e.kind, e.msg.to_string())) + error.downcast_ref::().map(|e| { + OpError::new(error_str_to_kind(&e.kind_str), e.msg.to_string()) + }) }) .or_else(|| error.downcast_ref::().map(|e| e.into())) .or_else(|| error.downcast_ref::().map(|e| e.into())) @@ -467,21 +492,21 @@ mod tests { #[test] fn test_simple_error() { let err = OpError::not_found("foo".to_string()); - assert_eq!(err.kind, ErrorKind::NotFound); + assert_eq!(err.kind_str, "NotFound"); assert_eq!(err.to_string(), "foo"); } #[test] fn test_io_error() { let err = OpError::from(io_error()); - assert_eq!(err.kind, ErrorKind::NotFound); + assert_eq!(err.kind_str, "NotFound"); assert_eq!(err.to_string(), "entity not found"); } #[test] fn test_url_error() { let err = OpError::from(url_error()); - assert_eq!(err.kind, ErrorKind::URIError); + assert_eq!(err.kind_str, "URIError"); assert_eq!(err.to_string(), "empty host"); } @@ -490,21 +515,21 @@ mod tests { #[test] fn test_import_map_error() { let err = OpError::from(import_map_error()); - assert_eq!(err.kind, ErrorKind::Other); + assert_eq!(err.kind_str, "Other"); assert_eq!(err.to_string(), "an import map error"); } #[test] fn test_bad_resource() { let err = OpError::bad_resource("Resource has been closed".to_string()); - assert_eq!(err.kind, ErrorKind::BadResource); + assert_eq!(err.kind_str, "BadResource"); assert_eq!(err.to_string(), "Resource has been closed"); } #[test] fn test_bad_resource_id() { let err = OpError::bad_resource_id(); - assert_eq!(err.kind, ErrorKind::BadResource); + assert_eq!(err.kind_str, "BadResource"); assert_eq!(err.to_string(), "Bad resource ID"); } @@ -513,7 +538,7 @@ mod tests { let err = OpError::permission_denied( "run again with the --allow-net flag".to_string(), ); - assert_eq!(err.kind, ErrorKind::PermissionDenied); + assert_eq!(err.kind_str, "PermissionDenied"); assert_eq!(err.to_string(), "run again with the --allow-net flag"); } } diff --git a/cli/ops/dispatch_json.rs b/cli/ops/dispatch_json.rs index c3a1c3b3fd..ad6947dd1f 100644 --- a/cli/ops/dispatch_json.rs +++ b/cli/ops/dispatch_json.rs @@ -27,7 +27,7 @@ pub enum JsonOp { fn json_err(err: OpError) -> Value { json!({ "message": err.msg, - "kind": err.kind as u32, + "kind": err.kind_str, }) } diff --git a/cli/ops/dispatch_minimal.rs b/cli/ops/dispatch_minimal.rs index c37e57e45f..9cb81d4bce 100644 --- a/cli/ops/dispatch_minimal.rs +++ b/cli/ops/dispatch_minimal.rs @@ -40,21 +40,24 @@ impl Into for Record { pub struct ErrorRecord { pub promise_id: i32, pub arg: i32, - pub error_code: i32, + pub error_len: i32, + pub error_code: Vec, pub error_message: Vec, } impl Into for ErrorRecord { fn into(self) -> Buf { - let v32: Vec = vec![self.promise_id, self.arg, self.error_code]; + let v32: Vec = vec![self.promise_id, self.arg, self.error_len]; let mut v8: Vec = Vec::new(); for n in v32 { v8.write_i32::(n).unwrap(); } + let mut code = self.error_code; let mut message = self.error_message; - // Align to 32bit word, padding with the space character. - message.resize((message.len() + 3usize) & !3usize, b' '); + v8.append(&mut code); v8.append(&mut message); + // Align to 32bit word, padding with the space character. + v8.resize((v8.len() + 3usize) & !3usize, b' '); v8.into_boxed_slice() } } @@ -62,13 +65,14 @@ impl Into for ErrorRecord { #[test] fn test_error_record() { let expected = vec![ - 1, 0, 0, 0, 255, 255, 255, 255, 10, 0, 0, 0, 69, 114, 114, 111, 114, 32, - 32, 32, + 1, 0, 0, 0, 255, 255, 255, 255, 11, 0, 0, 0, 66, 97, 100, 82, 101, 115, + 111, 117, 114, 99, 101, 69, 114, 114, 111, 114, ]; let err_record = ErrorRecord { promise_id: 1, arg: -1, - error_code: 10, + error_len: 11, + error_code: "BadResource".to_string().as_bytes().to_owned(), error_message: "Error".to_string().as_bytes().to_owned(), }; let buf: Buf = err_record.into(); @@ -128,7 +132,8 @@ where let error_record = ErrorRecord { promise_id: 0, arg: -1, - error_code: e.kind as i32, + error_len: e.kind_str.len() as i32, + error_code: e.kind_str.as_bytes().to_owned(), error_message: e.msg.as_bytes().to_owned(), }; return Op::Sync(error_record.into()); @@ -148,7 +153,8 @@ where let error_record = ErrorRecord { promise_id: record.promise_id, arg: -1, - error_code: err.kind as i32, + error_len: err.kind_str.len() as i32, + error_code: err.kind_str.as_bytes().to_owned(), error_message: err.msg.as_bytes().to_owned(), }; error_record.into() @@ -165,7 +171,8 @@ where let error_record = ErrorRecord { promise_id: record.promise_id, arg: -1, - error_code: err.kind as i32, + error_len: err.kind_str.len() as i32, + error_code: err.kind_str.as_bytes().to_owned(), error_message: err.msg.as_bytes().to_owned(), }; error_record.into() diff --git a/cli/ops/idna.rs b/cli/ops/idna.rs index 8ecef48620..ee78307dc9 100644 --- a/cli/ops/idna.rs +++ b/cli/ops/idna.rs @@ -3,7 +3,7 @@ //! https://url.spec.whatwg.org/#idna use super::dispatch_json::{Deserialize, JsonOp, Value}; -use crate::op_error::{ErrorKind, OpError}; +use crate::op_error::OpError; use crate::state::State; use deno_core::CoreIsolate; use deno_core::ZeroCopyBuf; @@ -13,13 +13,6 @@ pub fn init(i: &mut CoreIsolate, s: &State) { i.register_op("op_domain_to_ascii", s.stateful_json_op(op_domain_to_ascii)); } -fn invalid_domain_error() -> OpError { - OpError { - kind: ErrorKind::TypeError, - msg: "Invalid domain.".to_string(), - } -} - #[derive(Deserialize)] #[serde(rename_all = "camelCase")] struct DomainToAscii { @@ -35,9 +28,10 @@ fn op_domain_to_ascii( let args: DomainToAscii = serde_json::from_value(args)?; let domain = if args.be_strict { domain_to_ascii_strict(args.domain.as_str()) - .map_err(|_| invalid_domain_error())? + .map_err(|_| OpError::invalid_domain_error())? } else { - domain_to_ascii(args.domain.as_str()).map_err(|_| invalid_domain_error())? + domain_to_ascii(args.domain.as_str()) + .map_err(|_| OpError::invalid_domain_error())? }; Ok(JsonOp::Sync(json!(domain))) } diff --git a/cli/permissions.rs b/cli/permissions.rs index 2e378b4974..c89f8bcdb9 100644 --- a/cli/permissions.rs +++ b/cli/permissions.rs @@ -860,8 +860,8 @@ mod tests { perms4 .request_net(&Some("localhost:8080")) .unwrap_err() - .kind, - crate::op_error::ErrorKind::URIError + .kind_str, + "URIError" ); let mut perms5 = Permissions::from_flags(&Flags { @@ -870,8 +870,11 @@ mod tests { }); set_prompt_result(false); assert_eq!( - perms5.request_net(&Some("file:/1.txt")).unwrap_err().kind, - crate::op_error::ErrorKind::URIError + perms5 + .request_net(&Some("file:/1.txt")) + .unwrap_err() + .kind_str, + "URIError" ); drop(guard); diff --git a/cli/rt/01_errors.js b/cli/rt/01_errors.js index 8390dd803f..fb2bb78c27 100644 --- a/cli/rt/01_errors.js +++ b/cli/rt/01_errors.js @@ -1,101 +1,6 @@ // Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. ((window) => { - // Warning! The values in this enum are duplicated in cli/op_error.rs - // Update carefully! - const ErrorKind = { - 1: "NotFound", - 2: "PermissionDenied", - 3: "ConnectionRefused", - 4: "ConnectionReset", - 5: "ConnectionAborted", - 6: "NotConnected", - 7: "AddrInUse", - 8: "AddrNotAvailable", - 9: "BrokenPipe", - 10: "AlreadyExists", - 13: "InvalidData", - 14: "TimedOut", - 15: "Interrupted", - 16: "WriteZero", - 17: "UnexpectedEof", - 18: "BadResource", - 19: "Http", - 20: "URIError", - 21: "TypeError", - 22: "Other", - 23: "Busy", - - NotFound: 1, - PermissionDenied: 2, - ConnectionRefused: 3, - ConnectionReset: 4, - ConnectionAborted: 5, - NotConnected: 6, - AddrInUse: 7, - AddrNotAvailable: 8, - BrokenPipe: 9, - AlreadyExists: 10, - InvalidData: 13, - TimedOut: 14, - Interrupted: 15, - WriteZero: 16, - UnexpectedEof: 17, - BadResource: 18, - Http: 19, - URIError: 20, - TypeError: 21, - Other: 22, - Busy: 23, - }; - - function getErrorClass(kind) { - switch (kind) { - case ErrorKind.TypeError: - return TypeError; - case ErrorKind.Other: - return Error; - case ErrorKind.URIError: - return URIError; - case ErrorKind.NotFound: - return NotFound; - case ErrorKind.PermissionDenied: - return PermissionDenied; - case ErrorKind.ConnectionRefused: - return ConnectionRefused; - case ErrorKind.ConnectionReset: - return ConnectionReset; - case ErrorKind.ConnectionAborted: - return ConnectionAborted; - case ErrorKind.NotConnected: - return NotConnected; - case ErrorKind.AddrInUse: - return AddrInUse; - case ErrorKind.AddrNotAvailable: - return AddrNotAvailable; - case ErrorKind.BrokenPipe: - return BrokenPipe; - case ErrorKind.AlreadyExists: - return AlreadyExists; - case ErrorKind.InvalidData: - return InvalidData; - case ErrorKind.TimedOut: - return TimedOut; - case ErrorKind.Interrupted: - return Interrupted; - case ErrorKind.WriteZero: - return WriteZero; - case ErrorKind.UnexpectedEof: - return UnexpectedEof; - case ErrorKind.BadResource: - return BadResource; - case ErrorKind.Http: - return Http; - case ErrorKind.Busy: - return Busy; - } - } - class NotFound extends Error { constructor(msg) { super(msg); @@ -245,6 +150,5 @@ window.__bootstrap.errors = { errors, - getErrorClass, }; })(this); diff --git a/cli/rt/10_dispatch_json.js b/cli/rt/10_dispatch_json.js index 3d19ea62ae..05b4d46ed7 100644 --- a/cli/rt/10_dispatch_json.js +++ b/cli/rt/10_dispatch_json.js @@ -3,7 +3,6 @@ ((window) => { const core = window.Deno.core; const util = window.__bootstrap.util; - const getErrorClass = window.__bootstrap.errors.getErrorClass; // Using an object without a prototype because `Map` was causing GC problems. const promiseTable = Object.create(null); let _nextPromiseId = 1; @@ -22,7 +21,7 @@ function unwrapResponse(res) { if (res.err != null) { - throw new (getErrorClass(res.err.kind))(res.err.message); + throw new (core.getErrorClass(res.err.kind))(res.err.message); } util.assert(res.ok != null); return res.ok; diff --git a/cli/rt/10_dispatch_minimal.js b/cli/rt/10_dispatch_minimal.js index 6137449f41..0a0a4f99f2 100644 --- a/cli/rt/10_dispatch_minimal.js +++ b/cli/rt/10_dispatch_minimal.js @@ -3,7 +3,6 @@ ((window) => { const core = window.Deno.core; const util = window.__bootstrap.util; - const errorNs = window.__bootstrap.errors; // Using an object without a prototype because `Map` was causing GC problems. const promiseTableMin = Object.create(null); @@ -32,11 +31,13 @@ let err; if (arg < 0) { - const kind = result; - const message = decoder.decode(ui8.subarray(12)); - err = { kind, message }; + const codeLen = result; + const codeAndMessage = decoder.decode(ui8.subarray(12)); + const errorCode = codeAndMessage.slice(0, codeLen); + const message = codeAndMessage.slice(codeLen); + err = { kind: errorCode, message }; } else if (ui8.length != 12) { - throw new errorNs.errors.InvalidData("BadMessage"); + throw new TypeError("Malformed response message"); } return { @@ -49,7 +50,7 @@ function unwrapResponse(res) { if (res.err != null) { - throw new (errorNs.getErrorClass(res.err.kind))(res.err.message); + throw new (core.getErrorClass(res.err.kind))(res.err.message); } return res.result; } diff --git a/cli/rt/99_main.js b/cli/rt/99_main.js index 325881b5ad..873e422915 100644 --- a/cli/rt/99_main.js +++ b/cli/rt/99_main.js @@ -34,6 +34,7 @@ delete Object.prototype.__proto__; const fetch = window.__bootstrap.fetch; const denoNs = window.__bootstrap.denoNs; const denoNsUnstable = window.__bootstrap.denoNsUnstable; + const errors = window.__bootstrap.errors.errors; let windowIsClosing = false; @@ -175,6 +176,30 @@ delete Object.prototype.__proto__; return s; } + function registerErrors() { + core.registerErrorClass("NotFound", errors.NotFound); + core.registerErrorClass("PermissionDenied", errors.PermissionDenied); + core.registerErrorClass("ConnectionRefused", errors.ConnectionRefused); + core.registerErrorClass("ConnectionReset", errors.ConnectionReset); + core.registerErrorClass("ConnectionAborted", errors.ConnectionAborted); + core.registerErrorClass("NotConnected", errors.NotConnected); + core.registerErrorClass("AddrInUse", errors.AddrInUse); + core.registerErrorClass("AddrNotAvailable", errors.AddrNotAvailable); + core.registerErrorClass("BrokenPipe", errors.BrokenPipe); + core.registerErrorClass("AlreadyExists", errors.AlreadyExists); + core.registerErrorClass("InvalidData", errors.InvalidData); + core.registerErrorClass("TimedOut", errors.TimedOut); + core.registerErrorClass("Interrupted", errors.Interrupted); + core.registerErrorClass("WriteZero", errors.WriteZero); + core.registerErrorClass("UnexpectedEof", errors.UnexpectedEof); + core.registerErrorClass("BadResource", errors.BadResource); + core.registerErrorClass("Http", errors.Http); + core.registerErrorClass("URIError", URIError); + core.registerErrorClass("TypeError", TypeError); + core.registerErrorClass("Other", Error); + core.registerErrorClass("Busy", errors.Busy); + } + // https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope const windowOrWorkerGlobalScopeMethods = { atob: util.writable(atob), @@ -290,6 +315,8 @@ delete Object.prototype.__proto__; const { args, cwd, noColor, pid, ppid, repl, unstableFlag } = runtimeStart(); + registerErrors(); + const finalDenoNs = { core, internal: internalSymbol, @@ -347,6 +374,8 @@ delete Object.prototype.__proto__; internalName ?? name, ); + registerErrors(); + const finalDenoNs = { core, internal: internalSymbol, diff --git a/cli/tests/unit/dispatch_minimal_test.ts b/cli/tests/unit/dispatch_minimal_test.ts index 26296b469d..e10acfc54e 100644 --- a/cli/tests/unit/dispatch_minimal_test.ts +++ b/cli/tests/unit/dispatch_minimal_test.ts @@ -43,7 +43,7 @@ unitTest(function malformedMinimalControlBuffer(): void { header.byteLength / 4, ); const arg = buf32[1]; - const message = new TextDecoder().decode(res.slice(12)).trim(); + const codeAndMessage = new TextDecoder().decode(res.slice(12)).trim(); assert(arg < 0); - assertEquals(message, "Unparsable control buffer"); + assertEquals(codeAndMessage, "TypeErrorUnparsable control buffer"); }); diff --git a/cli/tsc/01_errors.js b/cli/tsc/01_errors.js index 8390dd803f..fb2bb78c27 100644 --- a/cli/tsc/01_errors.js +++ b/cli/tsc/01_errors.js @@ -1,101 +1,6 @@ // Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. ((window) => { - // Warning! The values in this enum are duplicated in cli/op_error.rs - // Update carefully! - const ErrorKind = { - 1: "NotFound", - 2: "PermissionDenied", - 3: "ConnectionRefused", - 4: "ConnectionReset", - 5: "ConnectionAborted", - 6: "NotConnected", - 7: "AddrInUse", - 8: "AddrNotAvailable", - 9: "BrokenPipe", - 10: "AlreadyExists", - 13: "InvalidData", - 14: "TimedOut", - 15: "Interrupted", - 16: "WriteZero", - 17: "UnexpectedEof", - 18: "BadResource", - 19: "Http", - 20: "URIError", - 21: "TypeError", - 22: "Other", - 23: "Busy", - - NotFound: 1, - PermissionDenied: 2, - ConnectionRefused: 3, - ConnectionReset: 4, - ConnectionAborted: 5, - NotConnected: 6, - AddrInUse: 7, - AddrNotAvailable: 8, - BrokenPipe: 9, - AlreadyExists: 10, - InvalidData: 13, - TimedOut: 14, - Interrupted: 15, - WriteZero: 16, - UnexpectedEof: 17, - BadResource: 18, - Http: 19, - URIError: 20, - TypeError: 21, - Other: 22, - Busy: 23, - }; - - function getErrorClass(kind) { - switch (kind) { - case ErrorKind.TypeError: - return TypeError; - case ErrorKind.Other: - return Error; - case ErrorKind.URIError: - return URIError; - case ErrorKind.NotFound: - return NotFound; - case ErrorKind.PermissionDenied: - return PermissionDenied; - case ErrorKind.ConnectionRefused: - return ConnectionRefused; - case ErrorKind.ConnectionReset: - return ConnectionReset; - case ErrorKind.ConnectionAborted: - return ConnectionAborted; - case ErrorKind.NotConnected: - return NotConnected; - case ErrorKind.AddrInUse: - return AddrInUse; - case ErrorKind.AddrNotAvailable: - return AddrNotAvailable; - case ErrorKind.BrokenPipe: - return BrokenPipe; - case ErrorKind.AlreadyExists: - return AlreadyExists; - case ErrorKind.InvalidData: - return InvalidData; - case ErrorKind.TimedOut: - return TimedOut; - case ErrorKind.Interrupted: - return Interrupted; - case ErrorKind.WriteZero: - return WriteZero; - case ErrorKind.UnexpectedEof: - return UnexpectedEof; - case ErrorKind.BadResource: - return BadResource; - case ErrorKind.Http: - return Http; - case ErrorKind.Busy: - return Busy; - } - } - class NotFound extends Error { constructor(msg) { super(msg); @@ -245,6 +150,5 @@ window.__bootstrap.errors = { errors, - getErrorClass, }; })(this); diff --git a/cli/tsc/10_dispatch_json.js b/cli/tsc/10_dispatch_json.js index 3d19ea62ae..a25014789a 100644 --- a/cli/tsc/10_dispatch_json.js +++ b/cli/tsc/10_dispatch_json.js @@ -3,7 +3,7 @@ ((window) => { const core = window.Deno.core; const util = window.__bootstrap.util; - const getErrorClass = window.__bootstrap.errors.getErrorClass; + // Using an object without a prototype because `Map` was causing GC problems. const promiseTable = Object.create(null); let _nextPromiseId = 1; @@ -22,7 +22,7 @@ function unwrapResponse(res) { if (res.err != null) { - throw new (getErrorClass(res.err.kind))(res.err.message); + throw new (core.getErrorClass(res.err.kind))(res.err.message); } util.assert(res.ok != null); return res.ok; diff --git a/cli/tsc/99_main_compiler.js b/cli/tsc/99_main_compiler.js index 41051f2e0f..23e25237a1 100644 --- a/cli/tsc/99_main_compiler.js +++ b/cli/tsc/99_main_compiler.js @@ -23,6 +23,7 @@ delete Object.prototype.__proto__; const dispatchJson = window.__bootstrap.dispatchJson; const util = window.__bootstrap.util; const errorStack = window.__bootstrap.errorStack; + const errors = window.__bootstrap.errors.errors; function opNow() { const res = dispatchJson.sendSync("op_now"); @@ -1851,6 +1852,27 @@ delete Object.prototype.__proto__; throw new Error("Worker runtime already bootstrapped"); } hasBootstrapped = true; + core.registerErrorClass("NotFound", errors.NotFound); + core.registerErrorClass("PermissionDenied", errors.PermissionDenied); + core.registerErrorClass("ConnectionRefused", errors.ConnectionRefused); + core.registerErrorClass("ConnectionReset", errors.ConnectionReset); + core.registerErrorClass("ConnectionAborted", errors.ConnectionAborted); + core.registerErrorClass("NotConnected", errors.NotConnected); + core.registerErrorClass("AddrInUse", errors.AddrInUse); + core.registerErrorClass("AddrNotAvailable", errors.AddrNotAvailable); + core.registerErrorClass("BrokenPipe", errors.BrokenPipe); + core.registerErrorClass("AlreadyExists", errors.AlreadyExists); + core.registerErrorClass("InvalidData", errors.InvalidData); + core.registerErrorClass("TimedOut", errors.TimedOut); + core.registerErrorClass("Interrupted", errors.Interrupted); + core.registerErrorClass("WriteZero", errors.WriteZero); + core.registerErrorClass("UnexpectedEof", errors.UnexpectedEof); + core.registerErrorClass("BadResource", errors.BadResource); + core.registerErrorClass("Http", errors.Http); + core.registerErrorClass("URIError", URIError); + core.registerErrorClass("TypeError", TypeError); + core.registerErrorClass("Other", Error); + core.registerErrorClass("Busy", errors.Busy); globalThis.__bootstrap = undefined; runtimeStart("TS"); } diff --git a/core/core.js b/core/core.js index b3c0ddc13c..5f9d6f9819 100644 --- a/core/core.js +++ b/core/core.js @@ -38,6 +38,7 @@ SharedQueue Binary Layout let initialized = false; let opsCache = {}; + const errorMap = {}; function maybeInit() { if (!initialized) { @@ -187,11 +188,26 @@ SharedQueue Binary Layout return send(opsCache[opName], control, ...zeroCopy); } + function registerErrorClass(errorName, errorClass) { + if (typeof errorMap[errorName] !== "undefined") { + throw new TypeError(`Error class for "${errorName}" already registered`); + } + errorMap[errorName] = errorClass; + } + + function getErrorClass(errorName) { + const errorClass = errorMap[errorName]; + assert(errorClass); + return errorClass; + } + Object.assign(window.Deno.core, { setAsyncHandler, dispatch: send, dispatchByName: dispatch, ops, + registerErrorClass, + getErrorClass, // sharedQueue is private but exposed for testing. sharedQueue: { MAX_RECORDS,