Skip to content

Commit

Permalink
lazy init
Browse files Browse the repository at this point in the history
  • Loading branch information
littledivy committed Nov 12, 2023
1 parent 2859088 commit 4d85c94
Show file tree
Hide file tree
Showing 9 changed files with 317 additions and 138 deletions.
80 changes: 71 additions & 9 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 4 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,9 @@ import { Foo } from "@ffi/example";
}
```

High performance. Codegen tries its best to take the fastest possible path for all bindings as-if they were written by hand to properly leverage the power of the Deno FFI JIT calls.
High performance. Codegen tries its best to take the fastest possible path for
all bindings as-if they were written by hand to properly leverage the power of
the Deno FFI JIT calls.

```
> make bench
Expand All @@ -83,4 +85,4 @@ benchmark time (avg) iter/s (min … max) p75
--------------------------------------------------------------- -----------------------------
add 6.88 ns/iter 145,297,626.6 (6.78 ns … 13.33 ns) 6.81 ns 8.22 ns 9.4 ns
bytelen 8.05 ns/iter 124,278,976.3 (7.81 ns … 18.1 ns) 8.09 ns 10.39 ns 11.64 ns
```
```
3 changes: 2 additions & 1 deletion deno_bindgen_cli/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,5 @@ path = "./main.rs"
[dependencies]
structopt = "0.3.26"
deno_bindgen_ir = { path = "../deno_bindgen_ir", version = "0.1.0" }
dlopen2 = "0.6.1"
dlopen2 = "0.6.1"
cargo_metadata = "0.18.1"
57 changes: 52 additions & 5 deletions deno_bindgen_cli/cargo.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,13 @@
use std::{io::Result, path::Path, process::Command};
use std::{
io::Result,
path::{Path, PathBuf},
process::{Command, Stdio},
};

pub struct Artifact {
pub path: PathBuf,
pub manifest_path: PathBuf,
}

#[derive(Default)]
pub struct Build {
Expand All @@ -15,18 +24,43 @@ impl Build {
self
}

pub fn build(self, path: &Path) -> Result<()> {
pub fn build(self, path: &Path) -> Result<Artifact> {
let mut cmd = Command::new("cargo");
cmd.current_dir(path).arg("build").arg("--lib");
cmd
.current_dir(path)
.arg("build")
.arg("--lib")
.arg("--message-format=json")
.stdout(Stdio::piped());

if self.release {
cmd.arg("--release");
}

let status = cmd.status()?;

let output = cmd.output()?;
if status.success() {
Ok(())
let reader = std::io::BufReader::new(output.stdout.as_slice());
for message in cargo_metadata::Message::parse_stream(reader) {
match message.unwrap() {
cargo_metadata::Message::CompilerArtifact(artifact) => {
if artifact.target.kind.contains(&"cdylib".to_string()) {
return Ok(Artifact {
path: PathBuf::from(artifact.filenames[0].to_string()),
manifest_path: PathBuf::from(
artifact.manifest_path.to_string(),
),
});
}
}
_ => {}
}
}

Err(std::io::Error::new(
std::io::ErrorKind::Other,
"failed to parse cargo output",
))?
} else {
println!(
"failed to execute `cargo`: exited with {}\n full command: {:?}",
Expand All @@ -37,3 +71,16 @@ impl Build {
}
}
}

pub fn metadata(path: &Path) -> Result<String> {
let metadata = cargo_metadata::MetadataCommand::new()
.manifest_path(path)
.exec()
.map_err(|e| {
println!("failed to execute `cargo metadata`: {}", e);
std::process::exit(1);
})
.unwrap();

Ok(metadata.root_package().unwrap().name.clone())
}
3 changes: 3 additions & 0 deletions deno_bindgen_cli/dlfcn.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ struct Api {
pub unsafe fn load_and_init(
path: &Path,
out: Option<PathBuf>,
lazy_init: bool,
) -> std::io::Result<()> {
let cont: Container<Api> = Container::load(path).map_err(|e| {
std::io::Error::new(
Expand All @@ -21,6 +22,8 @@ pub unsafe fn load_and_init(
cont.init_deno_bindgen(deno_bindgen_ir::codegen::Options {
target: deno_bindgen_ir::codegen::Target::Deno,
out,
local_dylib_path: path.to_path_buf(),
lazy_init,
});

Ok(())
Expand Down
17 changes: 12 additions & 5 deletions deno_bindgen_cli/main.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use std::path::PathBuf;

use cargo::Artifact;
use structopt::StructOpt;

mod cargo;
Expand All @@ -14,19 +15,25 @@ struct Opt {

#[structopt(short, long)]
out: Option<PathBuf>,

#[structopt(short, long)]
lazy_init: bool,
}

fn main() -> std::io::Result<()> {
let opt = Opt::from_args();

let cwd = std::env::current_dir().unwrap();
cargo::Build::new().release(opt.release).build(&cwd)?;
let Artifact {
path,
manifest_path,
} = cargo::Build::new().release(opt.release).build(&cwd)?;

let name = cargo::metadata(&manifest_path)?;
println!("Initializing {name}");

unsafe {
dlfcn::load_and_init(
&cwd.join("target/debug/libdeno_bindgen_test.dylib"),
opt.out,
)?
dlfcn::load_and_init(&PathBuf::from(path), opt.out, opt.lazy_init)?
};
Ok(())
}
61 changes: 54 additions & 7 deletions deno_bindgen_ir/codegen/deno.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use std::{
borrow::Cow,
io::{Result, Write},
path::Path,
};

use super::Generator;
Expand Down Expand Up @@ -110,22 +111,68 @@ impl From<Type> for DenoFfiType {

pub struct Codegen<'a> {
symbols: &'a [Inventory],
target: &'a Path,
lazy: bool,
}

impl<'a> Codegen<'a> {
pub fn new(symbols: &'a [Inventory]) -> Self {
Self { symbols }
pub fn new(symbols: &'a [Inventory], target: &'a Path, lazy: bool) -> Self {
Self {
symbols,
target,
lazy,
}
}

fn dlopen<W: Write>(&self, writer: &mut W) -> Result<()> {
if self.lazy {
return self.lazy_dlopen(writer);
}
writeln!(writer, "const {{ dlopen }} = Deno;\n")?;

writeln!(
writer,
"const {{ symbols }} = dlopen('./target/debug/libdeno_bindgen_test.dylib', {{"
)?;
let target = self.target.to_string_lossy();
writeln!(writer, "const {{ symbols }} = dlopen('{target}', {{")?;
self.write_symbols(writer)?;
writeln!(writer, "}});\n")?;

Ok(())
}

fn lazy_dlopen<W: Write>(&self, writer: &mut W) -> Result<()> {
writeln!(writer, "let symbols: any;\n")?;
let target = self.target.to_string_lossy();
writeln!(writer, "export function load(path: string = '{target}') {{")?;
writeln!(writer, " const {{ dlopen }} = Deno;\n")?;
writeln!(writer, " const {{ symbols: symbols_ }} = dlopen(path, {{")?;
struct WrapperWriter<'a, W: Write> {
writer: &'a mut W,
indent: usize,
}
impl<W: Write> Write for WrapperWriter<'_, W> {
fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
// Find newlines and indent them.
for byte in buf {
if *byte == b'\n' {
self.writer.write_all(b"\n")?;
self.writer.write_all(&vec![b' '; self.indent])?;
} else {
self.writer.write_all(&[*byte])?;
}
}

Ok(buf.len())
}

fn flush(&mut self) -> std::io::Result<()> {
self.writer.flush()
}
}
write!(writer, " ")?;
let mut wr = WrapperWriter { writer, indent: 2 };
self.write_symbols(&mut wr)?;
writeln!(wr, "}});\n")?;
write!(wr, "symbols = symbols_;")?;
writeln!(writer, "\n}}\n")?;

Ok(())
}

Expand Down
6 changes: 5 additions & 1 deletion deno_bindgen_ir/codegen/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ mod deno;
pub struct Options {
pub target: Target,
pub out: Option<PathBuf>,
pub local_dylib_path: PathBuf,
pub lazy_init: bool,
}

pub enum Target {
Expand All @@ -22,7 +24,9 @@ pub fn generate(
opt: Options,
) -> std::io::Result<()> {
let mut codegen = match opt.target {
Target::Deno => deno::Codegen::new(symbols),
Target::Deno => {
deno::Codegen::new(symbols, &opt.local_dylib_path, opt.lazy_init)
}
};

if let Some(out) = opt.out {
Expand Down
Loading

0 comments on commit 4d85c94

Please sign in to comment.