Skip to content
Merged
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
4 changes: 3 additions & 1 deletion src/bun_core/tty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,9 @@ impl RawModeGuard {
impl Drop for RawModeGuard {
#[inline]
fn drop(&mut self) {
let _ = self.state.set_mode(self.fd, Mode::Normal, SetAttrWhen::Drain);
let _ = self
.state
.set_mode(self.fd, Mode::Normal, SetAttrWhen::Drain);
}
}

Expand Down
170 changes: 114 additions & 56 deletions src/highway/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ unsafe extern "C" {

fn highway_count_char(haystack: *const u8, haystack_len: usize, needle: u8) -> usize;

#[cfg(not(miri))]
fn highway_memmem(
haystack: *const u8,
haystack_len: usize,
Expand All @@ -19,20 +20,23 @@ unsafe extern "C" {

// These three return `usize::MAX` for not-found (the empty needle matches at
// 0 / `haystack_len` respectively).
#[cfg(not(miri))]
fn highway_memrmem(
haystack: *const u8,
haystack_len: usize,
needle: *const u8,
needle_len: usize,
) -> usize;

#[cfg(not(miri))]
fn highway_memmem16(
haystack: *const u16,
haystack_len: usize,
needle: *const u16,
needle_len: usize,
) -> usize;

#[cfg(not(miri))]
fn highway_memrmem16(
haystack: *const u16,
haystack_len: usize,
Expand Down Expand Up @@ -157,6 +161,31 @@ unsafe extern "C" {
/// call into a caller's hot loop (see `pop_last_segment_t` in node/path.rs).
const SCALAR_CUTOFF: usize = 16;

/// Miri cannot call foreign functions, and the workspace denies std's search
/// methods everywhere else, so under Miri (`bun run rust:miri`) the search
/// wrappers below take their scalar path at every length. Kernels with no
/// scalar form here (hashing, hex, sourcemaps, lexer scans) stay FFI-only:
/// reaching one from a Miri-tested crate is a loud, immediate error.
Comment thread
robobun marked this conversation as resolved.
#[inline(always)]
fn scalar_only(len: usize) -> bool {
cfg!(miri) || len < SCALAR_CUTOFF
}

/// Scalar substring search for Miri. Callers have already handled the empty
/// needle and `haystack.len() < needle.len()`.
Comment thread
robobun marked this conversation as resolved.
#[cfg(miri)]
fn scalar_memmem<T: Eq>(haystack: &[T], needle: &[T]) -> Option<usize> {
(0..=haystack.len() - needle.len()).find(|&i| haystack[i..i + needle.len()] == *needle)
}

/// Reverse [`scalar_memmem`]: start index of the last occurrence.
#[cfg(miri)]
fn scalar_memrmem<T: Eq>(haystack: &[T], needle: &[T]) -> Option<usize> {
(0..=haystack.len() - needle.len())
.rev()
.find(|&i| haystack[i..i + needle.len()] == *needle)
}

/// The single-byte kernels return `haystack_len` for "not found".
#[inline(always)]
fn found_at(result: usize, haystack_len: usize) -> Option<usize> {
Expand All @@ -168,6 +197,7 @@ fn found_at(result: usize, haystack_len: usize) -> Option<usize> {
}

/// The `mem*mem*` kernels return `usize::MAX` for "not found".
#[cfg(not(miri))]
#[inline(always)]
fn match_at(result: usize) -> Option<usize> {
if result == usize::MAX {
Expand All @@ -179,7 +209,7 @@ fn match_at(result: usize) -> Option<usize> {

#[inline(always)]
pub fn index_of_char(haystack: &[u8], needle: u8) -> Option<usize> {
if haystack.len() < SCALAR_CUTOFF {
if scalar_only(haystack.len()) {
return haystack.iter().position(|&b| b == needle);
}
// SAFETY: haystack.ptr/len are a valid readable range.
Expand All @@ -191,7 +221,7 @@ pub fn index_of_char(haystack: &[u8], needle: u8) -> Option<usize> {

#[inline(always)]
pub fn last_index_of_char(haystack: &[u8], needle: u8) -> Option<usize> {
if haystack.len() < SCALAR_CUTOFF {
if scalar_only(haystack.len()) {
return haystack.iter().rposition(|&b| b == needle);
}
// SAFETY: haystack.ptr/len are a valid readable range.
Expand All @@ -205,7 +235,7 @@ pub fn last_index_of_char(haystack: &[u8], needle: u8) -> Option<usize> {
/// run of `value`), or `None` if every byte is `value`.
#[inline(always)]
pub fn index_of_not_char(haystack: &[u8], value: u8) -> Option<usize> {
if haystack.len() < SCALAR_CUTOFF {
if scalar_only(haystack.len()) {
return haystack.iter().position(|&b| b != value);
}
// SAFETY: haystack.ptr/len are a valid readable range.
Expand All @@ -217,7 +247,7 @@ pub fn index_of_not_char(haystack: &[u8], value: u8) -> Option<usize> {

#[inline(always)]
pub fn count_char(haystack: &[u8], needle: u8) -> usize {
if haystack.len() < SCALAR_CUTOFF {
if scalar_only(haystack.len()) {
return haystack.iter().filter(|&&b| b == needle).count();
}
// SAFETY: haystack.ptr/len are a valid readable range.
Expand All @@ -232,20 +262,27 @@ pub fn memmem(haystack: &[u8], needle: &[u8]) -> Option<usize> {
if haystack.len() < needle.len() {
return None;
}
// SAFETY: both (ptr,len) pairs are valid readable ranges.
let p = unsafe {
highway_memmem(
haystack.as_ptr(),
haystack.len(),
needle.as_ptr(),
needle.len(),
)
};
if p.is_null() {
None
} else {
// SAFETY: highway_memmem returns a pointer within `haystack` on success.
Some(unsafe { p.offset_from(haystack.as_ptr()) } as usize)
#[cfg(miri)]
{
scalar_memmem(haystack, needle)
}
#[cfg(not(miri))]
{
// SAFETY: both (ptr,len) pairs are valid readable ranges.
let p = unsafe {
highway_memmem(
haystack.as_ptr(),
haystack.len(),
needle.as_ptr(),
needle.len(),
)
};
if p.is_null() {
None
} else {
// SAFETY: highway_memmem returns a pointer within `haystack` on success.
Some(unsafe { p.offset_from(haystack.as_ptr()) } as usize)
}
}
}

Expand All @@ -259,18 +296,25 @@ pub fn memrmem(haystack: &[u8], needle: &[u8]) -> Option<usize> {
if haystack.len() < needle.len() {
return None;
}
// SAFETY: both (ptr,len) pairs are valid readable ranges.
let result = unsafe {
highway_memrmem(
haystack.as_ptr(),
haystack.len(),
needle.as_ptr(),
needle.len(),
)
};
let found = match_at(result);
debug_assert!(found.is_none_or(|i| haystack[i..].starts_with(needle)));
found
#[cfg(miri)]
{
scalar_memrmem(haystack, needle)
}
#[cfg(not(miri))]
{
// SAFETY: both (ptr,len) pairs are valid readable ranges.
let result = unsafe {
highway_memrmem(
haystack.as_ptr(),
haystack.len(),
needle.as_ptr(),
needle.len(),
)
};
let found = match_at(result);
debug_assert!(found.is_none_or(|i| haystack[i..].starts_with(needle)));
found
}
}

#[inline(always)]
Expand All @@ -281,18 +325,25 @@ pub fn memmem16(haystack: &[u16], needle: &[u16]) -> Option<usize> {
if haystack.len() < needle.len() {
return None;
}
// SAFETY: both (ptr,len) pairs are valid readable ranges (`&[u16]` is 2-byte aligned).
let result = unsafe {
highway_memmem16(
haystack.as_ptr(),
haystack.len(),
needle.as_ptr(),
needle.len(),
)
};
let found = match_at(result);
debug_assert!(found.is_none_or(|i| haystack[i..].starts_with(needle)));
found
#[cfg(miri)]
{
scalar_memmem(haystack, needle)
}
#[cfg(not(miri))]
{
// SAFETY: both (ptr,len) pairs are valid readable ranges (`&[u16]` is 2-byte aligned).
let result = unsafe {
highway_memmem16(
haystack.as_ptr(),
haystack.len(),
needle.as_ptr(),
needle.len(),
)
};
let found = match_at(result);
debug_assert!(found.is_none_or(|i| haystack[i..].starts_with(needle)));
found
}
}

/// Start index of the last occurrence of `needle`. An empty needle matches at
Expand All @@ -305,18 +356,25 @@ pub fn memrmem16(haystack: &[u16], needle: &[u16]) -> Option<usize> {
if haystack.len() < needle.len() {
return None;
}
// SAFETY: both (ptr,len) pairs are valid readable ranges (`&[u16]` is 2-byte aligned).
let result = unsafe {
highway_memrmem16(
haystack.as_ptr(),
haystack.len(),
needle.as_ptr(),
needle.len(),
)
};
let found = match_at(result);
debug_assert!(found.is_none_or(|i| haystack[i..].starts_with(needle)));
found
#[cfg(miri)]
{
scalar_memrmem(haystack, needle)
}
#[cfg(not(miri))]
{
// SAFETY: both (ptr,len) pairs are valid readable ranges (`&[u16]` is 2-byte aligned).
let result = unsafe {
highway_memrmem16(
haystack.as_ptr(),
haystack.len(),
needle.as_ptr(),
needle.len(),
)
};
let found = match_at(result);
debug_assert!(found.is_none_or(|i| haystack[i..].starts_with(needle)));
found
}
}

#[inline(always)]
Expand Down Expand Up @@ -461,7 +519,7 @@ pub fn index_of_any_char(haystack: &[u8], chars: &[u8]) -> Option<usize> {
return None;
}
debug_assert!(chars.len() >= 2 && chars.len() <= 16);
if haystack.len() < SCALAR_CUTOFF {
if scalar_only(haystack.len()) {
return haystack.iter().position(|b| chars.contains(b));
}

Expand Down Expand Up @@ -503,7 +561,7 @@ pub fn last_index_of_any_char(haystack: &[u8], chars: &[u8]) -> Option<usize> {
return None;
}
debug_assert!(chars.len() >= 2 && chars.len() <= 16);
if haystack.len() < SCALAR_CUTOFF {
if scalar_only(haystack.len()) {
return haystack.iter().rposition(|b| chars.contains(b));
}

Expand Down
6 changes: 5 additions & 1 deletion src/md/ansi_renderer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2535,7 +2535,11 @@ fn probe_kitty_graphics() -> bool {
Err(_) => return false,
};
let mut tty_state = bun_core::tty::State::new();
let _ = tty_state.set_mode(0, bun_core::tty::Mode::Raw, bun_core::tty::SetAttrWhen::Drain);
let _ = tty_state.set_mode(
0,
bun_core::tty::Mode::Raw,
bun_core::tty::SetAttrWhen::Drain,
);
let _restore = scopeguard::guard((saved_termios, tty_state), |(saved, mut state)| {
if bun_sys::posix::tcsetattr(0, bun_sys::posix::TCSA::Now, &saved).is_err() {
let _ = state.set_mode(
Expand Down
2 changes: 2 additions & 0 deletions src/parsers/yaml.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3311,6 +3311,8 @@ impl CollectionData for E::Object {
}

impl<'i, Enc: Encoding> Parser<'i, Enc> {
// By value so binding consumes the `#[must_use]` anchor token.
#[allow(clippy::needless_pass_by_value)]
fn bind_anchor(&mut self, anchor: PendingAnchor, node: Expr) -> Result<(), AllocError> {
self.anchors
.put(Enc::key_bytes(anchor.name.slice(self.input)), node)
Expand Down
2 changes: 1 addition & 1 deletion src/runtime/bake/bake_body.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ use core::ptr::NonNull;
use bun_alloc::Arena; // = bumpalo::Bump
use bun_collections::ArrayHashMap;
use bun_core::Output;
use bun_jsc::{JSGlobalObject, JSValue, JsError, JsResult, ZigStringSlice};
use bun_core::{ZStr, strings};
use bun_jsc::{JSGlobalObject, JSValue, JsError, JsResult, ZigStringSlice};
use bun_options_types::schema as bun_schema;
use bun_paths::{self as paths, PathBuffer};

Expand Down
5 changes: 4 additions & 1 deletion src/runtime/server/server_body.rs
Original file line number Diff line number Diff line change
Expand Up @@ -492,7 +492,10 @@ pub mod BunInfo {
// `JSON.toAST(allocator, BunInfo, info)` — hand-expanded:
let platform_props = bun_alloc::AstAlloc::vec_from_iter([
prop(b"os", str_expr(os_tag_name(info.platform.os))),
prop(b"arch", str_expr(arch_tag_name(bun_core::Environment::ARCH))),
prop(
b"arch",
str_expr(arch_tag_name(bun_core::Environment::ARCH)),
),
prop(b"version", str_expr(info.platform.version)),
]);
let platform_expr = Expr::init(
Expand Down
9 changes: 2 additions & 7 deletions src/runtime/socket/uws_handlers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -406,7 +406,7 @@ where
{
// `ns` is the live heap `NewSocket` stashed by `on_create`. The
// `on_*` handlers may free it, so they take `ThisPtr`, never `&mut`.
swallow(api::NewSocket::on_close(ns, wrap::<SSL>(s), code, reason));
api::NewSocket::on_close(ns, wrap::<SSL>(s), code, reason);
}
}
fn on_data_no_ext(s: *mut us_socket_t, data: &[u8]) {
Expand Down Expand Up @@ -436,12 +436,7 @@ where
fn on_handshake_no_ext(s: *mut us_socket_t, ok: bool, err: us_bun_verify_error_t) {
if let Some(ns) = *us_socket_t::opaque_mut(s).ext::<Option<ThisPtr<api::NewSocket<SSL>>>>()
{
swallow(api::NewSocket::on_handshake(
ns,
wrap::<SSL>(s),
ok as i32,
err,
));
api::NewSocket::on_handshake(ns, wrap::<SSL>(s), ok as i32, err);
}
}
}
Expand Down
3 changes: 2 additions & 1 deletion test/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
"__snapshots__", // bun snapshots (toMatchSnapshot)
"./snapshots",
"./js/deno",
"./node.js" // entire node.js upstream repository
"./node.js", // entire node.js upstream repository
"regression/issue/14477/*-mismatch.tsx" // deliberately-mismatched JSX, the test asserts the parse error
]
}
2 changes: 1 addition & 1 deletion tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
},
"references": [
{ "path": "./src" },
{ "path": "./src/bake" },
{ "path": "./src/runtime/bake" },
{ "path": "./src/js" },
{ "path": "./test" },
{ "path": "./packages/bun-types" }
Expand Down