Line data Source code
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 : // This general interpreter interface.
28 : // Author: Tim Eves
29 :
30 : // Build one of direct_machine.cpp or call_machine.cpp to implement this
31 : // interface.
32 :
33 : #pragma once
34 : #include <cstring>
35 : #include <graphite2/Types.h>
36 : #include "inc/Main.h"
37 :
38 : #if defined(__GNUC__)
39 : #if defined(__clang__) || (__GNUC__ * 100 + __GNUC_MINOR__ * 10) < 430
40 : #define HOT
41 : #if defined(__x86_64)
42 : #define REGPARM(n) __attribute__((regparm(n)))
43 : #else
44 : #define REGPARM(n)
45 : #endif
46 : #else
47 : #define HOT __attribute__((hot))
48 : #if defined(__x86_64)
49 : #define REGPARM(n) __attribute__((hot, regparm(n)))
50 : #else
51 : #define REGPARM(n)
52 : #endif
53 : #endif
54 : #else
55 : #define HOT
56 : #define REGPARM(n)
57 : #endif
58 :
59 : namespace graphite2 {
60 :
61 : // Forward declarations
62 : class Segment;
63 : class Slot;
64 : class SlotMap;
65 :
66 :
67 : namespace vm
68 : {
69 :
70 :
71 : typedef void * instr;
72 : typedef Slot * slotref;
73 :
74 : enum {VARARGS = 0xff, MAX_NAME_LEN=32};
75 :
76 : enum opcode {
77 : NOP = 0,
78 :
79 : PUSH_BYTE, PUSH_BYTEU, PUSH_SHORT, PUSH_SHORTU, PUSH_LONG,
80 :
81 : ADD, SUB, MUL, DIV,
82 : MIN_, MAX_,
83 : NEG,
84 : TRUNC8, TRUNC16,
85 :
86 : COND,
87 :
88 : AND, OR, NOT,
89 : EQUAL, NOT_EQ,
90 : LESS, GTR, LESS_EQ, GTR_EQ,
91 :
92 : NEXT, NEXT_N, COPY_NEXT,
93 : PUT_GLYPH_8BIT_OBS, PUT_SUBS_8BIT_OBS, PUT_COPY,
94 : INSERT, DELETE,
95 : ASSOC,
96 : CNTXT_ITEM,
97 :
98 : ATTR_SET, ATTR_ADD, ATTR_SUB,
99 : ATTR_SET_SLOT,
100 : IATTR_SET_SLOT,
101 : PUSH_SLOT_ATTR, PUSH_GLYPH_ATTR_OBS,
102 : PUSH_GLYPH_METRIC, PUSH_FEAT,
103 : PUSH_ATT_TO_GATTR_OBS, PUSH_ATT_TO_GLYPH_METRIC,
104 : PUSH_ISLOT_ATTR,
105 :
106 : PUSH_IGLYPH_ATTR, // not implemented
107 :
108 : POP_RET, RET_ZERO, RET_TRUE,
109 : IATTR_SET, IATTR_ADD, IATTR_SUB,
110 : PUSH_PROC_STATE, PUSH_VERSION,
111 : PUT_SUBS, PUT_SUBS2, PUT_SUBS3,
112 : PUT_GLYPH, PUSH_GLYPH_ATTR, PUSH_ATT_TO_GLYPH_ATTR,
113 : BITOR, BITAND, BITNOT,
114 : BITSET, SET_FEAT,
115 : MAX_OPCODE,
116 : // private opcodes for internal use only, comes after all other on disk opcodes
117 : TEMP_COPY = MAX_OPCODE
118 : };
119 :
120 : struct opcode_t
121 : {
122 : instr impl[2];
123 : uint8 param_sz;
124 : char name[MAX_NAME_LEN];
125 : };
126 :
127 :
128 : class Machine
129 : {
130 : public:
131 : typedef int32 stack_t;
132 : static size_t const STACK_ORDER = 10,
133 : STACK_MAX = 1 << STACK_ORDER,
134 : STACK_GUARD = 2;
135 :
136 : class Code;
137 :
138 : enum status_t {
139 : finished = 0,
140 : stack_underflow,
141 : stack_not_empty,
142 : stack_overflow,
143 : slot_offset_out_bounds,
144 : died_early
145 : };
146 :
147 : Machine(SlotMap &) throw();
148 : static const opcode_t * getOpcodeTable() throw();
149 :
150 : CLASS_NEW_DELETE;
151 :
152 : SlotMap & slotMap() const throw();
153 : status_t status() const throw();
154 : // operator bool () const throw();
155 :
156 : private:
157 : void check_final_stack(const stack_t * const sp);
158 : stack_t run(const instr * program, const byte * data,
159 : slotref * & map) HOT;
160 :
161 : SlotMap & _map;
162 : stack_t _stack[STACK_MAX + 2*STACK_GUARD];
163 : status_t _status;
164 : };
165 :
166 0 : inline Machine::Machine(SlotMap & map) throw()
167 0 : : _map(map), _status(finished)
168 : {
169 : // Initialise stack guard +1 entries as the stack pointer points to the
170 : // current top of stack, hence the first push will never write entry 0.
171 : // Initialising the guard space like this is unnecessary and is only
172 : // done to keep valgrind happy during fuzz testing. Hopefully loop
173 : // unrolling will flatten this.
174 0 : for (size_t n = STACK_GUARD + 1; n; --n) _stack[n-1] = 0;
175 0 : }
176 :
177 0 : inline SlotMap& Machine::slotMap() const throw()
178 : {
179 0 : return _map;
180 : }
181 :
182 0 : inline Machine::status_t Machine::status() const throw()
183 : {
184 0 : return _status;
185 : }
186 :
187 0 : inline void Machine::check_final_stack(const stack_t * const sp)
188 : {
189 0 : stack_t const * const base = _stack + STACK_GUARD,
190 0 : * const limit = base + STACK_MAX;
191 0 : if (sp < base) _status = stack_underflow; // This should be impossible now.
192 0 : else if (sp >= limit) _status = stack_overflow; // So should this.
193 0 : else if (sp != base) _status = stack_not_empty;
194 0 : }
195 :
196 : } // namespace vm
197 : } // namespace graphite2
198 :
199 :
200 :
|