diff --git a/apps/oxlint/src-js/generated/deserialize.js b/apps/oxlint/src-js/generated/deserialize.js index 7006562245dbd..f93db5fef552f 100644 --- a/apps/oxlint/src-js/generated/deserialize.js +++ b/apps/oxlint/src-js/generated/deserialize.js @@ -19,13 +19,6 @@ export function deserializeProgramOnly(buffer, sourceText, sourceByteLen, getLoc return deserializeWith(buffer, sourceText, sourceByteLen, getLoc, deserializeProgram); } -export function reset() { - // Increment `astId` counter. - // This prevents `program.comments` being accessed after the AST is done with. - // (see `deserializeProgram`) - astId++; -} - function deserializeWith(buffer, sourceTextInput, sourceByteLenInput, getLocInput, deserialize) { uint8 = buffer; uint32 = buffer.uint32; @@ -34,22 +27,21 @@ function deserializeWith(buffer, sourceTextInput, sourceByteLenInput, getLocInpu sourceByteLen = sourceByteLenInput; sourceIsAscii = sourceText.length === sourceByteLen; getLoc = getLocInput; - let data = deserialize(uint32[536870902]); + return deserialize(uint32[536870902]); +} + +export function resetBuffer() { + // Clear buffer and source text string to allow them to be garbage collected uint8 = uint32 = float64 = sourceText = void 0; - return data; + astId++; } function deserializeProgram(pos) { - // Buffers will be cleaned up after the main program is deserialized. - // We hold references here in case the comments need to be later accessed. - let refUint32 = uint32, - refUint8 = uint8, - refSourceText = sourceText, - localAstId = astId, + let localAstId = astId, end = deserializeU32(pos + 4), program = parent = { __proto__: NodeProto, @@ -58,21 +50,11 @@ function deserializeProgram(pos) { sourceType: deserializeModuleKind(pos + 125), hashbang: null, get comments() { + // Check AST in buffer is still the same AST (buffers are reused) if (localAstId !== astId) throw Error('Comments are only accessible while linting the file'); - // Restore buffers - uint32 = refUint32; - uint8 = refUint8; - sourceText = refSourceText; - // Deserialize the comments + // Deserialize the comments. + // Replace this getter with the comments array, so we don't deserialize twice. let comments = deserializeVecComment(pos + 24); - // Drop the references - refUint32 = - refUint8 = - refSourceText = - uint32 = - uint8 = - sourceText = - void 0; Object.defineProperty(this, 'comments', { value: comments }); return comments; }, diff --git a/apps/oxlint/src-js/plugins/source_code.ts b/apps/oxlint/src-js/plugins/source_code.ts index a33d96d9fca26..1180acb567f7c 100644 --- a/apps/oxlint/src-js/plugins/source_code.ts +++ b/apps/oxlint/src-js/plugins/source_code.ts @@ -3,7 +3,7 @@ import { DATA_POINTER_POS_32, SOURCE_LEN_OFFSET } from '../generated/constants.j // We use the deserializer which removes `ParenthesizedExpression`s from AST, // and with `range`, `loc`, and `parent` properties on AST nodes, to match ESLint // @ts-expect-error we need to generate `.d.ts` file for this module -import { deserializeProgramOnly, reset as resetAst } from '../../dist/generated/deserialize.js'; +import { deserializeProgramOnly, resetBuffer } from '../../dist/generated/deserialize.js'; import visitorKeys from '../generated/keys.js'; import { @@ -78,7 +78,7 @@ export function resetSourceAndAst(): void { buffer = null; sourceText = null; ast = null; - resetAst(); + resetBuffer(); resetLines(); } diff --git a/crates/oxc_ast/src/serialize/mod.rs b/crates/oxc_ast/src/serialize/mod.rs index d0d3b54ff858d..622897c5d9c14 100644 --- a/crates/oxc_ast/src/serialize/mod.rs +++ b/crates/oxc_ast/src/serialize/mod.rs @@ -121,14 +121,7 @@ impl Program<'_> { /// `Program` span start is 0 (not 5). #[ast_meta] #[estree(raw_deser = " - /* IF COMMENTS */ - // Buffers will be cleaned up after the main program is deserialized. - // We hold references here in case the comments need to be later accessed. - let refUint32 = uint32; - let refUint8 = uint8; - let refSourceText = sourceText; const localAstId = astId; - /* END_IF */ const start = IS_TS ? 0 : DESER[u32](POS_OFFSET.span.start), end = DESER[u32](POS_OFFSET.span.end); @@ -140,15 +133,11 @@ impl Program<'_> { hashbang: null, /* IF COMMENTS */ get comments() { + // Check AST in buffer is still the same AST (buffers are reused) if (localAstId !== astId) throw new Error('Comments are only accessible while linting the file'); - // Restore buffers - uint32 = refUint32; - uint8 = refUint8; - sourceText = refSourceText; - // Deserialize the comments + // Deserialize the comments. + // Replace this getter with the comments array, so we don't deserialize twice. const comments = DESER[Vec](POS_OFFSET.comments); - // Drop the references - refUint32 = refUint8 = refSourceText = uint32 = uint8 = sourceText = undefined; Object.defineProperty(this, 'comments', { value: comments }); return comments; }, diff --git a/napi/parser/generated/deserialize/js.js b/napi/parser/generated/deserialize/js.js index 4cc8cfcfbfab4..67e5e0d08d605 100644 --- a/napi/parser/generated/deserialize/js.js +++ b/napi/parser/generated/deserialize/js.js @@ -8,7 +8,9 @@ const textDecoder = new TextDecoder('utf-8', { ignoreBOM: true }), { fromCodePoint } = String; export function deserialize(buffer, sourceText, sourceByteLen) { - return deserializeWith(buffer, sourceText, sourceByteLen, null, deserializeRawTransferData); + let data = deserializeWith(buffer, sourceText, sourceByteLen, null, deserializeRawTransferData); + resetBuffer(); + return data; } function deserializeWith(buffer, sourceTextInput, sourceByteLenInput, getLocInput, deserialize) { @@ -18,13 +20,16 @@ function deserializeWith(buffer, sourceTextInput, sourceByteLenInput, getLocInpu sourceText = sourceTextInput; sourceByteLen = sourceByteLenInput; sourceIsAscii = sourceText.length === sourceByteLen; - let data = deserialize(uint32[536870902]); + return deserialize(uint32[536870902]); +} + +export function resetBuffer() { + // Clear buffer and source text string to allow them to be garbage collected uint8 = uint32 = float64 = sourceText = void 0; - return data; } function deserializeProgram(pos) { diff --git a/napi/parser/generated/deserialize/js_parent.js b/napi/parser/generated/deserialize/js_parent.js index d9674a44f2f24..903880de514c6 100644 --- a/napi/parser/generated/deserialize/js_parent.js +++ b/napi/parser/generated/deserialize/js_parent.js @@ -8,7 +8,9 @@ const textDecoder = new TextDecoder('utf-8', { ignoreBOM: true }), { fromCodePoint } = String; export function deserialize(buffer, sourceText, sourceByteLen) { - return deserializeWith(buffer, sourceText, sourceByteLen, null, deserializeRawTransferData); + let data = deserializeWith(buffer, sourceText, sourceByteLen, null, deserializeRawTransferData); + resetBuffer(); + return data; } function deserializeWith(buffer, sourceTextInput, sourceByteLenInput, getLocInput, deserialize) { @@ -18,13 +20,16 @@ function deserializeWith(buffer, sourceTextInput, sourceByteLenInput, getLocInpu sourceText = sourceTextInput; sourceByteLen = sourceByteLenInput; sourceIsAscii = sourceText.length === sourceByteLen; - let data = deserialize(uint32[536870902]); + return deserialize(uint32[536870902]); +} + +export function resetBuffer() { + // Clear buffer and source text string to allow them to be garbage collected uint8 = uint32 = float64 = sourceText = void 0; - return data; } function deserializeProgram(pos) { diff --git a/napi/parser/generated/deserialize/js_range.js b/napi/parser/generated/deserialize/js_range.js index c94c07751fc8a..b3e2c346c0e15 100644 --- a/napi/parser/generated/deserialize/js_range.js +++ b/napi/parser/generated/deserialize/js_range.js @@ -8,7 +8,9 @@ const textDecoder = new TextDecoder('utf-8', { ignoreBOM: true }), { fromCodePoint } = String; export function deserialize(buffer, sourceText, sourceByteLen) { - return deserializeWith(buffer, sourceText, sourceByteLen, null, deserializeRawTransferData); + let data = deserializeWith(buffer, sourceText, sourceByteLen, null, deserializeRawTransferData); + resetBuffer(); + return data; } function deserializeWith(buffer, sourceTextInput, sourceByteLenInput, getLocInput, deserialize) { @@ -18,13 +20,16 @@ function deserializeWith(buffer, sourceTextInput, sourceByteLenInput, getLocInpu sourceText = sourceTextInput; sourceByteLen = sourceByteLenInput; sourceIsAscii = sourceText.length === sourceByteLen; - let data = deserialize(uint32[536870902]); + return deserialize(uint32[536870902]); +} + +export function resetBuffer() { + // Clear buffer and source text string to allow them to be garbage collected uint8 = uint32 = float64 = sourceText = void 0; - return data; } function deserializeProgram(pos) { diff --git a/napi/parser/generated/deserialize/js_range_parent.js b/napi/parser/generated/deserialize/js_range_parent.js index 5c06466c741b2..0bc08304f1ad7 100644 --- a/napi/parser/generated/deserialize/js_range_parent.js +++ b/napi/parser/generated/deserialize/js_range_parent.js @@ -8,7 +8,9 @@ const textDecoder = new TextDecoder('utf-8', { ignoreBOM: true }), { fromCodePoint } = String; export function deserialize(buffer, sourceText, sourceByteLen) { - return deserializeWith(buffer, sourceText, sourceByteLen, null, deserializeRawTransferData); + let data = deserializeWith(buffer, sourceText, sourceByteLen, null, deserializeRawTransferData); + resetBuffer(); + return data; } function deserializeWith(buffer, sourceTextInput, sourceByteLenInput, getLocInput, deserialize) { @@ -18,13 +20,16 @@ function deserializeWith(buffer, sourceTextInput, sourceByteLenInput, getLocInpu sourceText = sourceTextInput; sourceByteLen = sourceByteLenInput; sourceIsAscii = sourceText.length === sourceByteLen; - let data = deserialize(uint32[536870902]); + return deserialize(uint32[536870902]); +} + +export function resetBuffer() { + // Clear buffer and source text string to allow them to be garbage collected uint8 = uint32 = float64 = sourceText = void 0; - return data; } function deserializeProgram(pos) { diff --git a/napi/parser/generated/deserialize/ts.js b/napi/parser/generated/deserialize/ts.js index 3a4b166d00e46..f57ab586abc0e 100644 --- a/napi/parser/generated/deserialize/ts.js +++ b/napi/parser/generated/deserialize/ts.js @@ -8,7 +8,9 @@ const textDecoder = new TextDecoder('utf-8', { ignoreBOM: true }), { fromCodePoint } = String; export function deserialize(buffer, sourceText, sourceByteLen) { - return deserializeWith(buffer, sourceText, sourceByteLen, null, deserializeRawTransferData); + let data = deserializeWith(buffer, sourceText, sourceByteLen, null, deserializeRawTransferData); + resetBuffer(); + return data; } function deserializeWith(buffer, sourceTextInput, sourceByteLenInput, getLocInput, deserialize) { @@ -18,13 +20,16 @@ function deserializeWith(buffer, sourceTextInput, sourceByteLenInput, getLocInpu sourceText = sourceTextInput; sourceByteLen = sourceByteLenInput; sourceIsAscii = sourceText.length === sourceByteLen; - let data = deserialize(uint32[536870902]); + return deserialize(uint32[536870902]); +} + +export function resetBuffer() { + // Clear buffer and source text string to allow them to be garbage collected uint8 = uint32 = float64 = sourceText = void 0; - return data; } function deserializeProgram(pos) { diff --git a/napi/parser/generated/deserialize/ts_parent.js b/napi/parser/generated/deserialize/ts_parent.js index 781582f7fc9de..1e2be5b85d427 100644 --- a/napi/parser/generated/deserialize/ts_parent.js +++ b/napi/parser/generated/deserialize/ts_parent.js @@ -8,7 +8,9 @@ const textDecoder = new TextDecoder('utf-8', { ignoreBOM: true }), { fromCodePoint } = String; export function deserialize(buffer, sourceText, sourceByteLen) { - return deserializeWith(buffer, sourceText, sourceByteLen, null, deserializeRawTransferData); + let data = deserializeWith(buffer, sourceText, sourceByteLen, null, deserializeRawTransferData); + resetBuffer(); + return data; } function deserializeWith(buffer, sourceTextInput, sourceByteLenInput, getLocInput, deserialize) { @@ -18,13 +20,16 @@ function deserializeWith(buffer, sourceTextInput, sourceByteLenInput, getLocInpu sourceText = sourceTextInput; sourceByteLen = sourceByteLenInput; sourceIsAscii = sourceText.length === sourceByteLen; - let data = deserialize(uint32[536870902]); + return deserialize(uint32[536870902]); +} + +export function resetBuffer() { + // Clear buffer and source text string to allow them to be garbage collected uint8 = uint32 = float64 = sourceText = void 0; - return data; } function deserializeProgram(pos) { diff --git a/napi/parser/generated/deserialize/ts_range.js b/napi/parser/generated/deserialize/ts_range.js index 2439b6447b0e9..f387e11dfaac4 100644 --- a/napi/parser/generated/deserialize/ts_range.js +++ b/napi/parser/generated/deserialize/ts_range.js @@ -8,7 +8,9 @@ const textDecoder = new TextDecoder('utf-8', { ignoreBOM: true }), { fromCodePoint } = String; export function deserialize(buffer, sourceText, sourceByteLen) { - return deserializeWith(buffer, sourceText, sourceByteLen, null, deserializeRawTransferData); + let data = deserializeWith(buffer, sourceText, sourceByteLen, null, deserializeRawTransferData); + resetBuffer(); + return data; } function deserializeWith(buffer, sourceTextInput, sourceByteLenInput, getLocInput, deserialize) { @@ -18,13 +20,16 @@ function deserializeWith(buffer, sourceTextInput, sourceByteLenInput, getLocInpu sourceText = sourceTextInput; sourceByteLen = sourceByteLenInput; sourceIsAscii = sourceText.length === sourceByteLen; - let data = deserialize(uint32[536870902]); + return deserialize(uint32[536870902]); +} + +export function resetBuffer() { + // Clear buffer and source text string to allow them to be garbage collected uint8 = uint32 = float64 = sourceText = void 0; - return data; } function deserializeProgram(pos) { diff --git a/napi/parser/generated/deserialize/ts_range_parent.js b/napi/parser/generated/deserialize/ts_range_parent.js index 141d8d8103045..8667ddbbb8c45 100644 --- a/napi/parser/generated/deserialize/ts_range_parent.js +++ b/napi/parser/generated/deserialize/ts_range_parent.js @@ -8,7 +8,9 @@ const textDecoder = new TextDecoder('utf-8', { ignoreBOM: true }), { fromCodePoint } = String; export function deserialize(buffer, sourceText, sourceByteLen) { - return deserializeWith(buffer, sourceText, sourceByteLen, null, deserializeRawTransferData); + let data = deserializeWith(buffer, sourceText, sourceByteLen, null, deserializeRawTransferData); + resetBuffer(); + return data; } function deserializeWith(buffer, sourceTextInput, sourceByteLenInput, getLocInput, deserialize) { @@ -18,13 +20,16 @@ function deserializeWith(buffer, sourceTextInput, sourceByteLenInput, getLocInpu sourceText = sourceTextInput; sourceByteLen = sourceByteLenInput; sourceIsAscii = sourceText.length === sourceByteLen; - let data = deserialize(uint32[536870902]); + return deserialize(uint32[536870902]); +} + +export function resetBuffer() { + // Clear buffer and source text string to allow them to be garbage collected uint8 = uint32 = float64 = sourceText = void 0; - return data; } function deserializeProgram(pos) { diff --git a/tasks/ast_tools/src/generators/raw_transfer.rs b/tasks/ast_tools/src/generators/raw_transfer.rs index 0828f9219df86..ce09e42b0ab5a 100644 --- a/tasks/ast_tools/src/generators/raw_transfer.rs +++ b/tasks/ast_tools/src/generators/raw_transfer.rs @@ -155,7 +155,9 @@ fn generate_deserializers( /* IF !LINTER */ export function deserialize(buffer, sourceText, sourceByteLen) {{ - return deserializeWith(buffer, sourceText, sourceByteLen, null, deserializeRawTransferData); + const data = deserializeWith(buffer, sourceText, sourceByteLen, null, deserializeRawTransferData); + resetBuffer(); + return data; }} /* END_IF */ @@ -163,13 +165,6 @@ fn generate_deserializers( export function deserializeProgramOnly(buffer, sourceText, sourceByteLen, getLoc) {{ return deserializeWith(buffer, sourceText, sourceByteLen, getLoc, deserializeProgram); }} - - export function reset() {{ - // Increment `astId` counter. - // This prevents `program.comments` being accessed after the AST is done with. - // (see `deserializeProgram`) - astId++; - }} /* END_IF */ function deserializeWith(buffer, sourceTextInput, sourceByteLenInput, getLocInput, deserialize) {{ @@ -183,11 +178,17 @@ fn generate_deserializers( if (LOC) getLoc = getLocInput; - const data = deserialize(uint32[{data_pointer_pos_32}]); + return deserialize(uint32[{data_pointer_pos_32}]); + }} + export function resetBuffer() {{ + // Clear buffer and source text string to allow them to be garbage collected uint8 = uint32 = float64 = sourceText = undefined; - return data; + // Increment `astId` counter. + // This prevents `program.comments` being accessed after the AST is done with. + // (see `deserializeProgram`) + if (COMMENTS) astId++; }} ");