gfx/graphite2/src/Code.cpp

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

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

mercurial