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

perf(cli): faster standalone executable determination #22717

Merged
merged 1 commit into from
Mar 5, 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
20 changes: 11 additions & 9 deletions cli/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -322,16 +322,18 @@ pub fn main() {
// initialize the V8 platform on a parent thread of all threads that will spawn
// V8 isolates.

let current_exe_path = current_exe().unwrap();
let standalone =
standalone::extract_standalone(&current_exe_path, args.clone());
let future = async move {
let current_exe_path = current_exe()?;
let standalone_res =
match standalone::extract_standalone(&current_exe_path, args.clone())
.await
{
Ok(Some((metadata, eszip))) => standalone::run(eszip, metadata).await,
Ok(None) => Ok(()),
Err(err) => Err(err),
};
let standalone_res = match standalone {
Ok(Some(future)) => {
let (metadata, eszip) = future.await?;
standalone::run(eszip, metadata).await
}
Ok(None) => Ok(()),
Err(err) => Err(err),
};
// TODO(bartlomieju): doesn't handle exit code set by the runtime properly
unwrap_or_exit(standalone_res);

Expand Down
13 changes: 9 additions & 4 deletions cli/mainrt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -69,11 +69,16 @@ fn unwrap_or_exit<T>(result: Result<T, AnyError>) -> T {

fn main() {
let args: Vec<String> = env::args().collect();
let current_exe_path = current_exe().unwrap();
let standalone =
standalone::extract_standalone(&current_exe_path, args.clone());
let future = async move {
let current_exe_path = current_exe().unwrap();
match standalone::extract_standalone(&current_exe_path, args).await {
Ok(Some((metadata, eszip))) => standalone::run(eszip, metadata).await,
Ok(None) => Err(generic_error("No archive found.")),
match standalone {
Ok(Some(future)) => {
let (metadata, eszip) = future.await?;
standalone::run(eszip, metadata).await
}
Ok(None) => Ok(()),
Err(err) => Err(err),
}
};
Expand Down
62 changes: 34 additions & 28 deletions cli/standalone/binary.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
use std::collections::BTreeMap;
use std::env::current_exe;
use std::fs;
use std::future::Future;
use std::io::Read;
use std::io::Seek;
use std::io::SeekFrom;
Expand Down Expand Up @@ -236,49 +237,54 @@ pub fn is_standalone_binary(exe_path: &Path) -> bool {
/// binary by skipping over the trailer width at the end of the file,
/// then checking for the magic trailer string `d3n0l4nd`. If found,
/// the bundle is executed. If not, this function exits with `Ok(None)`.
pub async fn extract_standalone(
pub fn extract_standalone(
exe_path: &Path,
cli_args: Vec<String>,
) -> Result<Option<(Metadata, eszip::EszipV2)>, AnyError> {
let file = std::fs::File::open(exe_path)?;

let mut bufreader =
deno_core::futures::io::BufReader::new(AllowStdIo::new(file));

let _trailer_pos = bufreader
.seek(SeekFrom::End(-(TRAILER_SIZE as i64)))
.await?;
) -> Result<
Option<impl Future<Output = Result<(Metadata, eszip::EszipV2), AnyError>>>,
AnyError,
> {
// We do the first part sync so it can complete quickly
let mut file = std::fs::File::open(exe_path)?;
file.seek(SeekFrom::End(-(TRAILER_SIZE as i64)))?;
let mut trailer = [0; TRAILER_SIZE];
bufreader.read_exact(&mut trailer).await?;
file.read_exact(&mut trailer)?;
let trailer = match Trailer::parse(&trailer)? {
None => return Ok(None),
Some(trailer) => trailer,
};

bufreader.seek(SeekFrom::Start(trailer.eszip_pos)).await?;
file.seek(SeekFrom::Start(trailer.eszip_pos))?;

// If we have an eszip, read it out
Ok(Some(async move {
let bufreader =
deno_core::futures::io::BufReader::new(AllowStdIo::new(file));

let (eszip, loader) = eszip::EszipV2::parse(bufreader)
.await
.context("Failed to parse eszip header")?;
let (eszip, loader) = eszip::EszipV2::parse(bufreader)
.await
.context("Failed to parse eszip header")?;

let mut bufreader = loader.await.context("Failed to parse eszip archive")?;
let mut bufreader =
loader.await.context("Failed to parse eszip archive")?;

bufreader
.seek(SeekFrom::Start(trailer.metadata_pos))
.await?;
bufreader
.seek(SeekFrom::Start(trailer.metadata_pos))
.await?;

let mut metadata = String::new();
let mut metadata = String::new();

bufreader
.take(trailer.metadata_len())
.read_to_string(&mut metadata)
.await
.context("Failed to read metadata from the current executable")?;
bufreader
.take(trailer.metadata_len())
.read_to_string(&mut metadata)
.await
.context("Failed to read metadata from the current executable")?;

let mut metadata: Metadata = serde_json::from_str(&metadata).unwrap();
metadata.argv.append(&mut cli_args[1..].to_vec());
let mut metadata: Metadata = serde_json::from_str(&metadata).unwrap();
metadata.argv.append(&mut cli_args[1..].to_vec());

Ok(Some((metadata, eszip)))
Ok((metadata, eszip))
}))
}

const TRAILER_SIZE: usize = std::mem::size_of::<Trailer>() + 8; // 8 bytes for the magic trailer string
Expand Down