mirror of
https://github.com/danbulant/oxc
synced 2026-05-19 12:19:15 +00:00
perf(codegen): avoid a heap allocation when printing floats (#8807)
This commit is contained in:
parent
f8548ec9c7
commit
d8fac6d76b
3 changed files with 19 additions and 16 deletions
1
Cargo.lock
generated
1
Cargo.lock
generated
|
|
@ -1692,6 +1692,7 @@ dependencies = [
|
|||
"oxc_syntax",
|
||||
"pico-args",
|
||||
"rustc-hash",
|
||||
"ryu-js",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
|
|||
|
|
@ -27,13 +27,14 @@ oxc_index = { workspace = true }
|
|||
oxc_mangler = { workspace = true }
|
||||
oxc_sourcemap = { workspace = true }
|
||||
oxc_span = { workspace = true }
|
||||
oxc_syntax = { workspace = true, features = ["to_js_string"] }
|
||||
oxc_syntax = { workspace = true }
|
||||
|
||||
assert-unchecked = { workspace = true }
|
||||
bitflags = { workspace = true }
|
||||
cow-utils = { workspace = true }
|
||||
nonmax = { workspace = true }
|
||||
rustc-hash = { workspace = true }
|
||||
ryu-js = { workspace = true }
|
||||
|
||||
[dev-dependencies]
|
||||
base64 = { workspace = true }
|
||||
|
|
|
|||
|
|
@ -575,12 +575,13 @@ impl<'a> Codegen<'a> {
|
|||
}
|
||||
|
||||
fn print_non_negative_float(&mut self, num: f64) {
|
||||
use oxc_syntax::number::ToJsString;
|
||||
// Inline the buffer here to avoid heap allocation on `buffer.format(*self).to_string()`.
|
||||
let mut buffer = ryu_js::Buffer::new();
|
||||
if num < 1000.0 && num.fract() == 0.0 {
|
||||
self.print_str(&num.to_js_string());
|
||||
self.print_str(buffer.format(num));
|
||||
self.need_space_before_dot = self.code_len();
|
||||
} else {
|
||||
let s = Self::get_minified_number(num);
|
||||
let s = Self::get_minified_number(num, &mut buffer);
|
||||
self.print_str(&s);
|
||||
if !s.bytes().any(|b| matches!(b, b'.' | b'e' | b'x')) {
|
||||
self.need_space_before_dot = self.code_len();
|
||||
|
|
@ -691,25 +692,25 @@ impl<'a> Codegen<'a> {
|
|||
// `get_minified_number` from terser
|
||||
// https://github.com/terser/terser/blob/c5315c3fd6321d6b2e076af35a70ef532f498505/lib/output.js#L2418
|
||||
#[allow(clippy::cast_possible_truncation, clippy::cast_sign_loss, clippy::cast_possible_wrap)]
|
||||
fn get_minified_number(num: f64) -> String {
|
||||
fn get_minified_number(num: f64, buffer: &mut ryu_js::Buffer) -> Cow<'_, str> {
|
||||
use cow_utils::CowUtils;
|
||||
use oxc_syntax::number::ToJsString;
|
||||
|
||||
if num < 1000.0 && num.fract() == 0.0 {
|
||||
return num.to_js_string();
|
||||
return Cow::Borrowed(buffer.format(num));
|
||||
}
|
||||
|
||||
let mut s = num.to_js_string();
|
||||
let mut s = buffer.format(num);
|
||||
|
||||
if s.starts_with("0.") {
|
||||
s = s[1..].to_string();
|
||||
s = &s[1..];
|
||||
}
|
||||
|
||||
s = s.cow_replacen("e+", "e", 1).to_string();
|
||||
let s = s.cow_replacen("e+", "e", 1);
|
||||
|
||||
let mut candidates = vec![s.clone()];
|
||||
|
||||
if num.fract() == 0.0 {
|
||||
candidates.push(format!("0x{:x}", num as u128));
|
||||
candidates.push(Cow::Owned(format!("0x{:x}", num as u128)));
|
||||
}
|
||||
|
||||
// create `1e-2`
|
||||
|
|
@ -717,14 +718,14 @@ impl<'a> Codegen<'a> {
|
|||
if let Some((i, _)) = s[1..].bytes().enumerate().find(|(_, c)| *c != b'0') {
|
||||
let len = i + 1; // `+1` to include the dot.
|
||||
let digits = &s[len..];
|
||||
candidates.push(format!("{digits}e-{}", digits.len() + len - 1));
|
||||
candidates.push(Cow::Owned(format!("{digits}e-{}", digits.len() + len - 1)));
|
||||
}
|
||||
}
|
||||
|
||||
// create 1e2
|
||||
if s.ends_with('0') {
|
||||
if let Some((len, _)) = s.bytes().rev().enumerate().find(|(_, c)| *c != b'0') {
|
||||
candidates.push(format!("{}e{len}", &s[0..s.len() - len]));
|
||||
candidates.push(Cow::Owned(format!("{}e{len}", &s[0..s.len() - len])));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -733,13 +734,13 @@ impl<'a> Codegen<'a> {
|
|||
if let Some((integer, point, exponent)) =
|
||||
s.split_once('.').and_then(|(a, b)| b.split_once('e').map(|e| (a, e.0, e.1)))
|
||||
{
|
||||
candidates.push(format!(
|
||||
candidates.push(Cow::Owned(format!(
|
||||
"{integer}{point}e{}",
|
||||
exponent.parse::<isize>().unwrap() - point.len() as isize
|
||||
));
|
||||
)));
|
||||
}
|
||||
|
||||
candidates.into_iter().min_by_key(String::len).unwrap()
|
||||
candidates.into_iter().min_by_key(|c| c.len()).unwrap()
|
||||
}
|
||||
|
||||
fn add_source_mapping(&mut self, span: Span) {
|
||||
|
|
|
|||
Loading…
Reference in a new issue