Skip to content
Open
29 changes: 1 addition & 28 deletions src/bun_core/string/immutable/unicode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -585,7 +585,7 @@ impl BOM {
}
}

pub(crate) fn length(self) -> usize {
pub fn length(self) -> usize {
self.get_header().len()
}

Expand Down Expand Up @@ -615,33 +615,6 @@ impl BOM {
}
}
}

/// This is required for the fs `use_shared_buffer` flag. we cannot free that pointer.
/// The returned slice will always point to the base of the input.
///
/// Requires an arraylist in case it must be grown.
pub fn remove_and_convert_to_utf8_without_dealloc<'a>(self, list: &'a mut Vec<u8>) -> &'a [u8] {
match self {
BOM::Utf8 => {
let n = Self::UTF8_BYTES.len();
let len = list.len();
list.copy_within(n.., 0);
&list[..len - n]
}
BOM::Utf16Le => {
// See `remove_and_convert_to_utf8_and_free` — `&list[2..]` has no
// u16-alignment guarantee, so use the byte-level transcode helper.
let out = crate::strings_impl::to_utf8_alloc_from_le_bytes(
&list[Self::UTF16_LE_BYTES.len()..],
);
list.clear();
list.extend_from_slice(&out);
// Return the list slice (not `out`, the new alloc) to honor the
// "always points to the base of the input" doc comment.
&list[..]
}
}
}
}

// https://github.com/WebKit/WebKit/blob/443e796d1538654c34f2690e39600c70c8052b63/Source/WebCore/PAL/pal/text/TextCodecUTF8.cpp#L69
Expand Down
52 changes: 43 additions & 9 deletions src/bundler/ParseTask.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1451,6 +1451,15 @@ pub mod parse_worker {
// getCodeForParseTaskWithoutPlugins
// ───────────────────────────────────────────────────────────────────────────

/// A loader that copies its file emits the bytes of the read.
fn bom_handling_for(loader: Loader) -> Fs::BomHandling {
if loader.should_copy_for_bundling() {
Fs::BomHandling::Keep
} else {
Fs::BomHandling::Convert
}
}

// `transpiler`/`resolver` are raw `*mut`.
// Callers pass `resolver = &mut (*transpiler).resolver`; taking
// `&mut Transpiler` + `&mut Resolver` would be aliased-`&mut` UB. We only
Expand All @@ -1462,7 +1471,7 @@ pub mod parse_worker {
resolver: *mut Resolver,
bump: &Bump,
file_path: &mut Fs::Path,
_loader: Loader,
bom_handling: Fs::BomHandling,
) -> core::result::Result<CacheEntry, AnyError> {
match &task.contents_or_fd {
ContentsOrFd::Fd { dir, file } => 'brk: {
Expand Down Expand Up @@ -1539,7 +1548,7 @@ pub mod parse_worker {
fs_ref,
file_path.text,
contents_dir,
false,
bom_handling,
contents_file.unwrap_valid(),
read_arena,
) {
Expand Down Expand Up @@ -1649,7 +1658,13 @@ pub mod parse_worker {

if !might_have_on_parse_plugins {
return get_code_for_parse_task_without_plugins(
task, log, transpiler, resolver, bump, file_path, *loader,
task,
log,
transpiler,
resolver,
bump,
file_path,
bom_handling_for(*loader),
);
}

Expand All @@ -1667,6 +1682,7 @@ pub mod parse_worker {
should_continue_running: &should_continue_running,
result: core::ptr::null_mut(),
original_contents: None,
original_text: None,
};

// SAFETY: ctx backref is valid for the bundle pass (outlives `'r`).
Expand Down Expand Up @@ -1710,6 +1726,8 @@ pub mod parse_worker {
// the duration of `run`. Returned to the caller when the plugin keeps
// the original source, dropped otherwise.
original_contents: Option<crate::cache::Contents>,
// The text of `original_contents` that `fetch_source_code` gave the plugin, for a file from disk.
original_text: Option<crate::cache::Contents>,
}

#[repr(C)]
Expand Down Expand Up @@ -1979,7 +1997,8 @@ pub mod parse_worker {
this.resolver,
this.bump,
this.file_path,
result.loader,
// The bytes on disk: `run` returns them or the text.
Fs::BomHandling::Keep,
) {
Ok(e) => e,
Err(e) => {
Expand All @@ -1997,10 +2016,19 @@ pub mod parse_worker {
// plugin keeps the original source, or drops it when the plugin
// replaces the source.
let fd = entry.fd;
this.original_contents = Some(core::mem::take(&mut entry.contents));
let on_disk = core::mem::take(&mut entry.contents);
// A plugin reads text, whatever the loader. Only a file from disk (`Arena`) is decoded.
this.original_text = match on_disk {
crate::cache::Contents::Arena { ptr, len } => {
Some(crate::cache::Contents::Arena { ptr, len }.convert_bom(Some(this.bump)))
}
_ => None,
};
this.original_contents = Some(on_disk);
let contents_slice = this
.original_contents
.original_text
.as_ref()
.or(this.original_contents.as_ref())
.expect("just set")
.as_slice();
let source_ptr = contents_slice.as_ptr();
Expand Down Expand Up @@ -2219,9 +2247,15 @@ pub mod parse_worker {
// (if any) drops with `self`.
let contents =
if !wrapper.original_source.is_null() && ptr == wrapper.original_source {
self.original_contents
let on_disk = self
.original_contents
.take()
.expect("original_contents set alongside original_source")
.expect("original_contents set alongside original_source");
// `wrapper.loader` is the loader of the task, which the parse step uses.
match self.original_text.take() {
Some(text) if !wrapper.loader.should_copy_for_bundling() => text,
_ => on_disk,
}
} else {
crate::cache::Contents::External {
ptr,
Expand All @@ -2245,7 +2279,7 @@ pub mod parse_worker {
self.resolver,
self.bump,
self.file_path,
*self.loader,
bom_handling_for(*self.loader),
)
}
}
Expand Down
10 changes: 3 additions & 7 deletions src/bundler/transpiler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1362,7 +1362,7 @@ impl<'a> Transpiler<'a> {
self.fs_mut(),
path.text,
dirname_fd,
USE_SHARED_BUFFER,
Fs::BomHandling::Convert,
file_descriptor,
if USE_SHARED_BUFFER { None } else { Some(arena) },
) {
Expand All @@ -1384,11 +1384,7 @@ impl<'a> Transpiler<'a> {
*file_fd_ptr = entry.fd;
}
// `Source.contents: &'static [u8]` (the AST crate's `Str`
// convention). The bytes live either in the per-thread shared
// buffer (`USE_SHARED_BUFFER` → `Contents::SharedBuffer`, no-op
// drop) or in `this_parse.arena` (`Contents::Arena`, no-op drop —
// bulk-freed by `mi_heap_destroy` when the per-call arena is
// recycled). Thread the
// convention). The bytes live in `this_parse.arena`, or on the heap for `USE_SHARED_BUFFER`. Thread the
// provenance-tagged backing alongside the `ParseResult` so it
// drops when the result is recycled — no `mem::forget`
// (PORTING.md §Forbidden patterns).
Expand Down Expand Up @@ -3042,7 +3038,7 @@ impl<'a> Transpiler<'a> {
self.fs_mut(),
file_path_text,
dirname_fd,
false,
Fs::BomHandling::Convert,
None,
None,
) {
Expand Down
Loading
Loading