Skip to content
Open
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
146 changes: 141 additions & 5 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ permissions: write-all

jobs:
build:
name: ${{ matrix.config.variant }} ${{ matrix.config.target }} ${{ matrix.config.v8_enable_pointer_compression && 'ptrcomp' || '' }} ${{ matrix.config.simdutf && 'simdutf' || '' }}
name: ${{ matrix.config.variant }} ${{ matrix.config.target }} ${{ matrix.config.v8_enable_pointer_compression && 'ptrcomp' || '' }} ${{ matrix.config.simdutf && 'simdutf' || '' }} ${{ matrix.config.no_icu && 'noicu' || '' }}
runs-on: ${{ matrix.config.os }}
timeout-minutes: 180
strategy:
Expand Down Expand Up @@ -181,13 +181,56 @@ jobs:
simdutf: true
cargo: cargo

# no_icu builds (i18n/ICU disabled). Built with simdutf to match the
# feature set the Deno CLI consumes, producing `_simdutf_noicu`
# archives. Release-only across the targets the CLI ships.
- os: macos-15-large
target: x86_64-apple-darwin
variant: release
v8_enable_pointer_compression: false
simdutf: true
no_icu: true
cargo: cargo

- os: macos-15
target: aarch64-apple-darwin
variant: release
v8_enable_pointer_compression: false
simdutf: true
no_icu: true
cargo: cargo

- os: ${{ github.repository == 'denoland/rusty_v8' && 'ubuntu-22.04-xl' || 'ubuntu-22.04' }}
target: x86_64-unknown-linux-gnu
variant: release
v8_enable_pointer_compression: false
simdutf: true
no_icu: true
cargo: cargo

- os: ${{ github.repository == 'denoland/rusty_v8' && 'ubuntu-22.04-xl' || 'ubuntu-22.04' }}
target: aarch64-unknown-linux-gnu
variant: release
v8_enable_pointer_compression: false
simdutf: true
no_icu: true
cargo: cargo

- os: ${{ github.repository == 'denoland/rusty_v8' && 'windows-2022-xxl' || 'windows-2022' }}
target: x86_64-pc-windows-msvc
variant: release # Note: we do not support windows debug builds.
v8_enable_pointer_compression: false
simdutf: true
no_icu: true
cargo: cargo

env:
V8_FROM_SOURCE: true
CARGO_VARIANT_FLAG: ${{ matrix.config.variant == 'release' && '--release' || '' }}
CARGO_FEATURE_FLAGS: ${{ format('{0} {1}', matrix.config.v8_enable_pointer_compression && '--features v8_enable_pointer_compression' || '', matrix.config.simdutf && '--features simdutf' || '') }}
CARGO_FEATURE_FLAGS: ${{ format('{0} {1} {2}', matrix.config.v8_enable_pointer_compression && '--features v8_enable_pointer_compression' || '', matrix.config.simdutf && '--features simdutf' || '', matrix.config.no_icu && '--features no_icu' || '') }}
LIB_NAME: ${{ contains(matrix.config.target, 'windows') && 'rusty_v8' || 'librusty_v8' }}
LIB_EXT: ${{ contains(matrix.config.target, 'windows') && 'lib' || 'a' }}
FEATURES_SUFFIX: ${{ format('{0}{1}', matrix.config.v8_enable_pointer_compression && '_ptrcomp' || '', matrix.config.simdutf && '_simdutf' || '') }}
FEATURES_SUFFIX: ${{ format('{0}{1}{2}', matrix.config.v8_enable_pointer_compression && '_ptrcomp' || '', matrix.config.simdutf && '_simdutf' || '', matrix.config.no_icu && '_noicu' || '') }}
RUSTFLAGS: -D warnings

steps:
Expand Down Expand Up @@ -251,7 +294,7 @@ jobs:
target/*/.*
target/*/build
target/*/deps
key: cargo1-${{ matrix.config.target }}-${{ matrix.config.variant }}-${{ matrix.config.v8_enable_pointer_compression }}-${{ matrix.config.simdutf }}-${{ hashFiles('Cargo.lock', 'build.rs', 'git_submodule_status.txt') }}
key: cargo1-${{ matrix.config.target }}-${{ matrix.config.variant }}-${{ matrix.config.v8_enable_pointer_compression }}-${{ matrix.config.simdutf }}-${{ matrix.config.no_icu }}-${{ hashFiles('Cargo.lock', 'build.rs', 'git_submodule_status.txt') }}
restore-keys: cargo1-${{ matrix.config.target }}-${{ matrix.config.variant }}-${{ matrix.config.v8_enable_pointer_compression }}-

- name: Install and start sccache
Expand Down Expand Up @@ -611,6 +654,99 @@ jobs:
name: src_binding_simdutf_release_aarch64-pc-windows-msvc.rs
path: target/src_binding_simdutf_release_aarch64-pc-windows-msvc.rs

build-windows-arm64-simdutf-noicu:
name: release aarch64-pc-windows-msvc simdutf noicu
runs-on: ${{ github.repository == 'denoland/rusty_v8' && 'windows-2022-xxl' || 'windows-2022' }}
timeout-minutes: 180
env:
CARGO_VARIANT_FLAG: --release
V8_FROM_SOURCE: true
CCACHE: ccache
LIB_NAME: rusty_v8
LIB_EXT: lib
FEATURES_SUFFIX: '_simdutf_noicu'
steps:
- name: Configure git
run: git config --global core.symlinks true

- name: Clone repository
uses: actions/checkout@v4
with:
fetch-depth: 10
submodules: recursive

- uses: dsherret/rust-toolchain-file@v1

- name: Install Windows ARM64 target
run: rustup target add aarch64-pc-windows-msvc

- name: Install nextest
uses: taiki-e/install-action@nextest

- name: Write git_submodule_status.txt
run: git submodule status --recursive > git_submodule_status.txt

- name: Cache
uses: actions/cache@v4
with:
path: |-
target/sccache
target/aarch64-pc-windows-msvc/release/gn_out
key: cargo1-aarch64-pc-windows-msvc-release-simdutf-noicu-${{ hashFiles('Cargo.lock', 'build.rs', 'git_submodule_status.txt') }}
restore-keys: cargo1-aarch64-pc-windows-msvc-release-simdutf-noicu-

- name: Install and start sccache
shell: pwsh
env:
SCCACHE_DIR: ${{ github.workspace }}/target/sccache
SCCACHE_CACHE_SIZE: 256M
SCCACHE_IDLE_TIMEOUT: 0
run: |
$version = "v0.8.2"
$platform = "x86_64-pc-windows-msvc"
$basename = "sccache-$version-$platform"
$url = "https://github.com/mozilla/sccache/releases/download/$version/$basename.tar.gz"
cd ~
curl -LO $url
tar -xzvf "$basename.tar.gz"
. $basename/sccache --start-server
echo "$(pwd)/$basename" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append

- name: Install Clang
run: python3 tools/clang/scripts/update.py

- name: Build (cross-compile, no tests)
env:
SCCACHE_IDLE_TIMEOUT: 0
run: cargo build --all-targets --locked --target aarch64-pc-windows-msvc --release --features simdutf --features no_icu

- name: Clippy
run: cargo clippy --all-targets --locked --target aarch64-pc-windows-msvc --release --features simdutf --features no_icu -- -D clippy::all

- name: Prepare binary publish
run: |
gzip -9c target/aarch64-pc-windows-msvc/release/gn_out/obj/rusty_v8.lib > target/rusty_v8_simdutf_noicu_release_aarch64-pc-windows-msvc.lib.gz
ls -l target/rusty_v8_simdutf_noicu_release_aarch64-pc-windows-msvc.lib.gz

cp target/aarch64-pc-windows-msvc/release/gn_out/src_binding.rs target/src_binding_simdutf_noicu_release_aarch64-pc-windows-msvc.rs
ls -l target/src_binding_simdutf_noicu_release_aarch64-pc-windows-msvc.rs

- name: Binary publish
uses: softprops/action-gh-release@v0.1.15
if: github.repository == 'denoland/rusty_v8' && startsWith(github.ref, 'refs/tags/')
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
files: |
target/rusty_v8_simdutf_noicu_release_aarch64-pc-windows-msvc.lib.gz
target/src_binding_simdutf_noicu_release_aarch64-pc-windows-msvc.rs

- name: Upload CI artifacts
uses: actions/upload-artifact@v4
with:
name: src_binding_simdutf_noicu_release_aarch64-pc-windows-msvc.rs
path: target/src_binding_simdutf_noicu_release_aarch64-pc-windows-msvc.rs

test-windows-arm64:
name: test aarch64-pc-windows-msvc
needs: build-windows-arm64
Expand Down Expand Up @@ -643,7 +779,7 @@ jobs:
run: cargo nextest run -v --all-targets --locked --target aarch64-pc-windows-msvc --release --no-fail-fast

publish:
needs: [build, build-windows-arm64, build-windows-arm64-simdutf]
needs: [build, build-windows-arm64, build-windows-arm64-simdutf, build-windows-arm64-simdutf-noicu]
runs-on: ${{ github.repository == 'denoland/rusty_v8' && 'ubuntu-22.04-xl' || 'ubuntu-22.04' }}
if: github.repository == 'denoland/rusty_v8' && startsWith(github.ref, 'refs/tags/')
steps:
Expand Down
9 changes: 9 additions & 0 deletions BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,11 @@ import("//build/config/host_byteorder.gni")

declare_args() {
rusty_v8_enable_simdutf = false

# Gates the ICU bindings in src/binding.cc. Set to false (via the `no_icu`
# cargo feature) when V8 is built with v8_enable_i18n_support=false, so the
# static library still links without ICU.
rusty_v8_enable_i18n = true
}

static_library("rusty_v8") {
Expand Down Expand Up @@ -63,6 +68,10 @@ config("rusty_v8_config") {
defines += [ "RUSTY_V8_ENABLE_SIMDUTF" ]
}

if (rusty_v8_enable_i18n) {
defines += [ "RUSTY_V8_ENABLE_I18N" ]
}

if (is_clang) {
cflags += [
"-fcolor-diagnostics",
Expand Down
5 changes: 5 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,11 @@ opt-level = 1
default = ["use_custom_libcxx"]
use_custom_libcxx = []
simdutf = []
# Opt-out feature that builds V8 without i18n/ICU support. Enabling it drops the
# embedded ICU data (~10MB) and the `Intl` API from the resulting static
# library. It is modelled as an opt-out so that existing consumers (including
# those that set `default-features = false`) keep ICU without any changes.
no_icu = []
v8_enable_pointer_compression = []
v8_enable_sandbox = ["v8_enable_pointer_compression"]
v8_enable_v8_checks = []
Expand Down
142 changes: 142 additions & 0 deletions benches/string.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
fn main() {
if cfg!(debug_assertions) || std::env::var("CI").is_ok() {
return;
}

let platform = v8::new_default_platform(0, false).make_shared();
v8::V8::initialize_platform(platform);
v8::V8::initialize();
let isolate = &mut v8::Isolate::new(v8::CreateParams::default());
v8::scope!(let scope, isolate);
let context = v8::Context::new(scope, Default::default());
let scope = &mut v8::ContextScope::new(scope, context);

println!(
"simdutf feature: {}",
if cfg!(feature = "simdutf") {
"ENABLED"
} else {
"DISABLED"
}
);
println!();

// --- Build test strings of various sizes ---
let sizes: &[usize] = &[16, 64, 256, 1024, 4096, 16384];

for &size in sizes {
println!("=== String length: {size} ===");

// 1) Pure ASCII one-byte string
{
let ascii_data: String =
(0..size).map(|i| (b'A' + (i % 26) as u8) as char).collect();
let v8_str = v8::String::new(scope, &ascii_data).unwrap();
bench_to_rust_string_lossy(scope, v8_str, "ascii_to_rust_string_lossy");
bench_write_utf8_into(scope, v8_str, "ascii_write_utf8_into");
bench_to_rust_cow_lossy(scope, v8_str, "ascii_to_rust_cow_lossy");
}

// 2) Latin-1 string (non-ASCII one-byte)
// Create via new_from_one_byte with bytes in 0x80..0xFF range
{
let latin1_data: Vec<u8> =
(0..size).map(|i| 0xC0 + (i % 64) as u8).collect();
let v8_str = v8::String::new_from_one_byte(
scope,
&latin1_data,
v8::NewStringType::Normal,
)
.unwrap();
bench_to_rust_string_lossy(scope, v8_str, "latin1_to_rust_string_lossy");
bench_write_utf8_into(scope, v8_str, "latin1_write_utf8_into");
bench_to_rust_cow_lossy(scope, v8_str, "latin1_to_rust_cow_lossy");
}

// 3) Two-byte string (UTF-16 with characters outside Latin-1)
// Use codepoints like U+0400..U+04FF (Cyrillic) to force two-byte representation
{
let utf16_data: Vec<u16> =
(0..size).map(|i| 0x0400 + (i % 256) as u16).collect();
let v8_str = v8::String::new_from_two_byte(
scope,
&utf16_data,
v8::NewStringType::Normal,
)
.unwrap();
bench_to_rust_string_lossy(scope, v8_str, "twobyte_to_rust_string_lossy");
bench_write_utf8_into(scope, v8_str, "twobyte_write_utf8_into");
bench_to_rust_cow_lossy(scope, v8_str, "twobyte_to_rust_cow_lossy");
}

println!();
}
}

fn bench_to_rust_string_lossy(
scope: &mut v8::PinScope<'_, '_>,
s: v8::Local<'_, v8::String>,
label: &str,
) {
let iterations = iterations_for_length(s.length());
let start = std::time::Instant::now();
for _ in 0..iterations {
let _ = std::hint::black_box(s.to_rust_string_lossy(scope));
}
let elapsed = start.elapsed();
print_result(label, elapsed, iterations, s.length());
}

fn bench_write_utf8_into(
scope: &mut v8::PinScope<'_, '_>,
s: v8::Local<'_, v8::String>,
label: &str,
) {
let iterations = iterations_for_length(s.length());
let mut buf = String::new();
let start = std::time::Instant::now();
for _ in 0..iterations {
s.write_utf8_into(scope, &mut buf);
std::hint::black_box(&buf);
}
let elapsed = start.elapsed();
print_result(label, elapsed, iterations, s.length());
}

fn bench_to_rust_cow_lossy(
scope: &mut v8::PinScope<'_, '_>,
s: v8::Local<'_, v8::String>,
label: &str,
) {
let iterations = iterations_for_length(s.length());
let start = std::time::Instant::now();
for _ in 0..iterations {
let mut buffer = [std::mem::MaybeUninit::uninit(); 2048];
let _ = std::hint::black_box(s.to_rust_cow_lossy(scope, &mut buffer));
}
let elapsed = start.elapsed();
print_result(label, elapsed, iterations, s.length());
}

fn iterations_for_length(len: usize) -> u64 {
// More iterations for shorter strings to get stable timings
match len {
0..=64 => 5_000_000,
65..=512 => 2_000_000,
513..=4096 => 500_000,
_ => 100_000,
}
}

fn print_result(
label: &str,
elapsed: std::time::Duration,
iterations: u64,
length: usize,
) {
let total_ns = elapsed.as_nanos() as f64;
let ns_per_iter = total_ns / iterations as f64;
let throughput_mb =
(length as f64 * iterations as f64) / (elapsed.as_secs_f64() * 1e6);
println!(" {ns_per_iter:8.1} ns/iter {throughput_mb:8.1} MB/s {label}",);
}
11 changes: 11 additions & 0 deletions build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -318,6 +318,14 @@ fn build_v8(is_asan: bool) {
env::var("CARGO_FEATURE_SIMDUTF").is_ok()
));

// When the `no_icu` feature is enabled, build V8 without i18n/ICU support.
// `v8_enable_i18n_support=false` drops the embedded ICU data and the `Intl`
// API, while `rusty_v8_enable_i18n` gates the ICU bindings in
// `src/binding.cc` so the static library still links without ICU.
let enable_i18n = env::var("CARGO_FEATURE_NO_ICU").is_err();
gn_args.push(format!("v8_enable_i18n_support={enable_i18n}"));
gn_args.push(format!("rusty_v8_enable_i18n={enable_i18n}"));

// Fix GN's host_cpu detection when using x86_64 bins on Apple Silicon
if cfg!(target_os = "macos") && cfg!(target_arch = "aarch64") {
gn_args.push("host_cpu=\"arm64\"".to_string());
Expand Down Expand Up @@ -571,6 +579,9 @@ fn prebuilt_features_suffix() -> String {
if env::var("CARGO_FEATURE_SIMDUTF").is_ok() {
features.push_str("_simdutf");
}
if env::var("CARGO_FEATURE_NO_ICU").is_ok() {
features.push_str("_noicu");
}
features
}

Expand Down
Empty file added empty.js
Empty file.
Loading
Loading