freetype/truetype: jump opcodes.

R=gri, bsiegert
CC=golang-dev
http://codereview.appspot.com/6344079
This commit is contained in:
Nigel Tao 2012-07-05 20:29:35 +10:00
parent 523d04e0a7
commit e843d5cf7c
3 changed files with 78 additions and 20 deletions

View file

@ -25,7 +25,7 @@ func (h *hinter) run(program []byte) error {
steps, pc, top int
opcode uint8
)
for int(pc) < len(program) {
for 0 <= pc && int(pc) < len(program) {
steps++
if steps == 100000 {
return errors.New("truetype: hinting: too many steps")
@ -43,6 +43,11 @@ func (h *hinter) run(program []byte) error {
opcode = 1
goto ifelse
case opJMPR:
top--
pc += int(h.stack[top])
continue
case opDUP:
if int(top) >= len(h.stack) {
return errors.New("truetype: hinting: stack overflow")
@ -89,36 +94,36 @@ func (h *hinter) run(program []byte) error {
// No-op.
case opLT:
h.stack[top-2] = bool2int32(h.stack[top-2] < h.stack[top-1])
top--
h.stack[top-1] = bool2int32(h.stack[top-1] < h.stack[top])
case opLTEQ:
h.stack[top-2] = bool2int32(h.stack[top-2] <= h.stack[top-1])
top--
h.stack[top-1] = bool2int32(h.stack[top-1] <= h.stack[top])
case opGT:
h.stack[top-2] = bool2int32(h.stack[top-2] > h.stack[top-1])
top--
h.stack[top-1] = bool2int32(h.stack[top-1] > h.stack[top])
case opGTEQ:
h.stack[top-2] = bool2int32(h.stack[top-2] >= h.stack[top-1])
top--
h.stack[top-1] = bool2int32(h.stack[top-1] >= h.stack[top])
case opEQ:
h.stack[top-2] = bool2int32(h.stack[top-2] == h.stack[top-1])
top--
h.stack[top-1] = bool2int32(h.stack[top-1] == h.stack[top])
case opNEQ:
h.stack[top-2] = bool2int32(h.stack[top-2] != h.stack[top-1])
top--
h.stack[top-1] = bool2int32(h.stack[top-1] != h.stack[top])
case opAND:
h.stack[top-2] = bool2int32(h.stack[top-2] != 0 && h.stack[top-1] != 0)
top--
h.stack[top-1] = bool2int32(h.stack[top-1] != 0 && h.stack[top] != 0)
case opOR:
h.stack[top-2] = bool2int32(h.stack[top-2]|h.stack[top-1] != 0)
top--
h.stack[top-1] = bool2int32(h.stack[top-1]|h.stack[top] != 0)
case opNOT:
h.stack[top-1] = bool2int32(h.stack[top-1] == 0)
@ -134,23 +139,23 @@ func (h *hinter) run(program []byte) error {
// No-op.
case opADD:
h.stack[top-2] += h.stack[top-1]
top--
h.stack[top-1] += h.stack[top]
case opSUB:
h.stack[top-2] -= h.stack[top-1]
top--
h.stack[top-1] -= h.stack[top]
case opDIV:
if h.stack[top-1] == 0 {
top--
if h.stack[top] == 0 {
return errors.New("truetype: hinting: division by zero")
}
h.stack[top-2] = int32((int64(h.stack[top-2]) << 6) / int64(h.stack[top-1]))
top--
h.stack[top-1] = int32((int64(h.stack[top-1]) << 6) / int64(h.stack[top]))
case opMUL:
h.stack[top-2] = int32((int64(h.stack[top-2]) * int64(h.stack[top-1])) >> 6)
top--
h.stack[top-1] = int32((int64(h.stack[top-1]) * int64(h.stack[top])) >> 6)
case opABS:
if h.stack[top-1] < 0 {
@ -167,6 +172,20 @@ func (h *hinter) run(program []byte) error {
h.stack[top-1] += 63
h.stack[top-1] &^= 63
case opJROT:
top -= 2
if h.stack[top+1] != 0 {
pc += int(h.stack[top])
continue
}
case opJROF:
top -= 2
if h.stack[top+1] == 0 {
pc += int(h.stack[top])
continue
}
case opPUSHB000, opPUSHB001, opPUSHB010, opPUSHB011, opPUSHB100, opPUSHB101, opPUSHB110, opPUSHB111:
opcode -= opPUSHB000 - 1
goto push

View file

@ -26,6 +26,18 @@ func TestBytecode(t *testing.T) {
nil,
"underflow",
},
{
"infinite loop",
[]byte{
opPUSHW000, // [-1]
0xff,
0xff,
opDUP, // [-1, -1]
opJMPR, // [-1]
},
nil,
"too many steps",
},
{
"unbalanced if/else",
[]byte{
@ -36,6 +48,33 @@ func TestBytecode(t *testing.T) {
nil,
"unbalanced",
},
{
"jumps",
[]byte{
opPUSHB001, // [10, 2]
10,
2,
opJMPR, // [10]
opDUP, // not executed
opDUP, // [10, 10]
opPUSHB010, // [10, 10, 20, 2, 1]
20,
2,
1,
opJROT, // [10, 10, 20]
opDUP, // not executed
opDUP, // [10, 10, 20, 20]
opPUSHB010, // [10, 10, 20, 20, 30, 2, 1]
30,
2,
1,
opJROF, // [10, 10, 20, 20, 30]
opDUP, // [10, 10, 20, 20, 30, 30]
opDUP, // [10, 10, 20, 20, 30, 30, 30]
},
[]int32{10, 10, 20, 20, 30, 30, 30},
"",
},
{
"stack ops",
[]byte{

View file

@ -38,7 +38,7 @@ const (
opRTHG = 0x19
opSMD = 0x1a
opELSE = 0x1b // ELSE clause
opJMPR = 0x1c
opJMPR = 0x1c // JuMP Relative
opSCVTCI = 0x1d
opSSWCI = 0x1e
opSSW = 0x1f
@ -130,8 +130,8 @@ const (
opDELTAC3 = 0x75
opSROUND = 0x76
opS45ROUND = 0x77
opJROT = 0x78
opJROF = 0x79
opJROT = 0x78 // Jump Relative On True
opJROF = 0x79 // Jump Relative On False
opROFF = 0x7a
op_0x7b = 0x7b
opRUTG = 0x7c
@ -272,13 +272,13 @@ const (
var popCount = [256]uint8{
// 1, 2, 3, 4, 5, 6, 7, 8, 9, a, b, c, d, e, f
q, q, q, q, q, q, q, q, q, q, q, q, q, q, q, q, // 0x00 - 0x0f
q, q, q, q, q, q, q, q, q, q, q, 0, q, q, q, q, // 0x10 - 0x1f
q, q, q, q, q, q, q, q, q, q, q, 0, 1, q, q, q, // 0x10 - 0x1f
1, 1, 0, 2, 0, 1, 1, q, q, q, q, q, q, q, q, q, // 0x20 - 0x2f
q, q, q, q, q, q, q, q, q, q, q, q, q, q, q, q, // 0x30 - 0x3f
0, 0, q, q, q, q, q, q, q, q, q, q, q, q, q, 0, // 0x40 - 0x4f
2, 2, 2, 2, 2, 2, q, q, 1, 0, 2, 2, 1, q, q, q, // 0x50 - 0x5f
2, 2, 2, 2, 1, 1, 1, 1, q, q, q, q, q, q, q, q, // 0x60 - 0x6f
q, q, q, q, q, q, q, q, q, q, q, q, q, q, q, q, // 0x70 - 0x7f
q, q, q, q, q, q, q, q, 2, 2, q, q, q, q, q, q, // 0x70 - 0x7f
q, q, q, q, q, q, q, q, q, q, q, q, q, q, q, q, // 0x80 - 0x8f
q, q, q, q, q, q, q, q, q, q, q, q, q, q, q, q, // 0x90 - 0x9f
q, q, q, q, q, q, q, q, q, q, q, q, q, q, q, q, // 0xa0 - 0xaf