gfx/graphite2/src/Code.cpp

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/gfx/graphite2/src/Code.cpp	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,619 @@
     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 class represents loaded graphite stack machine code.  It performs 
    1.31 +// basic sanity checks, on the incoming code to prevent more obvious problems
    1.32 +// from crashing graphite.
    1.33 +// Author: Tim Eves
    1.34 +
    1.35 +#include <cassert>
    1.36 +#include <cstddef>
    1.37 +#include <cstdlib>
    1.38 +#include <cstring>
    1.39 +#include "graphite2/Segment.h"
    1.40 +#include "inc/Code.h"
    1.41 +#include "inc/Face.h"
    1.42 +#include "inc/GlyphFace.h"
    1.43 +#include "inc/GlyphCache.h"
    1.44 +#include "inc/Machine.h"
    1.45 +#include "inc/Rule.h"
    1.46 +#include "inc/Silf.h"
    1.47 +
    1.48 +#include <stdio.h>
    1.49 +
    1.50 +#ifdef NDEBUG
    1.51 +#ifdef __GNUC__
    1.52 +#pragma GCC diagnostic ignored "-Wunused-parameter"
    1.53 +#endif
    1.54 +#endif
    1.55 +
    1.56 +
    1.57 +using namespace graphite2;
    1.58 +using namespace vm;
    1.59 +
    1.60 +namespace {
    1.61 +
    1.62 +inline bool is_return(const instr i) {
    1.63 +    const opcode_t * opmap = Machine::getOpcodeTable();
    1.64 +    const instr pop_ret  = *opmap[POP_RET].impl,
    1.65 +                ret_zero = *opmap[RET_ZERO].impl,
    1.66 +                ret_true = *opmap[RET_TRUE].impl;
    1.67 +    return i == pop_ret || i == ret_zero || i == ret_true;
    1.68 +}
    1.69 +
    1.70 +struct context
    1.71 +{
    1.72 +    context(uint8 ref=0) : codeRef(ref) {flags.changed=false; flags.referenced=false; flags.inserted=false;}
    1.73 +    struct { 
    1.74 +        uint8   changed:1,
    1.75 +                referenced:1,
    1.76 +                inserted:1;
    1.77 +    } flags;
    1.78 +    uint8       codeRef;
    1.79 +};
    1.80 +
    1.81 +} // end namespace
    1.82 +
    1.83 +
    1.84 +class Machine::Code::decoder
    1.85 +{
    1.86 +public:
    1.87 +    struct limits;
    1.88 +    struct analysis
    1.89 +    {
    1.90 +        uint8     slotref;
    1.91 +        context   contexts[256];
    1.92 +        byte      max_ref;
    1.93 +        
    1.94 +        analysis() : slotref(0), max_ref(0) {};
    1.95 +        void set_ref(int index) throw();
    1.96 +        void set_changed(int index) throw();
    1.97 +
    1.98 +    };
    1.99 +    
   1.100 +    decoder(const limits & lims, Code &code) throw();
   1.101 +    
   1.102 +    bool        load(const byte * bc_begin, const byte * bc_end);
   1.103 +    void        apply_analysis(instr * const code, instr * code_end);
   1.104 +    byte        max_ref() { return _analysis.max_ref; }
   1.105 +    int         pre_context() const { return _pre_context; }
   1.106 +    
   1.107 +private:
   1.108 +    opcode      fetch_opcode(const byte * bc);
   1.109 +    void        analyse_opcode(const opcode, const int8 * const dp) throw();
   1.110 +    bool        emit_opcode(opcode opc, const byte * & bc);
   1.111 +    bool        validate_opcode(const opcode opc, const byte * const bc);
   1.112 +    bool        valid_upto(const uint16 limit, const uint16 x) const throw();
   1.113 +    void        failure(const status_t s) const throw() { _code.failure(s); }
   1.114 +    
   1.115 +    Code              & _code;
   1.116 +    int                 _pre_context;
   1.117 +    uint16              _rule_length;
   1.118 +    instr             * _instr;
   1.119 +    byte              * _data;
   1.120 +    const limits      & _max;
   1.121 +    analysis            _analysis;
   1.122 +};
   1.123 +
   1.124 +
   1.125 +struct Machine::Code::decoder::limits
   1.126 +{
   1.127 +  const byte * const bytecode;
   1.128 +  const uint8        pre_context;
   1.129 +  const uint16       rule_length,
   1.130 +                     classes,
   1.131 +                     glyf_attrs,
   1.132 +                     features;
   1.133 +  const byte         attrid[gr_slatMax];
   1.134 +};
   1.135 +   
   1.136 +inline Machine::Code::decoder::decoder(const limits & lims, Code &code) throw()
   1.137 +: _code(code),
   1.138 +  _pre_context(code._constraint ? 0 : lims.pre_context), 
   1.139 +  _rule_length(code._constraint ? 1 : lims.rule_length), 
   1.140 +  _instr(code._code), _data(code._data), _max(lims)
   1.141 +{ }
   1.142 +    
   1.143 +
   1.144 +
   1.145 +Machine::Code::Code(bool is_constraint, const byte * bytecode_begin, const byte * const bytecode_end,
   1.146 +           uint8 pre_context, uint16 rule_length, const Silf & silf, const Face & face)
   1.147 + :  _code(0), _data(0), _data_size(0), _instr_count(0), _max_ref(0), _status(loaded),
   1.148 +    _constraint(is_constraint), _modify(false), _delete(false), _own(true)
   1.149 +{
   1.150 +#ifdef GRAPHITE2_TELEMETRY
   1.151 +    telemetry::category _code_cat(face.tele.code);
   1.152 +#endif
   1.153 +    assert(bytecode_begin != 0);
   1.154 +    if (bytecode_begin == bytecode_end)
   1.155 +    {
   1.156 +      ::new (this) Code();
   1.157 +      return;
   1.158 +    }
   1.159 +    assert(bytecode_end > bytecode_begin);
   1.160 +    const opcode_t *    op_to_fn = Machine::getOpcodeTable();
   1.161 +    
   1.162 +    // Allocate code and dat target buffers, these sizes are a worst case 
   1.163 +    // estimate.  Once we know their real sizes the we'll shrink them.
   1.164 +    _code = static_cast<instr *>(malloc((bytecode_end - bytecode_begin)
   1.165 +                                             * sizeof(instr)));
   1.166 +    _data = static_cast<byte *>(malloc((bytecode_end - bytecode_begin)
   1.167 +                                             * sizeof(byte)));
   1.168 +    
   1.169 +    if (!_code || !_data) {
   1.170 +        failure(alloc_failed);
   1.171 +        return;
   1.172 +    }
   1.173 +    
   1.174 +    const decoder::limits lims = {
   1.175 +        bytecode_end,
   1.176 +        pre_context,
   1.177 +        rule_length,
   1.178 +        silf.numClasses(),
   1.179 +        face.glyphs().numAttrs(),
   1.180 +        face.numFeatures(), 
   1.181 +        {1,1,1,1,1,1,1,1, 
   1.182 +         1,1,1,1,1,1,1,255,
   1.183 +         1,1,1,1,1,1,1,1, 
   1.184 +         1,1,1,1,1,1,0,0, 
   1.185 +         0,0,0,0,0,0,0,0, 
   1.186 +         0,0,0,0,0,0,0,0, 
   1.187 +         0,0,0,0,0,0,0, silf.numUser()}
   1.188 +    };
   1.189 +    
   1.190 +    decoder dec(lims, *this);
   1.191 +    if(!dec.load(bytecode_begin, bytecode_end))
   1.192 +       return;
   1.193 +    
   1.194 +    // Is this an empty program?
   1.195 +    if (_instr_count == 0)
   1.196 +    {
   1.197 +      release_buffers();
   1.198 +      ::new (this) Code();
   1.199 +      return;
   1.200 +    }
   1.201 +    
   1.202 +    // When we reach the end check we've terminated it correctly
   1.203 +    if (!is_return(_code[_instr_count-1])) {
   1.204 +        failure(missing_return);
   1.205 +        return;
   1.206 +    }
   1.207 +
   1.208 +    assert((_constraint && immutable()) || !_constraint);
   1.209 +    dec.apply_analysis(_code, _code + _instr_count);
   1.210 +    _max_ref = dec.max_ref();
   1.211 +    
   1.212 +    // Now we know exactly how much code and data the program really needs
   1.213 +    // realloc the buffers to exactly the right size so we don't waste any 
   1.214 +    // memory.
   1.215 +    assert((bytecode_end - bytecode_begin) >= std::ptrdiff_t(_instr_count));
   1.216 +    assert((bytecode_end - bytecode_begin) >= std::ptrdiff_t(_data_size));
   1.217 +    _code = static_cast<instr *>(realloc(_code, (_instr_count+1)*sizeof(instr)));
   1.218 +    _data = static_cast<byte *>(realloc(_data, _data_size*sizeof(byte)));
   1.219 +
   1.220 +    if (!_code)
   1.221 +    {
   1.222 +        failure(alloc_failed);
   1.223 +        return;
   1.224 +    }
   1.225 +
   1.226 +    // Make this RET_ZERO, we should never reach this but just in case ...
   1.227 +    _code[_instr_count] = op_to_fn[RET_ZERO].impl[_constraint];
   1.228 +
   1.229 +#ifdef GRAPHITE2_TELEMETRY
   1.230 +    telemetry::count_bytes(_data_size + (_instr_count+1)*sizeof(instr));
   1.231 +#endif
   1.232 +}
   1.233 +
   1.234 +Machine::Code::~Code() throw ()
   1.235 +{
   1.236 +    if (_own)
   1.237 +        release_buffers();
   1.238 +}
   1.239 +
   1.240 +
   1.241 +bool Machine::Code::decoder::load(const byte * bc, const byte * bc_end)
   1.242 +{
   1.243 +    while (bc < bc_end)
   1.244 +    {
   1.245 +        const opcode opc = fetch_opcode(bc++);
   1.246 +        if (opc == vm::MAX_OPCODE)
   1.247 +            return false;
   1.248 +        
   1.249 +        analyse_opcode(opc, reinterpret_cast<const int8 *>(bc));
   1.250 +        
   1.251 +        if (!emit_opcode(opc, bc))
   1.252 +            return false;
   1.253 +    }
   1.254 +    
   1.255 +    return bool(_code);
   1.256 +}
   1.257 +
   1.258 +// Validation check and fixups.
   1.259 +//
   1.260 +
   1.261 +opcode Machine::Code::decoder::fetch_opcode(const byte * bc)
   1.262 +{
   1.263 +    const opcode opc = opcode(*bc++);
   1.264 +
   1.265 +    // Do some basic sanity checks based on what we know about the opcode
   1.266 +    if (!validate_opcode(opc, bc))  return MAX_OPCODE;
   1.267 +
   1.268 +    // And check it's arguments as far as possible
   1.269 +    switch (opc)
   1.270 +    {
   1.271 +        case NOP :
   1.272 +        case PUSH_BYTE :
   1.273 +        case PUSH_BYTEU :
   1.274 +        case PUSH_SHORT :
   1.275 +        case PUSH_SHORTU :
   1.276 +        case PUSH_LONG :
   1.277 +        case ADD :
   1.278 +        case SUB :
   1.279 +        case MUL :
   1.280 +        case DIV :
   1.281 +        case MIN_ :
   1.282 +        case MAX_ :
   1.283 +        case NEG :
   1.284 +        case TRUNC8 :
   1.285 +        case TRUNC16 :
   1.286 +        case COND :
   1.287 +        case AND :
   1.288 +        case OR :
   1.289 +        case NOT :
   1.290 +        case EQUAL :
   1.291 +        case NOT_EQ :
   1.292 +        case LESS :
   1.293 +        case GTR :
   1.294 +        case LESS_EQ :
   1.295 +        case GTR_EQ :
   1.296 +            break;
   1.297 +        case NEXT :
   1.298 +        case NEXT_N :           // runtime checked
   1.299 +        case COPY_NEXT :
   1.300 +            ++_pre_context;
   1.301 +            break;
   1.302 +        case PUT_GLYPH_8BIT_OBS :
   1.303 +            valid_upto(_max.classes, bc[0]);
   1.304 +            break;
   1.305 +        case PUT_SUBS_8BIT_OBS :
   1.306 +            valid_upto(_rule_length, _pre_context + int8(bc[0]));
   1.307 +            valid_upto(_max.classes, bc[1]);
   1.308 +            valid_upto(_max.classes, bc[2]);
   1.309 +            break;
   1.310 +        case PUT_COPY :
   1.311 +            valid_upto(_rule_length, _pre_context + int8(bc[0]));
   1.312 +            break;
   1.313 +        case INSERT :
   1.314 +            --_pre_context;
   1.315 +            break;
   1.316 +        case DELETE :
   1.317 +            break;
   1.318 +        case ASSOC :
   1.319 +            for (uint8 num = bc[0]; num; --num)
   1.320 +                valid_upto(_rule_length, _pre_context + int8(bc[num]));
   1.321 +            break;
   1.322 +        case CNTXT_ITEM :
   1.323 +            valid_upto(_max.rule_length, _max.pre_context + int8(bc[0]));
   1.324 +            if (bc + 2 + bc[1] >= _max.bytecode)  failure(jump_past_end);
   1.325 +            if (_pre_context != 0)                failure(nested_context_item);
   1.326 +            break;
   1.327 +        case ATTR_SET :
   1.328 +        case ATTR_ADD :
   1.329 +        case ATTR_SUB :
   1.330 +        case ATTR_SET_SLOT :
   1.331 +            valid_upto(gr_slatMax, bc[0]);
   1.332 +            break;
   1.333 +        case IATTR_SET_SLOT :
   1.334 +            if (valid_upto(gr_slatMax, bc[0]))
   1.335 +                valid_upto(_max.attrid[bc[0]], bc[1]);
   1.336 +            break;
   1.337 +        case PUSH_SLOT_ATTR :
   1.338 +            valid_upto(gr_slatMax, bc[0]);
   1.339 +            valid_upto(_rule_length, _pre_context + int8(bc[1]));
   1.340 +            break;
   1.341 +        case PUSH_GLYPH_ATTR_OBS :
   1.342 +            valid_upto(_max.glyf_attrs, bc[0]);
   1.343 +            valid_upto(_rule_length, _pre_context + int8(bc[1]));
   1.344 +            break;
   1.345 +        case PUSH_GLYPH_METRIC :
   1.346 +            valid_upto(kgmetDescent, bc[0]);
   1.347 +            valid_upto(_rule_length, _pre_context + int8(bc[1]));
   1.348 +            // level: dp[2] no check necessary
   1.349 +            break;
   1.350 +        case PUSH_FEAT :
   1.351 +            valid_upto(_max.features, bc[0]);
   1.352 +            valid_upto(_rule_length, _pre_context + int8(bc[1]));
   1.353 +            break;
   1.354 +        case PUSH_ATT_TO_GATTR_OBS :
   1.355 +            valid_upto(_max.glyf_attrs, bc[0]);
   1.356 +            valid_upto(_rule_length, _pre_context + int8(bc[1]));
   1.357 +            break;
   1.358 +        case PUSH_ATT_TO_GLYPH_METRIC :
   1.359 +            valid_upto(kgmetDescent, bc[0]);
   1.360 +            valid_upto(_rule_length, _pre_context + int8(bc[1]));
   1.361 +            // level: dp[2] no check necessary
   1.362 +            break;
   1.363 +        case PUSH_ISLOT_ATTR :
   1.364 +            if (valid_upto(gr_slatMax, bc[0]))
   1.365 +            {
   1.366 +                valid_upto(_rule_length, _pre_context + int8(bc[1]));
   1.367 +                valid_upto(_max.attrid[bc[0]], bc[2]);
   1.368 +            }
   1.369 +            break;
   1.370 +        case PUSH_IGLYPH_ATTR :// not implemented
   1.371 +        case POP_RET :
   1.372 +        case RET_ZERO :
   1.373 +        case RET_TRUE :
   1.374 +            break;
   1.375 +        case IATTR_SET :
   1.376 +        case IATTR_ADD :
   1.377 +        case IATTR_SUB :
   1.378 +            if (valid_upto(gr_slatMax, bc[0]))
   1.379 +                valid_upto(_max.attrid[bc[0]], bc[1]);
   1.380 +            break;
   1.381 +        case PUSH_PROC_STATE :  // dummy: dp[0] no check necessary
   1.382 +        case PUSH_VERSION :
   1.383 +            break;
   1.384 +        case PUT_SUBS :
   1.385 +            valid_upto(_rule_length, _pre_context + int8(bc[0]));
   1.386 +            valid_upto(_max.classes, uint16(bc[1]<< 8) | bc[2]);
   1.387 +            valid_upto(_max.classes, uint16(bc[3]<< 8) | bc[4]);
   1.388 +            break;
   1.389 +        case PUT_SUBS2 :        // not implemented
   1.390 +        case PUT_SUBS3 :        // not implemented
   1.391 +            break;
   1.392 +        case PUT_GLYPH :
   1.393 +            valid_upto(_max.classes, uint16(bc[0]<< 8) | bc[1]);
   1.394 +            break;
   1.395 +        case PUSH_GLYPH_ATTR :
   1.396 +        case PUSH_ATT_TO_GLYPH_ATTR :
   1.397 +            valid_upto(_max.glyf_attrs, uint16(bc[0]<< 8) | bc[1]);
   1.398 +            valid_upto(_rule_length, _pre_context + int8(bc[2]));
   1.399 +            break;
   1.400 +        default:
   1.401 +            failure(invalid_opcode);
   1.402 +            break;
   1.403 +    }
   1.404 +
   1.405 +    return bool(_code) ? opc : MAX_OPCODE;
   1.406 +}
   1.407 +
   1.408 +
   1.409 +void Machine::Code::decoder::analyse_opcode(const opcode opc, const int8  * arg) throw()
   1.410 +{
   1.411 +  if (_code._constraint) return;
   1.412 +  
   1.413 +  switch (opc)
   1.414 +  {
   1.415 +    case DELETE :
   1.416 +      _code._delete = true;
   1.417 +      break;
   1.418 +    case PUT_GLYPH_8BIT_OBS :
   1.419 +    case PUT_GLYPH :
   1.420 +      _code._modify = true;
   1.421 +      _analysis.set_changed(_analysis.slotref);
   1.422 +      break;
   1.423 +    case NEXT :
   1.424 +    case COPY_NEXT :
   1.425 +      if (!_analysis.contexts[_analysis.slotref].flags.inserted)
   1.426 +        ++_analysis.slotref;
   1.427 +      _analysis.contexts[_analysis.slotref] = context(_code._instr_count+1);
   1.428 +      if (_analysis.slotref > _analysis.max_ref) _analysis.max_ref = _analysis.slotref;
   1.429 +      break;
   1.430 +    case INSERT :
   1.431 +      _analysis.contexts[_analysis.slotref].flags.inserted = true;
   1.432 +      _code._modify = true;
   1.433 +      break;
   1.434 +    case PUT_SUBS_8BIT_OBS :    // slotref on 1st parameter
   1.435 +    case PUT_SUBS : 
   1.436 +      _code._modify = true;
   1.437 +      _analysis.set_changed(_analysis.slotref);
   1.438 +      // no break
   1.439 +    case PUT_COPY :
   1.440 +    {
   1.441 +      if (arg[0] != 0) { _analysis.set_changed(_analysis.slotref); _code._modify = true; }
   1.442 +      if (arg[0] <= 0 && -arg[0] <= _analysis.slotref - _analysis.contexts[_analysis.slotref].flags.inserted)
   1.443 +        _analysis.set_ref(_analysis.slotref + arg[0] - _analysis.contexts[_analysis.slotref].flags.inserted);
   1.444 +      else if (_analysis.slotref + arg[0] > _analysis.max_ref) _analysis.max_ref = _analysis.slotref + arg[0];
   1.445 +      break;
   1.446 +    }
   1.447 +    case PUSH_ATT_TO_GATTR_OBS : // slotref on 2nd parameter
   1.448 +        if (_code._constraint) return;
   1.449 +        // no break
   1.450 +    case PUSH_GLYPH_ATTR_OBS :
   1.451 +    case PUSH_SLOT_ATTR :
   1.452 +    case PUSH_GLYPH_METRIC :
   1.453 +    case PUSH_ATT_TO_GLYPH_METRIC :
   1.454 +    case PUSH_ISLOT_ATTR :
   1.455 +    case PUSH_FEAT :
   1.456 +      if (arg[1] <= 0 && -arg[1] <= _analysis.slotref - _analysis.contexts[_analysis.slotref].flags.inserted)
   1.457 +        _analysis.set_ref(_analysis.slotref + arg[1] - _analysis.contexts[_analysis.slotref].flags.inserted);
   1.458 +      else if (_analysis.slotref + arg[1] > _analysis.max_ref) _analysis.max_ref = _analysis.slotref + arg[1];
   1.459 +      break;
   1.460 +    case PUSH_ATT_TO_GLYPH_ATTR :
   1.461 +        if (_code._constraint) return;
   1.462 +        // no break
   1.463 +    case PUSH_GLYPH_ATTR :
   1.464 +      if (arg[2] <= 0 && -arg[2] <= _analysis.slotref - _analysis.contexts[_analysis.slotref].flags.inserted)
   1.465 +        _analysis.set_ref(_analysis.slotref + arg[2] - _analysis.contexts[_analysis.slotref].flags.inserted);
   1.466 +      else if (_analysis.slotref + arg[2] > _analysis.max_ref) _analysis.max_ref = _analysis.slotref + arg[2];
   1.467 +      break;
   1.468 +    case ASSOC :                // slotrefs in varargs
   1.469 +      break;
   1.470 +    default:
   1.471 +        break;
   1.472 +  }
   1.473 +}
   1.474 +
   1.475 +
   1.476 +bool Machine::Code::decoder::emit_opcode(opcode opc, const byte * & bc)
   1.477 +{
   1.478 +    const opcode_t * op_to_fn = Machine::getOpcodeTable();
   1.479 +    const opcode_t & op       = op_to_fn[opc];
   1.480 +    if (op.impl[_code._constraint] == 0)
   1.481 +    {
   1.482 +        failure(unimplemented_opcode_used);
   1.483 +        return false;
   1.484 +    }
   1.485 +
   1.486 +    const size_t     param_sz = op.param_sz == VARARGS ? bc[0] + 1 : op.param_sz;
   1.487 +
   1.488 +    // Add this instruction
   1.489 +    *_instr++ = op.impl[_code._constraint]; 
   1.490 +    ++_code._instr_count;
   1.491 +
   1.492 +    // Grab the parameters
   1.493 +    if (param_sz) {
   1.494 +        memcpy(_data, bc, param_sz * sizeof(byte));
   1.495 +        bc               += param_sz;
   1.496 +        _data            += param_sz;
   1.497 +        _code._data_size += param_sz;
   1.498 +    }
   1.499 +    
   1.500 +    // recursively decode a context item so we can split the skip into 
   1.501 +    // instruction and data portions.
   1.502 +    if (opc == CNTXT_ITEM)
   1.503 +    {
   1.504 +        assert(_pre_context == 0);
   1.505 +        _pre_context = _max.pre_context + int8(_data[-2]);
   1.506 +        _rule_length = _max.rule_length;
   1.507 +
   1.508 +        const size_t ctxt_start = _code._instr_count;
   1.509 +        byte & instr_skip = _data[-1];
   1.510 +        byte & data_skip  = *_data++;
   1.511 +        ++_code._data_size;
   1.512 +
   1.513 +        if (load(bc, bc + instr_skip))
   1.514 +        {
   1.515 +            bc += instr_skip;
   1.516 +            data_skip  = instr_skip - (_code._instr_count - ctxt_start);
   1.517 +            instr_skip = _code._instr_count - ctxt_start;
   1.518 +
   1.519 +            _rule_length = 1;
   1.520 +            _pre_context = 0;
   1.521 +        }
   1.522 +    }
   1.523 +    
   1.524 +    return bool(_code);
   1.525 +}
   1.526 +
   1.527 +
   1.528 +void Machine::Code::decoder::apply_analysis(instr * const code, instr * code_end)
   1.529 +{
   1.530 +    // insert TEMP_COPY commands for slots that need them (that change and are referenced later)
   1.531 +    int tempcount = 0;
   1.532 +    if (_code._constraint) return;
   1.533 +
   1.534 +    const instr temp_copy = Machine::getOpcodeTable()[TEMP_COPY].impl[0];
   1.535 +    for (const context * c = _analysis.contexts, * const ce = c + _analysis.slotref; c != ce; ++c)
   1.536 +    {
   1.537 +        if (!c->flags.referenced || !c->flags.changed) continue;
   1.538 +        
   1.539 +        instr * const tip = code + c->codeRef + tempcount;        
   1.540 +        memmove(tip+1, tip, (code_end - tip) * sizeof(instr));
   1.541 +        *tip = temp_copy;
   1.542 +        ++code_end;
   1.543 +        ++tempcount;
   1.544 +    }
   1.545 +    
   1.546 +    _code._instr_count = code_end - code;
   1.547 +}
   1.548 +
   1.549 +
   1.550 +inline
   1.551 +bool Machine::Code::decoder::validate_opcode(const opcode opc, const byte * const bc)
   1.552 +{
   1.553 +    if (opc >= MAX_OPCODE)
   1.554 +    {
   1.555 +        failure(invalid_opcode);
   1.556 +        return false;
   1.557 +    }
   1.558 +    const opcode_t & op = Machine::getOpcodeTable()[opc];
   1.559 +    const size_t param_sz = op.param_sz == VARARGS ? bc[0] + 1 : op.param_sz;
   1.560 +    if (bc + param_sz > _max.bytecode)
   1.561 +    {
   1.562 +        failure(arguments_exhausted);
   1.563 +        return false;
   1.564 +    }
   1.565 +    return true;
   1.566 +}
   1.567 +
   1.568 +
   1.569 +bool Machine::Code::decoder::valid_upto(const uint16 limit, const uint16 x) const throw()
   1.570 +{
   1.571 +    const bool t = x < limit;
   1.572 +    if (!t) failure(out_of_range_data);
   1.573 +    return t;
   1.574 +}
   1.575 +
   1.576 +
   1.577 +inline 
   1.578 +void Machine::Code::failure(const status_t s) throw() {
   1.579 +    release_buffers();
   1.580 +    _status = s;
   1.581 +}
   1.582 +
   1.583 +
   1.584 +inline
   1.585 +void Machine::Code::decoder::analysis::set_ref(const int index) throw() {
   1.586 +    contexts[index].flags.referenced = true;
   1.587 +    if (index > max_ref) max_ref = index;
   1.588 +}
   1.589 +
   1.590 +
   1.591 +inline
   1.592 +void Machine::Code::decoder::analysis::set_changed(const int index) throw() {
   1.593 +    contexts[index].flags.changed = true;
   1.594 +    if (index > max_ref) max_ref = index;
   1.595 +}
   1.596 +
   1.597 +
   1.598 +void Machine::Code::release_buffers() throw()
   1.599 +{
   1.600 +    free(_code);
   1.601 +    free(_data);
   1.602 +    _code = 0;
   1.603 +    _data = 0;
   1.604 +    _own  = false;
   1.605 +}
   1.606 +
   1.607 +
   1.608 +int32 Machine::Code::run(Machine & m, slotref * & map) const
   1.609 +{
   1.610 +    assert(_own);
   1.611 +    assert(*this);          // Check we are actually runnable
   1.612 +
   1.613 +    if (m.slotMap().size() <= size_t(_max_ref + m.slotMap().context()))
   1.614 +    {
   1.615 +        m._status = Machine::slot_offset_out_bounds;
   1.616 +//        return (m.slotMap().end() - map);
   1.617 +        return 1;
   1.618 +    }
   1.619 +
   1.620 +    return  m.run(_code, _data, map);
   1.621 +}
   1.622 +

mercurial