|
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 MAX_OPCODE, |
|
114 // private opcodes for internal use only, comes after all other on disk opcodes |
|
115 TEMP_COPY = MAX_OPCODE |
|
116 }; |
|
117 |
|
118 struct opcode_t |
|
119 { |
|
120 instr impl[2]; |
|
121 uint8 param_sz; |
|
122 char name[MAX_NAME_LEN]; |
|
123 }; |
|
124 |
|
125 |
|
126 class Machine |
|
127 { |
|
128 public: |
|
129 typedef int32 stack_t; |
|
130 static size_t const STACK_ORDER = 10, |
|
131 STACK_MAX = 1 << STACK_ORDER, |
|
132 STACK_GUARD = 2; |
|
133 |
|
134 class Code; |
|
135 |
|
136 enum status_t { |
|
137 finished = 0, |
|
138 stack_underflow, |
|
139 stack_not_empty, |
|
140 stack_overflow, |
|
141 slot_offset_out_bounds |
|
142 }; |
|
143 |
|
144 Machine(SlotMap &) throw(); |
|
145 static const opcode_t * getOpcodeTable() throw(); |
|
146 |
|
147 CLASS_NEW_DELETE; |
|
148 |
|
149 SlotMap & slotMap() const throw(); |
|
150 status_t status() const throw(); |
|
151 operator bool () const throw(); |
|
152 |
|
153 private: |
|
154 void check_final_stack(const stack_t * const sp); |
|
155 stack_t run(const instr * program, const byte * data, |
|
156 slotref * & map) HOT; |
|
157 |
|
158 SlotMap & _map; |
|
159 stack_t _stack[STACK_MAX + 2*STACK_GUARD]; |
|
160 status_t _status; |
|
161 }; |
|
162 |
|
163 inline Machine::Machine(SlotMap & map) throw() |
|
164 : _map(map), _status(finished) |
|
165 { |
|
166 // Initialise stack guard +1 entries as the stack pointer points to the |
|
167 // current top of stack, hence the first push will never write entry 0. |
|
168 // Initialising the guard space like this is unnecessary and is only |
|
169 // done to keep valgrind happy during fuzz testing. Hopefully loop |
|
170 // unrolling will flatten this. |
|
171 for (size_t n = STACK_GUARD + 1; n; --n) _stack[n-1] = 0; |
|
172 } |
|
173 |
|
174 inline SlotMap& Machine::slotMap() const throw() |
|
175 { |
|
176 return _map; |
|
177 } |
|
178 |
|
179 inline Machine::status_t Machine::status() const throw() |
|
180 { |
|
181 return _status; |
|
182 } |
|
183 |
|
184 inline void Machine::check_final_stack(const int32 * const sp) |
|
185 { |
|
186 stack_t const * const base = _stack + STACK_GUARD, |
|
187 * const limit = base + STACK_MAX; |
|
188 if (sp < base) _status = stack_underflow; // This should be impossible now. |
|
189 else if (sp >= limit) _status = stack_overflow; // So should this. |
|
190 else if (sp != base) _status = stack_not_empty; |
|
191 } |
|
192 |
|
193 } // namespace vm |
|
194 } // namespace graphite2 |
|
195 |
|
196 |
|
197 |