Improve runtime speed

This commit is contained in:
Simon Sawicki
2025-08-26 20:41:27 +02:00
parent d0490e114a
commit 860b4d8590
7 changed files with 98 additions and 149 deletions

View File

@@ -1,13 +1,10 @@
import {
type ArrowFunctionExpression,
type BlockStatement,
type Node,
} from "@babel/types";
import { type ESTree } from "meriyah";
import { matchesStructure } from "./utils.ts";
import { type DeepPartial } from "./types.ts";
const identifier: DeepPartial<Node> = {
const identifier: DeepPartial<ESTree.VariableDeclaration> = {
type: "VariableDeclaration",
kind: "var",
declarations: [
{
type: "VariableDeclarator",
@@ -24,35 +21,39 @@ const identifier: DeepPartial<Node> = {
},
},
],
kind: "var",
};
const catchBlockBody = [
{
"type": "ReturnStatement",
"argument": {
"type": "BinaryExpression",
"operator": "+",
"left": {
"type": "MemberExpression",
"object": {
"type": "Identifier",
type: "ReturnStatement",
argument: {
type: "BinaryExpression",
left: {
type: "MemberExpression",
object: {
type: "Identifier",
},
"property": {
"type": "NumericLiteral",
computed: true,
property: {
type: "Literal",
},
optional: false,
},
"right": {
"type": "Identifier",
right: {
type: "Identifier",
},
operator: "+",
},
},
] as const;
export function extract(node: Node): ArrowFunctionExpression | null {
export function extract(
node: ESTree.Node,
): ESTree.ArrowFunctionExpression | null {
if (!matchesStructure(node, identifier)) {
// Fallback search for try { } catch { return X[12] + Y }
let name: string | undefined | null = null;
let block: BlockStatement | null = null;
let block: ESTree.BlockStatement | null | undefined = null;
switch (node.type) {
case "ExpressionStatement": {
if (
@@ -109,17 +110,15 @@ export function extract(node: Node): ArrowFunctionExpression | null {
return makeSolverFuncFromName(firstElement.name);
}
function makeSolverFuncFromName(name: string): ArrowFunctionExpression {
function makeSolverFuncFromName(name: string): ESTree.ArrowFunctionExpression {
return {
type: "ArrowFunctionExpression",
params: [
{
type: "Identifier",
name: "x",
name: "nsig",
},
],
async: false,
expression: true,
body: {
type: "CallExpression",
callee: {
@@ -129,9 +128,13 @@ function makeSolverFuncFromName(name: string): ArrowFunctionExpression {
arguments: [
{
type: "Identifier",
name: "x",
name: "nsig",
},
],
optional: false,
},
async: false,
expression: false,
generator: false,
};
}

View File

@@ -1,11 +1,14 @@
import { type Node } from "@babel/types";
import { parse } from "meriyah";
export const setupNodes: Node[] = [
export const setupNodes = parse(`
globalThis.XMLHttpRequest = { prototype: {} };
const window = Object.assign(Object.create(null), globalThis);
const document = {};
`).body || [
{
type: "ExpressionStatement",
expression: {
type: "AssignmentExpression",
operator: "=",
left: {
type: "MemberExpression",
object: {
@@ -17,23 +20,26 @@ export const setupNodes: Node[] = [
type: "Identifier",
name: "XMLHttpRequest",
},
optional: false,
},
operator: "=",
right: {
type: "ObjectExpression",
properties: [
{
type: "ObjectProperty",
method: false,
type: "Property",
key: {
type: "Identifier",
name: "prototype",
},
computed: false,
shorthand: false,
value: {
type: "ObjectExpression",
properties: [],
},
kind: "init",
computed: false,
method: false,
shorthand: false,
},
],
},
@@ -41,6 +47,7 @@ export const setupNodes: Node[] = [
},
{
type: "VariableDeclaration",
kind: "const",
declarations: [
{
type: "VariableDeclarator",
@@ -61,6 +68,7 @@ export const setupNodes: Node[] = [
type: "Identifier",
name: "assign",
},
optional: false,
},
arguments: [
{
@@ -76,25 +84,29 @@ export const setupNodes: Node[] = [
type: "Identifier",
name: "create",
},
optional: false,
},
arguments: [
{
type: "NullLiteral",
type: "Literal",
value: null,
},
],
optional: false,
},
{
type: "Identifier",
name: "globalThis",
},
],
optional: false,
},
},
],
kind: "const",
},
{
type: "VariableDeclaration",
kind: "const",
declarations: [
{
type: "VariableDeclarator",
@@ -108,6 +120,5 @@ export const setupNodes: Node[] = [
},
},
],
kind: "const",
},
];

View File

@@ -1,30 +1,23 @@
import {
type ArrowFunctionExpression,
type Expression,
type ExpressionStatement,
type FunctionExpression,
type Node,
} from "@babel/types";
import { type ESTree } from "meriyah";
import { matchesStructure } from "./utils.ts";
import { type DeepPartial } from "./types.ts";
const logicalExpression: DeepPartial<ExpressionStatement> = {
const logicalExpression: DeepPartial<ESTree.ExpressionStatement> = {
type: "ExpressionStatement",
expression: {
type: "LogicalExpression",
left: {
type: "Identifier",
},
operator: "&&",
right: {
type: "SequenceExpression",
expressions: [
{
type: "AssignmentExpression",
operator: "=",
left: {
type: "Identifier",
},
operator: "=",
right: {
type: "CallExpression",
callee: {
@@ -33,7 +26,7 @@ const logicalExpression: DeepPartial<ExpressionStatement> = {
arguments: {
or: [
[
{ type: "NumericLiteral" },
{ type: "Literal" },
{
type: "CallExpression",
callee: {
@@ -41,6 +34,7 @@ const logicalExpression: DeepPartial<ExpressionStatement> = {
name: "decodeURIComponent",
},
arguments: [{ type: "Identifier" }],
optional: false,
},
],
[
@@ -51,20 +45,20 @@ const logicalExpression: DeepPartial<ExpressionStatement> = {
name: "decodeURIComponent",
},
arguments: [{ type: "Identifier" }],
optional: false,
},
],
],
},
optional: false,
},
},
{
type: "CallExpression",
},
],
extra: {
parenthesized: true,
},
},
operator: "&&",
},
};
@@ -88,8 +82,12 @@ const identifier = {
}],
} as const;
export function extract(node: Node): ArrowFunctionExpression | null {
if (!matchesStructure(node, identifier as unknown as DeepPartial<Node>)) {
export function extract(
node: ESTree.Node,
): ESTree.ArrowFunctionExpression | null {
if (
!matchesStructure(node, identifier as unknown as DeepPartial<ESTree.Node>)
) {
return null;
}
const block = (node.type === "ExpressionStatement" &&
@@ -127,8 +125,6 @@ export function extract(node: Node): ArrowFunctionExpression | null {
name: "sig",
},
],
async: false,
expression: true,
body: {
type: "CallExpression",
callee: {
@@ -149,6 +145,10 @@ export function extract(node: Node): ArrowFunctionExpression | null {
name: "sig",
},
],
optional: false,
},
async: false,
expression: false,
generator: false,
};
}

View File

@@ -1,16 +1,12 @@
import { parse } from "@babel/parser";
import { generate } from "@babel/generator";
import { type ArrowFunctionExpression } from "@babel/types";
import { getFunctionNodes } from "./utils.ts";
import { type ESTree, parse } from "meriyah";
import { generate } from "astring";
import { extract as extractSig } from "./sig.ts";
import { extract as extractNsig } from "./nsig.ts";
import { setupNodes } from "./setup.ts";
export function preprocessPlayer(data: string): string {
const ast = parse(data, {
attachComment: false,
});
const body = ast.program.body;
const ast = parse(data);
const body = ast.body;
const block = (() => {
switch (body.length) {
@@ -45,10 +41,10 @@ export function preprocessPlayer(data: string): string {
})();
const found = {
nsig: [] as ArrowFunctionExpression[],
sig: [] as ArrowFunctionExpression[],
nsig: [] as ESTree.ArrowFunctionExpression[],
sig: [] as ESTree.ArrowFunctionExpression[],
};
const plainExpressions = block.body.filter((node) => {
const plainExpressions = block.body.filter((node: ESTree.Node) => {
const nsig = extractNsig(node);
if (nsig) {
found.nsig.push(nsig);
@@ -61,7 +57,7 @@ export function preprocessPlayer(data: string): string {
if (node.expression.type === "AssignmentExpression") {
return true;
}
return node.expression.type === "StringLiteral";
return node.expression.type === "Literal";
}
return true;
});
@@ -74,9 +70,7 @@ export function preprocessPlayer(data: string): string {
const message = `found ${unique.size} ${name} function possibilities`;
throw (
message +
(unique.size
? `: ${options.map((x) => generate(x)["code"]).join(", ")}`
: "")
(unique.size ? `: ${options.map((x) => generate(x)).join(", ")}` : "")
);
}
plainExpressions.push({
@@ -101,13 +95,9 @@ export function preprocessPlayer(data: string): string {
});
}
ast.program.body.splice(0, 0, ...setupNodes);
ast.body.splice(0, 0, ...setupNodes);
const { code } = generate(ast, {
comments: false,
compact: false,
concise: false,
});
const code = generate(ast);
return code;
}

View File

@@ -1,9 +1,8 @@
import { parse } from "@babel/parser";
import { type Node, type Statement } from "@babel/types";
import { type ESTree } from "meriyah";
import { type DeepPartial } from "./types.ts";
export function matchesStructure<T extends Node>(
obj: Node | Node[],
export function matchesStructure<T extends ESTree.Node>(
obj: ESTree.Node | ESTree.Node[],
structure: DeepPartial<T> | readonly DeepPartial<T>[],
): boolean {
if (Array.isArray(structure)) {
@@ -33,15 +32,6 @@ export function matchesStructure<T extends Node>(
return structure === obj;
}
export function getFunctionNodes(f: (...a: unknown[]) => void): Statement[] {
const func = parse(f.toString()).program.body[0];
if (func.type === "FunctionDeclaration") {
return func.body.body;
}
console.error("failed to parse function into nodes");
return [];
}
export function isOneOf<T>(value: unknown, ...of: readonly T[]): value is T {
return of.includes(value as T);
}