Alternatively,thecontentsofthisfilemaybeusedunderthetermsofthe MozillaPublicLicense(http://mozilla.org/MPL) or the GNU General Public License,aspublishedbytheFreeSoftwareFoundation,eitherversion2 oftheLicenseor(atyouroption)anylaterversion.
*/ // This class represents loaded graphite stack machine code. It performs // basic sanity checks, on the incoming code to prevent more obvious problems // from crashing graphite. // Author: Tim Eves
// Allocate code and data target buffers, these sizes are a worst case // estimate. Once we know their real sizes the we'll shrink them. if (_out) _code = reinterpret_cast<instr *>(*_out); else _code = static_cast<instr *>(malloc(estimateCodeDataOut(bytecode_end-bytecode_begin, 1, is_constraint ? 0 : rule_length)));
_data = reinterpret_cast<byte *>(_code + (bytecode_end - bytecode_begin));
if (!_code || !_data) {
failure(alloc_failed); return;
}
// Now we know exactly how much code and data the program really needs // realloc the buffers to exactly the right size so we don't waste any // memory.
assert((bytecode_end - bytecode_begin) >= ptrdiff_t(_instr_count));
assert((bytecode_end - bytecode_begin) >= ptrdiff_t(_data_size));
memmove(_code + (_instr_count+1), _data, _data_size*sizeof(byte));
size_t const total_sz = ((_instr_count+1) + (_data_size + sizeof(instr)-1)/sizeof(instr))*sizeof(instr); if (_out)
*_out += total_sz; else
{
instr * const old_code = _code;
_code = static_cast<instr *>(realloc(_code, total_sz)); if (!_code) free(old_code);
}
_data = reinterpret_cast<byte *>(_code + (_instr_count+1));
if (!_code)
{
failure(alloc_failed); return;
}
// Make this RET_ZERO, we should never reach this but just in case ...
_code[_instr_count] = op_to_fn[RET_ZERO].impl[_constraint];
// Do some basic sanity checks based on what we know about the opcode if (!validate_opcode(opc, bc)) return MAX_OPCODE;
// And check its arguments as far as possible switch (opcode(opc))
{ case NOP : break; case PUSH_BYTE : case PUSH_BYTEU : case PUSH_SHORT : case PUSH_SHORTU : case PUSH_LONG :
++_stack_depth; break; case ADD : case SUB : case MUL : case DIV : case MIN_ : case MAX_ : caseAND : caseOR : case EQUAL : caseNOT_EQ : case LESS : case GTR : case LESS_EQ : case GTR_EQ : caseBITOR : caseBITAND : if (--_stack_depth <= 0)
failure(underfull_stack); break; case NEG : case TRUNC8 : case TRUNC16 : caseNOT : case BITNOT : case BITSET : if (_stack_depth <= 0)
failure(underfull_stack); break; case COND :
_stack_depth -= 2; if (_stack_depth <= 0)
failure(underfull_stack); break; case NEXT_N : // runtime checked break; case NEXT : case COPY_NEXT :
++_out_index; if (_out_index < -1 || _out_index > _out_length || _slotref > _max.rule_length)
failure(out_of_range_data); break; case PUT_GLYPH_8BIT_OBS :
valid_upto(_max.classes, bc[0]);
test_context(); break; case PUT_SUBS_8BIT_OBS :
test_ref(int8(bc[0]));
valid_upto(_max.classes, bc[1]);
valid_upto(_max.classes, bc[2]);
test_context(); break; case PUT_COPY :
test_ref(int8(bc[0]));
test_context(); break; case INSERT : if (_passtype >= PASS_TYPE_POSITIONING)
failure(invalid_opcode);
++_out_length; if (_out_index < 0) ++_out_index; if (_out_index < -1 || _out_index >= _out_length)
failure(out_of_range_data); break; caseDELETE : if (_passtype >= PASS_TYPE_POSITIONING)
failure(invalid_opcode); if (_out_index < _max.pre_context)
failure(out_of_range_data);
--_out_index;
--_out_length; if (_out_index < -1 || _out_index > _out_length)
failure(out_of_range_data); break; case ASSOC : if (bc[0] == 0)
failure(out_of_range_data); for (uint8 num = bc[0]; num; --num)
test_ref(int8(bc[num]));
test_context(); break; case CNTXT_ITEM :
valid_upto(_max.rule_length, _max.pre_context + int8(bc[0])); if (bc + 2 + bc[1] >= _max.bytecode) failure(jump_past_end); if (_in_ctxt_item) failure(nested_context_item); break; case ATTR_SET : case ATTR_ADD : case ATTR_SUB : case ATTR_SET_SLOT : if (--_stack_depth < 0)
failure(underfull_stack);
valid_upto(gr_slatMax, bc[0]); if (attrCode(bc[0]) == gr_slatUserDefn) // use IATTR for user attributes
failure(out_of_range_data);
test_attr(attrCode(bc[0]));
test_context(); break; case IATTR_SET_SLOT : if (--_stack_depth < 0)
failure(underfull_stack); if (valid_upto(gr_slatMax, bc[0]))
valid_upto(_max.attrid[bc[0]], bc[1]);
test_attr(attrCode(bc[0]));
test_context(); break; case PUSH_SLOT_ATTR :
++_stack_depth;
valid_upto(gr_slatMax, bc[0]);
test_ref(int8(bc[1])); if (attrCode(bc[0]) == gr_slatUserDefn) // use IATTR for user attributes
failure(out_of_range_data);
test_attr(attrCode(bc[0])); break; case PUSH_GLYPH_ATTR_OBS : case PUSH_ATT_TO_GATTR_OBS :
++_stack_depth;
valid_upto(_max.glyf_attrs, bc[0]);
test_ref(int8(bc[1])); break; case PUSH_ATT_TO_GLYPH_METRIC : case PUSH_GLYPH_METRIC :
++_stack_depth;
valid_upto(kgmetDescent, bc[0]);
test_ref(int8(bc[1])); // level: dp[2] no check necessary break; case PUSH_FEAT :
++_stack_depth;
valid_upto(_max.features, bc[0]);
test_ref(int8(bc[1])); break; case PUSH_ISLOT_ATTR :
++_stack_depth; if (valid_upto(gr_slatMax, bc[0]))
{
test_ref(int8(bc[1]));
valid_upto(_max.attrid[bc[0]], bc[2]);
}
test_attr(attrCode(bc[0])); break; case PUSH_IGLYPH_ATTR :// not implemented
++_stack_depth; break; case POP_RET : if (--_stack_depth < 0)
failure(underfull_stack);
GR_FALLTHROUGH; // no break case RET_ZERO : case RET_TRUE : break; case IATTR_SET : case IATTR_ADD : case IATTR_SUB : if (--_stack_depth < 0)
failure(underfull_stack); if (valid_upto(gr_slatMax, bc[0]))
valid_upto(_max.attrid[bc[0]], bc[1]);
test_attr(attrCode(bc[0]));
test_context(); break; case PUSH_PROC_STATE : // dummy: dp[0] no check necessary case PUSH_VERSION :
++_stack_depth; break; case PUT_SUBS :
test_ref(int8(bc[0]));
valid_upto(_max.classes, uint16(bc[1]<< 8) | bc[2]);
valid_upto(_max.classes, uint16(bc[3]<< 8) | bc[4]);
test_context(); break; case PUT_SUBS2 : // not implemented case PUT_SUBS3 : // not implemented break; case PUT_GLYPH :
valid_upto(_max.classes, uint16(bc[0]<< 8) | bc[1]);
test_context(); break; case PUSH_GLYPH_ATTR : case PUSH_ATT_TO_GLYPH_ATTR :
++_stack_depth;
valid_upto(_max.glyf_attrs, uint16(bc[0]<< 8) | bc[1]);
test_ref(int8(bc[2])); break; case SET_FEAT :
valid_upto(_max.features, bc[0]);
test_ref(int8(bc[1])); break; default:
failure(invalid_opcode); break;
}
returnbool(_code) ? opcode(opc) : MAX_OPCODE;
}
void Machine::Code::decoder::analyse_opcode(const opcode opc, const int8 * arg) throw()
{ switch (opc)
{ caseDELETE :
_code._delete = true; break; case ASSOC :
set_changed(0); // for (uint8 num = arg[0]; num; --num) // _analysis.set_noref(num); break; case PUT_GLYPH_8BIT_OBS : case PUT_GLYPH :
_code._modify = true;
set_changed(0); break; case ATTR_SET : case ATTR_ADD : case ATTR_SUB : case ATTR_SET_SLOT : case IATTR_SET_SLOT : case IATTR_SET : case IATTR_ADD : case IATTR_SUB :
set_noref(0); break; case NEXT : case COPY_NEXT :
++_slotref;
_contexts[_slotref] = context(uint8(_code._instr_count+1)); // if (_analysis.slotref > _analysis.max_ref) _analysis.max_ref = _analysis.slotref; break; case INSERT : if (_slotref >= 0) --_slotref;
_code._modify = true; break; case PUT_SUBS_8BIT_OBS : // slotref on 1st parameter case PUT_SUBS :
_code._modify = true;
set_changed(0);
GR_FALLTHROUGH; // no break case PUT_COPY : if (arg[0] != 0) { set_changed(0); _code._modify = true; }
set_ref(arg[0]); break; case PUSH_GLYPH_ATTR_OBS : case PUSH_SLOT_ATTR : case PUSH_GLYPH_METRIC : case PUSH_ATT_TO_GATTR_OBS : case PUSH_ATT_TO_GLYPH_METRIC : case PUSH_ISLOT_ATTR : case PUSH_FEAT : case SET_FEAT :
set_ref(arg[1]); break; case PUSH_ATT_TO_GLYPH_ATTR : case PUSH_GLYPH_ATTR :
set_ref(arg[2]); break; default: break;
}
}
// Add this instruction
*_instr++ = op.impl[_code._constraint];
++_code._instr_count;
// Grab the parameters if (param_sz) {
memcpy(_data, bc, param_sz * sizeof(byte));
bc += param_sz;
_data += param_sz;
_code._data_size += param_sz;
}
// recursively decode a context item so we can split the skip into // instruction and data portions. if (opc == CNTXT_ITEM)
{
assert(_out_index == 0);
_in_ctxt_item = true;
_out_index = _max.pre_context + int8(_data[-2]);
_slotref = int8(_data[-2]);
_out_length = _max.rule_length;
void Machine::Code::decoder::apply_analysis(instr * const code, instr * code_end)
{ // insert TEMP_COPY commands for slots that need them (that change and are referenced later) int tempcount = 0; if (_code._constraint) return;
const instr temp_copy = Machine::getOpcodeTable()[TEMP_COPY].impl[0]; for (const context * c = _contexts, * const ce = c + _slotref; c < ce; ++c)
{ if (!c->flags.referenced || !c->flags.changed) continue;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.