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 direct threaded interpreter implmentation for machine.h michael@0: // Author: Tim Eves michael@0: michael@0: // Build either this interpreter or the call_machine implementation. michael@0: // The direct threaded interpreter is relies upon a gcc feature called michael@0: // labels-as-values so is only portable to compilers that support the michael@0: // extension (gcc only as far as I know) however it should build on any michael@0: // architecture gcc supports. michael@0: // This is twice as fast as the call threaded model and is likely faster on michael@0: // inorder processors with short pipelines and little branch prediction such michael@0: // as the ARM and possibly Atom chips. michael@0: michael@0: 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: #define STARTOP(name) name: { michael@0: #define ENDOP }; goto *((sp - sb)/Machine::STACK_MAX ? &&end : *++ip); michael@0: #define EXIT(status) { push(status); goto end; } michael@0: michael@0: #define do_(name) &&name michael@0: michael@0: michael@0: using namespace graphite2; michael@0: using namespace vm; michael@0: michael@0: namespace { michael@0: michael@0: const void * direct_run(const bool get_table_mode, michael@0: const instr * program, michael@0: const byte * data, michael@0: Machine::stack_t * stack, michael@0: slotref * & __map, michael@0: SlotMap * __smap=0) michael@0: { michael@0: // We need to define and return to opcode table from within this function michael@0: // other inorder to take the addresses of the instruction bodies. michael@0: #include "inc/opcode_table.h" michael@0: if (get_table_mode) michael@0: return opcode_table; michael@0: michael@0: // Declare virtual machine registers michael@0: const instr * ip = program; michael@0: const byte * dp = data; michael@0: Machine::stack_t * sp = stack + Machine::STACK_GUARD, michael@0: * const sb = sp; michael@0: SlotMap & smap = *__smap; michael@0: Segment & seg = smap.segment; michael@0: slotref is = *__map, michael@0: * map = __map, michael@0: * const mapb = smap.begin()+smap.context(); michael@0: int8 flags = 0; michael@0: michael@0: // start the program michael@0: goto **ip; michael@0: michael@0: // Pull in the opcode definitions michael@0: #include "inc/opcodes.h" michael@0: michael@0: end: michael@0: __map = map; michael@0: *__map = is; michael@0: return sp; michael@0: } michael@0: michael@0: } michael@0: michael@0: const opcode_t * Machine::getOpcodeTable() throw() michael@0: { michael@0: slotref * dummy; michael@0: return static_cast(direct_run(true, 0, 0, 0, dummy, 0)); michael@0: } michael@0: michael@0: michael@0: Machine::stack_t Machine::run(const instr * program, michael@0: const byte * data, michael@0: slotref * & is) michael@0: { michael@0: assert(program != 0); michael@0: michael@0: const stack_t *sp = static_cast( michael@0: direct_run(false, program, data, _stack, is, &_map)); michael@0: const stack_t ret = sp == _stack+STACK_GUARD+1 ? *sp-- : 0; michael@0: check_final_stack(sp); michael@0: return ret; michael@0: } michael@0: