Skip to content

Implement missing Type 4 operators and speed up execution - #606

Merged
Velli20 merged 2 commits into
mainfrom
type4-operators-and-faster-execution
Oct 25, 2026
Merged

Velli20 merged 2 commits into
mainfrom
type4-operators-and-faster-execution

Conversation

@Velli20

@Velli20 Velli20 commented Oct 25, 2026

Copy link
Copy Markdown
Owner

Summary

Type 4 operators (fixes #591)

  • Adds neg, exp, ln, ceiling and round, which previously failed to parse with InvalidNumber and made the owning shading or color space fail to load.
  • log is now base 10 (it computed the natural log).
  • atan returns angles in [0, 360) instead of (-180, 180].
  • floor and truncate keep the operand's type, so 1e10 floor no longer fails with an overflow. cvi remains the real→integer conversion.

Faster execution

  • if/ifelse procedures run on the caller's operand stack instead of cloning it into each child frame and copying it back.
  • copy uses extend_from_within instead of a temporary Vec.
  • execute takes the input stack by value, so PostScriptCalculatorFunction::interpolate hands over its Vec instead of having it copied.

New criterion bench crates/pdf-postscript/benches/calculator.rs (256 samples per iteration). Median of 5 interleaved A/B rounds against the first commit, release profile:

Program Before After Change
nested ifelse 124.3 µs 82.0 µs −34%
arithmetic 139.4 µs 119.7 µs −14%
stack shuffling 156.2 µs 119.3 µs −24%

Parsing allocations are left to #590.

Test plan

  • cargo test -p pdf-postscript -p pdf-function
  • cargo clippy -p pdf-postscript -p pdf-function --all-targets --all-features -- -D warnings, cargo fmt --check
  • Scratch evaluation of edge cases: -2147483648 neg, -8 0.5 exp (error), 100 log, -1 -1 atan (225), 1e10 floor, ±2.5 round

🤖 Generated with Claude Code

Velli20 and others added 2 commits October 25, 2026 18:03
…cate

neg, exp, ln, ceiling and round had no Operator variant, so a Type 4
function using any of them failed to parse with InvalidNumber. They now
parse and evaluate: neg keeps integers (an i32::MIN operand becomes a
real), exp and ln return reals and reject undefined results, and
ceiling and round keep the operand's type, with round taking halves
toward positive infinity.

log was the natural logarithm; it is now base 10. atan returned angles
in (-180, 180]; they are now normalized into [0, 360). floor and
truncate converted every result to an integer, which also made large
reals such as 1e10 fail with an overflow; they now keep the operand's
type, like ceiling and round.

Fixes #591

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Each taken if/ifelse cloned the whole operand stack into the child frame
and copied it back when the procedure finished. Procedures now run on
the caller's stack: frames only track the operators and instruction
pointer, and the stack lives in an OperandStack beside them. copy
extends the stack from within instead of collecting a temporary Vec,
and execute takes the input stack by value so the caller's Vec is
reused instead of copied.

A criterion bench (benches/calculator.rs) runs three programs over 256
samples each. Against the previous commit, median of five interleaved
rounds with the release profile:

  nested ifelse   124.3 µs -> 82.0 µs  (-34%)
  arithmetic      139.4 µs -> 119.7 µs (-14%)
  stack shuffling 156.2 µs -> 119.3 µs (-24%)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown

Conformance reads

Documents that Safe-PDF reads differently from the base commit, compared with PDFium. A read
regresses when Safe-PDF fails to open a document it opened before, crashes or times out, or
counts a different number of pages than PDFium.

pdf.js corpus

1009 documents compared with b22d974: 0 read worse, 2 read better.

Improvements

Document Base This pull request
issue17190_1 timeout: time limit exceeded (stage safe-read) read, 1 page
issue19517 timeout: time limit exceeded (stage safe-read) read, 1 page

840 documents of the PDFium corpus read as on b22d974.

Details are in the job summaries of the workflow run. Rerun a case locally with
cargo conformance run --corpus <corpus> --read-only --case <id>.

@Velli20
Velli20 merged commit ec5d7a5 into main Oct 25, 2026
10 checks passed
@Velli20
Velli20 deleted the type4-operators-and-faster-execution branch October 25, 2026 16:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Implement the missing Type 4 PostScript operators and fix log, atan, floor, truncate

1 participant