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 :
|