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
is_return(const instr i)59 inline bool is_return(const instr i) {
60 const opcode_t * opmap = Machine::getOpcodeTable();
61 const instr pop_ret = *opmap[POP_RET].impl,
62 ret_zero = *opmap[RET_ZERO].impl,
63 ret_true = *opmap[RET_TRUE].impl;
64 return i == pop_ret || i == ret_zero || i == ret_true;
65 }
66
67 struct context
68 {
context__anon17f2ddcb0111::context69 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);
max_ref()90 byte max_ref() { return _max_ref; }
out_index() const91 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 bool test_attr(attrCode attr) const throw();
failure(const status_t s) const105 void failure(const status_t s) const throw() { _code.failure(s); }
106
107 Code & _code;
108 int _out_index;
109 uint16 _out_length;
110 instr * _instr;
111 byte * _data;
112 limits & _max;
113 enum passtype _passtype;
114 int _stack_depth;
115 bool _in_ctxt_item;
116 int16 _slotref;
117 context _contexts[NUMCONTEXTS];
118 byte _max_ref;
119 };
120
121
122 struct Machine::Code::decoder::limits
123 {
124 const byte * bytecode;
125 const uint8 pre_context;
126 const uint16 rule_length,
127 classes,
128 glyf_attrs,
129 features;
130 const byte attrid[gr_slatMax];
131 };
132
decoder(limits & lims,Code & code,enum passtype pt)133 inline Machine::Code::decoder::decoder(limits & lims, Code &code, enum passtype pt) throw()
134 : _code(code),
135 _out_index(code._constraint ? 0 : lims.pre_context),
136 _out_length(code._constraint ? 1 : lims.rule_length),
137 _instr(code._code), _data(code._data), _max(lims), _passtype(pt),
138 _stack_depth(0),
139 _in_ctxt_item(false),
140 _slotref(0),
141 _max_ref(0)
142 { }
143
144
145
Code(bool is_constraint,const byte * bytecode_begin,const byte * const bytecode_end,uint8 pre_context,uint16 rule_length,const Silf & silf,const Face & face,enum passtype pt,byte ** const _out)146 Machine::Code::Code(bool is_constraint, const byte * bytecode_begin, const byte * const bytecode_end,
147 uint8 pre_context, uint16 rule_length, const Silf & silf, const Face & face,
148 enum passtype pt, byte * * const _out)
149 : _code(0), _data(0), _data_size(0), _instr_count(0), _max_ref(0), _status(loaded),
150 _constraint(is_constraint), _modify(false), _delete(false), _own(_out==0)
151 {
152 #ifdef GRAPHITE2_TELEMETRY
153 telemetry::category _code_cat(face.tele.code);
154 #endif
155 assert(bytecode_begin != 0);
156 if (bytecode_begin == bytecode_end)
157 {
158 // ::new (this) Code();
159 return;
160 }
161 assert(bytecode_end > bytecode_begin);
162 const opcode_t * op_to_fn = Machine::getOpcodeTable();
163
164 // Allocate code and data target buffers, these sizes are a worst case
165 // estimate. Once we know their real sizes the we'll shrink them.
166 if (_out) _code = reinterpret_cast<instr *>(*_out);
167 else _code = static_cast<instr *>(malloc(estimateCodeDataOut(bytecode_end-bytecode_begin, 1, is_constraint ? 0 : rule_length)));
168 _data = reinterpret_cast<byte *>(_code + (bytecode_end - bytecode_begin));
169
170 if (!_code || !_data) {
171 failure(alloc_failed);
172 return;
173 }
174
175 decoder::limits lims = {
176 bytecode_end,
177 pre_context,
178 rule_length,
179 silf.numClasses(),
180 face.glyphs().numAttrs(),
181 face.numFeatures(),
182 {1,1,1,1,1,1,1,1,
183 1,1,1,1,1,1,1,255,
184 1,1,1,1,1,1,1,1,
185 1,1,1,1,1,1,0,0,
186 0,0,0,0,0,0,0,0,
187 0,0,0,0,0,0,0,0,
188 0,0,0,0,0,0,0, silf.numUser()}
189 };
190
191 decoder dec(lims, *this, pt);
192 if(!dec.load(bytecode_begin, bytecode_end))
193 return;
194
195 // Is this an empty program?
196 if (_instr_count == 0)
197 {
198 release_buffers();
199 ::new (this) Code();
200 return;
201 }
202
203 // When we reach the end check we've terminated it correctly
204 if (!is_return(_code[_instr_count-1])) {
205 failure(missing_return);
206 return;
207 }
208
209 assert((_constraint && immutable()) || !_constraint);
210 dec.apply_analysis(_code, _code + _instr_count);
211 _max_ref = dec.max_ref();
212
213 // Now we know exactly how much code and data the program really needs
214 // realloc the buffers to exactly the right size so we don't waste any
215 // memory.
216 assert((bytecode_end - bytecode_begin) >= ptrdiff_t(_instr_count));
217 assert((bytecode_end - bytecode_begin) >= ptrdiff_t(_data_size));
218 memmove(_code + (_instr_count+1), _data, _data_size*sizeof(byte));
219 size_t const total_sz = ((_instr_count+1) + (_data_size + sizeof(instr)-1)/sizeof(instr))*sizeof(instr);
220 if (_out)
221 *_out += total_sz;
222 else
223 {
224 instr * const old_code = _code;
225 _code = static_cast<instr *>(realloc(_code, total_sz));
226 if (!_code) free(old_code);
227 }
228 _data = reinterpret_cast<byte *>(_code + (_instr_count+1));
229
230 if (!_code)
231 {
232 failure(alloc_failed);
233 return;
234 }
235
236 // Make this RET_ZERO, we should never reach this but just in case ...
237 _code[_instr_count] = op_to_fn[RET_ZERO].impl[_constraint];
238
239 #ifdef GRAPHITE2_TELEMETRY
240 telemetry::count_bytes(_data_size + (_instr_count+1)*sizeof(instr));
241 #endif
242 }
243
~Code()244 Machine::Code::~Code() throw ()
245 {
246 if (_own)
247 release_buffers();
248 }
249
250
load(const byte * bc,const byte * bc_end)251 bool Machine::Code::decoder::load(const byte * bc, const byte * bc_end)
252 {
253 _max.bytecode = bc_end;
254 while (bc < bc_end)
255 {
256 const opcode opc = fetch_opcode(bc++);
257 if (opc == vm::MAX_OPCODE)
258 return false;
259
260 analyse_opcode(opc, reinterpret_cast<const int8 *>(bc));
261
262 if (!emit_opcode(opc, bc))
263 return false;
264 }
265
266 return bool(_code);
267 }
268
269 // Validation check and fixups.
270 //
271
fetch_opcode(const byte * bc)272 opcode Machine::Code::decoder::fetch_opcode(const byte * bc)
273 {
274 const byte opc = *bc++;
275
276 // Do some basic sanity checks based on what we know about the opcode
277 if (!validate_opcode(opc, bc)) return MAX_OPCODE;
278
279 // And check its arguments as far as possible
280 switch (opcode(opc))
281 {
282 case NOP :
283 break;
284 case PUSH_BYTE :
285 case PUSH_BYTEU :
286 case PUSH_SHORT :
287 case PUSH_SHORTU :
288 case PUSH_LONG :
289 ++_stack_depth;
290 break;
291 case ADD :
292 case SUB :
293 case MUL :
294 case DIV :
295 case MIN_ :
296 case MAX_ :
297 case AND :
298 case OR :
299 case EQUAL :
300 case NOT_EQ :
301 case LESS :
302 case GTR :
303 case LESS_EQ :
304 case GTR_EQ :
305 case BITOR :
306 case BITAND :
307 if (--_stack_depth <= 0)
308 failure(underfull_stack);
309 break;
310 case NEG :
311 case TRUNC8 :
312 case TRUNC16 :
313 case NOT :
314 case BITNOT :
315 case BITSET :
316 if (_stack_depth <= 0)
317 failure(underfull_stack);
318 break;
319 case COND :
320 _stack_depth -= 2;
321 if (_stack_depth <= 0)
322 failure(underfull_stack);
323 break;
324 case NEXT_N : // runtime checked
325 break;
326 case NEXT :
327 case COPY_NEXT :
328 ++_out_index;
329 if (_out_index < -1 || _out_index > _out_length || _slotref > _max.rule_length)
330 failure(out_of_range_data);
331 break;
332 case PUT_GLYPH_8BIT_OBS :
333 valid_upto(_max.classes, bc[0]);
334 test_context();
335 break;
336 case PUT_SUBS_8BIT_OBS :
337 test_ref(int8(bc[0]));
338 valid_upto(_max.classes, bc[1]);
339 valid_upto(_max.classes, bc[2]);
340 test_context();
341 break;
342 case PUT_COPY :
343 test_ref(int8(bc[0]));
344 test_context();
345 break;
346 case INSERT :
347 if (_passtype >= PASS_TYPE_POSITIONING)
348 failure(invalid_opcode);
349 ++_out_length;
350 if (_out_index < 0) ++_out_index;
351 if (_out_index < -1 || _out_index >= _out_length)
352 failure(out_of_range_data);
353 break;
354 case DELETE :
355 if (_passtype >= PASS_TYPE_POSITIONING)
356 failure(invalid_opcode);
357 if (_out_index < _max.pre_context)
358 failure(out_of_range_data);
359 --_out_index;
360 --_out_length;
361 if (_out_index < -1 || _out_index > _out_length)
362 failure(out_of_range_data);
363 break;
364 case ASSOC :
365 if (bc[0] == 0)
366 failure(out_of_range_data);
367 for (uint8 num = bc[0]; num; --num)
368 test_ref(int8(bc[num]));
369 test_context();
370 break;
371 case CNTXT_ITEM :
372 valid_upto(_max.rule_length, _max.pre_context + int8(bc[0]));
373 if (bc + 2 + bc[1] >= _max.bytecode) failure(jump_past_end);
374 if (_in_ctxt_item) failure(nested_context_item);
375 break;
376 case ATTR_SET :
377 case ATTR_ADD :
378 case ATTR_SUB :
379 case ATTR_SET_SLOT :
380 if (--_stack_depth < 0)
381 failure(underfull_stack);
382 valid_upto(gr_slatMax, bc[0]);
383 if (attrCode(bc[0]) == gr_slatUserDefn) // use IATTR for user attributes
384 failure(out_of_range_data);
385 test_attr(attrCode(bc[0]));
386 test_context();
387 break;
388 case IATTR_SET_SLOT :
389 if (--_stack_depth < 0)
390 failure(underfull_stack);
391 if (valid_upto(gr_slatMax, bc[0]))
392 valid_upto(_max.attrid[bc[0]], bc[1]);
393 test_attr(attrCode(bc[0]));
394 test_context();
395 break;
396 case PUSH_SLOT_ATTR :
397 ++_stack_depth;
398 valid_upto(gr_slatMax, bc[0]);
399 test_ref(int8(bc[1]));
400 if (attrCode(bc[0]) == gr_slatUserDefn) // use IATTR for user attributes
401 failure(out_of_range_data);
402 test_attr(attrCode(bc[0]));
403 break;
404 case PUSH_GLYPH_ATTR_OBS :
405 case PUSH_ATT_TO_GATTR_OBS :
406 ++_stack_depth;
407 valid_upto(_max.glyf_attrs, bc[0]);
408 test_ref(int8(bc[1]));
409 break;
410 case PUSH_ATT_TO_GLYPH_METRIC :
411 case PUSH_GLYPH_METRIC :
412 ++_stack_depth;
413 valid_upto(kgmetDescent, bc[0]);
414 test_ref(int8(bc[1]));
415 // level: dp[2] no check necessary
416 break;
417 case PUSH_FEAT :
418 ++_stack_depth;
419 valid_upto(_max.features, bc[0]);
420 test_ref(int8(bc[1]));
421 break;
422 case PUSH_ISLOT_ATTR :
423 ++_stack_depth;
424 if (valid_upto(gr_slatMax, bc[0]))
425 {
426 test_ref(int8(bc[1]));
427 valid_upto(_max.attrid[bc[0]], bc[2]);
428 }
429 test_attr(attrCode(bc[0]));
430 break;
431 case PUSH_IGLYPH_ATTR :// not implemented
432 ++_stack_depth;
433 break;
434 case POP_RET :
435 if (--_stack_depth < 0)
436 failure(underfull_stack);
437 GR_FALLTHROUGH;
438 // no break
439 case RET_ZERO :
440 case RET_TRUE :
441 break;
442 case IATTR_SET :
443 case IATTR_ADD :
444 case IATTR_SUB :
445 if (--_stack_depth < 0)
446 failure(underfull_stack);
447 if (valid_upto(gr_slatMax, bc[0]))
448 valid_upto(_max.attrid[bc[0]], bc[1]);
449 test_attr(attrCode(bc[0]));
450 test_context();
451 break;
452 case PUSH_PROC_STATE : // dummy: dp[0] no check necessary
453 case PUSH_VERSION :
454 ++_stack_depth;
455 break;
456 case PUT_SUBS :
457 test_ref(int8(bc[0]));
458 valid_upto(_max.classes, uint16(bc[1]<< 8) | bc[2]);
459 valid_upto(_max.classes, uint16(bc[3]<< 8) | bc[4]);
460 test_context();
461 break;
462 case PUT_SUBS2 : // not implemented
463 case PUT_SUBS3 : // not implemented
464 break;
465 case PUT_GLYPH :
466 valid_upto(_max.classes, uint16(bc[0]<< 8) | bc[1]);
467 test_context();
468 break;
469 case PUSH_GLYPH_ATTR :
470 case PUSH_ATT_TO_GLYPH_ATTR :
471 ++_stack_depth;
472 valid_upto(_max.glyf_attrs, uint16(bc[0]<< 8) | bc[1]);
473 test_ref(int8(bc[2]));
474 break;
475 case SET_FEAT :
476 valid_upto(_max.features, bc[0]);
477 test_ref(int8(bc[1]));
478 break;
479 default:
480 failure(invalid_opcode);
481 break;
482 }
483
484 return bool(_code) ? opcode(opc) : MAX_OPCODE;
485 }
486
487
analyse_opcode(const opcode opc,const int8 * arg)488 void Machine::Code::decoder::analyse_opcode(const opcode opc, const int8 * arg) throw()
489 {
490 switch (opc)
491 {
492 case DELETE :
493 _code._delete = true;
494 break;
495 case ASSOC :
496 set_changed(0);
497 // for (uint8 num = arg[0]; num; --num)
498 // _analysis.set_noref(num);
499 break;
500 case PUT_GLYPH_8BIT_OBS :
501 case PUT_GLYPH :
502 _code._modify = true;
503 set_changed(0);
504 break;
505 case ATTR_SET :
506 case ATTR_ADD :
507 case ATTR_SUB :
508 case ATTR_SET_SLOT :
509 case IATTR_SET_SLOT :
510 case IATTR_SET :
511 case IATTR_ADD :
512 case IATTR_SUB :
513 set_noref(0);
514 break;
515 case NEXT :
516 case COPY_NEXT :
517 ++_slotref;
518 _contexts[_slotref] = context(uint8(_code._instr_count+1));
519 // if (_analysis.slotref > _analysis.max_ref) _analysis.max_ref = _analysis.slotref;
520 break;
521 case INSERT :
522 if (_slotref >= 0) --_slotref;
523 _code._modify = true;
524 break;
525 case PUT_SUBS_8BIT_OBS : // slotref on 1st parameter
526 case PUT_SUBS :
527 _code._modify = true;
528 set_changed(0);
529 GR_FALLTHROUGH;
530 // no break
531 case PUT_COPY :
532 if (arg[0] != 0) { set_changed(0); _code._modify = true; }
533 set_ref(arg[0]);
534 break;
535 case PUSH_GLYPH_ATTR_OBS :
536 case PUSH_SLOT_ATTR :
537 case PUSH_GLYPH_METRIC :
538 case PUSH_ATT_TO_GATTR_OBS :
539 case PUSH_ATT_TO_GLYPH_METRIC :
540 case PUSH_ISLOT_ATTR :
541 case PUSH_FEAT :
542 case SET_FEAT :
543 set_ref(arg[1]);
544 break;
545 case PUSH_ATT_TO_GLYPH_ATTR :
546 case PUSH_GLYPH_ATTR :
547 set_ref(arg[2]);
548 break;
549 default:
550 break;
551 }
552 }
553
554
emit_opcode(opcode opc,const byte * & bc)555 bool Machine::Code::decoder::emit_opcode(opcode opc, const byte * & bc)
556 {
557 const opcode_t * op_to_fn = Machine::getOpcodeTable();
558 const opcode_t & op = op_to_fn[opc];
559 if (op.impl[_code._constraint] == 0)
560 {
561 failure(unimplemented_opcode_used);
562 return false;
563 }
564
565 const size_t param_sz = op.param_sz == VARARGS ? bc[0] + 1 : op.param_sz;
566
567 // Add this instruction
568 *_instr++ = op.impl[_code._constraint];
569 ++_code._instr_count;
570
571 // Grab the parameters
572 if (param_sz) {
573 memcpy(_data, bc, param_sz * sizeof(byte));
574 bc += param_sz;
575 _data += param_sz;
576 _code._data_size += param_sz;
577 }
578
579 // recursively decode a context item so we can split the skip into
580 // instruction and data portions.
581 if (opc == CNTXT_ITEM)
582 {
583 assert(_out_index == 0);
584 _in_ctxt_item = true;
585 _out_index = _max.pre_context + int8(_data[-2]);
586 _slotref = int8(_data[-2]);
587 _out_length = _max.rule_length;
588
589 const size_t ctxt_start = _code._instr_count;
590 byte & instr_skip = _data[-1];
591 byte & data_skip = *_data++;
592 ++_code._data_size;
593 const byte *curr_end = _max.bytecode;
594
595 if (load(bc, bc + instr_skip))
596 {
597 bc += instr_skip;
598 data_skip = instr_skip - byte(_code._instr_count - ctxt_start);
599 instr_skip = byte(_code._instr_count - ctxt_start);
600 _max.bytecode = curr_end;
601
602 _out_length = 1;
603 _out_index = 0;
604 _slotref = 0;
605 _in_ctxt_item = false;
606 }
607 else
608 {
609 _out_index = 0;
610 _slotref = 0;
611 return false;
612 }
613 }
614
615 return bool(_code);
616 }
617
618
apply_analysis(instr * const code,instr * code_end)619 void Machine::Code::decoder::apply_analysis(instr * const code, instr * code_end)
620 {
621 // insert TEMP_COPY commands for slots that need them (that change and are referenced later)
622 int tempcount = 0;
623 if (_code._constraint) return;
624
625 const instr temp_copy = Machine::getOpcodeTable()[TEMP_COPY].impl[0];
626 for (const context * c = _contexts, * const ce = c + _slotref; c < ce; ++c)
627 {
628 if (!c->flags.referenced || !c->flags.changed) continue;
629
630 instr * const tip = code + c->codeRef + tempcount;
631 memmove(tip+1, tip, (code_end - tip) * sizeof(instr));
632 *tip = temp_copy;
633 ++code_end;
634 ++tempcount;
635 _code._delete = true;
636 }
637
638 _code._instr_count = code_end - code;
639 }
640
641
642 inline
validate_opcode(const byte opc,const byte * const bc)643 bool Machine::Code::decoder::validate_opcode(const byte opc, const byte * const bc)
644 {
645 if (opc >= MAX_OPCODE)
646 {
647 failure(invalid_opcode);
648 return false;
649 }
650 const opcode_t & op = Machine::getOpcodeTable()[opc];
651 if (op.impl[_code._constraint] == 0)
652 {
653 failure(unimplemented_opcode_used);
654 return false;
655 }
656 if (op.param_sz == VARARGS && bc >= _max.bytecode)
657 {
658 failure(arguments_exhausted);
659 return false;
660 }
661 const size_t param_sz = op.param_sz == VARARGS ? bc[0] + 1 : op.param_sz;
662 if (bc - 1 + param_sz >= _max.bytecode)
663 {
664 failure(arguments_exhausted);
665 return false;
666 }
667 return true;
668 }
669
670
valid_upto(const uint16 limit,const uint16 x) const671 bool Machine::Code::decoder::valid_upto(const uint16 limit, const uint16 x) const throw()
672 {
673 const bool t = (limit != 0) && (x < limit);
674 if (!t) failure(out_of_range_data);
675 return t;
676 }
677
678 inline
test_ref(int8 index) const679 bool Machine::Code::decoder::test_ref(int8 index) const throw()
680 {
681 if (_code._constraint && !_in_ctxt_item)
682 {
683 if (index > 0 || -index > _max.pre_context)
684 {
685 failure(out_of_range_data);
686 return false;
687 }
688 }
689 else
690 {
691 if (_max.rule_length == 0
692 || (_slotref + _max.pre_context + index >= _max.rule_length)
693 || (_slotref + _max.pre_context + index < 0))
694 {
695 failure(out_of_range_data);
696 return false;
697 }
698 }
699 return true;
700 }
701
test_context() const702 bool Machine::Code::decoder::test_context() const throw()
703 {
704 if (_out_index >= _out_length || _out_index < 0 || _slotref >= NUMCONTEXTS - 1)
705 {
706 failure(out_of_range_data);
707 return false;
708 }
709 return true;
710 }
711
test_attr(attrCode) const712 bool Machine::Code::decoder::test_attr(attrCode) const throw()
713 {
714 #if 0 // This code is coming but causes backward compatibility problems.
715 if (_passtype < PASS_TYPE_POSITIONING)
716 {
717 if (attr != gr_slatBreak && attr != gr_slatDir && attr != gr_slatUserDefn
718 && attr != gr_slatCompRef)
719 {
720 failure(out_of_range_data);
721 return false;
722 }
723 }
724 #endif
725 return true;
726 }
727
728 inline
failure(const status_t s)729 void Machine::Code::failure(const status_t s) throw() {
730 release_buffers();
731 _status = s;
732 }
733
734
735 inline
set_ref(int index)736 void Machine::Code::decoder::set_ref(int index) throw() {
737 if (index + _slotref < 0 || index + _slotref >= NUMCONTEXTS) return;
738 _contexts[index + _slotref].flags.referenced = true;
739 if (index + _slotref > _max_ref) _max_ref = index + _slotref;
740 }
741
742
743 inline
set_noref(int index)744 void Machine::Code::decoder::set_noref(int index) throw() {
745 if (index + _slotref < 0 || index + _slotref >= NUMCONTEXTS) return;
746 if (index + _slotref > _max_ref) _max_ref = index + _slotref;
747 }
748
749
750 inline
set_changed(int index)751 void Machine::Code::decoder::set_changed(int index) throw() {
752 if (index + _slotref < 0 || index + _slotref >= NUMCONTEXTS) return;
753 _contexts[index + _slotref].flags.changed= true;
754 if (index + _slotref > _max_ref) _max_ref = index + _slotref;
755 }
756
757
release_buffers()758 void Machine::Code::release_buffers() throw()
759 {
760 if (_own)
761 free(_code);
762 _code = 0;
763 _data = 0;
764 _own = false;
765 }
766
767
run(Machine & m,slotref * & map) const768 int32 Machine::Code::run(Machine & m, slotref * & map) const
769 {
770 // assert(_own);
771 assert(*this); // Check we are actually runnable
772
773 if (m.slotMap().size() <= size_t(_max_ref + m.slotMap().context())
774 || m.slotMap()[_max_ref + m.slotMap().context()] == 0)
775 {
776 m._status = Machine::slot_offset_out_bounds;
777 return 1;
778 // return m.run(_code, _data, map);
779 }
780
781 return m.run(_code, _data, map);
782 }
783