Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -347,8 +347,8 @@ pub(super) fn async_generator_yield(
// 3. Let generator be the value of the Generator component of genContext.
// 4. Assert: GetGeneratorKind() is async.
let generator_function = ECMAScriptFunction::try_from(gen_context.function.unwrap()).unwrap();
let func_data = &agent[generator_function];
assert!(func_data.ecmascript_function.is_async && func_data.ecmascript_function.is_generator);
let f = generator_function.get_ast(agent, gc.nogc());
assert!(f.is_async() && f.is_generator());
// 5. Let completion be NormalCompletion(value).
let completion = AsyncGeneratorRequestCompletion::Ok(value);
// 6. Assert: The execution context stack has at least two elements.
Expand Down
291 changes: 206 additions & 85 deletions nova_vm/src/ecmascript/builtins/ecmascript_function.rs

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ use crate::{
builders::builtin_function_builder::BuiltinFunctionBuilder,
builtins::{
ArgumentsList, Behaviour, Builtin, BuiltinIntrinsicConstructor, ECMAScriptFunction,
OrdinaryFunctionCreateParams, make_constructor,
FunctionAstRef, OrdinaryFunctionCreateParams, make_constructor,
ordinary::get_prototype_from_constructor, ordinary_function_create, set_function_name,
},
execution::{Agent, Environment, JsResult, ProtoIntrinsics, Realm, agent::ExceptionType},
Expand Down Expand Up @@ -306,11 +306,7 @@ pub(crate) fn create_dynamic_function<'a>(
// SAFETY: source_code was not shared.
source_code: Some(unsafe { source_code.take(agent) }),
source_text: function.span,
parameters_list: &function.params,
body: function.body.as_ref().unwrap(),
is_concise_arrow_function: false,
is_async: function.r#async,
is_generator: function.generator,
ast: FunctionAstRef::from(function),
lexical_this: false,
env: Environment::Global(
agent
Expand Down
8 changes: 1 addition & 7 deletions nova_vm/src/ecmascript/builtins/global_object.rs
Original file line number Diff line number Diff line change
Expand Up @@ -406,13 +406,7 @@ pub(crate) fn perform_eval<'gc>(
// 29. If result is a normal completion, then
match result {
Ok(_) => {
let source_code = agent
.running_execution_context()
.ecmascript_code
.as_ref()
.unwrap()
.source_code
.bind(gc.nogc());
let source_code = agent.current_source_code(gc.nogc());
let exe = Executable::compile_eval_body(agent, body, source_code, gc.nogc())
.scope(agent, gc.nogc());
// a. Set result to Completion(Evaluation of body).
Expand Down
188 changes: 115 additions & 73 deletions nova_vm/src/ecmascript/execution/agent.rs
Original file line number Diff line number Diff line change
Expand Up @@ -714,7 +714,9 @@ impl GcAgent {
.expect(error_message)
.take()
.expect(error_message);
while !self.realm_roots.is_empty() && self.realm_roots.last().unwrap().is_none() {
while let Some(r) = self.realm_roots.last()
&& r.is_none()
{
let _ = self.realm_roots.pop();
}
}
Expand Down Expand Up @@ -975,7 +977,10 @@ impl Agent {
/// Get current Realm's global environment.
pub fn current_global_env<'a>(&self, gc: NoGcScope<'a, '_>) -> GlobalEnvironment<'a> {
let realm = self.current_realm(gc);
self[realm].global_env.unwrap().bind(gc)
let Some(e) = self[realm].global_env.bind(gc) else {
panic_corrupted_agent()
};
e
}

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

/// Set the current executiono context's Realm.
pub(crate) fn set_current_realm(&mut self, realm: Realm) {
self.execution_context_stack.last_mut().unwrap().realm = realm.unbind();
let Some(ctx) = self.execution_context_stack.last_mut() else {
panic_corrupted_agent()
};
ctx.realm = realm.unbind();
}

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

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

pub(crate) fn running_execution_context(&self) -> &ExecutionContext {
self.execution_context_stack.last().unwrap()
let Some(ctx) = self.execution_context_stack.last() else {
panic_corrupted_agent()
};
ctx
}

pub(crate) fn is_evaluating_strict_code(&self) -> bool {
let Some(strict) = self
.running_execution_context()
.ecmascript_code
.map(|e| e.is_strict_mode)
else {
panic_corrupted_agent()
};
strict
}

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

pub(crate) fn current_source_code<'a>(&self, gc: NoGcScope<'a, '_>) -> SourceCode<'a> {
self.execution_context_stack
let Some(s) = self
.execution_context_stack
.last()
.unwrap()
.ecmascript_code
.as_ref()
.unwrap()
.source_code
.bind(gc)
.and_then(|s| s.ecmascript_code.as_ref())
.map(|e| e.source_code.bind(gc))
else {
panic_corrupted_agent()
};
s
}

/// Returns the running execution context's LexicalEnvironment.
pub(crate) fn current_lexical_environment<'a>(&self, gc: NoGcScope<'a, '_>) -> Environment<'a> {
self.execution_context_stack
let Some(e) = self
.execution_context_stack
.last()
.unwrap()
.ecmascript_code
.as_ref()
.unwrap()
.lexical_environment
.bind(gc)
.and_then(|s| s.ecmascript_code.as_ref())
.map(|e| e.lexical_environment.bind(gc))
else {
panic_corrupted_agent()
};
e
}

/// Returns the running execution context's VariableEnvironment.
pub(crate) fn current_variable_environment<'a>(
&self,
gc: NoGcScope<'a, '_>,
) -> Environment<'a> {
self.execution_context_stack
let Some(e) = self
.execution_context_stack
.last()
.unwrap()
.ecmascript_code
.as_ref()
.unwrap()
.variable_environment
.bind(gc)
.and_then(|s| s.ecmascript_code.as_ref())
.map(|e| e.variable_environment.bind(gc))
else {
panic_corrupted_agent()
};
e
}

/// Returns the running execution context's PrivateEnvironment.
pub(crate) fn current_private_environment<'a>(
&self,
gc: NoGcScope<'a, '_>,
) -> Option<PrivateEnvironment<'a>> {
self.execution_context_stack
let Some(e) = self
.execution_context_stack
.last()
.unwrap()
.ecmascript_code
.as_ref()
.unwrap()
.private_environment
.bind(gc)
.and_then(|s| s.ecmascript_code.as_ref())
.map(|e| e.private_environment.bind(gc))
else {
panic_corrupted_agent()
};
e
}

/// Sets the running execution context's LexicalEnvironment.
pub(crate) fn set_current_lexical_environment(&mut self, env: Environment) {
self.execution_context_stack
let Some(_) = self
.execution_context_stack
.last_mut()
.unwrap()
.ecmascript_code
.as_mut()
.unwrap()
.lexical_environment = env.unbind();
.and_then(|s| s.ecmascript_code.as_mut())
.map(|e| {
e.lexical_environment = env.unbind();
})
else {
panic_corrupted_agent()
};
}

/// Sets the running execution context's VariableEnvironment.
pub(crate) fn set_current_variable_environment(&mut self, env: Environment) {
self.execution_context_stack
let Some(_) = self
.execution_context_stack
.last_mut()
.unwrap()
.ecmascript_code
.as_mut()
.unwrap()
.variable_environment = env.unbind();
.and_then(|s| s.ecmascript_code.as_mut())
.map(|e| {
e.variable_environment = env.unbind();
})
else {
panic_corrupted_agent()
};
}

/// Sets the running execution context's PrivateEnvironment.
pub(crate) fn set_current_private_environment(&mut self, env: Option<PrivateEnvironment>) {
self.execution_context_stack
let Some(_) = self
.execution_context_stack
.last_mut()
.unwrap()
.ecmascript_code
.as_mut()
.unwrap()
.private_environment = env.unbind();
.and_then(|s| s.ecmascript_code.as_mut())
.map(|e| {
e.private_environment = env.unbind();
})
else {
panic_corrupted_agent()
};
}

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

/// Panics if no active function object exists.
pub(crate) fn active_function_object<'a>(&self, gc: NoGcScope<'a, '_>) -> Function<'a> {
self.execution_context_stack
let Some(f) = self
.execution_context_stack
.last()
.unwrap()
.function
.unwrap()
.bind(gc)
.and_then(|s| s.function.bind(gc))
else {
panic_corrupted_agent()
};
f
}

/// ### [9.4.1 GetActiveScriptOrModule ( )](https://tc39.es/ecma262/#sec-getactivescriptormodule)
Expand All @@ -1267,10 +1308,14 @@ impl Agent {
&self,
gc: NoGcScope<'a, '_>,
) -> Option<ScriptOrModule<'a>> {
self.execution_context_stack
.last()?
.script_or_module
.bind(gc)
let Some(s) = self
.execution_context_stack
.last()
.map(|s| s.script_or_module.bind(gc))
else {
panic_corrupted_agent()
};
s
}

/// Get access to the Host data, useful to share state between calls of built-in functions.
Expand Down Expand Up @@ -1354,12 +1399,11 @@ pub(crate) fn get_active_script_or_module<'a>(
if agent.execution_context_stack.is_empty() {
return None;
}
let ec = agent
agent
.execution_context_stack
.iter()
.rev()
.find(|context| context.script_or_module.is_some());
ec.map(|context| context.script_or_module.unwrap())
.find_map(|context| context.script_or_module)
}

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

// 3. Let strict be IsStrict(the syntactic production that is being evaluated).
let strict = agent
.running_execution_context()
.ecmascript_code
.unwrap()
.is_strict_mode;
let strict = agent.is_evaluating_strict_code();

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

// 3. Let strict be IsStrict(the syntactic production that is being evaluated).
let strict = agent
.running_execution_context()
.ecmascript_code
.unwrap()
.is_strict_mode;
let strict = agent.is_evaluating_strict_code();

// 4. Return ? GetIdentifierReference(env, name, strict).
get_identifier_reference(
Expand Down Expand Up @@ -1558,3 +1594,9 @@ impl HeapMarkAndSweep for Agent {
global_symbol_registry.sweep_values(compactions);
}
}

#[cold]
#[inline(never)]
fn panic_corrupted_agent() -> ! {
panic!("Agent is corrupted")
}
13 changes: 3 additions & 10 deletions nova_vm/src/ecmascript/execution/environments.rs
Original file line number Diff line number Diff line change
Expand Up @@ -563,12 +563,7 @@ impl<'e> Environment<'e> {
js_result_into_try(e.get_binding_value(agent, name, is_strict, gc))
}
Environment::Global(e) => e.try_get_binding_value(agent, name, cache, is_strict, gc),
Environment::Module(e) => {
let Some(value) = e.get_binding_value(agent, name, is_strict, gc) else {
return throw_uninitialized_binding(agent, name, gc).into();
};
TryResult::Continue(value)
}
Environment::Module(e) => e.try_get_binding_value(agent, name, is_strict, gc),
Environment::Object(e) => e.try_get_binding_value(agent, name, cache, is_strict, gc),
}
}
Expand Down Expand Up @@ -601,10 +596,8 @@ impl<'e> Environment<'e> {
Environment::Global(e) => e.get_binding_value(agent, name, is_strict, gc),
Environment::Module(e) => {
let gc = gc.into_nogc();
let Some(value) = e.bind(gc).get_binding_value(agent, name, is_strict, gc) else {
return Err(throw_uninitialized_binding(agent, name, gc));
};
Ok(value)
e.bind(gc)
.env_get_binding_value(agent, name, is_strict, gc.into_nogc())
}
Environment::Object(e) => e.get_binding_value(agent, name, is_strict, gc),
}
Expand Down
Loading