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
16namespace graphite2 {
17
18class Silf;
19class Face;
20
21enum passtype {
22 PASS_TYPE_UNKNOWN = 0,
23 PASS_TYPE_LINEBREAK,
24 PASS_TYPE_SUBSTITUTE,
25 PASS_TYPE_POSITIONING,
26 PASS_TYPE_JUSTIFICATION
27};
28
29namespace vm {
30
31class Machine::Code
32{
33public:
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
48private:
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
65public:
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
91inline
92size_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
100inline 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
107inline 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
122inline 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
138inline 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