Skip to content

Commit ebd8fde

Browse files
Merge pull request #281 from Tcode-Motion/bolt-vm-preallocate-14489445380383539937
⚡ Bolt: Pre-allocate collections in VM executor
2 parents 1413aa7 + 2e55172 commit ebd8fde

6 files changed

Lines changed: 145 additions & 56 deletions

File tree

‎runtime/vm/src/executor.rs‎

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -488,7 +488,12 @@ impl VM {
488488

489489
Opcode::Call => {
490490
if let Some(Operand::Count(arg_count)) = inst_operands.first() {
491-
let mut args = Vec::new();
491+
// ⚡ Bolt Performance Optimization:
492+
// Pre-allocate the argument vector capacity up to the available stack size.
493+
// This avoids dynamic reallocation overhead in the hot VM loop while
494+
// preventing potential OOM panics from malformed bytecode with huge argument counts.
495+
let mut args =
496+
Vec::with_capacity((*arg_count as usize).min(self.stack.len()));
492497
for _ in 0..*arg_count {
493498
args.push(self.stack.pop()?);
494499
}
@@ -693,7 +698,11 @@ impl VM {
693698

694699
Opcode::MakeList => {
695700
if let Some(Operand::Count(n)) = inst_operands.first() {
696-
let mut items = Vec::new();
701+
// ⚡ Bolt Performance Optimization:
702+
// Pre-allocate the list capacity up to the available stack size.
703+
// This avoids dynamic reallocation overhead in the hot VM loop while
704+
// preventing potential OOM panics from malformed bytecode with huge item counts.
705+
let mut items = Vec::with_capacity((*n as usize).min(self.stack.len()));
697706
for _ in 0..*n {
698707
items.push(self.stack.pop()?);
699708
}
@@ -709,7 +718,14 @@ impl VM {
709718

710719
Opcode::MakeMap => {
711720
if let Some(Operand::Count(n)) = inst_operands.first() {
712-
let mut entries = indexmap::IndexMap::new();
721+
// ⚡ Bolt Performance Optimization:
722+
// Pre-allocate the map capacity up to half the available stack size
723+
// (since each entry consumes a key and a value on the stack).
724+
// This avoids dynamic reallocation overhead in the hot VM loop while
725+
// preventing potential OOM panics from malformed bytecode with huge item counts.
726+
let mut entries = indexmap::IndexMap::with_capacity(
727+
(*n as usize).min(self.stack.len() / 2),
728+
);
713729
for _ in 0..*n {
714730
let val = self.stack.pop()?;
715731
let key_val = self.stack.pop()?;

‎stdlib/src/net.rs‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1+
use crate::net_handler::{tcp_connect_fn, tcp_listen_fn, tcp_recv_fn, tcp_send_fn};
12
use crate::{StdFunction, StdlibModule, StdlibRegistry};
23
use std::collections::HashMap;
34
use std::rc::Rc;
45
use techscript_runtime::context::Capability;
5-
use crate::net_handler::{tcp_listen_fn, tcp_connect_fn, tcp_send_fn, tcp_recv_fn};
66

77
impl StdlibRegistry {
88
pub fn register_net(&mut self) {

‎stdlib/src/net_handler.rs‎

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -35,14 +35,13 @@ pub fn tcp_connect_fn(
3535
) -> Result<RuntimeValue, RuntimeError> {
3636
let ip = args[0].try_into_string()?;
3737
let port = args[1].try_into_int()?;
38-
let stream =
39-
std::net::TcpStream::connect(format!("{}:{}", ip, port)).map_err(|e| {
40-
RuntimeError::new(
41-
RuntimeErrorKind::InvalidOperation(format!("TCP connect error: {}", e)),
42-
None,
43-
None,
44-
)
45-
})?;
38+
let stream = std::net::TcpStream::connect(format!("{}:{}", ip, port)).map_err(|e| {
39+
RuntimeError::new(
40+
RuntimeErrorKind::InvalidOperation(format!("TCP connect error: {}", e)),
41+
None,
42+
None,
43+
)
44+
})?;
4645
let handle_id = ctx.resources.borrow_mut().insert(stream);
4746
let mut stream_map = IndexMap::new();
4847
stream_map.insert("ip".to_string(), RuntimeValue::Str(ip));

‎stdlib/src/strings.rs‎

Lines changed: 69 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,18 @@
11
use crate::{StdFunction, StdlibModule, StdlibRegistry};
22
use std::collections::HashMap;
33
use std::rc::Rc;
4-
use techscript_runtime::{error::RuntimeError, error::RuntimeErrorKind, value::RuntimeValue};
54
use techscript_runtime::RuntimeContext;
5+
use techscript_runtime::{error::RuntimeError, error::RuntimeErrorKind, value::RuntimeValue};
66

77
fn trim(_ctx: &mut RuntimeContext, args: Vec<RuntimeValue>) -> Result<RuntimeValue, RuntimeError> {
88
let s = args[0].try_into_string()?;
99
Ok(RuntimeValue::Str(s.trim().to_string()))
1010
}
1111

12-
fn replace(_ctx: &mut RuntimeContext, args: Vec<RuntimeValue>) -> Result<RuntimeValue, RuntimeError> {
12+
fn replace(
13+
_ctx: &mut RuntimeContext,
14+
args: Vec<RuntimeValue>,
15+
) -> Result<RuntimeValue, RuntimeError> {
1316
let source = args[0].try_into_string()?;
1417
let from = args[1].try_into_string()?;
1518
let to = args[2].try_into_string()?;
@@ -49,50 +52,77 @@ fn join(_ctx: &mut RuntimeContext, args: Vec<RuntimeValue>) -> Result<RuntimeVal
4952
}
5053
}
5154

52-
fn to_lower(_ctx: &mut RuntimeContext, args: Vec<RuntimeValue>) -> Result<RuntimeValue, RuntimeError> {
55+
fn to_lower(
56+
_ctx: &mut RuntimeContext,
57+
args: Vec<RuntimeValue>,
58+
) -> Result<RuntimeValue, RuntimeError> {
5359
let s = args[0].try_into_string()?;
5460
Ok(RuntimeValue::Str(s.to_lowercase()))
5561
}
5662

57-
fn to_upper(_ctx: &mut RuntimeContext, args: Vec<RuntimeValue>) -> Result<RuntimeValue, RuntimeError> {
63+
fn to_upper(
64+
_ctx: &mut RuntimeContext,
65+
args: Vec<RuntimeValue>,
66+
) -> Result<RuntimeValue, RuntimeError> {
5867
let s = args[0].try_into_string()?;
5968
Ok(RuntimeValue::Str(s.to_uppercase()))
6069
}
6170

62-
fn contains(_ctx: &mut RuntimeContext, args: Vec<RuntimeValue>) -> Result<RuntimeValue, RuntimeError> {
71+
fn contains(
72+
_ctx: &mut RuntimeContext,
73+
args: Vec<RuntimeValue>,
74+
) -> Result<RuntimeValue, RuntimeError> {
6375
let s = args[0].try_into_string()?;
6476
let sub = args[1].try_into_string()?;
6577
Ok(RuntimeValue::Bool(s.contains(&sub)))
6678
}
6779

68-
fn from_int(_ctx: &mut RuntimeContext, args: Vec<RuntimeValue>) -> Result<RuntimeValue, RuntimeError> {
80+
fn from_int(
81+
_ctx: &mut RuntimeContext,
82+
args: Vec<RuntimeValue>,
83+
) -> Result<RuntimeValue, RuntimeError> {
6984
let val = args[0].try_into_int()?;
7085
Ok(RuntimeValue::Str(val.to_string()))
7186
}
7287

73-
fn from_float(_ctx: &mut RuntimeContext, args: Vec<RuntimeValue>) -> Result<RuntimeValue, RuntimeError> {
88+
fn from_float(
89+
_ctx: &mut RuntimeContext,
90+
args: Vec<RuntimeValue>,
91+
) -> Result<RuntimeValue, RuntimeError> {
7492
let val = args[0].try_into_float()?;
7593
Ok(RuntimeValue::Str(val.to_string()))
7694
}
7795

78-
fn from_bool(_ctx: &mut RuntimeContext, args: Vec<RuntimeValue>) -> Result<RuntimeValue, RuntimeError> {
96+
fn from_bool(
97+
_ctx: &mut RuntimeContext,
98+
args: Vec<RuntimeValue>,
99+
) -> Result<RuntimeValue, RuntimeError> {
79100
let val = args[0].try_into_bool()?;
80101
Ok(RuntimeValue::Str(val.to_string()))
81102
}
82103

83-
fn trim(_ctx: &mut techscript_runtime::RuntimeContext, args: Vec<RuntimeValue>) -> Result<RuntimeValue, RuntimeError> {
104+
fn trim(
105+
_ctx: &mut techscript_runtime::RuntimeContext,
106+
args: Vec<RuntimeValue>,
107+
) -> Result<RuntimeValue, RuntimeError> {
84108
let s = args[0].try_into_string()?;
85109
Ok(RuntimeValue::Str(s.trim().to_string()))
86110
}
87111

88-
fn replace(_ctx: &mut techscript_runtime::RuntimeContext, args: Vec<RuntimeValue>) -> Result<RuntimeValue, RuntimeError> {
112+
fn replace(
113+
_ctx: &mut techscript_runtime::RuntimeContext,
114+
args: Vec<RuntimeValue>,
115+
) -> Result<RuntimeValue, RuntimeError> {
89116
let source = args[0].try_into_string()?;
90117
let from = args[1].try_into_string()?;
91118
let to = args[2].try_into_string()?;
92119
Ok(RuntimeValue::Str(source.replace(&from, &to)))
93120
}
94121

95-
fn split(_ctx: &mut techscript_runtime::RuntimeContext, args: Vec<RuntimeValue>) -> Result<RuntimeValue, RuntimeError> {
122+
fn split(
123+
_ctx: &mut techscript_runtime::RuntimeContext,
124+
args: Vec<RuntimeValue>,
125+
) -> Result<RuntimeValue, RuntimeError> {
96126
let s = args[0].try_into_string()?;
97127
let pat = args[1].try_into_string()?;
98128
let parts: Vec<RuntimeValue> = s
@@ -105,7 +135,10 @@ fn split(_ctx: &mut techscript_runtime::RuntimeContext, args: Vec<RuntimeValue>)
105135
})
106136
}
107137

108-
fn join(_ctx: &mut techscript_runtime::RuntimeContext, args: Vec<RuntimeValue>) -> Result<RuntimeValue, RuntimeError> {
138+
fn join(
139+
_ctx: &mut techscript_runtime::RuntimeContext,
140+
args: Vec<RuntimeValue>,
141+
) -> Result<RuntimeValue, RuntimeError> {
109142
let sep = args[1].try_into_string()?;
110143
if let RuntimeValue::List { items, .. } = &args[0] {
111144
let mut str_parts = Vec::new();
@@ -125,33 +158,51 @@ fn join(_ctx: &mut techscript_runtime::RuntimeContext, args: Vec<RuntimeValue>)
125158
}
126159
}
127160

128-
fn to_lower(_ctx: &mut techscript_runtime::RuntimeContext, args: Vec<RuntimeValue>) -> Result<RuntimeValue, RuntimeError> {
161+
fn to_lower(
162+
_ctx: &mut techscript_runtime::RuntimeContext,
163+
args: Vec<RuntimeValue>,
164+
) -> Result<RuntimeValue, RuntimeError> {
129165
let s = args[0].try_into_string()?;
130166
Ok(RuntimeValue::Str(s.to_lowercase()))
131167
}
132168

133-
fn to_upper(_ctx: &mut techscript_runtime::RuntimeContext, args: Vec<RuntimeValue>) -> Result<RuntimeValue, RuntimeError> {
169+
fn to_upper(
170+
_ctx: &mut techscript_runtime::RuntimeContext,
171+
args: Vec<RuntimeValue>,
172+
) -> Result<RuntimeValue, RuntimeError> {
134173
let s = args[0].try_into_string()?;
135174
Ok(RuntimeValue::Str(s.to_uppercase()))
136175
}
137176

138-
fn contains(_ctx: &mut techscript_runtime::RuntimeContext, args: Vec<RuntimeValue>) -> Result<RuntimeValue, RuntimeError> {
177+
fn contains(
178+
_ctx: &mut techscript_runtime::RuntimeContext,
179+
args: Vec<RuntimeValue>,
180+
) -> Result<RuntimeValue, RuntimeError> {
139181
let s = args[0].try_into_string()?;
140182
let sub = args[1].try_into_string()?;
141183
Ok(RuntimeValue::Bool(s.contains(&sub)))
142184
}
143185

144-
fn from_int(_ctx: &mut techscript_runtime::RuntimeContext, args: Vec<RuntimeValue>) -> Result<RuntimeValue, RuntimeError> {
186+
fn from_int(
187+
_ctx: &mut techscript_runtime::RuntimeContext,
188+
args: Vec<RuntimeValue>,
189+
) -> Result<RuntimeValue, RuntimeError> {
145190
let val = args[0].try_into_int()?;
146191
Ok(RuntimeValue::Str(val.to_string()))
147192
}
148193

149-
fn from_float(_ctx: &mut techscript_runtime::RuntimeContext, args: Vec<RuntimeValue>) -> Result<RuntimeValue, RuntimeError> {
194+
fn from_float(
195+
_ctx: &mut techscript_runtime::RuntimeContext,
196+
args: Vec<RuntimeValue>,
197+
) -> Result<RuntimeValue, RuntimeError> {
150198
let val = args[0].try_into_float()?;
151199
Ok(RuntimeValue::Str(val.to_string()))
152200
}
153201

154-
fn from_bool(_ctx: &mut techscript_runtime::RuntimeContext, args: Vec<RuntimeValue>) -> Result<RuntimeValue, RuntimeError> {
202+
fn from_bool(
203+
_ctx: &mut techscript_runtime::RuntimeContext,
204+
args: Vec<RuntimeValue>,
205+
) -> Result<RuntimeValue, RuntimeError> {
155206
let val = args[0].try_into_bool()?;
156207
Ok(RuntimeValue::Str(val.to_string()))
157208
}

‎stdlib/src/web.rs‎

Lines changed: 45 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -362,7 +362,10 @@ fn dsl_to_html_inner(val: &RuntimeValue, html: &mut String) {
362362
}
363363
}
364364

365-
fn web_start(ctx: &mut RuntimeContext, args: Vec<RuntimeValue>) -> Result<RuntimeValue, RuntimeError> {
365+
fn web_start(
366+
ctx: &mut RuntimeContext,
367+
args: Vec<RuntimeValue>,
368+
) -> Result<RuntimeValue, RuntimeError> {
366369
if !ctx.config.capabilities.contains(&Capability::Network) {
367370
return Err(RuntimeError::new(
368371
techscript_runtime::error::RuntimeErrorKind::InvalidOperation(
@@ -414,17 +417,26 @@ fn web_start(ctx: &mut RuntimeContext, args: Vec<RuntimeValue>) -> Result<Runtim
414417
}
415418
}
416419
});
417-
Ok(RuntimeValue::Str(format!("Server started on port {}", port)))
420+
Ok(RuntimeValue::Str(format!(
421+
"Server started on port {}",
422+
port
423+
)))
418424
}
419425

420-
fn web_page(_ctx: &mut RuntimeContext, args: Vec<RuntimeValue>) -> Result<RuntimeValue, RuntimeError> {
426+
fn web_page(
427+
_ctx: &mut RuntimeContext,
428+
args: Vec<RuntimeValue>,
429+
) -> Result<RuntimeValue, RuntimeError> {
421430
let _path = args[0].to_string();
422431
let content = args[1].to_string();
423432
*PAGE_CONTENT.lock().unwrap() = content;
424433
Ok(RuntimeValue::Null)
425434
}
426435

427-
fn web_serve(ctx: &mut RuntimeContext, args: Vec<RuntimeValue>) -> Result<RuntimeValue, RuntimeError> {
436+
fn web_serve(
437+
ctx: &mut RuntimeContext,
438+
args: Vec<RuntimeValue>,
439+
) -> Result<RuntimeValue, RuntimeError> {
428440
if !ctx.config.capabilities.contains(&Capability::Network) {
429441
return Err(RuntimeError::new(
430442
techscript_runtime::error::RuntimeErrorKind::InvalidOperation(
@@ -474,21 +486,33 @@ fn web_serve(ctx: &mut RuntimeContext, args: Vec<RuntimeValue>) -> Result<Runtim
474486
}
475487
}
476488
});
477-
Ok(RuntimeValue::Str(format!("Server started on port {}", port)))
489+
Ok(RuntimeValue::Str(format!(
490+
"Server started on port {}",
491+
port
492+
)))
478493
}
479494

480-
fn web_stop(_ctx: &mut RuntimeContext, _args: Vec<RuntimeValue>) -> Result<RuntimeValue, RuntimeError> {
495+
fn web_stop(
496+
_ctx: &mut RuntimeContext,
497+
_args: Vec<RuntimeValue>,
498+
) -> Result<RuntimeValue, RuntimeError> {
481499
SERVER_RUNNING.store(false, Ordering::SeqCst);
482500
Ok(RuntimeValue::Null)
483501
}
484502

485-
fn web_set_content(_ctx: &mut RuntimeContext, args: Vec<RuntimeValue>) -> Result<RuntimeValue, RuntimeError> {
503+
fn web_set_content(
504+
_ctx: &mut RuntimeContext,
505+
args: Vec<RuntimeValue>,
506+
) -> Result<RuntimeValue, RuntimeError> {
486507
let new_content = args[0].to_string();
487508
*PAGE_CONTENT.lock().unwrap() = new_content;
488509
Ok(RuntimeValue::Str("Content updated".to_string()))
489510
}
490511

491-
fn web_fetch(ctx: &mut RuntimeContext, args: Vec<RuntimeValue>) -> Result<RuntimeValue, RuntimeError> {
512+
fn web_fetch(
513+
ctx: &mut RuntimeContext,
514+
args: Vec<RuntimeValue>,
515+
) -> Result<RuntimeValue, RuntimeError> {
492516
if !ctx.config.capabilities.contains(&Capability::Network) {
493517
return Err(RuntimeError::new(
494518
techscript_runtime::error::RuntimeErrorKind::InvalidOperation(
@@ -510,35 +534,32 @@ fn web_fetch(ctx: &mut RuntimeContext, args: Vec<RuntimeValue>) -> Result<Runtim
510534
));
511535
}
512536

513-
let agent = ureq::builder()
514-
.resolver(SafeResolver)
515-
.redirects(0)
516-
.build();
517-
let body = agent.get(&url)
537+
let agent = ureq::builder().resolver(SafeResolver).redirects(0).build();
538+
let body = agent
539+
.get(&url)
518540
.call()
519541
.map_err(|e| {
520542
RuntimeError::new(
521-
techscript_runtime::error::RuntimeErrorKind::InvalidOperation(
522-
e.to_string(),
523-
),
543+
techscript_runtime::error::RuntimeErrorKind::InvalidOperation(e.to_string()),
524544
None,
525545
None,
526546
)
527547
})?
528548
.into_string()
529549
.map_err(|e| {
530550
RuntimeError::new(
531-
techscript_runtime::error::RuntimeErrorKind::InvalidOperation(
532-
e.to_string(),
533-
),
551+
techscript_runtime::error::RuntimeErrorKind::InvalidOperation(e.to_string()),
534552
None,
535553
None,
536554
)
537555
})?;
538556
Ok(RuntimeValue::Str(body))
539557
}
540558

541-
fn web_render_html(ctx: &mut RuntimeContext, _args: Vec<RuntimeValue>) -> Result<RuntimeValue, RuntimeError> {
559+
fn web_render_html(
560+
ctx: &mut RuntimeContext,
561+
_args: Vec<RuntimeValue>,
562+
) -> Result<RuntimeValue, RuntimeError> {
542563
let env = ctx.global_env.borrow();
543564
let blocks = match env.lookup("_dsl_blocks") {
544565
Ok(RuntimeValue::List { items, .. }) => items.borrow().clone(),
@@ -551,7 +572,10 @@ fn web_render_html(ctx: &mut RuntimeContext, _args: Vec<RuntimeValue>) -> Result
551572
Ok(RuntimeValue::Str(html))
552573
}
553574

554-
fn web_render_dsl(_ctx: &mut RuntimeContext, args: Vec<RuntimeValue>) -> Result<RuntimeValue, RuntimeError> {
575+
fn web_render_dsl(
576+
_ctx: &mut RuntimeContext,
577+
args: Vec<RuntimeValue>,
578+
) -> Result<RuntimeValue, RuntimeError> {
555579
let html = dsl_to_html(&args[0]);
556580
Ok(RuntimeValue::Str(html))
557581
}

0 commit comments

Comments
 (0)