LCOV - code coverage report
Current view: top level - gfx/graphite2/src - Code.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 339 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 22 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*  GRAPHITE2 LICENSING
       2             : 
       3             :     Copyright 2010, SIL International
       4             :     All rights reserved.
       5             : 
       6             :     This library is free software; you can redistribute it and/or modify
       7             :     it under the terms of the GNU Lesser General Public License as published
       8             :     by the Free Software Foundation; either version 2.1 of License, or
       9             :     (at your option) any later version.
      10             : 
      11             :     This program is distributed in the hope that it will be useful,
      12             :     but WITHOUT ANY WARRANTY; without even the implied warranty of
      13             :     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      14             :     Lesser General Public License for more details.
      15             : 
      16             :     You should also have received a copy of the GNU Lesser General Public
      17             :     License along with this library in the file named "LICENSE".
      18             :     If not, write to the Free Software Foundation, 51 Franklin Street, 
      19             :     Suite 500, Boston, MA 02110-1335, USA or visit their web page on the 
      20             :     internet at http://www.fsf.org/licenses/lgpl.html.
      21             : 
      22             : Alternatively, the contents of this file may be used under the terms of the
      23             : Mozilla Public License (http://mozilla.org/MPL) or the GNU General Public
      24             : License, as published by the Free Software Foundation, either version 2
      25             : of the License or (at your option) any later version.
      26             : */
      27             : // This class represents loaded graphite stack machine code.  It performs 
      28             : // basic sanity checks, on the incoming code to prevent more obvious problems
      29             : // from crashing graphite.
      30             : // Author: Tim Eves
      31             : 
      32             : #include <cassert>
      33             : #include <cstddef>
      34             : #include <cstdlib>
      35             : #include <cstring>
      36             : #include "graphite2/Segment.h"
      37             : #include "inc/Code.h"
      38             : #include "inc/Face.h"
      39             : #include "inc/GlyphFace.h"
      40             : #include "inc/GlyphCache.h"
      41             : #include "inc/Machine.h"
      42             : #include "inc/Rule.h"
      43             : #include "inc/Silf.h"
      44             : 
      45             : #include <cstdio>
      46             : 
      47             : #ifdef NDEBUG
      48             : #ifdef __GNUC__
      49             : #pragma GCC diagnostic ignored "-Wunused-parameter"
      50             : #endif
      51             : #endif
      52             : 
      53             : 
      54             : using namespace graphite2;
      55             : using namespace vm;
      56             : 
      57             : namespace {
      58             : 
      59           0 : inline bool is_return(const instr i) {
      60           0 :     const opcode_t * opmap = Machine::getOpcodeTable();
      61           0 :     const instr pop_ret  = *opmap[POP_RET].impl,
      62           0 :                 ret_zero = *opmap[RET_ZERO].impl,
      63           0 :                 ret_true = *opmap[RET_TRUE].impl;
      64           0 :     return i == pop_ret || i == ret_zero || i == ret_true;
      65             : }
      66             : 
      67             : struct context
      68             : {
      69           0 :     context(uint8 ref=0) : codeRef(ref) {flags.changed=false; flags.referenced=false;}
      70             :     struct { 
      71             :         uint8   changed:1,
      72             :                 referenced:1;
      73             :     } flags;
      74             :     uint8       codeRef;
      75             : };
      76             : 
      77             : } // end namespace
      78             : 
      79             : 
      80             : class Machine::Code::decoder
      81             : {
      82             : public:
      83             :     struct limits;
      84             :     static const int NUMCONTEXTS = 256;
      85             :     
      86             :     decoder(limits & lims, Code &code, enum passtype pt) throw();
      87             :     
      88             :     bool        load(const byte * bc_begin, const byte * bc_end);
      89             :     void        apply_analysis(instr * const code, instr * code_end);
      90           0 :     byte        max_ref() { return _max_ref; }
      91             :     int         out_index() const { return _out_index; }
      92             :     
      93             : private:
      94             :     void        set_ref(int index) throw();
      95             :     void        set_noref(int index) throw();
      96             :     void        set_changed(int index) throw();
      97             :     opcode      fetch_opcode(const byte * bc);
      98             :     void        analyse_opcode(const opcode, const int8 * const dp) throw();
      99             :     bool        emit_opcode(opcode opc, const byte * & bc);
     100             :     bool        validate_opcode(const byte opc, const byte * const bc);
     101             :     bool        valid_upto(const uint16 limit, const uint16 x) const throw();
     102             :     bool        test_context() const throw();
     103             :     bool        test_ref(int8 index) const throw();
     104           0 :     void        failure(const status_t s) const throw() { _code.failure(s); }
     105             :     
     106             :     Code              & _code;
     107             :     int                 _out_index;
     108             :     uint16              _out_length;
     109             :     instr             * _instr;
     110             :     byte              * _data;
     111             :     limits            & _max;
     112             :     enum passtype       _passtype;
     113             :     int                 _stack_depth;
     114             :     bool                _in_ctxt_item;
     115             :     int16               _slotref;
     116             :     context             _contexts[NUMCONTEXTS];
     117             :     byte                _max_ref;
     118             : };
     119             : 
     120             : 
     121             : struct Machine::Code::decoder::limits
     122             : {
     123             :   const byte       * bytecode;
     124             :   const uint8        pre_context;
     125             :   const uint16       rule_length,
     126             :                      classes,
     127             :                      glyf_attrs,
     128             :                      features;
     129             :   const byte         attrid[gr_slatMax];
     130             : };
     131             :    
     132           0 : inline Machine::Code::decoder::decoder(limits & lims, Code &code, enum passtype pt) throw()
     133             : : _code(code),
     134           0 :   _out_index(code._constraint ? 0 : lims.pre_context), 
     135           0 :   _out_length(code._constraint ? 1 : lims.rule_length), 
     136           0 :   _instr(code._code), _data(code._data), _max(lims), _passtype(pt),
     137             :   _stack_depth(0),
     138             :   _in_ctxt_item(false),
     139             :   _slotref(0),
     140           0 :   _max_ref(0)
     141           0 : { }
     142             :     
     143             : 
     144             : 
     145           0 : Machine::Code::Code(bool is_constraint, const byte * bytecode_begin, const byte * const bytecode_end,
     146             :            uint8 pre_context, uint16 rule_length, const Silf & silf, const Face & face,
     147           0 :            enum passtype pt, byte * * const _out)
     148             :  :  _code(0), _data(0), _data_size(0), _instr_count(0), _max_ref(0), _status(loaded),
     149           0 :     _constraint(is_constraint), _modify(false), _delete(false), _own(_out==0)
     150             : {
     151             : #ifdef GRAPHITE2_TELEMETRY
     152             :     telemetry::category _code_cat(face.tele.code);
     153             : #endif
     154           0 :     assert(bytecode_begin != 0);
     155           0 :     if (bytecode_begin == bytecode_end)
     156             :     {
     157             :       // ::new (this) Code();
     158           0 :       return;
     159             :     }
     160           0 :     assert(bytecode_end > bytecode_begin);
     161           0 :     const opcode_t *    op_to_fn = Machine::getOpcodeTable();
     162             :     
     163             :     // Allocate code and data target buffers, these sizes are a worst case
     164             :     // estimate.  Once we know their real sizes the we'll shrink them.
     165           0 :     if (_out)   _code = reinterpret_cast<instr *>(*_out);
     166           0 :     else        _code = static_cast<instr *>(malloc(estimateCodeDataOut(bytecode_end-bytecode_begin, 1, is_constraint ? 0 : rule_length)));
     167           0 :     _data = reinterpret_cast<byte *>(_code + (bytecode_end - bytecode_begin));
     168             :     
     169           0 :     if (!_code || !_data) {
     170           0 :         failure(alloc_failed);
     171           0 :         return;
     172             :     }
     173             :     
     174             :     decoder::limits lims = {
     175             :         bytecode_end,
     176             :         pre_context,
     177             :         rule_length,
     178           0 :         silf.numClasses(),
     179           0 :         face.glyphs().numAttrs(),
     180           0 :         face.numFeatures(), 
     181             :         {1,1,1,1,1,1,1,1, 
     182             :          1,1,1,1,1,1,1,255,
     183             :          1,1,1,1,1,1,1,1, 
     184             :          1,1,1,1,1,1,0,0, 
     185             :          0,0,0,0,0,0,0,0, 
     186             :          0,0,0,0,0,0,0,0, 
     187           0 :          0,0,0,0,0,0,0, silf.numUser()}
     188           0 :     };
     189             :     
     190           0 :     decoder dec(lims, *this, pt);
     191           0 :     if(!dec.load(bytecode_begin, bytecode_end))
     192           0 :        return;
     193             :     
     194             :     // Is this an empty program?
     195           0 :     if (_instr_count == 0)
     196             :     {
     197           0 :       release_buffers();
     198           0 :       ::new (this) Code();
     199           0 :       return;
     200             :     }
     201             :     
     202             :     // When we reach the end check we've terminated it correctly
     203           0 :     if (!is_return(_code[_instr_count-1])) {
     204           0 :         failure(missing_return);
     205           0 :         return;
     206             :     }
     207             : 
     208           0 :     assert((_constraint && immutable()) || !_constraint);
     209           0 :     dec.apply_analysis(_code, _code + _instr_count);
     210           0 :     _max_ref = dec.max_ref();
     211             :     
     212             :     // Now we know exactly how much code and data the program really needs
     213             :     // realloc the buffers to exactly the right size so we don't waste any 
     214             :     // memory.
     215           0 :     assert((bytecode_end - bytecode_begin) >= ptrdiff_t(_instr_count));
     216           0 :     assert((bytecode_end - bytecode_begin) >= ptrdiff_t(_data_size));
     217           0 :     memmove(_code + (_instr_count+1), _data, _data_size*sizeof(byte));
     218           0 :     size_t const total_sz = ((_instr_count+1) + (_data_size + sizeof(instr)-1)/sizeof(instr))*sizeof(instr);
     219           0 :     if (_out)
     220           0 :         *_out += total_sz;
     221             :     else
     222           0 :         _code = static_cast<instr *>(realloc(_code, total_sz));
     223           0 :    _data = reinterpret_cast<byte *>(_code + (_instr_count+1));
     224             : 
     225           0 :     if (!_code)
     226             :     {
     227           0 :         failure(alloc_failed);
     228           0 :         return;
     229             :     }
     230             : 
     231             :     // Make this RET_ZERO, we should never reach this but just in case ...
     232           0 :     _code[_instr_count] = op_to_fn[RET_ZERO].impl[_constraint];
     233             : 
     234             : #ifdef GRAPHITE2_TELEMETRY
     235             :     telemetry::count_bytes(_data_size + (_instr_count+1)*sizeof(instr));
     236             : #endif
     237             : }
     238             : 
     239           0 : Machine::Code::~Code() throw ()
     240             : {
     241           0 :     if (_own)
     242           0 :         release_buffers();
     243           0 : }
     244             : 
     245             : 
     246           0 : bool Machine::Code::decoder::load(const byte * bc, const byte * bc_end)
     247             : {
     248           0 :     _max.bytecode = bc_end;
     249           0 :     while (bc < bc_end)
     250             :     {
     251           0 :         const opcode opc = fetch_opcode(bc++);
     252           0 :         if (opc == vm::MAX_OPCODE)
     253           0 :             return false;
     254             :         
     255           0 :         analyse_opcode(opc, reinterpret_cast<const int8 *>(bc));
     256             :         
     257           0 :         if (!emit_opcode(opc, bc))
     258           0 :             return false;
     259             :     }
     260             :     
     261           0 :     return bool(_code);
     262             : }
     263             : 
     264             : // Validation check and fixups.
     265             : //
     266             : 
     267           0 : opcode Machine::Code::decoder::fetch_opcode(const byte * bc)
     268             : {
     269           0 :     const byte opc = *bc++;
     270             : 
     271             :     // Do some basic sanity checks based on what we know about the opcode
     272           0 :     if (!validate_opcode(opc, bc))  return MAX_OPCODE;
     273             : 
     274             :     // And check it's arguments as far as possible
     275           0 :     switch (opcode(opc))
     276             :     {
     277             :         case NOP :
     278           0 :             break;
     279             :         case PUSH_BYTE :
     280             :         case PUSH_BYTEU :
     281             :         case PUSH_SHORT :
     282             :         case PUSH_SHORTU :
     283             :         case PUSH_LONG :
     284           0 :             ++_stack_depth;
     285           0 :             break;
     286             :         case ADD :
     287             :         case SUB :
     288             :         case MUL :
     289             :         case DIV :
     290             :         case MIN_ :
     291             :         case MAX_ :
     292             :         case AND :
     293             :         case OR :
     294             :         case EQUAL :
     295             :         case NOT_EQ :
     296             :         case LESS :
     297             :         case GTR :
     298             :         case LESS_EQ :
     299             :         case GTR_EQ :
     300             :         case BITOR :
     301             :         case BITAND :
     302           0 :             if (--_stack_depth <= 0)
     303           0 :                 failure(underfull_stack);
     304           0 :             break;
     305             :         case NEG :
     306             :         case TRUNC8 :
     307             :         case TRUNC16 :
     308             :         case NOT :
     309             :         case BITNOT :
     310             :         case BITSET :
     311           0 :             if (_stack_depth <= 0)
     312           0 :                 failure(underfull_stack);
     313           0 :             break;
     314             :         case COND :
     315           0 :             _stack_depth -= 2;
     316           0 :             if (_stack_depth <= 0)
     317           0 :                 failure(underfull_stack);
     318           0 :             break;
     319             :         case NEXT :
     320             :         case NEXT_N :           // runtime checked
     321             :         case COPY_NEXT :
     322           0 :             ++_out_index;
     323           0 :             if (_out_index < -1 || _out_index > _out_length || _slotref > _max.rule_length)
     324           0 :                 failure(out_of_range_data);
     325           0 :             break;
     326             :         case PUT_GLYPH_8BIT_OBS :
     327           0 :             valid_upto(_max.classes, bc[0]);
     328           0 :             test_context();
     329           0 :             break;
     330             :         case PUT_SUBS_8BIT_OBS :
     331           0 :             test_ref(int8(bc[0]));
     332           0 :             valid_upto(_max.classes, bc[1]);
     333           0 :             valid_upto(_max.classes, bc[2]);
     334           0 :             test_context();
     335           0 :             break;
     336             :         case PUT_COPY :
     337           0 :             test_ref(int8(bc[0]));
     338           0 :             test_context();
     339           0 :             break;
     340             :         case INSERT :
     341           0 :             if (_passtype >= PASS_TYPE_POSITIONING)
     342           0 :                 failure(invalid_opcode);
     343           0 :             ++_out_length;
     344           0 :             if (_out_index < 0) ++_out_index;
     345           0 :             if (_out_index < -1 || _out_index >= _out_length)
     346           0 :                 failure(out_of_range_data);
     347           0 :             break;
     348             :         case DELETE :
     349           0 :             if (_passtype >= PASS_TYPE_POSITIONING)
     350           0 :                 failure(invalid_opcode);
     351           0 :             if (_out_index < _max.pre_context)
     352           0 :                 failure(out_of_range_data);
     353           0 :             --_out_index;
     354           0 :             --_out_length;
     355           0 :             if (_out_index < -1 || _out_index > _out_length)
     356           0 :                 failure(out_of_range_data);
     357           0 :             break;
     358             :         case ASSOC :
     359           0 :             if (bc[0] == 0)
     360           0 :                 failure(out_of_range_data);
     361           0 :             for (uint8 num = bc[0]; num; --num)
     362           0 :                 test_ref(int8(bc[num]));
     363           0 :             test_context();
     364           0 :             break;
     365             :         case CNTXT_ITEM :
     366           0 :             valid_upto(_max.rule_length, _max.pre_context + int8(bc[0]));
     367           0 :             if (bc + 2 + bc[1] >= _max.bytecode)    failure(jump_past_end);
     368           0 :             if (_in_ctxt_item)                      failure(nested_context_item);
     369           0 :             break;
     370             :         case ATTR_SET :
     371             :         case ATTR_ADD :
     372             :         case ATTR_SUB :
     373             :         case ATTR_SET_SLOT :
     374           0 :             if (--_stack_depth < 0)
     375           0 :                 failure(underfull_stack);
     376           0 :             valid_upto(gr_slatMax, bc[0]);
     377           0 :             if (attrCode(bc[0]) == gr_slatUserDefn)     // use IATTR for user attributes
     378           0 :                 failure(out_of_range_data);
     379           0 :             test_context();
     380           0 :             break;
     381             :         case IATTR_SET_SLOT :
     382           0 :             if (--_stack_depth < 0)
     383           0 :                 failure(underfull_stack);
     384           0 :             if (valid_upto(gr_slatMax, bc[0]))
     385           0 :                 valid_upto(_max.attrid[bc[0]], bc[1]);
     386           0 :             test_context();
     387           0 :             break;
     388             :         case PUSH_SLOT_ATTR :
     389           0 :             ++_stack_depth;
     390           0 :             valid_upto(gr_slatMax, bc[0]);
     391           0 :             test_ref(int8(bc[1]));
     392           0 :             if (attrCode(bc[0]) == gr_slatUserDefn)     // use IATTR for user attributes
     393           0 :                 failure(out_of_range_data);
     394           0 :             break;
     395             :         case PUSH_GLYPH_ATTR_OBS :
     396             :         case PUSH_ATT_TO_GATTR_OBS :
     397           0 :             ++_stack_depth;
     398           0 :             valid_upto(_max.glyf_attrs, bc[0]);
     399           0 :             test_ref(int8(bc[1]));
     400           0 :             break;
     401             :         case PUSH_ATT_TO_GLYPH_METRIC :
     402             :         case PUSH_GLYPH_METRIC :
     403           0 :             ++_stack_depth;
     404           0 :             valid_upto(kgmetDescent, bc[0]);
     405           0 :             test_ref(int8(bc[1]));
     406             :             // level: dp[2] no check necessary
     407           0 :             break;
     408             :         case PUSH_FEAT :
     409           0 :             ++_stack_depth;
     410           0 :             valid_upto(_max.features, bc[0]);
     411           0 :             test_ref(int8(bc[1]));
     412           0 :             break;
     413             :         case PUSH_ISLOT_ATTR :
     414           0 :             ++_stack_depth;
     415           0 :             if (valid_upto(gr_slatMax, bc[0]))
     416             :             {
     417           0 :                 test_ref(int8(bc[1]));
     418           0 :                 valid_upto(_max.attrid[bc[0]], bc[2]);
     419             :             }
     420           0 :             break;
     421             :         case PUSH_IGLYPH_ATTR :// not implemented
     422           0 :             ++_stack_depth;
     423           0 :             break;
     424             :         case POP_RET :
     425           0 :             if (--_stack_depth < 0)
     426           0 :                 failure(underfull_stack);
     427             :             GR_FALLTHROUGH;
     428             :             // no break
     429             :         case RET_ZERO :
     430             :         case RET_TRUE :
     431           0 :             break;
     432             :         case IATTR_SET :
     433             :         case IATTR_ADD :
     434             :         case IATTR_SUB :
     435           0 :             if (--_stack_depth < 0)
     436           0 :                 failure(underfull_stack);
     437           0 :             if (valid_upto(gr_slatMax, bc[0]))
     438           0 :                 valid_upto(_max.attrid[bc[0]], bc[1]);
     439           0 :             test_context();
     440           0 :             break;
     441             :         case PUSH_PROC_STATE :  // dummy: dp[0] no check necessary
     442             :         case PUSH_VERSION :
     443           0 :             ++_stack_depth;
     444           0 :             break;
     445             :         case PUT_SUBS :
     446           0 :             test_ref(int8(bc[0]));
     447           0 :             valid_upto(_max.classes, uint16(bc[1]<< 8) | bc[2]);
     448           0 :             valid_upto(_max.classes, uint16(bc[3]<< 8) | bc[4]);
     449           0 :             test_context();
     450           0 :             break;
     451             :         case PUT_SUBS2 :        // not implemented
     452             :         case PUT_SUBS3 :        // not implemented
     453           0 :             break;
     454             :         case PUT_GLYPH :
     455           0 :             valid_upto(_max.classes, uint16(bc[0]<< 8) | bc[1]);
     456           0 :             test_context();
     457           0 :             break;
     458             :         case PUSH_GLYPH_ATTR :
     459             :         case PUSH_ATT_TO_GLYPH_ATTR :
     460           0 :             ++_stack_depth;
     461           0 :             valid_upto(_max.glyf_attrs, uint16(bc[0]<< 8) | bc[1]);
     462           0 :             test_ref(int8(bc[2]));
     463           0 :             break;
     464             :         case SET_FEAT :
     465           0 :             valid_upto(_max.features, bc[0]);
     466           0 :             test_ref(int8(bc[1]));
     467           0 :             break;
     468             :         default:
     469           0 :             failure(invalid_opcode);
     470           0 :             break;
     471             :     }
     472             : 
     473           0 :     return bool(_code) ? opcode(opc) : MAX_OPCODE;
     474             : }
     475             : 
     476             : 
     477           0 : void Machine::Code::decoder::analyse_opcode(const opcode opc, const int8  * arg) throw()
     478             : {
     479           0 :   switch (opc)
     480             :   {
     481             :     case DELETE :
     482           0 :       _code._delete = true;
     483           0 :       break;
     484             :     case ASSOC :
     485           0 :       set_changed(0);
     486             : //      for (uint8 num = arg[0]; num; --num)
     487             : //        _analysis.set_noref(num);
     488           0 :       break;
     489             :     case PUT_GLYPH_8BIT_OBS :
     490             :     case PUT_GLYPH :
     491           0 :       _code._modify = true;
     492           0 :       set_changed(0);
     493           0 :       break;
     494             :     case ATTR_SET :
     495             :     case ATTR_ADD :
     496             :     case ATTR_SUB :
     497             :     case ATTR_SET_SLOT :
     498             :     case IATTR_SET_SLOT :
     499             :     case IATTR_SET :
     500             :     case IATTR_ADD :
     501             :     case IATTR_SUB :
     502           0 :       set_noref(0);
     503           0 :       break;
     504             :     case NEXT :
     505             :     case COPY_NEXT :
     506           0 :       ++_slotref;
     507           0 :       _contexts[_slotref] = context(_code._instr_count+1);
     508             :       // if (_analysis.slotref > _analysis.max_ref) _analysis.max_ref = _analysis.slotref;
     509           0 :       break;
     510             :     case INSERT :
     511           0 :       if (_slotref >= 0) --_slotref;
     512           0 :       _code._modify = true;
     513           0 :       break;
     514             :     case PUT_SUBS_8BIT_OBS :    // slotref on 1st parameter
     515             :     case PUT_SUBS : 
     516           0 :       _code._modify = true;
     517           0 :       set_changed(0);
     518             :       GR_FALLTHROUGH;
     519             :       // no break
     520             :     case PUT_COPY :
     521           0 :       if (arg[0] != 0) { set_changed(0); _code._modify = true; }
     522           0 :       set_ref(arg[0]);
     523           0 :       break;
     524             :     case PUSH_GLYPH_ATTR_OBS :
     525             :     case PUSH_SLOT_ATTR :
     526             :     case PUSH_GLYPH_METRIC :
     527             :     case PUSH_ATT_TO_GATTR_OBS :
     528             :     case PUSH_ATT_TO_GLYPH_METRIC :
     529             :     case PUSH_ISLOT_ATTR :
     530             :     case PUSH_FEAT :
     531             :     case SET_FEAT :
     532           0 :       set_ref(arg[1]);
     533           0 :       break;
     534             :     case PUSH_ATT_TO_GLYPH_ATTR :
     535             :     case PUSH_GLYPH_ATTR :
     536           0 :       set_ref(arg[2]);
     537           0 :       break;
     538             :     default:
     539           0 :         break;
     540             :   }
     541           0 : }
     542             : 
     543             : 
     544           0 : bool Machine::Code::decoder::emit_opcode(opcode opc, const byte * & bc)
     545             : {
     546           0 :     const opcode_t * op_to_fn = Machine::getOpcodeTable();
     547           0 :     const opcode_t & op       = op_to_fn[opc];
     548           0 :     if (op.impl[_code._constraint] == 0)
     549             :     {
     550           0 :         failure(unimplemented_opcode_used);
     551           0 :         return false;
     552             :     }
     553             : 
     554           0 :     const size_t     param_sz = op.param_sz == VARARGS ? bc[0] + 1 : op.param_sz;
     555             : 
     556             :     // Add this instruction
     557           0 :     *_instr++ = op.impl[_code._constraint]; 
     558           0 :     ++_code._instr_count;
     559             : 
     560             :     // Grab the parameters
     561           0 :     if (param_sz) {
     562           0 :         memcpy(_data, bc, param_sz * sizeof(byte));
     563           0 :         bc               += param_sz;
     564           0 :         _data            += param_sz;
     565           0 :         _code._data_size += param_sz;
     566             :     }
     567             :     
     568             :     // recursively decode a context item so we can split the skip into 
     569             :     // instruction and data portions.
     570           0 :     if (opc == CNTXT_ITEM)
     571             :     {
     572           0 :         assert(_out_index == 0);
     573           0 :         _in_ctxt_item = true;
     574           0 :         _out_index = _max.pre_context + int8(_data[-2]);
     575           0 :         _slotref = int8(_data[-2]);
     576           0 :         _out_length = _max.rule_length;
     577             : 
     578           0 :         const size_t ctxt_start = _code._instr_count;
     579           0 :         byte & instr_skip = _data[-1];
     580           0 :         byte & data_skip  = *_data++;
     581           0 :         ++_code._data_size;
     582           0 :         const byte *curr_end = _max.bytecode;
     583             : 
     584           0 :         if (load(bc, bc + instr_skip))
     585             :         {
     586           0 :             bc += instr_skip;
     587           0 :             data_skip  = instr_skip - (_code._instr_count - ctxt_start);
     588           0 :             instr_skip = _code._instr_count - ctxt_start;
     589           0 :             _max.bytecode = curr_end;
     590             : 
     591           0 :             _out_length = 1;
     592           0 :             _out_index = 0;
     593           0 :             _slotref = 0;
     594           0 :             _in_ctxt_item = false;
     595             :         }
     596             :         else
     597             :         {
     598           0 :             _out_index = 0;
     599           0 :             _slotref = 0;
     600           0 :             return false;
     601             :         }
     602             :     }
     603             :     
     604           0 :     return bool(_code);
     605             : }
     606             : 
     607             : 
     608           0 : void Machine::Code::decoder::apply_analysis(instr * const code, instr * code_end)
     609             : {
     610             :     // insert TEMP_COPY commands for slots that need them (that change and are referenced later)
     611           0 :     int tempcount = 0;
     612           0 :     if (_code._constraint) return;
     613             : 
     614           0 :     const instr temp_copy = Machine::getOpcodeTable()[TEMP_COPY].impl[0];
     615           0 :     for (const context * c = _contexts, * const ce = c + _slotref; c < ce; ++c)
     616             :     {
     617           0 :         if (!c->flags.referenced || !c->flags.changed) continue;
     618             :         
     619           0 :         instr * const tip = code + c->codeRef + tempcount;        
     620           0 :         memmove(tip+1, tip, (code_end - tip) * sizeof(instr));
     621           0 :         *tip = temp_copy;
     622           0 :         ++code_end;
     623           0 :         ++tempcount;
     624           0 :         _code._delete = true;
     625             :     }
     626             :     
     627           0 :     _code._instr_count = code_end - code;
     628             : }
     629             : 
     630             : 
     631             : inline
     632           0 : bool Machine::Code::decoder::validate_opcode(const byte opc, const byte * const bc)
     633             : {
     634           0 :     if (opc >= MAX_OPCODE)
     635             :     {
     636           0 :         failure(invalid_opcode);
     637           0 :         return false;
     638             :     }
     639           0 :     const opcode_t & op = Machine::getOpcodeTable()[opc];
     640           0 :     if (op.impl[_code._constraint] == 0)
     641             :     {
     642           0 :         failure(unimplemented_opcode_used);
     643           0 :         return false;
     644             :     }
     645           0 :     if (op.param_sz == VARARGS && bc >= _max.bytecode)
     646             :     {
     647           0 :         failure(arguments_exhausted);
     648           0 :         return false;
     649             :     }
     650           0 :     const size_t param_sz = op.param_sz == VARARGS ? bc[0] + 1 : op.param_sz;
     651           0 :     if (bc - 1 + param_sz >= _max.bytecode)
     652             :     {
     653           0 :         failure(arguments_exhausted);
     654           0 :         return false;
     655             :     }
     656           0 :     return true;
     657             : }
     658             : 
     659             : 
     660           0 : bool Machine::Code::decoder::valid_upto(const uint16 limit, const uint16 x) const throw()
     661             : {
     662           0 :     const bool t = (limit != 0) && (x < limit);
     663           0 :     if (!t) failure(out_of_range_data);
     664           0 :     return t;
     665             : }
     666             : 
     667             : inline
     668           0 : bool Machine::Code::decoder::test_ref(int8 index) const throw()
     669             : {
     670           0 :     if (_code._constraint && !_in_ctxt_item)
     671             :     {
     672           0 :         if (index > 0 || -index > _max.pre_context)
     673             :         {
     674           0 :             failure(out_of_range_data);
     675           0 :             return false;
     676             :         }
     677             :     }
     678             :     else
     679           0 :         return valid_upto(_max.rule_length, _slotref + _max.pre_context + index);
     680           0 :     return true;
     681             : }
     682             : 
     683           0 : bool Machine::Code::decoder::test_context() const throw()
     684             : {
     685           0 :     if (_out_index >= _out_length || _out_index < 0 || _slotref >= NUMCONTEXTS - 1)
     686             :     {
     687           0 :         failure(out_of_range_data);
     688           0 :         return false;
     689             :     }
     690           0 :     return true;
     691             : }
     692             : 
     693             : inline 
     694           0 : void Machine::Code::failure(const status_t s) throw() {
     695           0 :     release_buffers();
     696           0 :     _status = s;
     697           0 : }
     698             : 
     699             : 
     700             : inline
     701           0 : void Machine::Code::decoder::set_ref(int index) throw() {
     702           0 :     if (index + _slotref < 0 || index + _slotref >= NUMCONTEXTS) return;
     703           0 :     _contexts[index + _slotref].flags.referenced = true;
     704           0 :     if (index + _slotref > _max_ref) _max_ref = index + _slotref;
     705             : }
     706             : 
     707             : 
     708             : inline
     709           0 : void Machine::Code::decoder::set_noref(int index) throw() {
     710           0 :     if (index + _slotref < 0 || index + _slotref >= NUMCONTEXTS) return;
     711           0 :     if (index + _slotref > _max_ref) _max_ref = index + _slotref;
     712             : }
     713             : 
     714             : 
     715             : inline
     716           0 : void Machine::Code::decoder::set_changed(int index) throw() {
     717           0 :     if (index + _slotref < 0 || index + _slotref >= NUMCONTEXTS) return;
     718           0 :     _contexts[index + _slotref].flags.changed= true;
     719           0 :     if (index + _slotref > _max_ref) _max_ref = index + _slotref;
     720             : }
     721             : 
     722             : 
     723           0 : void Machine::Code::release_buffers() throw()
     724             : {
     725           0 :     if (_own)
     726           0 :         free(_code);
     727           0 :     _code = 0;
     728           0 :     _data = 0;
     729           0 :     _own  = false;
     730           0 : }
     731             : 
     732             : 
     733           0 : int32 Machine::Code::run(Machine & m, slotref * & map) const
     734             : {
     735             : //    assert(_own);
     736           0 :     assert(*this);          // Check we are actually runnable
     737             : 
     738           0 :     if (m.slotMap().size() <= size_t(_max_ref + m.slotMap().context())
     739           0 :         || m.slotMap()[_max_ref + m.slotMap().context()] == 0)
     740             :     {
     741           0 :         m._status = Machine::slot_offset_out_bounds;
     742           0 :         return 1;
     743             : //        return m.run(_code, _data, map);
     744             :     }
     745             : 
     746           0 :     return  m.run(_code, _data, map);
     747             : }
     748             : 

Generated by: LCOV version 1.13