Skip to content

Commit 9057f6b

Browse files
committed
perf(allocator): make String non-drop
1 parent 01a5e5d commit 9057f6b

File tree

1 file changed

+16
-9
lines changed

1 file changed

+16
-9
lines changed

crates/oxc_allocator/src/string.rs

+16-9
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,15 @@ use crate::{Allocator, Vec};
2222
///
2323
/// UTF-8 encoded, growable string. Identical to [`std::string::String`] except that it stores
2424
/// string contents in arena allocator.
25+
//
26+
// We wrap the inner `BumpaloString` in `ManuallyDrop` to make `String` non-Drop.
27+
// `bumpalo::collections::String` is a wrapper around `bumpalo::collections::Vec<u8>`.
28+
// Even though a `Vec<u8>` cannot require dropping (because `u8` is not `Drop`), `Vec<u8>` still has
29+
// a `Drop` impl, which means `bumpalo::collections::String` is `Drop` too.
30+
// We want to make it clear to compiler that `String` doesn't require dropping, so it doesn't
31+
// produce pointless "drop guard" code to handle dropping a `String` in case of a panic.
2532
#[derive(PartialOrd, Eq, Ord)]
26-
pub struct String<'alloc>(BumpaloString<'alloc>);
33+
pub struct String<'alloc>(ManuallyDrop<BumpaloString<'alloc>>);
2734

2835
impl<'alloc> String<'alloc> {
2936
/// Creates a new empty [`String`].
@@ -38,7 +45,7 @@ impl<'alloc> String<'alloc> {
3845
/// [`with_capacity_in`]: String::with_capacity_in
3946
#[inline(always)]
4047
pub fn new_in(allocator: &'alloc Allocator) -> String<'alloc> {
41-
Self(BumpaloString::new_in(allocator.bump()))
48+
Self(ManuallyDrop::new(BumpaloString::new_in(allocator.bump())))
4249
}
4350

4451
/// Creates a new empty [`String`] with specified capacity.
@@ -57,7 +64,7 @@ impl<'alloc> String<'alloc> {
5764
/// [`new_in`]: String::new_in
5865
#[inline(always)]
5966
pub fn with_capacity_in(capacity: usize, allocator: &'alloc Allocator) -> String<'alloc> {
60-
Self(BumpaloString::with_capacity_in(capacity, allocator.bump()))
67+
Self(ManuallyDrop::new(BumpaloString::with_capacity_in(capacity, allocator.bump())))
6168
}
6269

6370
/// Construct a new [`String`] from a string slice.
@@ -73,7 +80,7 @@ impl<'alloc> String<'alloc> {
7380
/// ```
7481
#[inline(always)]
7582
pub fn from_str_in(s: &str, allocator: &'alloc Allocator) -> String<'alloc> {
76-
Self(BumpaloString::from_str_in(s, allocator.bump()))
83+
Self(ManuallyDrop::new(BumpaloString::from_str_in(s, allocator.bump())))
7784
}
7885

7986
/// Convert `Vec<u8>` into [`String`].
@@ -105,7 +112,7 @@ impl<'alloc> String<'alloc> {
105112
// Lifetime of returned `String` is same as lifetime of original `Vec<u8>`.
106113
let inner = ManuallyDrop::into_inner(bytes.0);
107114
let (ptr, len, capacity, bump) = inner.into_raw_parts_with_alloc();
108-
Self(BumpaloString::from_raw_parts_in(ptr, len, capacity, bump))
115+
Self(ManuallyDrop::new(BumpaloString::from_raw_parts_in(ptr, len, capacity, bump)))
109116
}
110117

111118
/// Creates a new [`String`] from a length, capacity, and pointer.
@@ -137,8 +144,6 @@ impl<'alloc> String<'alloc> {
137144
/// let len = s.len();
138145
/// let capacity = s.capacity();
139146
///
140-
/// mem::forget(s);
141-
///
142147
/// let s = String::from_raw_parts_in(ptr, len, capacity, &allocator);
143148
///
144149
/// assert_eq!(s, "hello");
@@ -153,7 +158,8 @@ impl<'alloc> String<'alloc> {
153158
allocator: &'alloc Allocator,
154159
) -> String<'alloc> {
155160
// SAFETY: Safety conditions of this method are the same as `BumpaloString`'s method
156-
Self(BumpaloString::from_raw_parts_in(buf, length, capacity, allocator.bump()))
161+
let inner = BumpaloString::from_raw_parts_in(buf, length, capacity, allocator.bump());
162+
Self(ManuallyDrop::new(inner))
157163
}
158164

159165
/// Convert this `String<'alloc>` into an `&'alloc str`. This is analogous to
@@ -170,7 +176,8 @@ impl<'alloc> String<'alloc> {
170176
/// ```
171177
#[inline(always)]
172178
pub fn into_bump_str(self) -> &'alloc str {
173-
self.0.into_bump_str()
179+
let inner = ManuallyDrop::into_inner(self.0);
180+
inner.into_bump_str()
174181
}
175182
}
176183

0 commit comments

Comments
 (0)