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 class represents loaded graphite stack machine code. It performs |
5 | // basic sanity checks, on the incoming code to prevent more obvious problems |
6 | // from crashing graphite. |
7 | // Author: Tim Eves |
8 | |
9 | #pragma once |
10 | |
11 | #include <cassert> |
12 | #include <graphite2/Types.h> |
13 | #include "inc/Main.h" |
14 | #include "inc/Machine.h" |
15 | |
16 | namespace graphite2 { |
17 | |
18 | class Silf; |
19 | class Face; |
20 | |
21 | enum passtype { |
22 | PASS_TYPE_UNKNOWN = 0, |
23 | PASS_TYPE_LINEBREAK, |
24 | PASS_TYPE_SUBSTITUTE, |
25 | PASS_TYPE_POSITIONING, |
26 | PASS_TYPE_JUSTIFICATION |
27 | }; |
28 | |
29 | namespace vm { |
30 | |
31 | class Machine::Code |
32 | { |
33 | public: |
34 | enum status_t |
35 | { |
36 | loaded, |
37 | alloc_failed, |
38 | invalid_opcode, |
39 | unimplemented_opcode_used, |
40 | out_of_range_data, |
41 | jump_past_end, |
42 | arguments_exhausted, |
43 | missing_return, |
44 | nested_context_item, |
45 | underfull_stack |
46 | }; |
47 | |
48 | private: |
49 | class decoder; |
50 | |
51 | instr * _code; |
52 | byte * _data; |
53 | size_t _data_size, |
54 | _instr_count; |
55 | byte _max_ref; |
56 | mutable status_t _status; |
57 | bool _constraint, |
58 | _modify, |
59 | _delete; |
60 | mutable bool _own; |
61 | |
62 | void release_buffers() throw (); |
63 | void failure(const status_t) throw(); |
64 | |
65 | public: |
66 | static size_t estimateCodeDataOut(size_t num_bytecodes, int nRules, int nSlots); |
67 | |
68 | Code() throw(); |
69 | Code(bool is_constraint, const byte * bytecode_begin, const byte * const bytecode_end, |
70 | uint8 pre_context, uint16 rule_length, const Silf &, const Face &, |
71 | enum passtype pt, byte * * const _out = 0); |
72 | Code(const Machine::Code &) throw(); |
73 | ~Code() throw(); |
74 | |
75 | Code & operator=(const Code &rhs) throw(); |
76 | operator bool () const throw() { return _code && status() == loaded; } |
77 | status_t status() const throw() { return _status; } |
78 | bool constraint() const throw() { return _constraint; } |
79 | size_t dataSize() const throw() { return _data_size; } |
80 | size_t instructionCount() const throw() { return _instr_count; } |
81 | bool immutable() const throw() { return !(_delete || _modify); } |
82 | bool deletes() const throw() { return _delete; } |
83 | size_t maxRef() const throw() { return _max_ref; } |
84 | void externalProgramMoved(ptrdiff_t) throw(); |
85 | |
86 | int32 run(Machine &m, slotref * & map) const; |
87 | |
88 | CLASS_NEW_DELETE; |
89 | }; |
90 | |
91 | inline |
92 | size_t Machine::Code::estimateCodeDataOut(size_t n_bc, int nRules, int nSlots) |
93 | { |
94 | // max is: all codes are instructions + 1 for each rule + max tempcopies |
95 | // allocate space for separate maximal code and data then merge them later |
96 | return (n_bc + nRules + nSlots) * sizeof(instr) + n_bc * sizeof(byte); |
97 | } |
98 | |
99 | |
100 | inline Machine::Code::Code() throw() |
101 | : _code(0), _data(0), _data_size(0), _instr_count(0), _max_ref(0), |
102 | _status(loaded), _constraint(false), _modify(false), _delete(false), |
103 | _own(false) |
104 | { |
105 | } |
106 | |
107 | inline Machine::Code::Code(const Machine::Code &obj) throw () |
108 | : _code(obj._code), |
109 | _data(obj._data), |
110 | _data_size(obj._data_size), |
111 | _instr_count(obj._instr_count), |
112 | _max_ref(obj._max_ref), |
113 | _status(obj._status), |
114 | _constraint(obj._constraint), |
115 | _modify(obj._modify), |
116 | _delete(obj._delete), |
117 | _own(obj._own) |
118 | { |
119 | obj._own = false; |
120 | } |
121 | |
122 | inline Machine::Code & Machine::Code::operator=(const Machine::Code &rhs) throw() { |
123 | if (_instr_count > 0) |
124 | release_buffers(); |
125 | _code = rhs._code; |
126 | _data = rhs._data; |
127 | _data_size = rhs._data_size; |
128 | _instr_count = rhs._instr_count; |
129 | _status = rhs._status; |
130 | _constraint = rhs._constraint; |
131 | _modify = rhs._modify; |
132 | _delete = rhs._delete; |
133 | _own = rhs._own; |
134 | rhs._own = false; |
135 | return *this; |
136 | } |
137 | |
138 | inline void Machine::Code::externalProgramMoved(ptrdiff_t dist) throw() |
139 | { |
140 | if (_code && !_own) |
141 | { |
142 | _code += dist / signed(sizeof(instr)); |
143 | _data += dist; |
144 | } |
145 | } |
146 | |
147 | } // namespace vm |
148 | } // namespace graphite2 |
149 | |