Skip to content

Commit 2c0bbd7

Browse files
authored
perf(engine): Do not create an arguments object when it won't be accessed (#909)
1 parent aa6a62a commit 2c0bbd7

File tree

21 files changed

+542
-465
lines changed

21 files changed

+542
-465
lines changed

nova_vm/src/ecmascript/builtins/control_abstraction_objects/async_generator_objects/async_generator_abstract_operations.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -347,8 +347,8 @@ pub(super) fn async_generator_yield(
347347
// 3. Let generator be the value of the Generator component of genContext.
348348
// 4. Assert: GetGeneratorKind() is async.
349349
let generator_function = ECMAScriptFunction::try_from(gen_context.function.unwrap()).unwrap();
350-
let func_data = &agent[generator_function];
351-
assert!(func_data.ecmascript_function.is_async && func_data.ecmascript_function.is_generator);
350+
let f = generator_function.get_ast(agent, gc.nogc());
351+
assert!(f.is_async() && f.is_generator());
352352
// 5. Let completion be NormalCompletion(value).
353353
let completion = AsyncGeneratorRequestCompletion::Ok(value);
354354
// 6. Assert: The execution context stack has at least two elements.

nova_vm/src/ecmascript/builtins/ecmascript_function.rs

Lines changed: 206 additions & 85 deletions
Large diffs are not rendered by default.

nova_vm/src/ecmascript/builtins/fundamental_objects/function_objects/function_constructor.rs

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ use crate::{
1111
builders::builtin_function_builder::BuiltinFunctionBuilder,
1212
builtins::{
1313
ArgumentsList, Behaviour, Builtin, BuiltinIntrinsicConstructor, ECMAScriptFunction,
14-
OrdinaryFunctionCreateParams, make_constructor,
14+
FunctionAstRef, OrdinaryFunctionCreateParams, make_constructor,
1515
ordinary::get_prototype_from_constructor, ordinary_function_create, set_function_name,
1616
},
1717
execution::{Agent, Environment, JsResult, ProtoIntrinsics, Realm, agent::ExceptionType},
@@ -306,11 +306,7 @@ pub(crate) fn create_dynamic_function<'a>(
306306
// SAFETY: source_code was not shared.
307307
source_code: Some(unsafe { source_code.take(agent) }),
308308
source_text: function.span,
309-
parameters_list: &function.params,
310-
body: function.body.as_ref().unwrap(),
311-
is_concise_arrow_function: false,
312-
is_async: function.r#async,
313-
is_generator: function.generator,
309+
ast: FunctionAstRef::from(function),
314310
lexical_this: false,
315311
env: Environment::Global(
316312
agent

nova_vm/src/ecmascript/builtins/global_object.rs

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -406,13 +406,7 @@ pub(crate) fn perform_eval<'gc>(
406406
// 29. If result is a normal completion, then
407407
match result {
408408
Ok(_) => {
409-
let source_code = agent
410-
.running_execution_context()
411-
.ecmascript_code
412-
.as_ref()
413-
.unwrap()
414-
.source_code
415-
.bind(gc.nogc());
409+
let source_code = agent.current_source_code(gc.nogc());
416410
let exe = Executable::compile_eval_body(agent, body, source_code, gc.nogc())
417411
.scope(agent, gc.nogc());
418412
// a. Set result to Completion(Evaluation of body).

nova_vm/src/ecmascript/execution/agent.rs

Lines changed: 115 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -714,7 +714,9 @@ impl GcAgent {
714714
.expect(error_message)
715715
.take()
716716
.expect(error_message);
717-
while !self.realm_roots.is_empty() && self.realm_roots.last().unwrap().is_none() {
717+
while let Some(r) = self.realm_roots.last()
718+
&& r.is_none()
719+
{
718720
let _ = self.realm_roots.pop();
719721
}
720722
}
@@ -975,7 +977,10 @@ impl Agent {
975977
/// Get current Realm's global environment.
976978
pub fn current_global_env<'a>(&self, gc: NoGcScope<'a, '_>) -> GlobalEnvironment<'a> {
977979
let realm = self.current_realm(gc);
978-
self[realm].global_env.unwrap().bind(gc)
980+
let Some(e) = self[realm].global_env.bind(gc) else {
981+
panic_corrupted_agent()
982+
};
983+
e
979984
}
980985

981986
/// Get current Realm's global object.
@@ -991,12 +996,19 @@ impl Agent {
991996

992997
/// Set the current executiono context's Realm.
993998
pub(crate) fn set_current_realm(&mut self, realm: Realm) {
994-
self.execution_context_stack.last_mut().unwrap().realm = realm.unbind();
999+
let Some(ctx) = self.execution_context_stack.last_mut() else {
1000+
panic_corrupted_agent()
1001+
};
1002+
ctx.realm = realm.unbind();
9951003
}
9961004

9971005
/// Internal method to get current Realm's identifier without binding.
1006+
#[inline]
9981007
pub(crate) fn current_realm_id_internal(&self) -> Realm<'static> {
999-
self.execution_context_stack.last().unwrap().realm
1008+
let Some(r) = self.execution_context_stack.last().map(|ctx| ctx.realm) else {
1009+
panic_corrupted_agent()
1010+
};
1011+
r
10001012
}
10011013

10021014
pub(crate) fn current_realm_record(&self) -> &RealmRecord<'static> {
@@ -1091,7 +1103,21 @@ impl Agent {
10911103
}
10921104

10931105
pub(crate) fn running_execution_context(&self) -> &ExecutionContext {
1094-
self.execution_context_stack.last().unwrap()
1106+
let Some(ctx) = self.execution_context_stack.last() else {
1107+
panic_corrupted_agent()
1108+
};
1109+
ctx
1110+
}
1111+
1112+
pub(crate) fn is_evaluating_strict_code(&self) -> bool {
1113+
let Some(strict) = self
1114+
.running_execution_context()
1115+
.ecmascript_code
1116+
.map(|e| e.is_strict_mode)
1117+
else {
1118+
panic_corrupted_agent()
1119+
};
1120+
strict
10951121
}
10961122

10971123
pub(crate) fn check_call_depth<'gc>(&mut self, gc: NoGcScope<'gc, '_>) -> JsResult<'gc, ()> {
@@ -1131,89 +1157,102 @@ impl Agent {
11311157
}
11321158

11331159
pub(crate) fn current_source_code<'a>(&self, gc: NoGcScope<'a, '_>) -> SourceCode<'a> {
1134-
self.execution_context_stack
1160+
let Some(s) = self
1161+
.execution_context_stack
11351162
.last()
1136-
.unwrap()
1137-
.ecmascript_code
1138-
.as_ref()
1139-
.unwrap()
1140-
.source_code
1141-
.bind(gc)
1163+
.and_then(|s| s.ecmascript_code.as_ref())
1164+
.map(|e| e.source_code.bind(gc))
1165+
else {
1166+
panic_corrupted_agent()
1167+
};
1168+
s
11421169
}
11431170

11441171
/// Returns the running execution context's LexicalEnvironment.
11451172
pub(crate) fn current_lexical_environment<'a>(&self, gc: NoGcScope<'a, '_>) -> Environment<'a> {
1146-
self.execution_context_stack
1173+
let Some(e) = self
1174+
.execution_context_stack
11471175
.last()
1148-
.unwrap()
1149-
.ecmascript_code
1150-
.as_ref()
1151-
.unwrap()
1152-
.lexical_environment
1153-
.bind(gc)
1176+
.and_then(|s| s.ecmascript_code.as_ref())
1177+
.map(|e| e.lexical_environment.bind(gc))
1178+
else {
1179+
panic_corrupted_agent()
1180+
};
1181+
e
11541182
}
11551183

11561184
/// Returns the running execution context's VariableEnvironment.
11571185
pub(crate) fn current_variable_environment<'a>(
11581186
&self,
11591187
gc: NoGcScope<'a, '_>,
11601188
) -> Environment<'a> {
1161-
self.execution_context_stack
1189+
let Some(e) = self
1190+
.execution_context_stack
11621191
.last()
1163-
.unwrap()
1164-
.ecmascript_code
1165-
.as_ref()
1166-
.unwrap()
1167-
.variable_environment
1168-
.bind(gc)
1192+
.and_then(|s| s.ecmascript_code.as_ref())
1193+
.map(|e| e.variable_environment.bind(gc))
1194+
else {
1195+
panic_corrupted_agent()
1196+
};
1197+
e
11691198
}
11701199

11711200
/// Returns the running execution context's PrivateEnvironment.
11721201
pub(crate) fn current_private_environment<'a>(
11731202
&self,
11741203
gc: NoGcScope<'a, '_>,
11751204
) -> Option<PrivateEnvironment<'a>> {
1176-
self.execution_context_stack
1205+
let Some(e) = self
1206+
.execution_context_stack
11771207
.last()
1178-
.unwrap()
1179-
.ecmascript_code
1180-
.as_ref()
1181-
.unwrap()
1182-
.private_environment
1183-
.bind(gc)
1208+
.and_then(|s| s.ecmascript_code.as_ref())
1209+
.map(|e| e.private_environment.bind(gc))
1210+
else {
1211+
panic_corrupted_agent()
1212+
};
1213+
e
11841214
}
11851215

11861216
/// Sets the running execution context's LexicalEnvironment.
11871217
pub(crate) fn set_current_lexical_environment(&mut self, env: Environment) {
1188-
self.execution_context_stack
1218+
let Some(_) = self
1219+
.execution_context_stack
11891220
.last_mut()
1190-
.unwrap()
1191-
.ecmascript_code
1192-
.as_mut()
1193-
.unwrap()
1194-
.lexical_environment = env.unbind();
1221+
.and_then(|s| s.ecmascript_code.as_mut())
1222+
.map(|e| {
1223+
e.lexical_environment = env.unbind();
1224+
})
1225+
else {
1226+
panic_corrupted_agent()
1227+
};
11951228
}
11961229

11971230
/// Sets the running execution context's VariableEnvironment.
11981231
pub(crate) fn set_current_variable_environment(&mut self, env: Environment) {
1199-
self.execution_context_stack
1232+
let Some(_) = self
1233+
.execution_context_stack
12001234
.last_mut()
1201-
.unwrap()
1202-
.ecmascript_code
1203-
.as_mut()
1204-
.unwrap()
1205-
.variable_environment = env.unbind();
1235+
.and_then(|s| s.ecmascript_code.as_mut())
1236+
.map(|e| {
1237+
e.variable_environment = env.unbind();
1238+
})
1239+
else {
1240+
panic_corrupted_agent()
1241+
};
12061242
}
12071243

12081244
/// Sets the running execution context's PrivateEnvironment.
12091245
pub(crate) fn set_current_private_environment(&mut self, env: Option<PrivateEnvironment>) {
1210-
self.execution_context_stack
1246+
let Some(_) = self
1247+
.execution_context_stack
12111248
.last_mut()
1212-
.unwrap()
1213-
.ecmascript_code
1214-
.as_mut()
1215-
.unwrap()
1216-
.private_environment = env.unbind();
1249+
.and_then(|s| s.ecmascript_code.as_mut())
1250+
.map(|e| {
1251+
e.private_environment = env.unbind();
1252+
})
1253+
else {
1254+
panic_corrupted_agent()
1255+
};
12171256
}
12181257

12191258
/// Allocates a range of PrivateName identifiers and returns the first in
@@ -1249,12 +1288,14 @@ impl Agent {
12491288

12501289
/// Panics if no active function object exists.
12511290
pub(crate) fn active_function_object<'a>(&self, gc: NoGcScope<'a, '_>) -> Function<'a> {
1252-
self.execution_context_stack
1291+
let Some(f) = self
1292+
.execution_context_stack
12531293
.last()
1254-
.unwrap()
1255-
.function
1256-
.unwrap()
1257-
.bind(gc)
1294+
.and_then(|s| s.function.bind(gc))
1295+
else {
1296+
panic_corrupted_agent()
1297+
};
1298+
f
12581299
}
12591300

12601301
/// ### [9.4.1 GetActiveScriptOrModule ( )](https://tc39.es/ecma262/#sec-getactivescriptormodule)
@@ -1267,10 +1308,14 @@ impl Agent {
12671308
&self,
12681309
gc: NoGcScope<'a, '_>,
12691310
) -> Option<ScriptOrModule<'a>> {
1270-
self.execution_context_stack
1271-
.last()?
1272-
.script_or_module
1273-
.bind(gc)
1311+
let Some(s) = self
1312+
.execution_context_stack
1313+
.last()
1314+
.map(|s| s.script_or_module.bind(gc))
1315+
else {
1316+
panic_corrupted_agent()
1317+
};
1318+
s
12741319
}
12751320

12761321
/// Get access to the Host data, useful to share state between calls of built-in functions.
@@ -1354,12 +1399,11 @@ pub(crate) fn get_active_script_or_module<'a>(
13541399
if agent.execution_context_stack.is_empty() {
13551400
return None;
13561401
}
1357-
let ec = agent
1402+
agent
13581403
.execution_context_stack
13591404
.iter()
13601405
.rev()
1361-
.find(|context| context.script_or_module.is_some());
1362-
ec.map(|context| context.script_or_module.unwrap())
1406+
.find_map(|context| context.script_or_module)
13631407
}
13641408

13651409
/// ### Try [9.4.2 ResolveBinding ( name \[ , env \] )](https://tc39.es/ecma262/#sec-resolvebinding)
@@ -1384,11 +1428,7 @@ pub(crate) fn try_resolve_binding<'a>(
13841428
// Implicit from env's type.
13851429

13861430
// 3. Let strict be IsStrict(the syntactic production that is being evaluated).
1387-
let strict = agent
1388-
.running_execution_context()
1389-
.ecmascript_code
1390-
.unwrap()
1391-
.is_strict_mode;
1431+
let strict = agent.is_evaluating_strict_code();
13921432

13931433
// 4. Return ? GetIdentifierReference(env, name, strict).
13941434
try_get_identifier_reference(agent, env, name, cache, strict, gc)
@@ -1423,11 +1463,7 @@ pub(crate) fn resolve_binding<'a, 'b>(
14231463
// Implicit from env's type.
14241464

14251465
// 3. Let strict be IsStrict(the syntactic production that is being evaluated).
1426-
let strict = agent
1427-
.running_execution_context()
1428-
.ecmascript_code
1429-
.unwrap()
1430-
.is_strict_mode;
1466+
let strict = agent.is_evaluating_strict_code();
14311467

14321468
// 4. Return ? GetIdentifierReference(env, name, strict).
14331469
get_identifier_reference(
@@ -1558,3 +1594,9 @@ impl HeapMarkAndSweep for Agent {
15581594
global_symbol_registry.sweep_values(compactions);
15591595
}
15601596
}
1597+
1598+
#[cold]
1599+
#[inline(never)]
1600+
fn panic_corrupted_agent() -> ! {
1601+
panic!("Agent is corrupted")
1602+
}

nova_vm/src/ecmascript/execution/environments.rs

Lines changed: 3 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -563,12 +563,7 @@ impl<'e> Environment<'e> {
563563
js_result_into_try(e.get_binding_value(agent, name, is_strict, gc))
564564
}
565565
Environment::Global(e) => e.try_get_binding_value(agent, name, cache, is_strict, gc),
566-
Environment::Module(e) => {
567-
let Some(value) = e.get_binding_value(agent, name, is_strict, gc) else {
568-
return throw_uninitialized_binding(agent, name, gc).into();
569-
};
570-
TryResult::Continue(value)
571-
}
566+
Environment::Module(e) => e.try_get_binding_value(agent, name, is_strict, gc),
572567
Environment::Object(e) => e.try_get_binding_value(agent, name, cache, is_strict, gc),
573568
}
574569
}
@@ -601,10 +596,8 @@ impl<'e> Environment<'e> {
601596
Environment::Global(e) => e.get_binding_value(agent, name, is_strict, gc),
602597
Environment::Module(e) => {
603598
let gc = gc.into_nogc();
604-
let Some(value) = e.bind(gc).get_binding_value(agent, name, is_strict, gc) else {
605-
return Err(throw_uninitialized_binding(agent, name, gc));
606-
};
607-
Ok(value)
599+
e.bind(gc)
600+
.env_get_binding_value(agent, name, is_strict, gc.into_nogc())
608601
}
609602
Environment::Object(e) => e.get_binding_value(agent, name, is_strict, gc),
610603
}

0 commit comments

Comments
 (0)