Merge pull request #21048 from Snuffleupagus/buildPostScriptJsFunction-forceInterpreter

Shorten the `src/core/postscript/` code a tiny bit
This commit is contained in:
Tim van der Meij 2026-04-05 18:19:33 +02:00 committed by GitHub
commit dd8f0a327f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 40 additions and 44 deletions

View File

@ -544,7 +544,7 @@ class PSStackToTree {
static #init() { static #init() {
// Binary operator ids — used by _evalOp. // Binary operator ids — used by _evalOp.
PSStackToTree.#binaryOps = new Set([ this.#binaryOps = new Set([
TOKEN.add, TOKEN.add,
TOKEN.sub, TOKEN.sub,
TOKEN.mul, TOKEN.mul,
@ -565,7 +565,7 @@ class PSStackToTree {
TOKEN.bitshift, TOKEN.bitshift,
]); ]);
// Unary operator ids. // Unary operator ids.
PSStackToTree.#unaryOps = new Set([ this.#unaryOps = new Set([
TOKEN.abs, TOKEN.abs,
TOKEN.neg, TOKEN.neg,
TOKEN.ceiling, TOKEN.ceiling,
@ -583,7 +583,7 @@ class PSStackToTree {
]); ]);
// Unary operators where f(f(x)) = f(x) — applying them twice is the same // Unary operators where f(f(x)) = f(x) — applying them twice is the same
// as applying them once. // as applying them once.
PSStackToTree.#idempotentUnary = new Set([ this.#idempotentUnary = new Set([
TOKEN.abs, TOKEN.abs,
TOKEN.ceiling, TOKEN.ceiling,
TOKEN.cvi, TOKEN.cvi,
@ -594,7 +594,7 @@ class PSStackToTree {
]); ]);
// Maps each comparison operator to its logical negation. // Maps each comparison operator to its logical negation.
// Used to simplify not(comparison) → negated-comparison. // Used to simplify not(comparison) → negated-comparison.
PSStackToTree.#negatedComparison = new Map([ this.#negatedComparison = new Map([
[TOKEN.eq, TOKEN.ne], [TOKEN.eq, TOKEN.ne],
[TOKEN.ne, TOKEN.eq], [TOKEN.ne, TOKEN.eq],
[TOKEN.lt, TOKEN.ge], [TOKEN.lt, TOKEN.ge],

View File

@ -327,8 +327,8 @@ class PsJsCompiler {
let ip = 0, let ip = 0,
sp = 0; sp = 0;
const n = ir.length; const n = ir.length;
const stack = PsJsCompiler.#stack; const stack = this.#stack;
const tmp = PsJsCompiler.#tmp; const tmp = this.#tmp;
while (ip < n) { while (ip < n) {
switch (ir[ip++] | 0) { switch (ir[ip++] | 0) {
@ -795,9 +795,15 @@ class PSStackBasedInterpreter {
* @param {number[]} range flat [min0,max0, ] * @param {number[]} range flat [min0,max0, ]
* @returns {Function} `(src, srcOffset, dest, destOffset) => void` * @returns {Function} `(src, srcOffset, dest, destOffset) => void`
*/ */
function buildPostScriptJsFunction(source, domain, range) { function buildPostScriptJsFunction(
source,
domain,
range,
forceInterpreter = false
) {
const program = parsePostScriptFunction(source); const program = parsePostScriptFunction(source);
const ir = new PsJsCompiler(domain, range).compile(program); const ir =
!forceInterpreter && new PsJsCompiler(domain, range).compile(program);
if (ir) { if (ir) {
return (src, srcOffset, dest, destOffset) => { return (src, srcOffset, dest, destOffset) => {
PsJsCompiler.execute(ir, src, srcOffset, dest, destOffset); PsJsCompiler.execute(ir, src, srcOffset, dest, destOffset);
@ -807,14 +813,4 @@ function buildPostScriptJsFunction(source, domain, range) {
return PSStackBasedInterpreter.build(program, domain, range); return PSStackBasedInterpreter.build(program, domain, range);
} }
/** export { buildPostScriptJsFunction };
* @param {import("./ast.js").PsProgram} program
* @param {number[]} domain flat [min0,max0, ]
* @param {number[]} range flat [min0,max0, ]
* @returns {Function} `(src, srcOffset, dest, destOffset) => void`
*/
function buildPostScriptProgramFunction(program, domain, range) {
return PSStackBasedInterpreter.build(program, domain, range);
}
export { buildPostScriptJsFunction, buildPostScriptProgramFunction };

View File

@ -120,8 +120,8 @@ class Lexer {
operatorSingletons[name] = token; operatorSingletons[name] = token;
} }
} }
Lexer.#singletons = singletons; this.#singletons = singletons;
Lexer.#operatorSingletons = operatorSingletons; this.#operatorSingletons = operatorSingletons;
} }
constructor(data) { constructor(data) {

View File

@ -170,7 +170,7 @@ class PsWasmCompiler {
static #init() { static #init() {
// TOKEN comparison ids → Wasm f64 comparison opcodes (leave i32 on stack). // TOKEN comparison ids → Wasm f64 comparison opcodes (leave i32 on stack).
PsWasmCompiler.#comparisonToOp = new Map([ this.#comparisonToOp = new Map([
[TOKEN.eq, OP.f64_eq], [TOKEN.eq, OP.f64_eq],
[TOKEN.ne, OP.f64_ne], [TOKEN.ne, OP.f64_ne],
[TOKEN.lt, OP.f64_lt], [TOKEN.lt, OP.f64_lt],
@ -179,18 +179,20 @@ class PsWasmCompiler {
[TOKEN.ge, OP.f64_ge], [TOKEN.ge, OP.f64_ge],
]); ]);
// Index of each import function by name. // Index of each import function by name.
PsWasmCompiler.#importIdx = Object.create(null); this.#importIdx = Object.create(null);
for (let i = 0; i < MATH_IMPORTS.length; i++) { for (let i = 0; i < MATH_IMPORTS.length; i++) {
PsWasmCompiler.#importIdx[MATH_IMPORTS[i][0]] = i; this.#importIdx[MATH_IMPORTS[i][0]] = i;
} }
PsWasmCompiler.#degToRad = Math.PI / 180; this.#degToRad = Math.PI / 180;
PsWasmCompiler.#radToDeg = 180 / Math.PI; this.#radToDeg = 180 / Math.PI;
// Import type entries are identical on every compilation — compute once. // Import type entries are identical on every compilation — compute once.
PsWasmCompiler.#importTypeEntries = MATH_IMPORTS.map( this.#importTypeEntries = MATH_IMPORTS.map(([, , , params, results]) => [
([, , , params, results]) => [FUNC_TYPE, ...vec(params), ...vec(results)] FUNC_TYPE,
); ...vec(params),
...vec(results),
]);
// Static Wasm sections that never change between compilations. // Static Wasm sections that never change between compilations.
PsWasmCompiler.#importSection = new Uint8Array( this.#importSection = new Uint8Array(
section( section(
SECTION.import, SECTION.import,
vec( vec(
@ -204,16 +206,16 @@ class PsWasmCompiler {
) )
); );
// One function, type index 0. // One function, type index 0.
PsWasmCompiler.#functionSection = new Uint8Array( this.#functionSection = new Uint8Array(
section(SECTION.function, vec([[0]])) section(SECTION.function, vec([[0]]))
); );
// Min 1 page (64 KiB), no max. // Min 1 page (64 KiB), no max.
// https://webassembly.github.io/spec/core/binary/types.html#binary-limits // https://webassembly.github.io/spec/core/binary/types.html#binary-limits
PsWasmCompiler.#memorySection = new Uint8Array( this.#memorySection = new Uint8Array(
section(SECTION.memory, vec([[0x00, 0x01]])) section(SECTION.memory, vec([[0x00, 0x01]]))
); );
// Export "fn" (func index = nImports) and "mem" (memory) for the wrapper. // Export "fn" (func index = nImports) and "mem" (memory) for the wrapper.
PsWasmCompiler.#exportSection = new Uint8Array( this.#exportSection = new Uint8Array(
section( section(
SECTION.export, SECTION.export,
vec([ vec([
@ -228,7 +230,7 @@ class PsWasmCompiler {
); );
// Wasm binary magic + version (constant). // Wasm binary magic + version (constant).
// https://webassembly.github.io/spec/core/binary/modules.html#binary-magic // https://webassembly.github.io/spec/core/binary/modules.html#binary-magic
PsWasmCompiler.#wasmMagicVersion = new Uint8Array([ this.#wasmMagicVersion = new Uint8Array([
0x00, 0x00,
0x61, 0x61,
0x73, 0x73,
@ -239,9 +241,9 @@ class PsWasmCompiler {
0x00, // version 1 0x00, // version 1
]); ]);
const f64Buf = new ArrayBuffer(8); const f64Buf = new ArrayBuffer(8);
PsWasmCompiler.#f64View = new DataView(f64Buf); this.#f64View = new DataView(f64Buf);
PsWasmCompiler.#f64Arr = new Uint8Array(f64Buf); this.#f64Arr = new Uint8Array(f64Buf);
PsWasmCompiler.#initialized = true; this.#initialized = true;
} }
constructor(domain, range) { constructor(domain, range) {

View File

@ -13,10 +13,6 @@
* limitations under the License. * limitations under the License.
*/ */
import {
buildPostScriptJsFunction,
buildPostScriptProgramFunction,
} from "../../src/core/postscript/js_evaluator.js";
import { import {
buildPostScriptWasmFunction, buildPostScriptWasmFunction,
compilePostScriptToWasm, compilePostScriptToWasm,
@ -39,6 +35,7 @@ import {
PsTernaryNode, PsTernaryNode,
PsUnaryNode, PsUnaryNode,
} from "../../src/core/postscript/ast.js"; } from "../../src/core/postscript/ast.js";
import { buildPostScriptJsFunction } from "../../src/core/postscript/js_evaluator.js";
// Precision argument for toBeCloseTo() in trigonometric tests. // Precision argument for toBeCloseTo() in trigonometric tests.
const TRIGONOMETRY_EPS = 1e-10; const TRIGONOMETRY_EPS = 1e-10;
@ -209,10 +206,11 @@ describe("PostScript Type 4 lexer, parser, and Wasm compiler", function () {
// direct program interpreter otherwise. // direct program interpreter otherwise.
const jsFn = buildPostScriptJsFunction(src, domain, range); const jsFn = buildPostScriptJsFunction(src, domain, range);
// Direct interpreter: always available, never uses PSStackToTree. // Direct interpreter: always available, never uses PSStackToTree.
const interpFn = buildPostScriptProgramFunction( const interpFn = buildPostScriptJsFunction(
parsePostScriptFunction(src), src,
domain, domain,
range range,
/* forceInterpreter = */ true
); );
if (!wasmFn) { if (!wasmFn) {