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