harfbuzz/src/graphite2/src/inc/Code.h

149 lines
4.0 KiB
C++

// SPDX-License-Identifier: MIT
// Copyright 2010, SIL International, All rights reserved.
// This class represents loaded graphite stack machine code. It performs
// basic sanity checks, on the incoming code to prevent more obvious problems
// from crashing graphite.
// Author: Tim Eves
#pragma once
#include <cassert>
#include <graphite2/Types.h>
#include "inc/Main.h"
#include "inc/Machine.h"
namespace graphite2 {
class Silf;
class Face;
enum passtype {
PASS_TYPE_UNKNOWN = 0,
PASS_TYPE_LINEBREAK,
PASS_TYPE_SUBSTITUTE,
PASS_TYPE_POSITIONING,
PASS_TYPE_JUSTIFICATION
};
namespace vm {
class Machine::Code
{
public:
enum status_t
{
loaded,
alloc_failed,
invalid_opcode,
unimplemented_opcode_used,
out_of_range_data,
jump_past_end,
arguments_exhausted,
missing_return,
nested_context_item,
underfull_stack
};
private:
class decoder;
instr * _code;
byte * _data;
size_t _data_size,
_instr_count;
byte _max_ref;
mutable status_t _status;
bool _constraint,
_modify,
_delete;
mutable bool _own;
void release_buffers() throw ();
void failure(const status_t) throw();
public:
static size_t estimateCodeDataOut(size_t num_bytecodes, int nRules, int nSlots);
Code() throw();
Code(bool is_constraint, const byte * bytecode_begin, const byte * const bytecode_end,
uint8_t pre_context, uint16_t rule_length, const Silf &, const Face &,
enum passtype pt, byte * * const _out = 0);
Code(const Machine::Code &) throw();
~Code() throw();
Code & operator=(const Code &rhs) throw();
operator bool () const throw() { return _code && status() == loaded; }
status_t status() const throw() { return _status; }
bool constraint() const throw() { return _constraint; }
size_t dataSize() const throw() { return _data_size; }
size_t instructionCount() const throw() { return _instr_count; }
bool immutable() const throw() { return !(_delete || _modify); }
bool deletes() const throw() { return _delete; }
size_t maxRef() const throw() { return _max_ref; }
void externalProgramMoved(ptrdiff_t) throw();
int32_t run(Machine &m, ShapingContext::map_t::iterator & slot_in, slotref & slot_out) const;
CLASS_NEW_DELETE;
};
inline
size_t Machine::Code::estimateCodeDataOut(size_t n_bc, int nRules, int nSlots)
{
// max is: all codes are instructions + 1 for each rule + max tempcopies
// allocate space for separate maximal code and data then merge them later
return (n_bc + nRules + nSlots) * sizeof(instr) + n_bc * sizeof(byte);
}
inline Machine::Code::Code() throw()
: _code(0), _data(0), _data_size(0), _instr_count(0), _max_ref(0),
_status(loaded), _constraint(false), _modify(false), _delete(false),
_own(false)
{
}
inline Machine::Code::Code(const Machine::Code &obj) throw ()
: _code(obj._code),
_data(obj._data),
_data_size(obj._data_size),
_instr_count(obj._instr_count),
_max_ref(obj._max_ref),
_status(obj._status),
_constraint(obj._constraint),
_modify(obj._modify),
_delete(obj._delete),
_own(obj._own)
{
obj._own = false;
}
inline Machine::Code & Machine::Code::operator=(const Machine::Code &rhs) throw() {
if (_instr_count > 0)
release_buffers();
_code = rhs._code;
_data = rhs._data;
_data_size = rhs._data_size;
_instr_count = rhs._instr_count;
_status = rhs._status;
_constraint = rhs._constraint;
_modify = rhs._modify;
_delete = rhs._delete;
_own = rhs._own;
rhs._own = false;
return *this;
}
inline void Machine::Code::externalProgramMoved(ptrdiff_t dist) throw()
{
if (_code && !_own)
{
_code += dist / signed(sizeof(instr));
_data += dist;
}
}
} // namespace vm
} // namespace graphite2