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

Switch QuickJS to QuickJS-NG #369

Merged
merged 37 commits into from
Nov 5, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
f14a8f8
Switch QuickJS to QuickJS-NG
richarddavison Oct 2, 2024
a147920
Format
richarddavison Oct 2, 2024
2c79359
Add compile time dump flags
richarddavison Oct 4, 2024
c7e76e8
Format
richarddavison Oct 4, 2024
7988333
Sync quickjs-ng
richarddavison Oct 4, 2024
a08933f
Fix ClassId across multiple runtimes
richarddavison Oct 8, 2024
ee734ac
Clippy & update qjs
richarddavison Oct 8, 2024
d1bf4c7
Update rust version in tests (stable once_cell)
richarddavison Oct 8, 2024
61aaa79
Update bindings
richarddavison Oct 8, 2024
22dde95
Update some bindings
richarddavison Oct 8, 2024
e002ea0
Fix ClassId impl
richarddavison Oct 9, 2024
d05f7a0
msvc build flags
richarddavison Oct 9, 2024
c2ff2b3
Add flags for both bindgen and builder
richarddavison Oct 9, 2024
d973db5
Format
richarddavison Oct 9, 2024
5dd64cc
Test just enable atomics and set c to be 11
richarddavison Oct 9, 2024
fef3802
Change flag format
richarddavison Oct 9, 2024
9f6e448
Set c std to 11 only
richarddavison Oct 9, 2024
08f3a20
Try setting CLAGS env
richarddavison Oct 9, 2024
859f2aa
Delete manually created bindings
richarddavison Oct 9, 2024
12b15e6
Debug target
richarddavison Oct 9, 2024
033074a
Debug target
richarddavison Oct 9, 2024
7c8151f
Debug CARGO_TARGET_TMPDIR
richarddavison Oct 9, 2024
443ff4f
Move class list to opaque
richarddavison Oct 10, 2024
1eca63c
Log binding
richarddavison Oct 10, 2024
0729d39
Update bindings
richarddavison Oct 10, 2024
ef00aec
Debug build target
richarddavison Oct 10, 2024
7c83c57
Fix windows build
richarddavison Oct 15, 2024
e5c6666
Fix 32 nan boxing
richarddavison Oct 16, 2024
36ef173
Remove the need for QJS patches :)
richarddavison Oct 16, 2024
71586b1
Format
richarddavison Oct 16, 2024
a08decd
Rebase, format and fix issues
richarddavison Oct 31, 2024
b730861
Clippy and format
richarddavison Oct 31, 2024
31960b4
Fix windows build
richarddavison Oct 31, 2024
9afc8a3
Use alloc_zeroed instead of writing
richarddavison Nov 5, 2024
d0ce0d8
Update QJS
richarddavison Nov 5, 2024
f3af1bf
Revert to 1.65 since we no longer uses once_cell
richarddavison Nov 5, 2024
30ef71c
Add missing intrinsics
richarddavison Nov 5, 2024
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
6 changes: 5 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -372,6 +372,7 @@ jobs:
run: |
cargo clean
cargo build ${{ matrix.optimization && '--release' || '' }} --manifest-path sys/Cargo.toml --target ${{ matrix.target }} --features bindgen,update-bindings,logging
cat sys/src/bindings/${{ matrix.target }}.rs
- name: Upload bindings
if: matrix.task == 'bindings'
uses: actions/upload-artifact@v4
Expand All @@ -381,7 +382,10 @@ jobs:
overwrite: true
- name: Build
if: ${{ !matrix.no-build }}
run: cargo build ${{ matrix.optimization && '--release' || '' }} --target ${{ matrix.target }} --no-default-features --features ${{ matrix.features }}
env:
BUILD_TARGET: ${{ matrix.target }}
run: |
cargo build ${{ matrix.optimization && '--release' || '' }} --target ${{ matrix.target }} --no-default-features --features ${{ matrix.features }}
- name: Test
if: ${{ !matrix.no-build && !matrix.no-test }}
timeout-minutes: 12
Expand Down
2 changes: 1 addition & 1 deletion .gitmodules
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
[submodule "rquickjs-sys/quickjs"]
path = sys/quickjs
url = https://github.com/bellard/quickjs.git
url = https://github.com/quickjs-ng/quickjs.git
99 changes: 26 additions & 73 deletions core/src/allocator.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
//! Tools for using different allocators with QuickJS.

use crate::qjs;
use std::ptr;

mod rust;

Expand All @@ -24,6 +23,11 @@ pub unsafe trait Allocator {
///
fn alloc(&mut self, size: usize) -> *mut u8;

/// Allocates memory for an array of num objects of size and initializes all bytes in the allocated storage to zero.
///
///
fn calloc(&mut self, count: usize, size: usize) -> *mut u8;

/// De-allocate previously allocated memory
///
/// # Safety
Expand Down Expand Up @@ -65,6 +69,7 @@ impl AllocatorHolder {
A: Allocator,
{
qjs::JSMallocFunctions {
js_calloc: Some(Self::calloc::<A>),
js_malloc: Some(Self::malloc::<A>),
js_free: Some(Self::free::<A>),
js_realloc: Some(Self::realloc::<A>),
Expand All @@ -83,47 +88,30 @@ impl AllocatorHolder {
self.0
}

fn size_t(size: usize) -> qjs::size_t {
size.try_into().expect(qjs::SIZE_T_ERROR)
}

unsafe extern "C" fn malloc<A>(
state: *mut qjs::JSMallocState,
unsafe extern "C" fn calloc<A>(
opaque: *mut qjs::c_void,
count: qjs::size_t,
size: qjs::size_t,
) -> *mut qjs::c_void
where
A: Allocator,
{
if size == 0 {
return ptr::null_mut();
}

let state = &mut *state;

if state.malloc_size + size > state.malloc_limit {
return ptr::null_mut();
}

let allocator = &mut *(opaque as *mut DynAllocator);
let rust_size: usize = size.try_into().expect(qjs::SIZE_T_ERROR);
// simulate the default behavior of libc::malloc

let allocator = &mut *(state.opaque as *mut DynAllocator);

let res = allocator.alloc(rust_size as _);

if res.is_null() {
return ptr::null_mut();
}

let size = A::usable_size(res);

state.malloc_count += 1;
state.malloc_size += Self::size_t(size);
let rust_count: usize = count.try_into().expect(qjs::SIZE_T_ERROR);
allocator.calloc(rust_count, rust_size) as *mut qjs::c_void
}

res as *mut qjs::c_void
unsafe extern "C" fn malloc<A>(opaque: *mut qjs::c_void, size: qjs::size_t) -> *mut qjs::c_void
where
A: Allocator,
{
let allocator = &mut *(opaque as *mut DynAllocator);
let rust_size: usize = size.try_into().expect(qjs::SIZE_T_ERROR);
allocator.alloc(rust_size) as *mut qjs::c_void
}

unsafe extern "C" fn free<A>(state: *mut qjs::JSMallocState, ptr: *mut qjs::c_void)
unsafe extern "C" fn free<A>(opaque: *mut qjs::c_void, ptr: *mut qjs::c_void)
where
A: Allocator,
{
Expand All @@ -133,56 +121,21 @@ impl AllocatorHolder {
return;
}

let state = &mut *state;
state.malloc_count -= 1;

let size = A::usable_size(ptr as *mut u8);

let allocator = &mut *(state.opaque as *mut DynAllocator);
let allocator = &mut *(opaque as *mut DynAllocator);
allocator.dealloc(ptr as _);

state.malloc_size -= Self::size_t(size);
}

unsafe extern "C" fn realloc<A>(
state: *mut qjs::JSMallocState,
opaque: *mut qjs::c_void,
ptr: *mut qjs::c_void,
size: qjs::size_t,
) -> *mut qjs::c_void
where
A: Allocator,
{
let state_ref = &mut *state;
let allocator = &mut *(state_ref.opaque as *mut DynAllocator);

// simulate the default behavior of libc::realloc
if ptr.is_null() {
return Self::malloc::<A>(state, size);
} else if size == 0 {
Self::free::<A>(state, ptr);
return ptr::null_mut();
}

let old_size = Self::size_t(A::usable_size(ptr as *mut u8));

let new_malloc_size = state_ref.malloc_size - old_size + size;
if new_malloc_size > state_ref.malloc_limit {
return ptr::null_mut();
}

let ptr = allocator.realloc(ptr as _, size.try_into().expect(qjs::SIZE_T_ERROR))
as *mut qjs::c_void;

if ptr.is_null() {
return ptr::null_mut();
}

let actual_size = Self::size_t(A::usable_size(ptr as *mut u8));

state_ref.malloc_size -= old_size;
state_ref.malloc_size += actual_size;

ptr
let rust_size: usize = size.try_into().expect(qjs::SIZE_T_ERROR);
let allocator = &mut *(opaque as *mut DynAllocator);
allocator.realloc(ptr as _, rust_size) as *mut qjs::c_void
}

unsafe extern "C" fn malloc_usable_size<A>(ptr: *const qjs::c_void) -> qjs::size_t
Expand Down
39 changes: 39 additions & 0 deletions core/src/allocator/rust.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,37 @@ fn round_size(size: usize) -> usize {
pub struct RustAllocator;

unsafe impl Allocator for RustAllocator {
fn calloc(&mut self, count: usize, size: usize) -> *mut u8 {
if count == 0 || size == 0 {
return ptr::null_mut();
}

let total_size = count.checked_mul(size).expect("overflow");

let total_size = round_size(total_size);

// Calculate the total allocated size including header
let alloc_size = HEADER_SIZE + total_size;

let layout = if let Ok(layout) = Layout::from_size_align(alloc_size, ALLOC_ALIGN) {
layout
} else {
return ptr::null_mut();
};

let ptr = unsafe { alloc::alloc_zeroed(layout) };

if ptr.is_null() {
return ptr::null_mut();
}

let header = unsafe { &mut *(ptr as *mut Header) };
header.size = total_size;

let ptr = unsafe { ptr.add(HEADER_SIZE) };
ptr
}

fn alloc(&mut self, size: usize) -> *mut u8 {
let size = round_size(size);
let alloc_size = size + HEADER_SIZE;
Expand Down Expand Up @@ -110,6 +141,14 @@ mod test {
}
}

fn calloc(&mut self, count: usize, size: usize) -> *mut u8 {
unsafe {
let res = RustAllocator.calloc(count, size);
ALLOC_SIZE.fetch_add(RustAllocator::usable_size(res), Ordering::AcqRel);
res
}
}

unsafe fn dealloc(&mut self, ptr: *mut u8) {
ALLOC_SIZE.fetch_sub(RustAllocator::usable_size(ptr), Ordering::AcqRel);
RustAllocator.dealloc(ptr);
Expand Down
2 changes: 1 addition & 1 deletion core/src/class.rs
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ impl<'js, C: JsClass<'js>> Class<'js, C> {
///
/// Returns `None` if the class is not yet registered or if the class doesn't have a prototype.
pub fn prototype(ctx: &Ctx<'js>) -> Result<Option<Object<'js>>> {
unsafe { ctx.get_opaque().get_or_insert_prototype::<C>(&ctx) }
unsafe { ctx.get_opaque().get_or_insert_prototype::<C>(ctx) }
}

/// Create a constructor for the current class using its definition.
Expand Down
16 changes: 5 additions & 11 deletions core/src/context/async.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
use super::{intrinsic, r#ref::ContextRef, ContextBuilder, Intrinsic};
use crate::{markers::ParallelSend, qjs, runtime::AsyncRuntime, Ctx, Error, Result};
use crate::{
context::ctx::RefCountHeader, markers::ParallelSend, qjs, runtime::AsyncRuntime, Ctx, Error,
Result,
};
use std::{future::Future, mem, pin::Pin, ptr::NonNull};

mod future;
Expand Down Expand Up @@ -108,7 +111,7 @@ impl Drop for Inner {
None => {
#[cfg(not(feature = "parallel"))]
{
let p = unsafe { &mut *(self.ctx.as_ptr() as *mut qjs::JSRefCountHeader) };
let p = unsafe { &mut *(self.ctx.as_ptr() as *mut RefCountHeader) };
if p.ref_count <= 1 {
// Lock was poisoned, this should only happen on a panic.
// We should still free the context.
Expand Down Expand Up @@ -202,15 +205,6 @@ impl AsyncContext {
ContextBuilder::default()
}

pub async fn enable_big_num_ext(&self, enable: bool) {
let guard = self.0.rt.inner.lock().await;
guard.runtime.update_stack_top();
unsafe { qjs::JS_EnableBignumExt(self.0.ctx.as_ptr(), i32::from(enable)) }
// Explicitly drop the guard to ensure it is valid during the entire use of runtime
guard.drop_pending();
mem::drop(guard)
}

/// Returns the associated runtime
pub fn runtime(&self) -> &AsyncRuntime {
&self.0.rt
Expand Down
15 changes: 4 additions & 11 deletions core/src/context/base.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use super::{intrinsic, r#ref::ContextRef, ContextBuilder, Intrinsic};
use super::{ctx::RefCountHeader, intrinsic, r#ref::ContextRef, ContextBuilder, Intrinsic};
use crate::{qjs, Ctx, Error, Result, Runtime};
use std::{mem, ptr::NonNull};

Expand Down Expand Up @@ -84,14 +84,6 @@ impl Context {
ContextBuilder::default()
}

pub fn enable_big_num_ext(&self, enable: bool) {
let guard = self.0.rt.inner.lock();
guard.update_stack_top();
unsafe { qjs::JS_EnableBignumExt(self.0.ctx.as_ptr(), i32::from(enable)) }
// Explicitly drop the guard to ensure it is valid during the entire use of runtime
mem::drop(guard)
}

/// Returns the associated runtime
pub fn runtime(&self) -> &Runtime {
&self.0.rt
Expand Down Expand Up @@ -127,7 +119,7 @@ impl Drop for Context {
let guard = match self.0.rt.inner.try_lock() {
Some(x) => x,
None => {
let p = unsafe { &mut *(self.0.ctx.as_ptr() as *mut qjs::JSRefCountHeader) };
let p = unsafe { &mut *(self.0.ctx.as_ptr() as *mut RefCountHeader) };
if p.ref_count <= 1 {
// Lock was poisoned, this should only happen on a panic.
// We should still free the context.
Expand Down Expand Up @@ -253,9 +245,10 @@ mod test {
println!("done");
}

// Will be improved by https://github.com/quickjs-ng/quickjs/pull/406
#[test]
#[should_panic(
expected = "Error:[eval_script]:1:4 invalid first character of private name\n at eval_script:1:4\n"
expected = "Error: invalid first character of private name\n at eval_script:1:1\n"
)]
fn exception() {
test_with(|ctx| {
Expand Down
21 changes: 6 additions & 15 deletions core/src/context/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,8 +56,6 @@ pub mod intrinsic {
Date JS_AddIntrinsicDate,
/// Add evaluation support
Eval JS_AddIntrinsicEval,
/// Add string normalization
StringNormalize JS_AddIntrinsicStringNormalize,
/// Add RegExp compiler
RegExpCompiler JS_AddIntrinsicRegExpCompiler,
/// Add RegExp object support
Expand All @@ -74,14 +72,10 @@ pub mod intrinsic {
Promise JS_AddIntrinsicPromise,
/// Add BigInt support
BigInt JS_AddIntrinsicBigInt,
/// Add BigFloat support
BigFloat JS_AddIntrinsicBigFloat,
/// Add BigDecimal support
BigDecimal JS_AddIntrinsicBigDecimal,
/// Add operator overloading support
Operators JS_AddIntrinsicOperators,
/// Enable bignum extension
BignumExt JS_EnableBignumExt (1),
/// Add Performance support
Performance JS_AddPerformance,
/// Add WeakRef support
WeakRef JS_AddIntrinsicWeakRef,
}

/// An alias for [`BaseObjects`]
Expand All @@ -94,7 +88,6 @@ pub mod intrinsic {
pub type All = (
Date,
Eval,
StringNormalize,
RegExpCompiler,
RegExp,
Json,
Expand All @@ -103,10 +96,8 @@ pub mod intrinsic {
TypedArrays,
Promise,
BigInt,
BigFloat,
BigDecimal,
Operators,
BignumExt,
Performance,
WeakRef,
);
}

Expand Down
Loading