Skip to content

Commit 0636080

Browse files
committed
refactor(napi/parser, allocator): raw transfer: store buffer size and align as consts
1 parent d009bdb commit 0636080

File tree

12 files changed

+119
-44
lines changed

12 files changed

+119
-44
lines changed

.github/generated/ast_changes_watch_list.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
src:
55
- '.github/generated/ast_changes_watch_list.yml'
6+
- 'crates/oxc_allocator/src/generated/fixed_size_constants.rs'
67
- 'crates/oxc_ast/src/ast/comment.rs'
78
- 'crates/oxc_ast/src/ast/js.rs'
89
- 'crates/oxc_ast/src/ast/jsx.rs'
@@ -68,6 +69,7 @@ src:
6869
- 'napi/parser/generated/lazy/walk.js'
6970
- 'napi/parser/src/generated/assert_layouts.rs'
7071
- 'napi/parser/src/generated/derive_estree.rs'
72+
- 'napi/parser/src/generated/raw_transfer_constants.rs'
7173
- 'napi/parser/src/raw_transfer_types.rs'
7274
- 'npm/oxc-types/types.d.ts'
7375
- 'tasks/ast_tools/src/**'

crates/oxc_allocator/src/fixed_size.rs

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,12 @@ use std::{
55
ptr::NonNull,
66
};
77

8-
use crate::Allocator;
8+
use crate::{
9+
Allocator,
10+
fixed_size_constants::{BUFFER_ALIGN, BUFFER_SIZE},
11+
};
912

1013
const TWO_GIB: usize = 1 << 31;
11-
const FOUR_GIB: usize = 1 << 32;
1214

1315
// What we ideally want is an allocation 2 GiB in size, aligned on 4 GiB.
1416
// But system allocator on Mac OS refuses allocations with 4 GiB alignment.
@@ -25,10 +27,8 @@ const FOUR_GIB: usize = 1 << 32;
2527
// Could just use that built-in workaround, rather than implementing our own, or allocate a 6 GiB chunk
2628
// with alignment 16, to skip Rust's built-in workaround.
2729
// Note: Rust's workaround will likely commit a whole page of memory, just to store the real pointer.
28-
const ALLOC_SIZE: usize = FOUR_GIB;
30+
const ALLOC_SIZE: usize = BUFFER_SIZE + TWO_GIB;
2931
const ALLOC_ALIGN: usize = TWO_GIB;
30-
const CHUNK_SIZE: usize = TWO_GIB;
31-
pub const CHUNK_ALIGN: usize = FOUR_GIB;
3232

3333
const ALLOC_LAYOUT: Layout = match Layout::from_size_align(ALLOC_SIZE, ALLOC_ALIGN) {
3434
Ok(layout) => layout,
@@ -71,12 +71,12 @@ impl FixedSizeAllocator {
7171
alloc_ptr.add(offset)
7272
};
7373

74-
debug_assert!(chunk_ptr.as_ptr() as usize % CHUNK_ALIGN == 0);
74+
debug_assert!(chunk_ptr.as_ptr() as usize % BUFFER_ALIGN == 0);
7575

76-
// SAFETY: Memory region starting at `chunk_ptr` with `CHUNK_SIZE` bytes is within
76+
// SAFETY: Memory region starting at `chunk_ptr` with `BUFFER_SIZE` bytes is within
7777
// the allocation we just made.
7878
// `chunk_ptr` has high alignment (4 GiB). `size` is large and a high power of 2 (2 GiB).
79-
let allocator = unsafe { Allocator::from_raw_parts(chunk_ptr, CHUNK_SIZE) };
79+
let allocator = unsafe { Allocator::from_raw_parts(chunk_ptr, BUFFER_SIZE) };
8080

8181
// Store pointer to original allocation, so it can be used to deallocate in `drop`
8282
Self { allocator: ManuallyDrop::new(allocator), alloc_ptr }
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
// Auto-generated code, DO NOT EDIT DIRECTLY!
2+
// To edit this generated file you have to edit `tasks/ast_tools/src/generators/raw_transfer.rs`.
3+
4+
#![expect(clippy::unreadable_literal)]
5+
6+
pub const BUFFER_SIZE: usize = 2147483648;
7+
pub const BUFFER_ALIGN: usize = 4294967296;

crates/oxc_allocator/src/lib.rs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,3 +65,20 @@ pub use pool::{AllocatorGuard, AllocatorPool};
6565
pub use string_builder::StringBuilder;
6666
pub use take_in::{Dummy, TakeIn};
6767
pub use vec::Vec;
68+
69+
mod generated {
70+
#[cfg(all(
71+
feature = "fixed_size",
72+
not(feature = "disable_fixed_size"),
73+
target_pointer_width = "64",
74+
target_endian = "little"
75+
))]
76+
pub mod fixed_size_constants;
77+
}
78+
#[cfg(all(
79+
feature = "fixed_size",
80+
not(feature = "disable_fixed_size"),
81+
target_pointer_width = "64",
82+
target_endian = "little"
83+
))]
84+
use generated::fixed_size_constants;

crates/oxc_allocator/src/pool.rs

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -117,10 +117,7 @@ mod wrapper {
117117
target_endian = "little"
118118
))]
119119
mod wrapper {
120-
use crate::{
121-
Allocator,
122-
fixed_size::{CHUNK_ALIGN, FixedSizeAllocator},
123-
};
120+
use crate::{Allocator, fixed_size::FixedSizeAllocator, fixed_size_constants::BUFFER_ALIGN};
124121

125122
/// Structure which wraps an [`Allocator`] with fixed size of 2 GiB, and aligned on 4 GiB.
126123
///
@@ -144,12 +141,12 @@ mod wrapper {
144141
self.0.reset();
145142

146143
// Set data pointer back to start.
147-
// SAFETY: Fixed-size allocators have data pointer originally aligned on `CHUNK_ALIGN`,
148-
// and size less than `CHUNK_ALIGN`. So we can restore original data pointer by rounding down
149-
// to next multiple of `CHUNK_ALIGN`.
144+
// SAFETY: Fixed-size allocators have data pointer originally aligned on `BUFFER_ALIGN`,
145+
// and size less than `BUFFER_ALIGN`. So we can restore original data pointer by rounding down
146+
// to next multiple of `BUFFER_ALIGN`.
150147
unsafe {
151148
let data_ptr = self.0.data_ptr();
152-
let offset = data_ptr.as_ptr() as usize % CHUNK_ALIGN;
149+
let offset = data_ptr.as_ptr() as usize % BUFFER_ALIGN;
153150
let data_ptr = data_ptr.sub(offset);
154151
self.0.set_data_ptr(data_ptr);
155152
}

napi/parser/generated/constants.js

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,16 @@
11
// Auto-generated code, DO NOT EDIT DIRECTLY!
22
// To edit this generated file you have to edit `tasks/ast_tools/src/generators/raw_transfer.rs`.
33

4-
const DATA_POINTER_POS_32 = 536870908,
4+
const BUFFER_SIZE = 2147483648,
5+
BUFFER_ALIGN = 4294967296,
6+
DATA_POINTER_POS_32 = 536870908,
57
IS_TS_FLAG_POS = 2147483636,
68
PROGRAM_OFFSET = 0;
79

8-
module.exports = { DATA_POINTER_POS_32, IS_TS_FLAG_POS, PROGRAM_OFFSET };
10+
module.exports = {
11+
BUFFER_SIZE,
12+
BUFFER_ALIGN,
13+
DATA_POINTER_POS_32,
14+
IS_TS_FLAG_POS,
15+
PROGRAM_OFFSET,
16+
};

napi/parser/raw-transfer/common.js

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ const {
77
parseAsyncRaw: parseAsyncRawBinding,
88
getBufferOffset,
99
} = require('../bindings.js');
10-
const { IS_TS_FLAG_POS } = require('../generated/constants.js');
10+
const { BUFFER_SIZE, BUFFER_ALIGN, IS_TS_FLAG_POS } = require('../generated/constants.js');
1111

1212
module.exports = {
1313
parseSyncRawImpl,
@@ -141,9 +141,8 @@ async function parseAsyncRawImpl(filename, sourceText, options, convert) {
141141
return data;
142142
}
143143

144-
const ONE_GIB = 1 << 30,
145-
TWO_GIB = ONE_GIB * 2,
146-
SIX_GIB = ONE_GIB * 6;
144+
const ARRAY_BUFFER_SIZE = BUFFER_SIZE + BUFFER_ALIGN;
145+
const ONE_GIB = 1 << 30;
147146

148147
// We keep a cache of buffers for raw transfer, so we can reuse them as much as possible.
149148
//
@@ -277,10 +276,10 @@ function clearBuffersCache() {
277276
* @returns {Uint8Array} - Buffer
278277
*/
279278
function createBuffer() {
280-
const arrayBuffer = new ArrayBuffer(SIX_GIB);
279+
const arrayBuffer = new ArrayBuffer(ARRAY_BUFFER_SIZE);
281280
const offset = getBufferOffset(new Uint8Array(arrayBuffer));
282-
const buffer = new Uint8Array(arrayBuffer, offset, TWO_GIB);
283-
buffer.uint32 = new Uint32Array(arrayBuffer, offset, TWO_GIB / 4);
284-
buffer.float64 = new Float64Array(arrayBuffer, offset, TWO_GIB / 8);
281+
const buffer = new Uint8Array(arrayBuffer, offset, BUFFER_SIZE);
282+
buffer.uint32 = new Uint32Array(arrayBuffer, offset, BUFFER_SIZE / 4);
283+
buffer.float64 = new Float64Array(arrayBuffer, offset, BUFFER_SIZE / 8);
285284
return buffer;
286285
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
// Auto-generated code, DO NOT EDIT DIRECTLY!
2+
// To edit this generated file you have to edit `tasks/ast_tools/src/generators/raw_transfer.rs`.
3+
4+
#![expect(clippy::unreadable_literal)]
5+
6+
pub const BUFFER_SIZE: usize = 2147483648;
7+
pub const BUFFER_ALIGN: usize = 4294967296;

napi/parser/src/lib.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,11 @@ mod generated {
4949
// Note: We intentionally don't import `generated/derive_estree.rs`. It's not needed.
5050
#[cfg(debug_assertions)]
5151
pub mod assert_layouts;
52+
#[cfg(all(target_pointer_width = "64", target_endian = "little"))]
53+
pub mod raw_transfer_constants;
5254
}
55+
#[cfg(all(target_pointer_width = "64", target_endian = "little"))]
56+
use generated::raw_transfer_constants;
5357

5458
#[derive(Clone, Copy, PartialEq, Eq)]
5559
enum AstType {

napi/parser/src/raw_transfer.rs

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ use oxc_napi::get_source_type;
1919

2020
use crate::{
2121
AstType, ParserOptions, get_ast_type, parse,
22+
raw_transfer_constants::{BUFFER_ALIGN, BUFFER_SIZE},
2223
raw_transfer_types::{EcmaScriptModule, Error, RawTransferData},
2324
};
2425

@@ -35,22 +36,19 @@ use crate::{
3536
// 2. JS bitwise operators work only on signed 32-bit integers, with 32nd bit as sign bit.
3637
// So avoiding the 32nd bit being set enables using `>>` bitshift operator, which may be cheaper
3738
// than `>>>`, without offsets being interpreted as negative.
38-
const TWO_GIB: usize = 1 << 31;
39-
const FOUR_GIB: usize = 1 << 32;
4039

41-
const BUFFER_SIZE: usize = TWO_GIB;
42-
const BUFFER_ALIGN: usize = FOUR_GIB;
4340
const BUMP_ALIGN: usize = 16;
4441

45-
/// Get offset within a `Uint8Array` which is aligned on 4 GiB.
42+
/// Get offset within a `Uint8Array` which is aligned on `BUFFER_ALIGN`.
4643
///
4744
/// Does not check that the offset is within bounds of `buffer`.
48-
/// To ensure it always is, provide a `Uint8Array` of at least 4 GiB size.
45+
/// To ensure it always is, provide a `Uint8Array` of at least `BUFFER_SIZE` bytes.
4946
#[napi(skip_typescript)]
5047
pub fn get_buffer_offset(buffer: Uint8Array) -> u32 {
5148
let buffer = &*buffer;
52-
let buffer_addr32 = buffer.as_ptr() as u32;
53-
0u32.wrapping_sub(buffer_addr32)
49+
let offset = BUFFER_ALIGN - (buffer.as_ptr() as usize % BUFFER_ALIGN);
50+
#[expect(clippy::cast_possible_truncation)]
51+
return offset as u32;
5452
}
5553

5654
/// Parse AST into provided `Uint8Array` buffer, synchronously.

0 commit comments

Comments
 (0)