perf(packages/codegen): remove branches from loops printing arrays (#27614)

Perf optimization.

Optimize printing arrays - `ArrayExpression` and `ArrayPattern`.

- Move branches out of the loops, so each loop iteration is as quick as possible.
- Convert `write` calls to `writeNoLast` wherever possible.
This commit is contained in:
overlookmotel committed 2026-10-12 21:13:12 +00:00
1 parent 760b60ba14
commit 3c289f3961
3 files changed
+108 -75

No files matched your search

@@ -3,7 +3,7 @@
import { typeAssertIs } from "../asserts.ts";
import { printPropertyKey } from "./binding_pattern.ts";
import { CAT_CLOSE_BRACKET, CAT_OTHER } from "./categories.ts";
import { write, writeWithMap, writeWithMapNamed } from "./write.ts";
import { write, writeNoLast, writeWithMap, writeWithMapNamed } from "./write.ts";
import { printExpression, printMemberExpression } from "./expression.ts";
import { printSpaceBeforeIdentifier } from "./space.ts";
import { CTX_NONE } from "./operators.ts";
@@ -141,36 +141,43 @@ function printAssignmentTargetMaybeDefault(
* @param state - Printer state
*/
function printArrayAssignmentTarget(node: ESTree.ArrayAssignmentTarget, state: State): void {
const { elements } = node;
let { length } = elements;
let rest: ESTree.BindingRestElement | ESTree.AssignmentTargetRest | null = null;
if (length > 0) {
const lastElement = elements[length - 1];
if (lastElement != null && lastElement.type === "RestElement") {
rest = lastElement;
length--;
}
}
writeWithMap(state, "[", CAT_OTHER, node.start, node.end, node);
for (let i = 0; i < length; i++) {
if (i !== 0) write(state, ", ", CAT_OTHER);
const element = elements[i];
if (element != null) {
typeAssertIs<ESTree.AssignmentTargetMaybeDefault>(element);
printAssignmentTargetMaybeDefault(element, state);
}
if (i === length - 1 && (element == null || rest !== null)) {
write(state, ",", CAT_OTHER);
}
}
const { elements } = node,
{ length } = elements;
if (rest !== null) {
if (length > 0) write(state, " ", CAT_OTHER);
writeWithMap(state, "...", CAT_OTHER, rest.start, rest.end, rest);
printAssignmentTarget(rest.argument, state);
if (length !== 0) {
const lastElement = elements[length - 1];
if (lastElement !== null && lastElement.type === "RestElement") {
// Print elements before the `RestElement`
const restIndex = length - 1;
for (let i = 0; i < restIndex; i++) {
// `RestElement` can only be last, and this loop stops before it
const element = elements[i] as ESTree.AssignmentTargetMaybeDefault | null;
if (element !== null) printAssignmentTargetMaybeDefault(element, state);
write(state, ", ", CAT_OTHER);
}
// Print `RestElement`
writeWithMap(state, "...", CAT_OTHER, lastElement.start, lastElement.end, lastElement);
printAssignmentTarget(lastElement.argument, state);
} else {
// `RestElement` can only be last, and the last element is not one
typeAssertIs<(ESTree.AssignmentTargetMaybeDefault | null)[]>(elements);
const firstElement = elements[0];
if (firstElement !== null) printAssignmentTargetMaybeDefault(firstElement, state);
for (let i = 1; i < length; i++) {
write(state, ", ", CAT_OTHER);
const element = elements[i];
if (element !== null) printAssignmentTargetMaybeDefault(element, state);
}
// A trailing hole needs a comma after it
if (lastElement === null) writeNoLast(state, ",");
}
}
write(state, "]", CAT_CLOSE_BRACKET);
@@ -2,7 +2,13 @@
import { typeAssertIs } from "../asserts.ts";
import { CAT_CLOSE_BRACKET, CAT_OTHER, CAT_QUESTION } from "./categories.ts";
import { write, writeWithMap, writeWithMapNamed, writeWithMapNamedPrivate } from "./write.ts";
import {
write,
writeNoLast,
writeWithMap,
writeWithMapNamed,
writeWithMapNamedPrivate,
} from "./write.ts";
import { printExpression } from "./expression.ts";
import { printSpaceBeforeIdentifier } from "./space.ts";
import { printLiteral } from "./literal.ts";
@@ -170,38 +176,43 @@ export function printPropertyKey(key: ESTree.PropertyKey, state: State): void {
* @param state - Printer state
*/
function printArrayBindingPattern(node: ESTree.ArrayPattern, state: State): void {
// Oxc stores the rest element separately from the other elements.
// A comma and a space separate it from any elements before it.
const { elements } = node;
let { length } = elements;
let rest: ESTree.BindingRestElement | null = null;
if (length > 0) {
const lastElement = elements[length - 1];
if (lastElement != null && lastElement.type === "RestElement") {
rest = lastElement;
length--;
}
}
writeWithMap(state, "[", CAT_OTHER, node.start, node.end, node);
for (let i = 0; i < length; i++) {
if (i !== 0) write(state, ", ", CAT_OTHER);
const { elements } = node,
{ length } = elements;
const element = elements[i];
if (element != null) printBindingPattern(element, state);
if (length !== 0) {
const lastElement = elements[length - 1];
if (lastElement !== null && lastElement.type === "RestElement") {
// Print elements before the `RestElement`
const restIndex = length - 1;
for (let i = 0; i < restIndex; i++) {
const element = elements[i];
if (element !== null) printBindingPattern(element, state);
write(state, ", ", CAT_OTHER);
}
if (i === length - 1 && (element == null || rest !== null)) write(state, ",", CAT_OTHER);
}
// Print `RestElement`
writeWithMap(state, "...", CAT_OTHER, lastElement.start, lastElement.end, lastElement);
printBindingPattern(lastElement.argument, state);
if (TS) {
const { typeAnnotation } = lastElement;
if (typeAnnotation != null) printTypeAnnotation(typeAnnotation, state);
}
} else {
// No `RestElement` - print all elements
const firstElement = elements[0];
if (firstElement !== null) printBindingPattern(firstElement, state);
if (rest !== null) {
if (length > 0) write(state, " ", CAT_OTHER);
writeWithMap(state, "...", CAT_OTHER, rest.start, rest.end, rest);
printBindingPattern(rest.argument, state);
if (TS) {
const { typeAnnotation } = rest;
if (typeAnnotation != null) printTypeAnnotation(typeAnnotation, state);
for (let i = 1; i < length; i++) {
write(state, ", ", CAT_OTHER);
const element = elements[i];
if (element !== null) printBindingPattern(element, state);
}
// A trailing hole needs a comma after it
if (lastElement === null) writeNoLast(state, ",");
}
}
+34 -19
View File
@@ -632,35 +632,50 @@ function printObjectProperty(node: ESTree.ObjectPropertyKind, state: State): voi
* @param state - Printer state
*/
function printArrayExpression(node: ESTree.ArrayExpression, state: State): void {
const { elements } = node;
const { length } = elements;
const isMultiLine = length > 2;
writeWithMap(state, "[", CAT_OTHER, node.start, node.end, node);
if (isMultiLine) state.indentLevel++;
const { elements } = node,
{ length } = elements;
for (let i = 0; i < length; i++) {
if (isMultiLine) {
write(state, i !== 0 ? ",\n" : "\n", CAT_OTHER);
printIndent(state);
} else if (i !== 0) {
write(state, ", ", CAT_OTHER);
}
if (length > 2) {
// 3 or more elements, each on its own line
state.indentLevel++;
writeNoLast(state, "\n");
printIndent(state);
const element = elements[i];
// `printExpression` prints a spread too
if (element != null) printExpression(element, state, PREC_COMMA, CTX_NONE);
const firstElement = elements[0];
if (firstElement !== null) printExpression(firstElement, state, PREC_COMMA, CTX_NONE);
if (i === length - 1 && element == null) {
write(state, ",", CAT_OTHER);
for (let i = 1; i < length; i++) {
// Indent level is at least 1, so `printIndent` always writes, which refreshes `last`
writeNoLast(state, ",\n");
printIndent(state);
const element = elements[i];
if (element !== null) printExpression(element, state, PREC_COMMA, CTX_NONE);
}
}
if (isMultiLine) {
write(state, "\n", CAT_OTHER);
// A trailing hole needs a comma after it.
// The last element is read again here, rather than kept from the loop,
// because keeping it would spill it to the stack on every turn of the loop.
writeNoLast(state, elements[length - 1] === null ? ",\n" : "\n");
state.indentLevel--;
printIndent(state);
} else if (length !== 0) {
// 1 or 2 elements, on one line
const firstElement = elements[0];
if (firstElement !== null) printExpression(firstElement, state, PREC_COMMA, CTX_NONE);
if (length === 2) {
write(state, ", ", CAT_OTHER);
const secondElement = elements[1];
if (secondElement !== null) printExpression(secondElement, state, PREC_COMMA, CTX_NONE);
}
// A trailing hole needs a comma after it
if (elements[length - 1] === null) writeNoLast(state, ",");
}
writeWithMapEnd(state, "]", CAT_CLOSE_BRACKET, node.start, node.end, node);