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 : #define HOT __attribute__((hot))
40 : #if defined(__x86_64)
41 : #define REGPARM(n) __attribute__((hot, regparm(n)))
42 : #else
43 : #define REGPARM(n)
44 : #endif
45 : #else
46 : #define HOT
47 : #define REGPARM(n)
48 : #endif
49 :
50 : namespace graphite2 {
51 :
52 : // Forward declarations
53 : class Segment;
54 : class Slot;
55 : class SlotMap;
56 :
57 :
58 : namespace vm
59 : {
60 :
61 :
62 : typedef void * instr;
63 : typedef Slot * slotref;
64 :
65 : enum {VARARGS = 0xff, MAX_NAME_LEN=32};
66 :
67 : enum opcode {
68 : NOP = 0,
69 :
70 : PUSH_BYTE, PUSH_BYTEU, PUSH_SHORT, PUSH_SHORTU, PUSH_LONG,
71 :
72 : ADD, SUB, MUL, DIV,
73 : MIN_, MAX_,
74 : NEG,
75 : TRUNC8, TRUNC16,
76 :
77 : COND,
78 :
79 : AND, OR, NOT,
80 : EQUAL, NOT_EQ,
81 : LESS, GTR, LESS_EQ, GTR_EQ,
82 :
83 : NEXT, NEXT_N, COPY_NEXT,
84 : PUT_GLYPH_8BIT_OBS, PUT_SUBS_8BIT_OBS, PUT_COPY,
85 : INSERT, DELETE,
86 : ASSOC,
87 : CNTXT_ITEM,
88 :
89 : ATTR_SET, ATTR_ADD, ATTR_SUB,
90 : ATTR_SET_SLOT,
91 : IATTR_SET_SLOT,
92 : PUSH_SLOT_ATTR, PUSH_GLYPH_ATTR_OBS,
93 : PUSH_GLYPH_METRIC, PUSH_FEAT,
94 : PUSH_ATT_TO_GATTR_OBS, PUSH_ATT_TO_GLYPH_METRIC,
95 : PUSH_ISLOT_ATTR,
96 :
97 : PUSH_IGLYPH_ATTR, // not implemented
98 :
99 : POP_RET, RET_ZERO, RET_TRUE,
100 : IATTR_SET, IATTR_ADD, IATTR_SUB,
101 : PUSH_PROC_STATE, PUSH_VERSION,
102 : PUT_SUBS, PUT_SUBS2, PUT_SUBS3,
103 : PUT_GLYPH, PUSH_GLYPH_ATTR, PUSH_ATT_TO_GLYPH_ATTR,
104 : MAX_OPCODE,
105 : // private opcodes for internal use only, comes after all other on disk opcodes
106 : TEMP_COPY = MAX_OPCODE
107 : };
108 :
109 : struct opcode_t
110 : {
111 : instr impl[2];
112 : uint8 param_sz;
113 : char name[MAX_NAME_LEN];
114 : };
115 :
116 :
117 : class Machine
118 : {
119 : public:
120 : typedef int32 stack_t;
121 : static size_t const STACK_ORDER = 10,
122 : STACK_MAX = 1 << STACK_ORDER,
123 : STACK_GUARD = 2;
124 :
125 : class Code;
126 :
127 : enum status_t {
128 : finished = 0,
129 : stack_underflow,
130 : stack_not_empty,
131 : stack_overflow,
132 : slot_offset_out_bounds
133 : };
134 :
135 : Machine(SlotMap &) throw();
136 : static const opcode_t * getOpcodeTable() throw();
137 :
138 : CLASS_NEW_DELETE;
139 :
140 : SlotMap & slotMap() const throw();
141 : status_t status() const throw();
142 : operator bool () const throw();
143 :
144 : private:
145 : void check_final_stack(const stack_t * const sp);
146 : stack_t run(const instr * program, const byte * data,
147 : slotref * & map) HOT;
148 :
149 : SlotMap & _map;
150 : stack_t _stack[STACK_MAX + 2*STACK_GUARD];
151 : status_t _status;
152 : };
153 :
154 0 : inline Machine::Machine(SlotMap & map) throw()
155 0 : : _map(map), _status(finished)
156 : {
157 0 : memset(_stack, 0, STACK_GUARD);
158 0 : }
159 :
160 0 : inline SlotMap& Machine::slotMap() const throw()
161 : {
162 0 : return _map;
163 : }
164 :
165 0 : inline Machine::status_t Machine::status() const throw()
166 : {
167 0 : return _status;
168 : }
169 :
170 0 : inline void Machine::check_final_stack(const int32 * const sp)
171 : {
172 0 : stack_t const * const base = _stack + STACK_GUARD,
173 0 : * const limit = base + STACK_MAX;
174 0 : if (sp < base) _status = stack_underflow; // This should be impossible now.
175 0 : else if (sp >= limit) _status = stack_overflow; // So should this.
176 0 : else if (sp != base) _status = stack_not_empty;
177 0 : else _status = finished;
178 0 : }
179 :
180 : } // namespace vm
181 : } // namespace graphite2
182 :
183 :
184 :
|