// SPDX-License-Identifier: MIT OR MPL-2.0 OR LGPL-2.1-or-later OR GPL-2.0-or-later // Copyright 2010, SIL International, All rights reserved. // This direct threaded interpreter implmentation for machine.h // Author: Tim Eves // Build either this interpreter or the call_machine implementation. // The direct threaded interpreter is relies upon a gcc feature called // labels-as-values so is only portable to compilers that support the // extension (gcc only as far as I know) however it should build on any // architecture gcc supports. // This is twice as fast as the call threaded model and is likely faster on // inorder processors with short pipelines and little branch prediction such // as the ARM and possibly Atom chips. #include <cassert> #include <cstring> #include "inc/Machine.h" #include "inc/Segment.h" #include "inc/Slot.h" #include "inc/Rule.h" #define STARTOP(name) … #define ENDOP … #define EXIT(status) … #define do_(name) … usingnamespacegraphite2; usingnamespacevm; namespace { // The GCC manual has this to say about labels as values: // The &&foo expressions for the same label might have different values // if the containing function is inlined or cloned. If a program relies // on them being always the same, __attribute__((__noinline__,__noclone__)) // should be used to prevent inlining and cloning. // // is_return in Code.cpp relies on being able to do comparisons, so it needs // them to be always the same. // // The GCC manual further adds: // If &&foo is used in a static variable initializer, inlining and // cloning is forbidden. // // In this file, &&foo *is* used in a static variable initializer, and it's not // entirely clear whether this should prevent inlining of the function or not. // In practice, though, clang 7 can end up inlining the function with ThinLTO, // which breaks at least is_return. https://bugs.llvm.org/show_bug.cgi?id=39241 // So all in all, we need at least the __noinline__ attribute. __noclone__ // is not supported by clang. __attribute__((__noinline__)) const void * direct_run(const bool get_table_mode, const instr * program, const byte * data, Machine::stack_t * stack, slotref * & __map, uint8 _dir, Machine::status_t & status, SlotMap * __smap=0) { … } } const opcode_t * Machine::getOpcodeTable() throw() { … } Machine::stack_t Machine::run(const instr * program, const byte * data, slotref * & is) { … }