1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/gfx/graphite2/src/inc/Machine.h Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,197 @@ 1.4 +/* GRAPHITE2 LICENSING 1.5 + 1.6 + Copyright 2010, SIL International 1.7 + All rights reserved. 1.8 + 1.9 + This library is free software; you can redistribute it and/or modify 1.10 + it under the terms of the GNU Lesser General Public License as published 1.11 + by the Free Software Foundation; either version 2.1 of License, or 1.12 + (at your option) any later version. 1.13 + 1.14 + This program is distributed in the hope that it will be useful, 1.15 + but WITHOUT ANY WARRANTY; without even the implied warranty of 1.16 + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 1.17 + Lesser General Public License for more details. 1.18 + 1.19 + You should also have received a copy of the GNU Lesser General Public 1.20 + License along with this library in the file named "LICENSE". 1.21 + If not, write to the Free Software Foundation, 51 Franklin Street, 1.22 + Suite 500, Boston, MA 02110-1335, USA or visit their web page on the 1.23 + internet at http://www.fsf.org/licenses/lgpl.html. 1.24 + 1.25 +Alternatively, the contents of this file may be used under the terms of the 1.26 +Mozilla Public License (http://mozilla.org/MPL) or the GNU General Public 1.27 +License, as published by the Free Software Foundation, either version 2 1.28 +of the License or (at your option) any later version. 1.29 +*/ 1.30 +// This general interpreter interface. 1.31 +// Author: Tim Eves 1.32 + 1.33 +// Build one of direct_machine.cpp or call_machine.cpp to implement this 1.34 +// interface. 1.35 + 1.36 +#pragma once 1.37 +#include <cstring> 1.38 +#include <graphite2/Types.h> 1.39 +#include "inc/Main.h" 1.40 + 1.41 +#if defined(__GNUC__) 1.42 +#if defined(__clang__) || (__GNUC__ * 100 + __GNUC_MINOR__ * 10) < 430 1.43 +#define HOT 1.44 +#if defined(__x86_64) 1.45 +#define REGPARM(n) __attribute__((regparm(n))) 1.46 +#else 1.47 +#define REGPARM(n) 1.48 +#endif 1.49 +#else 1.50 +#define HOT __attribute__((hot)) 1.51 +#if defined(__x86_64) 1.52 +#define REGPARM(n) __attribute__((hot, regparm(n))) 1.53 +#else 1.54 +#define REGPARM(n) 1.55 +#endif 1.56 +#endif 1.57 +#else 1.58 +#define HOT 1.59 +#define REGPARM(n) 1.60 +#endif 1.61 + 1.62 +namespace graphite2 { 1.63 + 1.64 +// Forward declarations 1.65 +class Segment; 1.66 +class Slot; 1.67 +class SlotMap; 1.68 + 1.69 + 1.70 +namespace vm 1.71 +{ 1.72 + 1.73 + 1.74 +typedef void * instr; 1.75 +typedef Slot * slotref; 1.76 + 1.77 +enum {VARARGS = 0xff, MAX_NAME_LEN=32}; 1.78 + 1.79 +enum opcode { 1.80 + NOP = 0, 1.81 + 1.82 + PUSH_BYTE, PUSH_BYTEU, PUSH_SHORT, PUSH_SHORTU, PUSH_LONG, 1.83 + 1.84 + ADD, SUB, MUL, DIV, 1.85 + MIN_, MAX_, 1.86 + NEG, 1.87 + TRUNC8, TRUNC16, 1.88 + 1.89 + COND, 1.90 + 1.91 + AND, OR, NOT, 1.92 + EQUAL, NOT_EQ, 1.93 + LESS, GTR, LESS_EQ, GTR_EQ, 1.94 + 1.95 + NEXT, NEXT_N, COPY_NEXT, 1.96 + PUT_GLYPH_8BIT_OBS, PUT_SUBS_8BIT_OBS, PUT_COPY, 1.97 + INSERT, DELETE, 1.98 + ASSOC, 1.99 + CNTXT_ITEM, 1.100 + 1.101 + ATTR_SET, ATTR_ADD, ATTR_SUB, 1.102 + ATTR_SET_SLOT, 1.103 + IATTR_SET_SLOT, 1.104 + PUSH_SLOT_ATTR, PUSH_GLYPH_ATTR_OBS, 1.105 + PUSH_GLYPH_METRIC, PUSH_FEAT, 1.106 + PUSH_ATT_TO_GATTR_OBS, PUSH_ATT_TO_GLYPH_METRIC, 1.107 + PUSH_ISLOT_ATTR, 1.108 + 1.109 + PUSH_IGLYPH_ATTR, // not implemented 1.110 + 1.111 + POP_RET, RET_ZERO, RET_TRUE, 1.112 + IATTR_SET, IATTR_ADD, IATTR_SUB, 1.113 + PUSH_PROC_STATE, PUSH_VERSION, 1.114 + PUT_SUBS, PUT_SUBS2, PUT_SUBS3, 1.115 + PUT_GLYPH, PUSH_GLYPH_ATTR, PUSH_ATT_TO_GLYPH_ATTR, 1.116 + MAX_OPCODE, 1.117 + // private opcodes for internal use only, comes after all other on disk opcodes 1.118 + TEMP_COPY = MAX_OPCODE 1.119 +}; 1.120 + 1.121 +struct opcode_t 1.122 +{ 1.123 + instr impl[2]; 1.124 + uint8 param_sz; 1.125 + char name[MAX_NAME_LEN]; 1.126 +}; 1.127 + 1.128 + 1.129 +class Machine 1.130 +{ 1.131 +public: 1.132 + typedef int32 stack_t; 1.133 + static size_t const STACK_ORDER = 10, 1.134 + STACK_MAX = 1 << STACK_ORDER, 1.135 + STACK_GUARD = 2; 1.136 + 1.137 + class Code; 1.138 + 1.139 + enum status_t { 1.140 + finished = 0, 1.141 + stack_underflow, 1.142 + stack_not_empty, 1.143 + stack_overflow, 1.144 + slot_offset_out_bounds 1.145 + }; 1.146 + 1.147 + Machine(SlotMap &) throw(); 1.148 + static const opcode_t * getOpcodeTable() throw(); 1.149 + 1.150 + CLASS_NEW_DELETE; 1.151 + 1.152 + SlotMap & slotMap() const throw(); 1.153 + status_t status() const throw(); 1.154 + operator bool () const throw(); 1.155 + 1.156 +private: 1.157 + void check_final_stack(const stack_t * const sp); 1.158 + stack_t run(const instr * program, const byte * data, 1.159 + slotref * & map) HOT; 1.160 + 1.161 + SlotMap & _map; 1.162 + stack_t _stack[STACK_MAX + 2*STACK_GUARD]; 1.163 + status_t _status; 1.164 +}; 1.165 + 1.166 +inline Machine::Machine(SlotMap & map) throw() 1.167 +: _map(map), _status(finished) 1.168 +{ 1.169 + // Initialise stack guard +1 entries as the stack pointer points to the 1.170 + // current top of stack, hence the first push will never write entry 0. 1.171 + // Initialising the guard space like this is unnecessary and is only 1.172 + // done to keep valgrind happy during fuzz testing. Hopefully loop 1.173 + // unrolling will flatten this. 1.174 + for (size_t n = STACK_GUARD + 1; n; --n) _stack[n-1] = 0; 1.175 +} 1.176 + 1.177 +inline SlotMap& Machine::slotMap() const throw() 1.178 +{ 1.179 + return _map; 1.180 +} 1.181 + 1.182 +inline Machine::status_t Machine::status() const throw() 1.183 +{ 1.184 + return _status; 1.185 +} 1.186 + 1.187 +inline void Machine::check_final_stack(const int32 * const sp) 1.188 +{ 1.189 + stack_t const * const base = _stack + STACK_GUARD, 1.190 + * const limit = base + STACK_MAX; 1.191 + if (sp < base) _status = stack_underflow; // This should be impossible now. 1.192 + else if (sp >= limit) _status = stack_overflow; // So should this. 1.193 + else if (sp != base) _status = stack_not_empty; 1.194 +} 1.195 + 1.196 +} // namespace vm 1.197 +} // namespace graphite2 1.198 + 1.199 + 1.200 +