1 /*  GRAPHITE2 LICENSING
2 
3     Copyright 2010, SIL International
4     All rights reserved.
5 
6     This library is free software; you can redistribute it and/or modify
7     it under the terms of the GNU Lesser General Public License as published
8     by the Free Software Foundation; either version 2.1 of License, or
9     (at your option) any later version.
10 
11     This program is distributed in the hope that it will be useful,
12     but WITHOUT ANY WARRANTY; without even the implied warranty of
13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14     Lesser General Public License for more details.
15 
16     You should also have received a copy of the GNU Lesser General Public
17     License along with this library in the file named "LICENSE".
18     If not, write to the Free Software Foundation, 51 Franklin Street,
19     Suite 500, Boston, MA 02110-1335, USA or visit their web page on the
20     internet at http://www.fsf.org/licenses/lgpl.html.
21 
22 Alternatively, the contents of this file may be used under the terms of the
23 Mozilla Public License (http://mozilla.org/MPL) or the GNU General Public
24 License, as published by the Free Software Foundation, either version 2
25 of the License or (at your option) any later version.
26 */
27 #pragma once
28 // This file will be pulled into and integrated into a machine implmentation
29 // DO NOT build directly and under no circumstances ever #include headers in
30 // here or you will break the direct_machine.
31 //
32 // Implementers' notes
33 // ==================
34 // You have access to a few primitives and the full C++ code:
35 //    declare_params(n) Tells the interpreter how many bytes of parameter
36 //                      space to claim for this instruction uses and
37 //                      initialises the param pointer.  You *must* before the
38 //                      first use of param.
39 //    use_params(n)     Claim n extra bytes of param space beyond what was
40 //                      claimed using delcare_param.
41 //    param             A const byte pointer for the parameter space claimed by
42 //                      this instruction.
43 //    binop(op)         Implement a binary operation on the stack using the
44 //                      specified C++ operator.
45 //    NOT_IMPLEMENTED   Any instruction body containing this will exit the
46 //                      program with an assertion error.  Instructions that are
47 //                      not implemented should also be marked NILOP in the
48 //                      opcodes tables this will cause the code class to spot
49 //                      them in a live code stream and throw a runtime_error
50 //                      instead.
51 //    push(n)           Push the value n onto the stack.
52 //    pop()             Pop the top most value and return it.
53 //
54 //    You have access to the following named fast 'registers':
55 //        sp        = The pointer to the current top of stack, the last value
56 //                    pushed.
57 //        seg       = A reference to the Segment this code is running over.
58 //        is        = The current slot index
59 //        isb       = The original base slot index at the start of this rule
60 //        isf       = The first positioned slot
61 //        isl       = The last positioned slot
62 //        ip        = The current instruction pointer
63 //        endPos    = Position of advance of last cluster
64 //        dir       = writing system directionality of the font
65 
66 
67 // #define NOT_IMPLEMENTED     assert(false)
68 // #define NOT_IMPLEMENTED
69 
70 #define binop(op)           const uint32 a = pop(); *sp = uint32(*sp) op a
71 #define sbinop(op)          const int32 a = pop(); *sp = int32(*sp) op a
72 #define use_params(n)       dp += n
73 
74 #define declare_params(n)   const byte * param = dp; \
75                             use_params(n);
76 
77 #define push(n)             { *++sp = n; }
78 #define pop()               (*sp--)
79 #define slotat(x)           (map[(x)])
80 #define DIE                 { is=seg.last(); status = Machine::died_early; EXIT(1); }
81 #define POSITIONED          1
82 
83 STARTOP(nop)
84     do {} while (0);
85 ENDOP
86 
87 STARTOP(push_byte)
88     declare_params(1);
89     push(int8(*param));
90 ENDOP
91 
92 STARTOP(push_byte_u)
93     declare_params(1);
94     push(uint8(*param));
95 ENDOP
96 
97 STARTOP(push_short)
98     declare_params(2);
99     const int16 r   = int16(param[0]) << 8
100                     | uint8(param[1]);
101     push(r);
102 ENDOP
103 
104 STARTOP(push_short_u)
105     declare_params(2);
106     const uint16 r  = uint16(param[0]) << 8
107                     | uint8(param[1]);
108     push(r);
109 ENDOP
110 
111 STARTOP(push_long)
112     declare_params(4);
113     const  int32 r  = int32(param[0]) << 24
114                     | uint32(param[1]) << 16
115                     | uint32(param[2]) << 8
116                     | uint8(param[3]);
117     push(r);
118 ENDOP
119 
120 STARTOP(add)
121     binop(+);
122 ENDOP
123 
124 STARTOP(sub)
125     binop(-);
126 ENDOP
127 
128 STARTOP(mul)
129     binop(*);
130 ENDOP
131 
132 STARTOP(div_)
133     const int32 b = pop();
134     const int32 a = int32(*sp);
135     if (b == 0 || (a == std::numeric_limits<int32>::min() && b == -1)) DIE;
136     *sp = int32(*sp) / b;
137 ENDOP
138 
139 STARTOP(min_)
140     const int32 a = pop(), b = *sp;
141     if (a < b) *sp = a;
142 ENDOP
143 
144 STARTOP(max_)
145     const int32 a = pop(), b = *sp;
146     if (a > b) *sp = a;
147 ENDOP
148 
149 STARTOP(neg)
150     *sp = uint32(-int32(*sp));
151 ENDOP
152 
153 STARTOP(trunc8)
154     *sp = uint8(*sp);
155 ENDOP
156 
157 STARTOP(trunc16)
158     *sp = uint16(*sp);
159 ENDOP
160 
161 STARTOP(cond)
162     const uint32 f = pop(), t = pop(), c = pop();
163     push(c ? t : f);
164 ENDOP
165 
166 STARTOP(and_)
167     binop(&&);
168 ENDOP
169 
170 STARTOP(or_)
171     binop(||);
172 ENDOP
173 
174 STARTOP(not_)
175     *sp = !*sp;
176 ENDOP
177 
178 STARTOP(equal)
179     binop(==);
180 ENDOP
181 
182 STARTOP(not_eq_)
183     binop(!=);
184 ENDOP
185 
186 STARTOP(less)
187     sbinop(<);
188 ENDOP
189 
190 STARTOP(gtr)
191     sbinop(>);
192 ENDOP
193 
194 STARTOP(less_eq)
195     sbinop(<=);
196 ENDOP
197 
198 STARTOP(gtr_eq)
199     sbinop(>=);
200 ENDOP
201 
202 STARTOP(next)
203     if (map - &smap[0] >= int(smap.size())) DIE
204     if (is)
205     {
206         if (is == smap.highwater())
207             smap.highpassed(true);
208         is = is->next();
209     }
210     ++map;
211 ENDOP
212 
213 //STARTOP(next_n)
214 //    use_params(1);
215 //    NOT_IMPLEMENTED;
216     //declare_params(1);
217     //const size_t num = uint8(*param);
218 //ENDOP
219 
220 //STARTOP(copy_next)
221 //     if (is) is = is->next();
222 //     ++map;
223 // ENDOP
224 
225 STARTOP(put_glyph_8bit_obs)
226     declare_params(1);
227     const unsigned int output_class = uint8(*param);
228     is->setGlyph(&seg, seg.getClassGlyph(output_class, 0));
229 ENDOP
230 
231 STARTOP(put_subs_8bit_obs)
232     declare_params(3);
233     const int           slot_ref     = int8(param[0]);
234     const unsigned int  input_class  = uint8(param[1]),
235                         output_class = uint8(param[2]);
236     uint16 index;
237     slotref slot = slotat(slot_ref);
238     if (slot)
239     {
240         index = seg.findClassIndex(input_class, slot->gid());
241         is->setGlyph(&seg, seg.getClassGlyph(output_class, index));
242     }
243 ENDOP
244 
245 STARTOP(put_copy)
246     declare_params(1);
247     const int  slot_ref = int8(*param);
248     if (is && !is->isDeleted())
249     {
250         slotref ref = slotat(slot_ref);
251         if (ref && ref != is)
252         {
253             int16 *tempUserAttrs = is->userAttrs();
254             if (is->attachedTo() || is->firstChild()) DIE
255             Slot *prev = is->prev();
256             Slot *next = is->next();
257             memcpy(tempUserAttrs, ref->userAttrs(), seg.numAttrs() * sizeof(uint16));
258             memcpy(is, ref, sizeof(Slot));
259             is->firstChild(NULL);
260             is->nextSibling(NULL);
261             is->userAttrs(tempUserAttrs);
262             is->next(next);
263             is->prev(prev);
264             if (is->attachedTo())
265                 is->attachedTo()->child(is);
266         }
267         is->markCopied(false);
268         is->markDeleted(false);
269     }
270 ENDOP
271 
272 STARTOP(insert)
273     if (smap.decMax() <= 0) DIE;
274     Slot *newSlot = seg.newSlot();
275     if (!newSlot) DIE;
276     Slot *iss = is;
277     while (iss && iss->isDeleted()) iss = iss->next();
278     if (!iss)
279     {
280         if (seg.last())
281         {
282             seg.last()->next(newSlot);
283             newSlot->prev(seg.last());
284             newSlot->before(seg.last()->before());
285             seg.last(newSlot);
286         }
287         else
288         {
289             seg.first(newSlot);
290             seg.last(newSlot);
291         }
292     }
293     else if (iss->prev())
294     {
295         iss->prev()->next(newSlot);
296         newSlot->prev(iss->prev());
297         newSlot->before(iss->prev()->after());
298     }
299     else
300     {
301         newSlot->prev(NULL);
302         newSlot->before(iss->before());
303         seg.first(newSlot);
304     }
305     newSlot->next(iss);
306     if (iss)
307     {
308         iss->prev(newSlot);
309         newSlot->originate(iss->original());
310         newSlot->after(iss->before());
311     }
312     else if (newSlot->prev())
313     {
314         newSlot->originate(newSlot->prev()->original());
315         newSlot->after(newSlot->prev()->after());
316     }
317     else
318     {
319         newSlot->originate(seg.defaultOriginal());
320     }
321     if (is == smap.highwater())
322         smap.highpassed(false);
323     is = newSlot;
324     seg.extendLength(1);
325     if (map != &smap[-1])
326         --map;
327 ENDOP
328 
329 STARTOP(delete_)
330     if (!is || is->isDeleted()) DIE
331     is->markDeleted(true);
332     if (is->prev())
333         is->prev()->next(is->next());
334     else
335         seg.first(is->next());
336 
337     if (is->next())
338         is->next()->prev(is->prev());
339     else
340         seg.last(is->prev());
341 
342 
343     if (is == smap.highwater())
344             smap.highwater(is->next());
345     if (is->prev())
346         is = is->prev();
347     seg.extendLength(-1);
348 ENDOP
349 
350 STARTOP(assoc)
351     declare_params(1);
352     unsigned int  num = uint8(*param);
353     const int8 *  assocs = reinterpret_cast<const int8 *>(param+1);
354     use_params(num);
355     int max = -1;
356     int min = -1;
357 
358     while (num-- > 0)
359     {
360         int sr = *assocs++;
361         slotref ts = slotat(sr);
362         if (ts && (min == -1 || ts->before() < min)) min = ts->before();
363         if (ts && ts->after() > max) max = ts->after();
364     }
365     if (min > -1)   // implies max > -1
366     {
367         is->before(min);
368         is->after(max);
369     }
370 ENDOP
371 
372 STARTOP(cntxt_item)
373     // It turns out this is a cunningly disguised condition forward jump.
374     declare_params(3);
375     const int       is_arg = int8(param[0]);
376     const size_t    iskip  = uint8(param[1]),
377                     dskip  = uint8(param[2]);
378 
379     if (mapb + is_arg != map)
380     {
381         ip += iskip;
382         dp += dskip;
383         push(true);
384     }
385 ENDOP
386 
387 STARTOP(attr_set)
388     declare_params(1);
389     const attrCode      slat = attrCode(uint8(*param));
390     const          int  val  = pop();
391     is->setAttr(&seg, slat, 0, val, smap);
392 ENDOP
393 
394 STARTOP(attr_add)
395     declare_params(1);
396     const attrCode      slat = attrCode(uint8(*param));
397     const     uint32_t  val  = pop();
398     if ((slat == gr_slatPosX || slat == gr_slatPosY) && (flags & POSITIONED) == 0)
399     {
400         seg.positionSlots(0, *smap.begin(), *(smap.end()-1), seg.currdir());
401         flags |= POSITIONED;
402     }
403     uint32_t res = uint32_t(is->getAttr(&seg, slat, 0));
404     is->setAttr(&seg, slat, 0, int32_t(val + res), smap);
405 ENDOP
406 
407 STARTOP(attr_sub)
408     declare_params(1);
409     const attrCode      slat = attrCode(uint8(*param));
410     const     uint32_t  val  = pop();
411     if ((slat == gr_slatPosX || slat == gr_slatPosY) && (flags & POSITIONED) == 0)
412     {
413         seg.positionSlots(0, *smap.begin(), *(smap.end()-1), seg.currdir());
414         flags |= POSITIONED;
415     }
416     uint32_t res = uint32_t(is->getAttr(&seg, slat, 0));
417     is->setAttr(&seg, slat, 0, int32_t(res - val), smap);
418 ENDOP
419 
420 STARTOP(attr_set_slot)
421     declare_params(1);
422     const attrCode  slat   = attrCode(uint8(*param));
423     const int       offset = int(map - smap.begin())*int(slat == gr_slatAttTo);
424     const int       val    = pop()  + offset;
425     is->setAttr(&seg, slat, offset, val, smap);
426 ENDOP
427 
428 STARTOP(iattr_set_slot)
429     declare_params(2);
430     const attrCode  slat = attrCode(uint8(param[0]));
431     const uint8     idx  = uint8(param[1]);
432     const int       val  = int(pop()  + (map - smap.begin())*int(slat == gr_slatAttTo));
433     is->setAttr(&seg, slat, idx, val, smap);
434 ENDOP
435 
436 STARTOP(push_slot_attr)
437     declare_params(2);
438     const attrCode      slat     = attrCode(uint8(param[0]));
439     const int           slot_ref = int8(param[1]);
440     if ((slat == gr_slatPosX || slat == gr_slatPosY) && (flags & POSITIONED) == 0)
441     {
442         seg.positionSlots(0, *smap.begin(), *(smap.end()-1), seg.currdir());
443         flags |= POSITIONED;
444     }
445     slotref slot = slotat(slot_ref);
446     if (slot)
447     {
448         int res = slot->getAttr(&seg, slat, 0);
449         push(res);
450     }
451 ENDOP
452 
453 STARTOP(push_glyph_attr_obs)
454     declare_params(2);
455     const unsigned int  glyph_attr = uint8(param[0]);
456     const int           slot_ref   = int8(param[1]);
457     slotref slot = slotat(slot_ref);
458     if (slot)
459         push(int32(seg.glyphAttr(slot->gid(), glyph_attr)));
460 ENDOP
461 
462 STARTOP(push_glyph_metric)
463     declare_params(3);
464     const unsigned int  glyph_attr  = uint8(param[0]);
465     const int           slot_ref    = int8(param[1]);
466     const signed int    attr_level  = uint8(param[2]);
467     slotref slot = slotat(slot_ref);
468     if (slot)
469         push(seg.getGlyphMetric(slot, glyph_attr, attr_level, dir));
470 ENDOP
471 
472 STARTOP(push_feat)
473     declare_params(2);
474     const unsigned int  feat        = uint8(param[0]);
475     const int           slot_ref    = int8(param[1]);
476     slotref slot = slotat(slot_ref);
477     if (slot)
478     {
479         uint8 fid = seg.charinfo(slot->original())->fid();
480         push(seg.getFeature(fid, feat));
481     }
482 ENDOP
483 
484 STARTOP(push_att_to_gattr_obs)
485     declare_params(2);
486     const unsigned int  glyph_attr  = uint8(param[0]);
487     const int           slot_ref    = int8(param[1]);
488     slotref slot = slotat(slot_ref);
489     if (slot)
490     {
491         slotref att = slot->attachedTo();
492         if (att) slot = att;
493         push(int32(seg.glyphAttr(slot->gid(), glyph_attr)));
494     }
495 ENDOP
496 
497 STARTOP(push_att_to_glyph_metric)
498     declare_params(3);
499     const unsigned int  glyph_attr  = uint8(param[0]);
500     const int           slot_ref    = int8(param[1]);
501     const signed int    attr_level  = uint8(param[2]);
502     slotref slot = slotat(slot_ref);
503     if (slot)
504     {
505         slotref att = slot->attachedTo();
506         if (att) slot = att;
507         push(int32(seg.getGlyphMetric(slot, glyph_attr, attr_level, dir)));
508     }
509 ENDOP
510 
511 STARTOP(push_islot_attr)
512     declare_params(3);
513     const attrCode  slat     = attrCode(uint8(param[0]));
514     const int           slot_ref = int8(param[1]),
515                         idx      = uint8(param[2]);
516     if ((slat == gr_slatPosX || slat == gr_slatPosY) && (flags & POSITIONED) == 0)
517     {
518         seg.positionSlots(0, *smap.begin(), *(smap.end()-1), seg.currdir());
519         flags |= POSITIONED;
520     }
521     slotref slot = slotat(slot_ref);
522     if (slot)
523     {
524         int res = slot->getAttr(&seg, slat, idx);
525         push(res);
526     }
527 ENDOP
528 
529 #if 0
530 STARTOP(push_iglyph_attr) // not implemented
531     NOT_IMPLEMENTED;
532 ENDOP
533 #endif
534 
535 STARTOP(pop_ret)
536     const uint32 ret = pop();
537     EXIT(ret);
538 ENDOP
539 
540 STARTOP(ret_zero)
541     EXIT(0);
542 ENDOP
543 
544 STARTOP(ret_true)
545     EXIT(1);
546 ENDOP
547 
548 STARTOP(iattr_set)
549     declare_params(2);
550     const attrCode      slat = attrCode(uint8(param[0]));
551     const uint8         idx  = uint8(param[1]);
552     const          int  val  = pop();
553     is->setAttr(&seg, slat, idx, val, smap);
554 ENDOP
555 
556 STARTOP(iattr_add)
557     declare_params(2);
558     const attrCode      slat = attrCode(uint8(param[0]));
559     const uint8         idx  = uint8(param[1]);
560     const     uint32_t  val  = pop();
561     if ((slat == gr_slatPosX || slat == gr_slatPosY) && (flags & POSITIONED) == 0)
562     {
563         seg.positionSlots(0, *smap.begin(), *(smap.end()-1), seg.currdir());
564         flags |= POSITIONED;
565     }
566     uint32_t res = uint32_t(is->getAttr(&seg, slat, idx));
567     is->setAttr(&seg, slat, idx, int32_t(val + res), smap);
568 ENDOP
569 
570 STARTOP(iattr_sub)
571     declare_params(2);
572     const attrCode      slat = attrCode(uint8(param[0]));
573     const uint8         idx  = uint8(param[1]);
574     const     uint32_t  val  = pop();
575     if ((slat == gr_slatPosX || slat == gr_slatPosY) && (flags & POSITIONED) == 0)
576     {
577         seg.positionSlots(0, *smap.begin(), *(smap.end()-1), seg.currdir());
578         flags |= POSITIONED;
579     }
580     uint32_t res = uint32_t(is->getAttr(&seg, slat, idx));
581     is->setAttr(&seg, slat, idx, int32_t(res - val), smap);
582 ENDOP
583 
584 STARTOP(push_proc_state)
585     use_params(1);
586     push(1);
587 ENDOP
588 
589 STARTOP(push_version)
590     push(0x00030000);
591 ENDOP
592 
593 STARTOP(put_subs)
594     declare_params(5);
595     const int        slot_ref     = int8(param[0]);
596     const unsigned int  input_class  = uint8(param[1]) << 8
597                                      | uint8(param[2]);
598     const unsigned int  output_class = uint8(param[3]) << 8
599                                      | uint8(param[4]);
600     slotref slot = slotat(slot_ref);
601     if (slot)
602     {
603         int index = seg.findClassIndex(input_class, slot->gid());
604         is->setGlyph(&seg, seg.getClassGlyph(output_class, index));
605     }
606 ENDOP
607 
608 #if 0
609 STARTOP(put_subs2) // not implemented
610     NOT_IMPLEMENTED;
611 ENDOP
612 
613 STARTOP(put_subs3) // not implemented
614     NOT_IMPLEMENTED;
615 ENDOP
616 #endif
617 
618 STARTOP(put_glyph)
619     declare_params(2);
620     const unsigned int output_class  = uint8(param[0]) << 8
621                                      | uint8(param[1]);
622     is->setGlyph(&seg, seg.getClassGlyph(output_class, 0));
623 ENDOP
624 
625 STARTOP(push_glyph_attr)
626     declare_params(3);
627     const unsigned int  glyph_attr  = uint8(param[0]) << 8
628                                     | uint8(param[1]);
629     const int           slot_ref    = int8(param[2]);
630     slotref slot = slotat(slot_ref);
631     if (slot)
632         push(int32(seg.glyphAttr(slot->gid(), glyph_attr)));
633 ENDOP
634 
635 STARTOP(push_att_to_glyph_attr)
636     declare_params(3);
637     const unsigned int  glyph_attr  = uint8(param[0]) << 8
638                                     | uint8(param[1]);
639     const int           slot_ref    = int8(param[2]);
640     slotref slot = slotat(slot_ref);
641     if (slot)
642     {
643         slotref att = slot->attachedTo();
644         if (att) slot = att;
645         push(int32(seg.glyphAttr(slot->gid(), glyph_attr)));
646     }
647 ENDOP
648 
649 STARTOP(temp_copy)
650     slotref newSlot = seg.newSlot();
651     if (!newSlot || !is) DIE;
652     int16 *tempUserAttrs = newSlot->userAttrs();
653     memcpy(newSlot, is, sizeof(Slot));
654     memcpy(tempUserAttrs, is->userAttrs(), seg.numAttrs() * sizeof(uint16));
655     newSlot->userAttrs(tempUserAttrs);
656     newSlot->markCopied(true);
657     *map = newSlot;
658 ENDOP
659 
660 STARTOP(band)
661     binop(&);
662 ENDOP
663 
664 STARTOP(bor)
665     binop(|);
666 ENDOP
667 
668 STARTOP(bnot)
669     *sp = ~*sp;
670 ENDOP
671 
672 STARTOP(setbits)
673     declare_params(4);
674     const uint16 m  = uint16(param[0]) << 8
675                     | uint8(param[1]);
676     const uint16 v  = uint16(param[2]) << 8
677                     | uint8(param[3]);
678     *sp = ((*sp) & ~m) | v;
679 ENDOP
680 
681 STARTOP(set_feat)
682     declare_params(2);
683     const unsigned int  feat        = uint8(param[0]);
684     const int           slot_ref    = int8(param[1]);
685     slotref slot = slotat(slot_ref);
686     if (slot)
687     {
688         uint8 fid = seg.charinfo(slot->original())->fid();
689         seg.setFeature(fid, feat, pop());
690     }
691 ENDOP
692