Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions src/js/internal/shared.ts
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,12 @@ class NodeAggregateError extends AggregateError {
return AggregateError;
}
}
// JSC reads `name` from the error and its direct prototype only: without this it prints as `Error`.
Object.defineProperty(NodeAggregateError.prototype, "name", {
value: "AggregateError",
writable: true,
configurable: true,
});

class ConnResetException extends Error {
constructor(msg) {
Expand Down
61 changes: 58 additions & 3 deletions src/jsc/ConsoleObject.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1088,13 +1088,13 @@ impl<'a> TablePrinter<'a> {
/// recover `&mut Self` from the `*mut io::Writer` they receive (same pattern as
/// `Output::QuietWriterAdapter::new_interface`).
#[repr(C)]
struct DynWriteAdapter<'a> {
pub(crate) struct DynWriteAdapter<'a> {
head: bun_core::io::Writer,
inner: &'a mut dyn bun_io::Write,
}

impl<'a> DynWriteAdapter<'a> {
fn new(inner: &'a mut dyn bun_io::Write) -> Self {
pub(crate) fn new(inner: &'a mut dyn bun_io::Write) -> Self {
Self {
head: bun_core::io::Writer {
write_all: Self::thunk_write_all,
Expand All @@ -1106,7 +1106,7 @@ impl<'a> DynWriteAdapter<'a> {

/// Reborrow as the `io::Writer` head.
#[inline]
fn interface(&mut self) -> &mut bun_core::io::Writer {
pub(crate) fn interface(&mut self) -> &mut bun_core::io::Writer {
// SAFETY: `head` is the first `#[repr(C)]` field, so `&mut self.head`
// and `&mut *self as *mut io::Writer` are the same address; the thunks
// below cast back to `*mut Self`.
Expand All @@ -1130,6 +1130,61 @@ impl<'a> DynWriteAdapter<'a> {
}
}

/// Writes `prefix` before every line that is not empty.
pub(crate) struct LinePrefixWriter<'a> {
inner: &'a mut dyn bun_io::Write,
prefix: &'static [u8],
trailing_newlines: u8,
}

impl<'a> LinePrefixWriter<'a> {
/// `trailing_newlines`: the `\n` count that ends what `inner` holds (2 after a blank line).
pub(crate) fn new(
inner: &'a mut dyn bun_io::Write,
prefix: &'static [u8],
trailing_newlines: u8,
) -> Self {
Self {
inner,
prefix,
trailing_newlines,
}
}

/// How many `\n` end what was written so far. It stops counting at 2.
pub(crate) fn trailing_newlines(&self) -> u8 {
self.trailing_newlines
}
}

impl bun_io::Write for LinePrefixWriter<'_> {
fn write_all(&mut self, bytes: &[u8]) -> Result<(), bun_core::Error> {
let mut rest = bytes;
while !rest.is_empty() {
let line_len = match strings::index_of_char_usize(rest, b'\n') {
Some(newline) => newline + 1,
None => rest.len(),
};
let (line, after) = rest.split_at(line_len);
if line == b"\n" {
self.trailing_newlines = (self.trailing_newlines + 1).min(2);
} else {
if self.trailing_newlines != 0 {
Comment thread
robobun marked this conversation as resolved.
Resolved
self.inner.write_all(self.prefix)?;
}
self.trailing_newlines = u8::from(line[line_len - 1] == b'\n');
}
self.inner.write_all(line)?;
rest = after;
}
Ok(())
}

fn flush(&mut self) -> Result<(), bun_core::Error> {
self.inner.flush()
}
}

pub fn write_trace(writer: &mut dyn bun_io::Write, global: &JSGlobalObject) {
let mut source_code = bun_core::Utf8Bytes::EMPTY;
let mut holder = crate::zig_exception::Holder::init();
Expand Down
2 changes: 2 additions & 0 deletions src/jsc/JSErrorCode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ pub struct JSErrorCode(pub u8);
#[allow(non_upper_case_globals)]
impl JSErrorCode {
pub const Error: Self = Self(0);
/// `JSErrorCodeAggregateError` in headers-handwritten.h.
pub const AggregateError: Self = Self(7);

// StackOverflow & OutOfMemoryError is not an ErrorType in "JavaScriptCore/ErrorType.h" within JSC, so the number here is just totally made up
}
Expand Down
51 changes: 51 additions & 0 deletions src/jsc/JSValue.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1030,6 +1030,17 @@ impl JSValue {
}
}

/// Own-storage read: no getter runs, and an accessor gives its `GetterSetter` cell.
pub(crate) fn fast_get_direct(
self,
global: &JSGlobalObject,
builtin_name: BuiltinName,
) -> Option<JSValue> {
debug_assert!(self.is_object());
let v = JSC__JSValue__fastGetDirect_(self, global, builtin_name as u8);
if v.is_empty() { None } else { Some(v) }
}

/// `get` for a key that is one of `BunCommonStrings.h`'s, without the
/// per-call `StringImpl` and atom-table probe.
pub fn get_common_string(
Expand Down Expand Up @@ -1960,6 +1971,11 @@ unsafe extern "C" {
safe fn JSC__JSValue__coerceToInt32(this: JSValue, global: &JSGlobalObject) -> i32;
safe fn JSC__JSValue__coerceToInt64(this: JSValue, global: &JSGlobalObject) -> i64;
safe fn JSC__JSValue__fastGet(this: JSValue, global: &JSGlobalObject, builtin: u8) -> JSValue;
safe fn JSC__JSValue__fastGetDirect_(
this: JSValue,
global: &JSGlobalObject,
builtin: u8,
) -> JSValue;
safe fn JSC__JSValue__jsonStringify(
this: JSValue,
global: &JSGlobalObject,
Expand Down Expand Up @@ -2499,6 +2515,41 @@ impl JSValue {
index => Some(index as u32),
}
}
/// Asserts `self` is a `JSArray` (`Array` or `DerivedArray`).
pub(crate) fn array_length(self) -> u32 {
debug_assert!(self.is_cell() && self.js_type().is_array());
unsafe extern "C" {
safe fn Bun__JSArray__length(this: JSValue) -> u32;
}
Bun__JSArray__length(self)
}
/// Own-storage read of a `JSArray`: `None` for a hole, out of range, or sparse storage.
pub(crate) fn try_get_index_quickly(self, index: u32) -> Option<JSValue> {
debug_assert!(self.is_cell() && self.js_type().is_array());
unsafe extern "C" {
safe fn Bun__JSArray__tryGetIndexQuickly(this: JSValue, index: u32) -> JSValue;
}
let value = Bun__JSArray__tryGetIndexQuickly(self, index);
if value.is_empty() { None } else { Some(value) }
}
/// The own present indexes of a `JSArray`, ascending. Runs no user code.
pub(crate) fn present_indexes(self) -> Vec<u32> {
debug_assert!(self.is_cell() && self.js_type().is_array());
unsafe extern "C" {
fn Bun__JSArray__presentIndexes(this: JSValue, out: *mut u32, capacity: u32) -> u32;
}
// SAFETY: the callee writes nothing when `capacity` is 0.
let count = unsafe { Bun__JSArray__presentIndexes(self, core::ptr::null_mut(), 0) };
let mut indexes = Vec::<u32>::new();
bun_core::handle_oom(indexes.try_reserve_exact(count as usize));
// SAFETY: `indexes` has room for `count` elements. The callee writes at
// most `count` of them and initializes each one that it counts.
unsafe {
let written = Bun__JSArray__presentIndexes(self, indexes.as_mut_ptr(), count);
indexes.set_len(written.min(count) as usize);
}
indexes
}
/// `JSValue.getNameProperty` — the value's `.name` (function/class
/// name). Empty for empty/`undefined`/`null`.
pub fn get_name_property(self, global: &JSGlobalObject) -> JsResult<bun_core::String> {
Expand Down
Loading
Loading