mirror of
https://github.com/mozilla/pdf.js.git
synced 2026-07-25 08:27:19 +02:00
Merge pull request #21601 from uwezkhan/fix-postscript-wasm-i32const-sleb128
Encode i32.const immediates as signed LEB128 in the PostScript Wasm compiler
This commit is contained in:
commit
09a45ad2af
@ -283,6 +283,21 @@ class PsWasmCompiler {
|
|||||||
} while (n !== 0);
|
} while (n !== 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// `i32.const` immediates are signed LEB128 (Wasm spec), so they must be
|
||||||
|
// emitted with sign extension — the unsigned encoder mis-encodes any value
|
||||||
|
// whose final 7-bit group has bit 0x40 set (e.g. 64 → 0x40 → decoded as −64).
|
||||||
|
_emitSLEB128(n) {
|
||||||
|
for (;;) {
|
||||||
|
const b = n & 0x7f;
|
||||||
|
n >>= 7; // arithmetic shift keeps the sign bit
|
||||||
|
if ((n === 0 && (b & 0x40) === 0) || (n === -1 && (b & 0x40) !== 0)) {
|
||||||
|
this._code.push(b);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this._code.push(b | 0x80);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
_emitF64Const(value) {
|
_emitF64Const(value) {
|
||||||
this._code.push(OP.f64_const);
|
this._code.push(OP.f64_const);
|
||||||
PsWasmCompiler.#f64View.setFloat64(0, value, true /* little-endian */);
|
PsWasmCompiler.#f64View.setFloat64(0, value, true /* little-endian */);
|
||||||
@ -532,11 +547,11 @@ class PsWasmCompiler {
|
|||||||
const shift = first.value;
|
const shift = first.value;
|
||||||
if (shift > 0) {
|
if (shift > 0) {
|
||||||
code.push(OP.i32_const);
|
code.push(OP.i32_const);
|
||||||
this._emitULEB128(shift);
|
this._emitSLEB128(shift);
|
||||||
code.push(OP.i32_shl);
|
code.push(OP.i32_shl);
|
||||||
} else if (shift < 0) {
|
} else if (shift < 0) {
|
||||||
code.push(OP.i32_const);
|
code.push(OP.i32_const);
|
||||||
this._emitULEB128(-shift);
|
this._emitSLEB128(-shift);
|
||||||
code.push(OP.i32_shr_s);
|
code.push(OP.i32_shr_s);
|
||||||
}
|
}
|
||||||
code.push(OP.f64_convert_i32_s);
|
code.push(OP.f64_convert_i32_s);
|
||||||
@ -870,7 +885,7 @@ class PsWasmCompiler {
|
|||||||
const min = this._range[i * 2];
|
const min = this._range[i * 2];
|
||||||
const max = this._range[i * 2 + 1];
|
const max = this._range[i * 2 + 1];
|
||||||
code.push(OP.i32_const);
|
code.push(OP.i32_const);
|
||||||
this._emitULEB128(i * 8);
|
this._emitSLEB128(i * 8);
|
||||||
if (!this._compileNode(outputs[i])) {
|
if (!this._compileNode(outputs[i])) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|||||||
1
test/pdfs/.gitignore
vendored
1
test/pdfs/.gitignore
vendored
@ -1,6 +1,7 @@
|
|||||||
*.pdf
|
*.pdf
|
||||||
*.error
|
*.error
|
||||||
|
|
||||||
|
!postscript_type4_many_outputs.pdf
|
||||||
!boundingBox_invalid.pdf
|
!boundingBox_invalid.pdf
|
||||||
!pdkids.pdf
|
!pdkids.pdf
|
||||||
!tracemonkey.pdf
|
!tracemonkey.pdf
|
||||||
|
|||||||
51
test/pdfs/postscript_type4_many_outputs.pdf
Normal file
51
test/pdfs/postscript_type4_many_outputs.pdf
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
%PDF-1.7
|
||||||
|
%âãÏÓ
|
||||||
|
1 0 obj
|
||||||
|
<< /Type /Catalog /Pages 2 0 R >>
|
||||||
|
endobj
|
||||||
|
2 0 obj
|
||||||
|
<< /Type /Pages /Kids [3 0 R] /Count 1 >>
|
||||||
|
endobj
|
||||||
|
3 0 obj
|
||||||
|
<< /Type /Page /Parent 2 0 R /MediaBox [0 0 200 200] /Resources << /Shading << /Sh1 4 0 R >> >> /Contents 5 0 R >>
|
||||||
|
endobj
|
||||||
|
4 0 obj
|
||||||
|
<< /ShadingType 2 /ColorSpace 6 0 R /Coords [0 0 200 0] /Domain [0 1] /Function 7 0 R /Extend [true true] >>
|
||||||
|
endobj
|
||||||
|
5 0 obj
|
||||||
|
<< /Length 30 >>
|
||||||
|
stream
|
||||||
|
q 0 0 200 200 re W n /Sh1 sh Q
|
||||||
|
endstream
|
||||||
|
endobj
|
||||||
|
6 0 obj
|
||||||
|
[/DeviceN [/c0 /c1 /c2 /c3 /c4 /c5 /c6 /c7 /c8] /DeviceCMYK 8 0 R]
|
||||||
|
endobj
|
||||||
|
7 0 obj
|
||||||
|
<< /FunctionType 4 /Domain [0 1] /Range [0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1] /Length 35 >>
|
||||||
|
stream
|
||||||
|
{ dup dup dup dup dup dup dup dup }
|
||||||
|
endstream
|
||||||
|
endobj
|
||||||
|
8 0 obj
|
||||||
|
<< /FunctionType 4 /Domain [0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1] /Range [0 1 0 1 0 1 0 1] /Length 41 >>
|
||||||
|
stream
|
||||||
|
{ pop pop pop pop pop pop pop pop 0 0 0 }
|
||||||
|
endstream
|
||||||
|
endobj
|
||||||
|
xref
|
||||||
|
0 9
|
||||||
|
0000000000 65535 f
|
||||||
|
0000000015 00000 n
|
||||||
|
0000000064 00000 n
|
||||||
|
0000000121 00000 n
|
||||||
|
0000000251 00000 n
|
||||||
|
0000000375 00000 n
|
||||||
|
0000000455 00000 n
|
||||||
|
0000000537 00000 n
|
||||||
|
0000000697 00000 n
|
||||||
|
trailer
|
||||||
|
<< /Size 9 /Root 1 0 R >>
|
||||||
|
startxref
|
||||||
|
875
|
||||||
|
%%EOF
|
||||||
@ -1,4 +1,11 @@
|
|||||||
[
|
[
|
||||||
|
{
|
||||||
|
"id": "postscript-type4-many-outputs",
|
||||||
|
"file": "pdfs/postscript_type4_many_outputs.pdf",
|
||||||
|
"md5": "90c1ebd35acc6c7d01f4fdb0ae0bef82",
|
||||||
|
"rounds": 1,
|
||||||
|
"type": "eq"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"id": "bug1755201",
|
"id": "bug1755201",
|
||||||
"file": "pdfs/bug1755201.pdf",
|
"file": "pdfs/bug1755201.pdf",
|
||||||
|
|||||||
@ -1049,6 +1049,26 @@ describe("PostScript Type 4 lexer, parser, and Wasm compiler", function () {
|
|||||||
);
|
);
|
||||||
expect(r2).toBeCloseTo(0.5, 9);
|
expect(r2).toBeCloseTo(0.5, 9);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("compiles functions with 9+ outputs (signed i32.const store offset)", async function () {
|
||||||
|
// Regression: each output's f64.store address is emitted as
|
||||||
|
// `i32.const (i * 8)`. i32.const immediates are *signed* LEB128, so the
|
||||||
|
// 9th output offset (64) must not be written with the unsigned encoder,
|
||||||
|
// which yields the byte 0x40 that Wasm decodes as -64 → out-of-bounds
|
||||||
|
// store → runtime trap. compileAndRun throws if the Wasm function traps.
|
||||||
|
for (const nOut of [9, 10, 16, 20]) {
|
||||||
|
const range = [];
|
||||||
|
for (let i = 0; i < nOut; i++) {
|
||||||
|
range.push(0, 1000);
|
||||||
|
}
|
||||||
|
const src = "{" + " dup".repeat(nOut - 1) + " }";
|
||||||
|
const out = compileAndRun(src, [0, 1], range, [0.5]);
|
||||||
|
expect(out.length).toBe(nOut);
|
||||||
|
for (const value of out) {
|
||||||
|
expect(value).toBeCloseTo(0.5, 10);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
// PSStackToTree
|
// PSStackToTree
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user