Skip to content
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
6 changes: 3 additions & 3 deletions crates/oxc_allocator/src/generated/fixed_size_constants.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,6 @@
#![expect(clippy::unreadable_literal)]
#![allow(dead_code)]

pub const BUFFER_SIZE: usize = 2147483632;
pub const BUFFER_ALIGN: usize = 4294967296;
pub const METADATA_SIZE: usize = 16;
pub const BLOCK_SIZE: usize = 2147483632;
pub const BLOCK_ALIGN: usize = 4294967296;
pub const RAW_METADATA_SIZE: usize = 16;
16 changes: 8 additions & 8 deletions crates/oxc_allocator/src/pool_fixed_size.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use std::{

use crate::{
Allocator,
fixed_size_constants::{BUFFER_ALIGN, BUFFER_SIZE, METADATA_SIZE},
fixed_size_constants::{BLOCK_ALIGN, BLOCK_SIZE, RAW_METADATA_SIZE},
};

const TWO_GIB: usize = 1 << 31;
Expand Down Expand Up @@ -101,7 +101,7 @@ impl Drop for AllocatorGuard<'_> {
// Could just use that built-in workaround, rather than implementing our own, or allocate a 6 GiB chunk
// with alignment 16, to skip Rust's built-in workaround.
// Note: Rust's workaround will likely commit a whole page of memory, just to store the real pointer.
const ALLOC_SIZE: usize = BUFFER_SIZE + TWO_GIB;
const ALLOC_SIZE: usize = BLOCK_SIZE + TWO_GIB;
const ALLOC_ALIGN: usize = TWO_GIB;

const ALLOC_LAYOUT: Layout = match Layout::from_size_align(ALLOC_SIZE, ALLOC_ALIGN) {
Expand Down Expand Up @@ -152,9 +152,9 @@ impl FixedSizeAllocator {
// SAFETY: We allocated 4 GiB of memory, so adding `offset` to `alloc_ptr` is in bounds
let chunk_ptr = unsafe { alloc_ptr.add(offset) };

debug_assert!(chunk_ptr.as_ptr() as usize % BUFFER_ALIGN == 0);
debug_assert!(chunk_ptr.as_ptr() as usize % BLOCK_ALIGN == 0);

const CHUNK_SIZE: usize = BUFFER_SIZE - METADATA_SIZE;
const CHUNK_SIZE: usize = BLOCK_SIZE - RAW_METADATA_SIZE;
const _: () = assert!(CHUNK_SIZE % Allocator::RAW_MIN_ALIGN == 0);

// SAFETY: Memory region starting at `chunk_ptr` with `CHUNK_SIZE` bytes is within
Expand All @@ -172,12 +172,12 @@ impl FixedSizeAllocator {
self.allocator.reset();

// Set data pointer back to start.
// SAFETY: Fixed-size allocators have data pointer originally aligned on `BUFFER_ALIGN`,
// and size less than `BUFFER_ALIGN`. So we can restore original data pointer by rounding down
// to next multiple of `BUFFER_ALIGN`.
// SAFETY: Fixed-size allocators have data pointer originally aligned on `BLOCK_ALIGN`,
// and size less than `BLOCK_ALIGN`. So we can restore original data pointer by rounding down
// to next multiple of `BLOCK_ALIGN`.
unsafe {
let data_ptr = self.allocator.data_ptr();
let offset = data_ptr.as_ptr() as usize % BUFFER_ALIGN;
let offset = data_ptr.as_ptr() as usize % BLOCK_ALIGN;
let data_ptr = data_ptr.sub(offset);
self.allocator.set_data_ptr(data_ptr);
}
Expand Down
6 changes: 3 additions & 3 deletions napi/parser/src/generated/raw_transfer_constants.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,6 @@
#![expect(clippy::unreadable_literal)]
#![allow(dead_code)]

pub const BUFFER_SIZE: usize = 2147483632;
pub const BUFFER_ALIGN: usize = 4294967296;
pub const METADATA_SIZE: usize = 16;
pub const BLOCK_SIZE: usize = 2147483632;
pub const BLOCK_ALIGN: usize = 4294967296;
pub const RAW_METADATA_SIZE: usize = 16;
20 changes: 10 additions & 10 deletions napi/parser/src/raw_transfer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ use oxc_napi::get_source_type;

use crate::{
AstType, ParserOptions, get_ast_type, parse,
raw_transfer_constants::{BUFFER_ALIGN, BUFFER_SIZE},
raw_transfer_constants::{BLOCK_ALIGN as BUFFER_ALIGN, BLOCK_SIZE as BUFFER_SIZE},
raw_transfer_types::{EcmaScriptModule, Error, RawTransferData, RawTransferMetadata},
};

Expand Down Expand Up @@ -182,14 +182,14 @@ unsafe fn parse_raw_impl(
// Leave space for source before it, and space for metadata after it.
// Metadata actually only takes 5 bytes, but round everything up to multiple of 16,
// as `bumpalo` requires that alignment.
const METADATA_SIZE: usize = size_of::<RawTransferMetadata>();
const RAW_METADATA_SIZE: usize = size_of::<RawTransferMetadata>();
const {
assert!(METADATA_SIZE >= BUMP_ALIGN);
assert!(is_multiple_of(METADATA_SIZE, BUMP_ALIGN));
assert!(RAW_METADATA_SIZE >= BUMP_ALIGN);
assert!(is_multiple_of(RAW_METADATA_SIZE, BUMP_ALIGN));
};
let source_len = source_len as usize;
let data_offset = source_len.next_multiple_of(BUMP_ALIGN);
let data_size = BUFFER_SIZE.saturating_sub(data_offset + METADATA_SIZE);
let data_size = BUFFER_SIZE.saturating_sub(data_offset + RAW_METADATA_SIZE);
assert!(data_size >= Allocator::RAW_MIN_SIZE, "Source text is too long");

// Create `Allocator`.
Expand Down Expand Up @@ -274,13 +274,13 @@ unsafe fn parse_raw_impl(
// Write metadata into end of buffer
#[allow(clippy::cast_possible_truncation)]
let metadata = RawTransferMetadata::new(data_ptr as u32, ast_type == AstType::TypeScript);
const METADATA_OFFSET: usize = BUFFER_SIZE - METADATA_SIZE;
const _: () = assert!(is_multiple_of(METADATA_OFFSET, BUMP_ALIGN));
// SAFETY: `METADATA_OFFSET` is less than length of `buffer`.
// `METADATA_OFFSET` is aligned on 16.
const RAW_METADATA_OFFSET: usize = BUFFER_SIZE - RAW_METADATA_SIZE;
const _: () = assert!(is_multiple_of(RAW_METADATA_OFFSET, BUMP_ALIGN));
// SAFETY: `RAW_METADATA_OFFSET` is less than length of `buffer`.
// `RAW_METADATA_OFFSET` is aligned on 16.
#[expect(clippy::cast_ptr_alignment)]
unsafe {
buffer_ptr.add(METADATA_OFFSET).cast::<RawTransferMetadata>().write(metadata);
buffer_ptr.add(RAW_METADATA_OFFSET).cast::<RawTransferMetadata>().write(metadata);
}
}

Expand Down
66 changes: 41 additions & 25 deletions tasks/ast_tools/src/generators/raw_transfer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,23 @@ use crate::{

use super::define_generator;

/// Size of raw transfer buffer.
/// Must be a multiple of 16.
/// Bytes reserved for `malloc`'s metadata
const MALLOC_RESERVED_SIZE: u32 = 16;

/// Minimum alignment requirement for end of `Allocator`'s chunk
#[expect(dead_code)]
const ALLOCATOR_CHUNK_END_ALIGN: u32 = 16;

/// Size of block of memory used for raw transfer.
/// This size includes metadata stored after the `Allocator` chunk which contains AST data.
///
/// Must be a multiple of [`ALLOCATOR_CHUNK_END_ALIGN`].
/// 16 bytes less than 2 GiB, to allow 16 bytes for `malloc` metadata (like Bumpalo does).
const BUFFER_SIZE: u32 = (1 << 31) - 16; // 2 GiB - 16 bytes
const _: () = assert!(BUFFER_SIZE % 16 == 0);
/// Alignment of raw transfer buffer.
const BUFFER_ALIGN: u64 = 1 << 32; // 4 GiB
const BLOCK_SIZE: u32 = (1 << 31) - MALLOC_RESERVED_SIZE; // 2 GiB - 16 bytes
const _: () = assert!(BLOCK_SIZE % ALLOCATOR_CHUNK_END_ALIGN == 0);

/// Alignment of block of memory used for raw transfer.
const BLOCK_ALIGN: u64 = 1 << 32; // 4 GiB

// Offsets of `Vec`'s fields.
// `Vec` is `#[repr(transparent)]` and `RawVec` is `#[repr(C)]`, so these offsets are fixed.
Expand Down Expand Up @@ -92,7 +102,7 @@ fn generate_deserializers(consts: Constants, schema: &Schema, codegen: &Codegen)

// Prelude to generated deserializer.
// Defines the main `deserialize` function.
let Constants { data_pointer_pos_32, .. } = consts;
let data_pointer_pos_32 = consts.data_pointer_pos / 4;

#[rustfmt::skip]
let prelude = format!("
Expand Down Expand Up @@ -992,20 +1002,26 @@ impl DeserializeFunctionName for PointerDef {
/// Constants for position of fields in buffer which deserialization starts from.
#[derive(Clone, Copy)]
struct Constants {
data_pointer_pos_32: u32,
/// Offset within buffer of `u32` containing position of `RawTransferData`
data_pointer_pos: u32,
/// Offset within buffer of `bool` indicating if AST is TS or JS
is_ts_pos: u32,
/// Offset of `Program` in buffer, relative to position of `RawTransferData`
program_offset: u32,
metadata_size: u32,
/// Size of `RawTransferData` in bytes
raw_metadata_size: u32,
}

/// Generate constants file.
fn generate_constants(consts: Constants) -> (String, TokenStream) {
let Constants { data_pointer_pos_32, is_ts_pos, program_offset, metadata_size } = consts;
let Constants { data_pointer_pos, is_ts_pos, program_offset, raw_metadata_size } = consts;

let data_pointer_pos_32 = data_pointer_pos / 4;

#[rustfmt::skip]
let js_output = format!("
const BUFFER_SIZE = {BUFFER_SIZE},
BUFFER_ALIGN = {BUFFER_ALIGN},
const BUFFER_SIZE = {BLOCK_SIZE},
BUFFER_ALIGN = {BLOCK_ALIGN},
DATA_POINTER_POS_32 = {data_pointer_pos_32},
IS_TS_FLAG_POS = {is_ts_pos},
PROGRAM_OFFSET = {program_offset};
Expand All @@ -1019,30 +1035,30 @@ fn generate_constants(consts: Constants) -> (String, TokenStream) {
}};
");

let buffer_size = number_lit(BUFFER_SIZE);
let buffer_align = number_lit(BUFFER_ALIGN);
let metadata_size = number_lit(metadata_size);
let block_size = number_lit(BLOCK_SIZE);
let block_align = number_lit(BLOCK_ALIGN);
let raw_metadata_size = number_lit(raw_metadata_size);
let rust_output = quote! {
#![expect(clippy::unreadable_literal)]
#![allow(dead_code)]

///@@line_break
pub const BUFFER_SIZE: usize = #buffer_size;
pub const BUFFER_ALIGN: usize = #buffer_align;
pub const METADATA_SIZE: usize = #metadata_size;
pub const BLOCK_SIZE: usize = #block_size;
pub const BLOCK_ALIGN: usize = #block_align;
pub const RAW_METADATA_SIZE: usize = #raw_metadata_size;
};

(js_output, rust_output)
}

/// Calculate constants.
fn get_constants(schema: &Schema) -> Constants {
let metadata_struct = schema.type_by_name("RawTransferMetadata").as_struct().unwrap();
let metadata_size = metadata_struct.layout_64().size;
let metadata_pos = BUFFER_SIZE - metadata_size;
let data_pointer_pos = metadata_pos + metadata_struct.field_by_name("data_offset").offset_64();
let data_pointer_pos_32 = data_pointer_pos / 4;
let is_ts_pos = metadata_pos + metadata_struct.field_by_name("is_ts").offset_64();
let raw_metadata_struct = schema.type_by_name("RawTransferMetadata").as_struct().unwrap();
let raw_metadata_size = raw_metadata_struct.layout_64().size;
let raw_metadata_pos = BLOCK_SIZE - raw_metadata_size;
let data_pointer_pos =
raw_metadata_pos + raw_metadata_struct.field_by_name("data_offset").offset_64();
let is_ts_pos = raw_metadata_pos + raw_metadata_struct.field_by_name("is_ts").offset_64();

let program_offset = schema
.type_by_name("RawTransferData")
Expand All @@ -1051,5 +1067,5 @@ fn get_constants(schema: &Schema) -> Constants {
.field_by_name("program")
.offset_64();

Constants { data_pointer_pos_32, is_ts_pos, program_offset, metadata_size }
Constants { data_pointer_pos, is_ts_pos, program_offset, raw_metadata_size }
}
Loading