mirror of
https://github.com/aljazceru/turso.git
synced 2026-02-21 07:55:18 +01:00
Merge 'parser: use YYSTACKDEPTH' from Lâm Hoàng Phúc
sqlite uses [fixed-size](https://github.com/sqlite/sqlite/blob/7fc6e6a27 26e650d3b82c6d3683bdbdc10e02467/tool/lempar.c#L238) array for `yystack` and grow stack if needed. Let replace `vec` with `smallvec` in rust version. after: ```sh sqlparser-rs parsing benchmark/sqlparser::select time: [564.19 ns 565.63 ns 567.18 ns] change: [-11.514% -11.288% -11.067%] (p = 0.00 < 0.05) Performance has improved. Found 4 outliers among 100 measurements (4.00%) 1 (1.00%) low mild 3 (3.00%) high mild sqlparser-rs parsing benchmark/sqlparser::with_select time: [1.9812 µs 1.9861 µs 1.9914 µs] change: [-7.5226% -7.3080% -7.0858%] (p = 0.00 < 0.05) Performance has improved. Found 5 outliers among 100 measurements (5.00%) 1 (1.00%) low mild 4 (4.00%) high mild ``` Reviewed-by: Jussi Saurio <jussi.saurio@gmail.com> Closes #1999
This commit is contained in:
5
Cargo.lock
generated
5
Cargo.lock
generated
@@ -3257,9 +3257,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "smallvec"
|
||||
version = "1.14.0"
|
||||
version = "1.15.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7fcf8323ef1faaee30a44a340193b1ac6814fd9b7b4e88e9d4519a3e4abe1cfd"
|
||||
checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03"
|
||||
|
||||
[[package]]
|
||||
name = "socket2"
|
||||
@@ -3917,6 +3917,7 @@ dependencies = [
|
||||
"memchr",
|
||||
"miette",
|
||||
"serde",
|
||||
"smallvec",
|
||||
"strum",
|
||||
"strum_macros",
|
||||
]
|
||||
|
||||
@@ -34,6 +34,7 @@ miette = "7.4.0"
|
||||
strum = { workspace = true }
|
||||
strum_macros = {workspace = true }
|
||||
serde = { workspace = true , optional = true, features = ["derive"] }
|
||||
smallvec = { version = "1.15.1", features = ["const_generics"] }
|
||||
|
||||
[dev-dependencies]
|
||||
env_logger = { version = "0.11", default-features = false }
|
||||
|
||||
@@ -4519,7 +4519,8 @@ void ReportTable(
|
||||
if( lemp->stacksize ){
|
||||
fprintf(out,"const YYSTACKDEPTH: usize = %s;\n",lemp->stacksize); lineno++;
|
||||
} else {
|
||||
fprintf(out, "const YYSTACKDEPTH: usize = 128;\n"); lineno++;
|
||||
// from sqlite: The default value is 100. A typical application will use less than about 20 levels of the stack. Developers whose applications contain SQL statements that need more than 100 LALR(1) stack entries should seriously consider refactoring their SQL as it is likely to be well beyond the ability of any human to comprehend.
|
||||
fprintf(out, "const YYSTACKDEPTH: usize = 100;\n"); lineno++;
|
||||
}
|
||||
if( lemp->errsym && lemp->errsym->useCnt ){
|
||||
fprintf(out,"const YYERRORSYMBOL: YYCODETYPE = %d;\n",lemp->errsym->index); lineno++;
|
||||
|
||||
@@ -184,12 +184,13 @@ pub struct yyParser<'input> {
|
||||
//#[cfg(not(feature = "YYNOERRORRECOVERY"))]
|
||||
yyerrcnt: i32, /* Shifts left before out of the error */
|
||||
%% /* A place to hold %extra_context */
|
||||
yystack: Vec<yyStackEntry<'input>>, /* The parser's stack */
|
||||
yystack: smallvec::SmallVec<[yyStackEntry<'input>; YYSTACKDEPTH]>, /* The parser's stack */
|
||||
}
|
||||
|
||||
use std::cmp::Ordering;
|
||||
use std::ops::Neg;
|
||||
impl<'input> yyParser<'input> {
|
||||
#[inline]
|
||||
fn shift(&self, shift: i8) -> usize {
|
||||
assert!(shift <= 1);
|
||||
match shift.cmp(&0) {
|
||||
@@ -199,6 +200,7 @@ impl<'input> yyParser<'input> {
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn yyidx_shift(&mut self, shift: i8) {
|
||||
match shift.cmp(&0) {
|
||||
Ordering::Greater => self.yyidx += shift as usize,
|
||||
@@ -207,12 +209,17 @@ impl<'input> yyParser<'input> {
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn yy_move(&mut self, shift: i8) -> yyStackEntry<'input> {
|
||||
use std::mem::take;
|
||||
let idx = self.shift(shift);
|
||||
take(&mut self.yystack[idx])
|
||||
|
||||
// TODO: The compiler optimizes `std::mem::take` to two `memcpy`
|
||||
// but `yyStackEntry` requires 168 bytes, so it is not worth it (maybe).
|
||||
assert_eq!(std::mem::size_of::<yyStackEntry>(), 168);
|
||||
std::mem::take(&mut self.yystack[idx])
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn push(&mut self, entry: yyStackEntry<'input>) {
|
||||
if self.yyidx == self.yystack.len() {
|
||||
self.yystack.push(entry);
|
||||
@@ -226,12 +233,14 @@ use std::ops::{Index, IndexMut};
|
||||
impl<'input> Index<i8> for yyParser<'input> {
|
||||
type Output = yyStackEntry<'input>;
|
||||
|
||||
#[inline]
|
||||
fn index(&self, shift: i8) -> &yyStackEntry<'input> {
|
||||
let idx = self.shift(shift);
|
||||
&self.yystack[idx]
|
||||
}
|
||||
}
|
||||
impl<'input> IndexMut<i8> for yyParser<'input> {
|
||||
#[inline]
|
||||
fn index_mut(&mut self, shift: i8) -> &mut yyStackEntry<'input> {
|
||||
let idx = self.shift(shift);
|
||||
&mut self.yystack[idx]
|
||||
@@ -261,9 +270,11 @@ static yyRuleName: [&str; YYNRULE] = [
|
||||
** of errors. Return 0 on success.
|
||||
*/
|
||||
impl yyParser<'_> {
|
||||
#[inline]
|
||||
fn yy_grow_stack_if_needed(&mut self) -> bool {
|
||||
false
|
||||
}
|
||||
#[inline]
|
||||
fn yy_grow_stack_for_push(&mut self) -> bool {
|
||||
// yystack is not prefilled with zero value like in C.
|
||||
if self.yyidx == self.yystack.len() {
|
||||
@@ -281,17 +292,15 @@ impl yyParser<'_> {
|
||||
pub fn new(
|
||||
%% /* Optional %extra_context parameter */
|
||||
) -> yyParser {
|
||||
let mut p = yyParser {
|
||||
yyParser {
|
||||
yyidx: 0,
|
||||
#[cfg(feature = "YYTRACKMAXSTACKDEPTH")]
|
||||
yyhwm: 0,
|
||||
yystack: Vec::with_capacity(YYSTACKDEPTH),
|
||||
yystack: smallvec::smallvec![yyStackEntry::default()],
|
||||
//#[cfg(not(feature = "YYNOERRORRECOVERY"))]
|
||||
yyerrcnt: -1,
|
||||
%% /* Optional %extra_context store */
|
||||
};
|
||||
p.push(yyStackEntry::default());
|
||||
p
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -299,6 +308,7 @@ impl yyParser<'_> {
|
||||
** Pop the parser's stack once.
|
||||
*/
|
||||
impl yyParser<'_> {
|
||||
#[inline]
|
||||
fn yy_pop_parser_stack(&mut self) {
|
||||
use std::mem::take;
|
||||
let _yytos = take(&mut self.yystack[self.yyidx]);
|
||||
@@ -319,6 +329,7 @@ impl yyParser<'_> {
|
||||
*/
|
||||
impl yyParser<'_> {
|
||||
#[expect(non_snake_case)]
|
||||
#[inline]
|
||||
pub fn ParseFinalize(&mut self) {
|
||||
while self.yyidx > 0 {
|
||||
self.yy_pop_parser_stack();
|
||||
@@ -333,9 +344,11 @@ impl yyParser<'_> {
|
||||
#[cfg(feature = "YYTRACKMAXSTACKDEPTH")]
|
||||
impl yyParser<'_> {
|
||||
#[expect(non_snake_case)]
|
||||
#[inline]
|
||||
pub fn ParseStackPeak(&self) -> usize {
|
||||
self.yyhwm
|
||||
}
|
||||
#[inline]
|
||||
fn yyhwm_incr(&mut self) {
|
||||
if self.yyidx > self.yyhwm {
|
||||
self.yyhwm += 1;
|
||||
@@ -488,6 +501,7 @@ fn yy_find_reduce_action(
|
||||
impl yyParser<'_> {
|
||||
#[expect(non_snake_case)]
|
||||
#[cfg(feature = "NDEBUG")]
|
||||
#[inline]
|
||||
fn yyTraceShift(&self, _: YYACTIONTYPE, _: &str) {
|
||||
}
|
||||
#[expect(non_snake_case)]
|
||||
@@ -893,6 +907,7 @@ impl<'input> yyParser<'input> {
|
||||
** Return the fallback token corresponding to canonical token iToken, or
|
||||
** 0 if iToken has no fallback.
|
||||
*/
|
||||
#[inline]
|
||||
pub fn parse_fallback(i_token: YYCODETYPE) -> YYCODETYPE {
|
||||
if YYFALLBACK {
|
||||
return yyFallback[i_token as usize];
|
||||
|
||||
Reference in New Issue
Block a user