mirror of
https://github.com/aphrody-labs/oxc.git
synced 2026-10-18 21:35:44 +00:00
perf(packages/codegen): reduce writes and branches printing functions (#27455)
Perf optimization. When printing a `function`, `node.async` is fairly unpredictable - some functions are async, others aren't. Make whether to print the `async` keyword a branchless decision. Also use a single write in all cases to print the whole prefix of the function (e.g. `function`, `declare async function` etc). The main win here is to avoid printing a single space as a separate `write` call in the common case of named functions.
This commit is contained in:
1 parent
5f3865cc2e
commit
b0dbfffbce
1 file changed
+64
-15
@@ -23,6 +23,47 @@ import { printTypeAnnotation, printTypeParameters } from "./typescript.ts";
|
||||
import type { State } from "../state.ts";
|
||||
import type * as ESTree from "../../../../npm/oxc-types/types.d.ts";
|
||||
|
||||
/**
|
||||
* The keywords a named function begins with, indexed as described in `printFunction`.
|
||||
*
|
||||
* Each ends with a space, which separates it from the name.
|
||||
* After `*` the space is not needed, but matches `oxc_codegen`'s style.
|
||||
*
|
||||
* Only TS builds include the `declare` forms.
|
||||
*/
|
||||
const NAMED_FUNCTION_PREFIXES = TS
|
||||
? [
|
||||
"function ",
|
||||
"async function ",
|
||||
"function* ",
|
||||
"async function* ",
|
||||
"declare function ",
|
||||
"declare async function ",
|
||||
"declare function* ",
|
||||
"declare async function* ",
|
||||
]
|
||||
: ["function ", "async function ", "function* ", "async function* "];
|
||||
|
||||
/**
|
||||
* The keywords an anonymous function begins with, indexed as described in `printFunction`.
|
||||
*
|
||||
* No trailing space is needed. The generator forms have one after `*` anyway, to match `oxc_codegen`'s style.
|
||||
*
|
||||
* Only TS builds include the `declare` forms.
|
||||
*/
|
||||
const ANONYMOUS_FUNCTION_PREFIXES = TS
|
||||
? [
|
||||
"function",
|
||||
"async function",
|
||||
"function* ",
|
||||
"async function* ",
|
||||
"declare function",
|
||||
"declare async function",
|
||||
"declare function* ",
|
||||
"declare async function* ",
|
||||
]
|
||||
: ["function", "async function", "function* ", "async function* "];
|
||||
|
||||
/**
|
||||
* Print a function declaration or expression, from `async` through to the closing brace of its body.
|
||||
*
|
||||
@@ -41,30 +82,38 @@ export function printFunction(node: ESTree.Function, state: State): void {
|
||||
|
||||
printSpaceBeforeIdentifier(state);
|
||||
|
||||
// The node's mapping goes on whichever of these is written first
|
||||
const declare = TS && node.declare;
|
||||
if (declare) {
|
||||
writeWithMap(state, "declare ", CAT_OTHER, node.start, node.end, node);
|
||||
writeIdent(state, node.async ? "async function" : "function");
|
||||
// The node's mapping goes on whatever keyword begins the function, which is written as a single string.
|
||||
//
|
||||
// The string comes from a table, rather than from testing each flag in turn.
|
||||
// Real code mixes `async` and plain functions freely, so a branch on `async` would often be mispredicted.
|
||||
// Bit 0 of the index is `async`, bit 1 is generator, and bit 2 is `declare` (TS builds only).
|
||||
//
|
||||
// V8 compiles each `flag === true` to a single compare against the `true` object, with no branch.
|
||||
// Any value other than `true` (e.g. `null` or `undefined`) counts as `false`.
|
||||
const generator = node.generator === true;
|
||||
const prefixIndex = TS
|
||||
? ((node.async === true) as unknown as number)
|
||||
| (((generator === true) as unknown as number) << 1)
|
||||
| (((node.declare === true) as unknown as number) << 2)
|
||||
: ((node.async === true) as unknown as number)
|
||||
| (((generator === true) as unknown as number) << 1);
|
||||
|
||||
const { id } = node;
|
||||
if (id != null) {
|
||||
writeWithMapNoLast(state, NAMED_FUNCTION_PREFIXES[prefixIndex], node.start, node.end, node);
|
||||
writeWithMapNamed(state, id.name, id.start, id.end, id);
|
||||
} else {
|
||||
writeWithMap(
|
||||
state,
|
||||
node.async ? "async function" : "function",
|
||||
CAT_IDENT,
|
||||
ANONYMOUS_FUNCTION_PREFIXES[prefixIndex],
|
||||
// Only the generator prefixes end with a space
|
||||
generator === true ? CAT_OTHER : CAT_IDENT,
|
||||
node.start,
|
||||
node.end,
|
||||
node,
|
||||
);
|
||||
}
|
||||
|
||||
if (node.generator) write(state, "* ", CAT_OTHER);
|
||||
|
||||
const { id } = node;
|
||||
if (id != null) {
|
||||
printSpaceBeforeIdentifier(state);
|
||||
writeWithMapNamed(state, id.name, id.start, id.end, id);
|
||||
}
|
||||
|
||||
if (TS) printTypeParameters(node.typeParameters, state);
|
||||
|
||||
printParenParams(node.params, state);
|
||||
|
||||
Reference in new issue
Block a user