michael@0: /* GRAPHITE2 LICENSING michael@0: michael@0: Copyright 2010, SIL International michael@0: All rights reserved. michael@0: michael@0: This library is free software; you can redistribute it and/or modify michael@0: it under the terms of the GNU Lesser General Public License as published michael@0: by the Free Software Foundation; either version 2.1 of License, or michael@0: (at your option) any later version. michael@0: michael@0: This program is distributed in the hope that it will be useful, michael@0: but WITHOUT ANY WARRANTY; without even the implied warranty of michael@0: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU michael@0: Lesser General Public License for more details. michael@0: michael@0: You should also have received a copy of the GNU Lesser General Public michael@0: License along with this library in the file named "LICENSE". michael@0: If not, write to the Free Software Foundation, 51 Franklin Street, michael@0: Suite 500, Boston, MA 02110-1335, USA or visit their web page on the michael@0: internet at http://www.fsf.org/licenses/lgpl.html. michael@0: michael@0: Alternatively, the contents of this file may be used under the terms of the michael@0: Mozilla Public License (http://mozilla.org/MPL) or the GNU General Public michael@0: License, as published by the Free Software Foundation, either version 2 michael@0: of the License or (at your option) any later version. michael@0: */ michael@0: // This call threaded interpreter implmentation for machine.h michael@0: // Author: Tim Eves michael@0: michael@0: // Build either this interpreter or the direct_machine implementation. michael@0: // The call threaded interpreter is portable across compilers and michael@0: // architectures as well as being useful to debug (you can set breakpoints on michael@0: // opcodes) but is slower that the direct threaded interpreter by a factor of 2 michael@0: michael@0: #include michael@0: #include michael@0: #include michael@0: #include "inc/Machine.h" michael@0: #include "inc/Segment.h" michael@0: #include "inc/Slot.h" michael@0: #include "inc/Rule.h" michael@0: michael@0: // Disable the unused parameter warning as th compiler is mistaken since dp michael@0: // is always updated (even if by 0) on every opcode. michael@0: #ifdef __GNUC__ michael@0: #pragma GCC diagnostic ignored "-Wunused-parameter" michael@0: #endif michael@0: michael@0: #define registers const byte * & dp, vm::Machine::stack_t * & sp, \ michael@0: vm::Machine::stack_t * const sb, regbank & reg michael@0: michael@0: // These are required by opcodes.h and should not be changed michael@0: #define STARTOP(name) bool name(registers) REGPARM(4);\ michael@0: bool name(registers) { michael@0: #define ENDOP return (sp - sb)/Machine::STACK_MAX==0; \ michael@0: } michael@0: michael@0: #define EXIT(status) { push(status); return false; } michael@0: michael@0: // This is required by opcode_table.h michael@0: #define do_(name) instr(name) michael@0: michael@0: michael@0: using namespace graphite2; michael@0: using namespace vm; michael@0: michael@0: struct regbank { michael@0: slotref is; michael@0: slotref * map; michael@0: SlotMap & smap; michael@0: slotref * const map_base; michael@0: const instr * & ip; michael@0: int8 flags; michael@0: }; michael@0: michael@0: typedef bool (* ip_t)(registers); michael@0: michael@0: // Pull in the opcode definitions michael@0: // We pull these into a private namespace so these otherwise common names dont michael@0: // pollute the toplevel namespace. michael@0: namespace { michael@0: #define smap reg.smap michael@0: #define seg smap.segment michael@0: #define is reg.is michael@0: #define ip reg.ip michael@0: #define map reg.map michael@0: #define mapb reg.map_base michael@0: #define flags reg.flags michael@0: michael@0: #include "inc/opcodes.h" michael@0: michael@0: #undef smap michael@0: #undef seg michael@0: #undef is michael@0: #undef ip michael@0: #undef map michael@0: #undef mapb michael@0: #undef flags michael@0: } michael@0: michael@0: Machine::stack_t Machine::run(const instr * program, michael@0: const byte * data, michael@0: slotref * & map) michael@0: michael@0: { michael@0: assert(program != 0); michael@0: michael@0: // Declare virtual machine registers michael@0: const instr * ip = program-1; michael@0: const byte * dp = data; michael@0: stack_t * sp = _stack + Machine::STACK_GUARD, michael@0: * const sb = sp; michael@0: regbank reg = {*map, map, _map, _map.begin()+_map.context(), ip, 0}; michael@0: michael@0: // Run the program michael@0: while ((reinterpret_cast(*++ip))(dp, sp, sb, reg)) {} michael@0: const stack_t ret = sp == _stack+STACK_GUARD+1 ? *sp-- : 0; michael@0: michael@0: check_final_stack(sp); michael@0: map = reg.map; michael@0: *map = reg.is; michael@0: return ret; michael@0: } michael@0: michael@0: // Pull in the opcode table michael@0: namespace { michael@0: #include "inc/opcode_table.h" michael@0: } michael@0: michael@0: const opcode_t * Machine::getOpcodeTable() throw() michael@0: { michael@0: return opcode_table; michael@0: } michael@0: michael@0: