Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(engine): GcScope #452

Merged
merged 2 commits into from
Nov 1, 2024
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
8 changes: 4 additions & 4 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -315,7 +315,7 @@ this is not a trivial piece of work. Right now calls in the engine look like
this:

```rs
fn call(agent: &mut Agent, value: Value) -> Value {
fn call(agent: &mut Agent, mut gc: Gc<'_, '_>, value: Value) -> Value {
// ...
}
```
Expand Down Expand Up @@ -372,7 +372,7 @@ this is called a reborrow and it's fine within a function but it cannot be done
intra-procedurally. What we could do is this:

```rs
fn call(agent: &mut Agent, value: Register<Value<'_>>) -> Register<Value<'_>> {
fn call(agent: &mut Agent, mut gc: Gc<'_, '_>, value: Register<Value<'_>>) -> Register<Value<'_>> {
// SAFETY: We've not called any methods that take `&mut Agent` before this.
// `Value` is thus still a valid reference.
let value = unsafe { value.bind(agent) };
Expand All @@ -391,10 +391,10 @@ But what about when we call some mutable function and need to keep a reference
to a stack value past that call? This is how that would look:

```rs
fn call(agent: &mut Agent, value: Register<Value<'_>>) -> JsResult<Register<Value<'_>>> {
fn call(agent: &mut Agent, mut gc: Gc<'_, '_>, value: Register<Value<'_>>) -> JsResult<Register<Value<'_>>> {
let value = unsafe { value.bind(agent) };
let kept_value: Global<Value<'static>> = value.make_global(value);
other_call(agent, value.into_register())?;
other_call(agent, gc.reborrow(), value.into_register())?;
let value = kept_value.take(agent);
// ...
}
Expand Down
23 changes: 19 additions & 4 deletions nova_cli/src/helper.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,21 +3,34 @@ use nova_vm::ecmascript::{
execution::{agent::ExceptionType, Agent, JsResult},
types::{InternalMethods, IntoValue, Object, PropertyDescriptor, PropertyKey, String, Value},
};
use nova_vm::engine::context::GcScope;
use oxc_diagnostics::OxcDiagnostic;

/// Initialize the global object with the built-in functions.
pub fn initialize_global_object(agent: &mut Agent, global: Object) {
pub fn initialize_global_object(agent: &mut Agent, mut gc: GcScope<'_, '_>, global: Object) {
// `print` function
fn print(agent: &mut Agent, _this: Value, args: ArgumentsList) -> JsResult<Value> {
fn print(
agent: &mut Agent,
gc: GcScope<'_, '_>,

_this: Value,
args: ArgumentsList,
) -> JsResult<Value> {
if args.len() == 0 {
println!();
} else {
println!("{}", args[0].to_string(agent)?.as_str(agent));
println!("{}", args[0].to_string(agent, gc)?.as_str(agent));
}
Ok(Value::Undefined)
}
// 'readTextFile' function
fn read_text_file(agent: &mut Agent, _: Value, args: ArgumentsList) -> JsResult<Value> {
fn read_text_file(
agent: &mut Agent,
_gc: GcScope<'_, '_>,

_: Value,
args: ArgumentsList,
) -> JsResult<Value> {
if args.len() != 1 {
return Err(agent
.throw_exception_with_static_message(ExceptionType::Error, "Expected 1 argument"));
Expand All @@ -42,6 +55,7 @@ pub fn initialize_global_object(agent: &mut Agent, global: Object) {
global
.internal_define_own_property(
agent,
gc.reborrow(),
property_key,
PropertyDescriptor {
value: Some(function.into_value()),
Expand All @@ -62,6 +76,7 @@ pub fn initialize_global_object(agent: &mut Agent, global: Object) {
global
.internal_define_own_property(
agent,
gc.reborrow(),
property_key,
PropertyDescriptor {
value: Some(function.into_value()),
Expand Down
105 changes: 59 additions & 46 deletions nova_cli/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,16 @@ use std::{cell::RefCell, collections::VecDeque, fmt::Debug};
use clap::{Parser as ClapParser, Subcommand};
use cliclack::{input, intro, set_theme};
use helper::{exit_with_parse_errors, initialize_global_object};
use nova_vm::ecmascript::{
execution::{
agent::{GcAgent, HostHooks, Job, Options},
Agent,
use nova_vm::{
ecmascript::{
execution::{
agent::{GcAgent, HostHooks, Job, Options},
Agent,
},
scripts_and_modules::script::{parse_script, script_evaluation},
types::{Object, String as JsString},
},
scripts_and_modules::script::{parse_script, script_evaluation},
types::{Object, String as JsString},
engine::context::GcScope,
};
use oxc_parser::Parser;
use oxc_semantic::{SemanticBuilder, SemanticBuilderReturn};
Expand Down Expand Up @@ -124,8 +127,8 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
host_hooks,
);
assert!(!paths.is_empty());
let create_global_object: Option<fn(&mut Agent) -> Object> = None;
let create_global_this_value: Option<fn(&mut Agent) -> Object> = None;
let create_global_object: Option<fn(&mut Agent, GcScope<'_, '_>) -> Object> = None;
let create_global_this_value: Option<fn(&mut Agent, GcScope<'_, '_>) -> Object> = None;
let realm = agent.create_realm(
create_global_object,
create_global_this_value,
Expand All @@ -138,45 +141,52 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
} else {
agent.gc();
}
agent.run_in_realm(&realm, |agent| -> Result<(), Box<dyn std::error::Error>> {
let realm = agent.current_realm_id();
let file = std::fs::read_to_string(&path)?;
let source_text = JsString::from_string(agent, file);
let script = match parse_script(agent, source_text, realm, !no_strict, None) {
Ok(script) => script,
Err(errors) => {
// Borrow the string data from the Agent
let source_text = source_text.as_str(agent);
exit_with_parse_errors(errors, &path, source_text)
}
};
let mut result = script_evaluation(agent, script);
agent.run_in_realm(
&realm,
|agent, mut gc| -> Result<(), Box<dyn std::error::Error>> {
let realm = agent.current_realm_id();
let file = std::fs::read_to_string(&path)?;
let source_text = JsString::from_string(agent, file);
let script = match parse_script(agent, source_text, realm, !no_strict, None)
{
Ok(script) => script,
Err(errors) => {
// Borrow the string data from the Agent
let source_text = source_text.as_str(agent);
exit_with_parse_errors(errors, &path, source_text)
}
};
let mut result = script_evaluation(agent, gc.reborrow(), script);

if result.is_ok() {
while let Some(job) = host_hooks.pop_promise_job() {
if let Err(err) = job.run(agent) {
result = Err(err);
break;
if result.is_ok() {
while let Some(job) = host_hooks.pop_promise_job() {
if let Err(err) = job.run(agent, gc.reborrow()) {
result = Err(err);
break;
}
}
}
}

match result {
Ok(result) => {
if verbose {
println!("{:?}", result);
match result {
Ok(result) => {
if verbose {
println!("{:?}", result);
}
}
Err(error) => {
eprintln!(
"Uncaught exception: {}",
error
.value()
.string_repr(agent, gc.reborrow(),)
.as_str(agent)
);
std::process::exit(1);
}
}
Err(error) => {
eprintln!(
"Uncaught exception: {}",
error.value().string_repr(agent).as_str(agent)
);
std::process::exit(1);
}
}
Ok(())
})?;
Ok(())
},
)?;
}
agent.remove_realm(realm);
}
Expand All @@ -189,8 +199,8 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
},
host_hooks,
);
let create_global_object: Option<fn(&mut Agent) -> Object> = None;
let create_global_this_value: Option<fn(&mut Agent) -> Object> = None;
let create_global_object: Option<fn(&mut Agent, GcScope<'_, '_>) -> Object> = None;
let create_global_this_value: Option<fn(&mut Agent, GcScope<'_, '_>) -> Object> = None;
let realm = agent.create_realm(
create_global_object,
create_global_this_value,
Expand All @@ -216,7 +226,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
continue;
}
placeholder = input.to_string();
agent.run_in_realm(&realm, |agent| {
agent.run_in_realm(&realm, |agent, mut gc| {
let realm = agent.current_realm_id();
let source_text = JsString::from_string(agent, input);
let script = match parse_script(agent, source_text, realm, true, None) {
Expand All @@ -225,15 +235,18 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
exit_with_parse_errors(errors, "<stdin>", &placeholder);
}
};
let result = script_evaluation(agent, script);
let result = script_evaluation(agent, gc.reborrow(), script);
match result {
Ok(result) => {
println!("{:?}\n", result);
}
Err(error) => {
eprintln!(
"Uncaught exception: {}",
error.value().string_repr(agent).as_str(agent)
error
.value()
.string_repr(agent, gc.reborrow(),)
.as_str(agent)
);
}
}
Expand Down
Loading