1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/gfx/graphite2/src/Pass.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,620 @@ 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 +#include "inc/Main.h" 1.31 +#include "inc/debug.h" 1.32 +#include "inc/Endian.h" 1.33 +#include "inc/Pass.h" 1.34 +#include <cstring> 1.35 +#include <cstdlib> 1.36 +#include <cassert> 1.37 +#include "inc/Segment.h" 1.38 +#include "inc/Code.h" 1.39 +#include "inc/Rule.h" 1.40 +#include "inc/Error.h" 1.41 + 1.42 +using namespace graphite2; 1.43 +using vm::Machine; 1.44 +typedef Machine::Code Code; 1.45 + 1.46 + 1.47 +Pass::Pass() 1.48 +: m_silf(0), 1.49 + m_cols(0), 1.50 + m_rules(0), 1.51 + m_ruleMap(0), 1.52 + m_startStates(0), 1.53 + m_transitions(0), 1.54 + m_states(0), 1.55 + m_flags(0), 1.56 + m_iMaxLoop(0), 1.57 + m_numGlyphs(0), 1.58 + m_numRules(0), 1.59 + m_numStates(0), 1.60 + m_numTransition(0), 1.61 + m_numSuccess(0), 1.62 + m_numColumns(0), 1.63 + m_minPreCtxt(0), 1.64 + m_maxPreCtxt(0) 1.65 +{ 1.66 +} 1.67 + 1.68 +Pass::~Pass() 1.69 +{ 1.70 + free(m_cols); 1.71 + free(m_startStates); 1.72 + free(m_transitions); 1.73 + free(m_states); 1.74 + free(m_ruleMap); 1.75 + 1.76 + delete [] m_rules; 1.77 +} 1.78 + 1.79 +bool Pass::readPass(const byte * const pass_start, size_t pass_length, size_t subtable_base, GR_MAYBE_UNUSED Face & face, Error &e) 1.80 +{ 1.81 + const byte * p = pass_start, 1.82 + * const pass_end = p + pass_length; 1.83 + size_t numRanges; 1.84 + 1.85 + if (e.test(pass_length < 40, E_BADPASSLENGTH)) return face.error(e); 1.86 + // Read in basic values 1.87 + m_flags = be::read<byte>(p); 1.88 + m_iMaxLoop = be::read<byte>(p); 1.89 + be::skip<byte>(p,2); // skip maxContext & maxBackup 1.90 + m_numRules = be::read<uint16>(p); 1.91 + be::skip<uint16>(p); // fsmOffset - not sure why we would want this 1.92 + const byte * const pcCode = pass_start + be::read<uint32>(p) - subtable_base, 1.93 + * const rcCode = pass_start + be::read<uint32>(p) - subtable_base, 1.94 + * const aCode = pass_start + be::read<uint32>(p) - subtable_base; 1.95 + be::skip<uint32>(p); 1.96 + m_numStates = be::read<uint16>(p); 1.97 + m_numTransition = be::read<uint16>(p); 1.98 + m_numSuccess = be::read<uint16>(p); 1.99 + m_numColumns = be::read<uint16>(p); 1.100 + numRanges = be::read<uint16>(p); 1.101 + be::skip<uint16>(p, 3); // skip searchRange, entrySelector & rangeShift. 1.102 + assert(p - pass_start == 40); 1.103 + // Perform some sanity checks. 1.104 + if ( e.test(m_numTransition > m_numStates, E_BADNUMTRANS) 1.105 + || e.test(m_numSuccess > m_numStates, E_BADNUMSUCCESS) 1.106 + || e.test(m_numSuccess + m_numTransition < m_numStates, E_BADNUMSTATES) 1.107 + || e.test(numRanges == 0, E_NORANGES)) 1.108 + return face.error(e); 1.109 + 1.110 + m_successStart = m_numStates - m_numSuccess; 1.111 + if (e.test(p + numRanges * 6 - 4 > pass_end, E_BADPASSLENGTH)) return face.error(e); 1.112 + m_numGlyphs = be::peek<uint16>(p + numRanges * 6 - 4) + 1; 1.113 + // Calculate the start of various arrays. 1.114 + const byte * const ranges = p; 1.115 + be::skip<uint16>(p, numRanges*3); 1.116 + const byte * const o_rule_map = p; 1.117 + be::skip<uint16>(p, m_numSuccess + 1); 1.118 + 1.119 + // More sanity checks 1.120 + if (e.test(reinterpret_cast<const byte *>(o_rule_map + m_numSuccess*sizeof(uint16)) > pass_end 1.121 + || p > pass_end, E_BADRULEMAPLEN)) 1.122 + return face.error(e); 1.123 + const size_t numEntries = be::peek<uint16>(o_rule_map + m_numSuccess*sizeof(uint16)); 1.124 + const byte * const rule_map = p; 1.125 + be::skip<uint16>(p, numEntries); 1.126 + 1.127 + if (e.test(p + 2*sizeof(uint8) > pass_end, E_BADPASSLENGTH)) return face.error(e); 1.128 + m_minPreCtxt = be::read<uint8>(p); 1.129 + m_maxPreCtxt = be::read<uint8>(p); 1.130 + if (e.test(m_minPreCtxt > m_maxPreCtxt, E_BADCTXTLENBOUNDS)) return face.error(e); 1.131 + const byte * const start_states = p; 1.132 + be::skip<int16>(p, m_maxPreCtxt - m_minPreCtxt + 1); 1.133 + const uint16 * const sort_keys = reinterpret_cast<const uint16 *>(p); 1.134 + be::skip<uint16>(p, m_numRules); 1.135 + const byte * const precontext = p; 1.136 + be::skip<byte>(p, m_numRules); 1.137 + be::skip<byte>(p); // skip reserved byte 1.138 + 1.139 + if (e.test(p + sizeof(uint16) > pass_end, E_BADCTXTLENS)) return face.error(e); 1.140 + const size_t pass_constraint_len = be::read<uint16>(p); 1.141 + const uint16 * const o_constraint = reinterpret_cast<const uint16 *>(p); 1.142 + be::skip<uint16>(p, m_numRules + 1); 1.143 + const uint16 * const o_actions = reinterpret_cast<const uint16 *>(p); 1.144 + be::skip<uint16>(p, m_numRules + 1); 1.145 + const byte * const states = p; 1.146 + be::skip<int16>(p, m_numTransition*m_numColumns); 1.147 + be::skip<byte>(p); // skip reserved byte 1.148 + if (e.test(p != pcCode, E_BADPASSCCODEPTR) || e.test(p >= pass_end, E_BADPASSLENGTH)) return face.error(e); 1.149 + be::skip<byte>(p, pass_constraint_len); 1.150 + if (e.test(p != rcCode, E_BADRULECCODEPTR) || e.test(p >= pass_end, E_BADPASSLENGTH) 1.151 + || e.test(size_t(rcCode - pcCode) != pass_constraint_len, E_BADCCODELEN)) return face.error(e); 1.152 + be::skip<byte>(p, be::peek<uint16>(o_constraint + m_numRules)); 1.153 + if (e.test(p != aCode, E_BADACTIONCODEPTR) || e.test(p >= pass_end, E_BADPASSLENGTH)) return face.error(e); 1.154 + be::skip<byte>(p, be::peek<uint16>(o_actions + m_numRules)); 1.155 + 1.156 + // We should be at the end or within the pass 1.157 + if (e.test(p > pass_end, E_BADPASSLENGTH)) return face.error(e); 1.158 + 1.159 + // Load the pass constraint if there is one. 1.160 + if (pass_constraint_len) 1.161 + { 1.162 + face.error_context(face.error_context() + 1); 1.163 + m_cPConstraint = vm::Machine::Code(true, pcCode, pcCode + pass_constraint_len, 1.164 + precontext[0], be::peek<uint16>(sort_keys), *m_silf, face); 1.165 + if (e.test(!m_cPConstraint, E_OUTOFMEM) 1.166 + || e.test(m_cPConstraint.status(), m_cPConstraint.status() + E_CODEFAILURE)) 1.167 + return face.error(e); 1.168 + face.error_context(face.error_context() - 1); 1.169 + } 1.170 + if (!readRanges(ranges, numRanges, e)) return face.error(e); 1.171 + if (!readRules(rule_map, numEntries, precontext, sort_keys, 1.172 + o_constraint, rcCode, o_actions, aCode, face, e)) return false; 1.173 +#ifdef GRAPHITE2_TELEMETRY 1.174 + telemetry::category _states_cat(face.tele.states); 1.175 +#endif 1.176 + return readStates(start_states, states, o_rule_map, face, e); 1.177 +} 1.178 + 1.179 + 1.180 +bool Pass::readRules(const byte * rule_map, const size_t num_entries, 1.181 + const byte *precontext, const uint16 * sort_key, 1.182 + const uint16 * o_constraint, const byte *rc_data, 1.183 + const uint16 * o_action, const byte * ac_data, 1.184 + Face & face, Error &e) 1.185 +{ 1.186 + const byte * const ac_data_end = ac_data + be::peek<uint16>(o_action + m_numRules); 1.187 + const byte * const rc_data_end = rc_data + be::peek<uint16>(o_constraint + m_numRules); 1.188 + 1.189 + if (e.test(!(m_rules = new Rule [m_numRules]), E_OUTOFMEM)) return face.error(e); 1.190 + precontext += m_numRules; 1.191 + sort_key += m_numRules; 1.192 + o_constraint += m_numRules; 1.193 + o_action += m_numRules; 1.194 + 1.195 + // Load rules. 1.196 + const byte * ac_begin = 0, * rc_begin = 0, 1.197 + * ac_end = ac_data + be::peek<uint16>(o_action), 1.198 + * rc_end = rc_data + be::peek<uint16>(o_constraint); 1.199 + Rule * r = m_rules + m_numRules - 1; 1.200 + for (size_t n = m_numRules; n; --n, --r, ac_end = ac_begin, rc_end = rc_begin) 1.201 + { 1.202 + face.error_context((face.error_context() & 0xFFFF00) + EC_ARULE + ((n - 1) << 24)); 1.203 + r->preContext = *--precontext; 1.204 + r->sort = be::peek<uint16>(--sort_key); 1.205 +#ifndef NDEBUG 1.206 + r->rule_idx = n - 1; 1.207 +#endif 1.208 + if (r->sort > 63 || r->preContext >= r->sort || r->preContext > m_maxPreCtxt || r->preContext < m_minPreCtxt) 1.209 + return false; 1.210 + ac_begin = ac_data + be::peek<uint16>(--o_action); 1.211 + --o_constraint; 1.212 + rc_begin = be::peek<uint16>(o_constraint) ? rc_data + be::peek<uint16>(o_constraint) : rc_end; 1.213 + 1.214 + if (ac_begin > ac_end || ac_begin > ac_data_end || ac_end > ac_data_end 1.215 + || rc_begin > rc_end || rc_begin > rc_data_end || rc_end > rc_data_end) 1.216 + return false; 1.217 + r->action = new vm::Machine::Code(false, ac_begin, ac_end, r->preContext, r->sort, *m_silf, face); 1.218 + r->constraint = new vm::Machine::Code(true, rc_begin, rc_end, r->preContext, r->sort, *m_silf, face); 1.219 + 1.220 + if (e.test(!r->action || !r->constraint, E_OUTOFMEM) 1.221 + || e.test(r->action->status() != Code::loaded, r->action->status() + E_CODEFAILURE) 1.222 + || e.test(r->constraint->status() != Code::loaded, r->constraint->status() + E_CODEFAILURE) 1.223 + || e.test(!r->constraint->immutable(), E_MUTABLECCODE)) 1.224 + return face.error(e); 1.225 + } 1.226 + 1.227 + // Load the rule entries map 1.228 + face.error_context((face.error_context() & 0xFFFF00) + EC_APASS); 1.229 + RuleEntry * re = m_ruleMap = gralloc<RuleEntry>(num_entries); 1.230 + if (e.test(!re, E_OUTOFMEM)) return face.error(e); 1.231 + for (size_t n = num_entries; n; --n, ++re) 1.232 + { 1.233 + const ptrdiff_t rn = be::read<uint16>(rule_map); 1.234 + if (e.test(rn >= m_numRules, E_BADRULENUM)) return face.error(e); 1.235 + re->rule = m_rules + rn; 1.236 + } 1.237 + 1.238 + return true; 1.239 +} 1.240 + 1.241 +static int cmpRuleEntry(const void *a, const void *b) { return (*(RuleEntry *)a < *(RuleEntry *)b ? -1 : 1.242 + (*(RuleEntry *)b < *(RuleEntry *)a ? 1 : 0)); } 1.243 + 1.244 +bool Pass::readStates(const byte * starts, const byte *states, const byte * o_rule_map, GR_MAYBE_UNUSED Face & face, Error &e) 1.245 +{ 1.246 +#ifdef GRAPHITE2_TELEMETRY 1.247 + telemetry::category _states_cat(face.tele.starts); 1.248 +#endif 1.249 + m_startStates = gralloc<uint16>(m_maxPreCtxt - m_minPreCtxt + 1); 1.250 +#ifdef GRAPHITE2_TELEMETRY 1.251 + telemetry::set_category(face.tele.states); 1.252 +#endif 1.253 + m_states = gralloc<State>(m_numStates); 1.254 +#ifdef GRAPHITE2_TELEMETRY 1.255 + telemetry::set_category(face.tele.transitions); 1.256 +#endif 1.257 + m_transitions = gralloc<uint16>(m_numTransition * m_numColumns); 1.258 + 1.259 + if (e.test(!m_startStates || !m_states || !m_transitions, E_OUTOFMEM)) return face.error(e); 1.260 + // load start states 1.261 + for (uint16 * s = m_startStates, 1.262 + * const s_end = s + m_maxPreCtxt - m_minPreCtxt + 1; s != s_end; ++s) 1.263 + { 1.264 + *s = be::read<uint16>(starts); 1.265 + if (e.test(*s >= m_numStates, E_BADSTATE)) 1.266 + { 1.267 + face.error_context((face.error_context() & 0xFFFF00) + EC_ASTARTS + ((s - m_startStates) << 24)); 1.268 + return face.error(e); // true; 1.269 + } 1.270 + } 1.271 + 1.272 + // load state transition table. 1.273 + for (uint16 * t = m_transitions, 1.274 + * const t_end = t + m_numTransition*m_numColumns; t != t_end; ++t) 1.275 + { 1.276 + *t = be::read<uint16>(states); 1.277 + if (e.test(*t >= m_numStates, E_BADSTATE)) 1.278 + { 1.279 + face.error_context((face.error_context() & 0xFFFF00) + EC_ATRANS + (((t - m_transitions) / m_numColumns) << 24)); 1.280 + return face.error(e); 1.281 + } 1.282 + } 1.283 + 1.284 + State * s = m_states, 1.285 + * const success_begin = m_states + m_numStates - m_numSuccess; 1.286 + const RuleEntry * rule_map_end = m_ruleMap + be::peek<uint16>(o_rule_map + m_numSuccess*sizeof(uint16)); 1.287 + for (size_t n = m_numStates; n; --n, ++s) 1.288 + { 1.289 + RuleEntry * const begin = s < success_begin ? 0 : m_ruleMap + be::read<uint16>(o_rule_map), 1.290 + * const end = s < success_begin ? 0 : m_ruleMap + be::peek<uint16>(o_rule_map); 1.291 + 1.292 + if (e.test(begin >= rule_map_end || end > rule_map_end || begin > end, E_BADRULEMAPPING)) 1.293 + { 1.294 + face.error_context((face.error_context() & 0xFFFF00) + EC_ARULEMAP + (n << 24)); 1.295 + return face.error(e); 1.296 + } 1.297 + s->rules = begin; 1.298 + s->rules_end = (end - begin <= FiniteStateMachine::MAX_RULES)? end : 1.299 + begin + FiniteStateMachine::MAX_RULES; 1.300 + qsort(begin, end - begin, sizeof(RuleEntry), &cmpRuleEntry); 1.301 + } 1.302 + 1.303 + return true; 1.304 +} 1.305 + 1.306 +bool Pass::readRanges(const byte * ranges, size_t num_ranges, Error &e) 1.307 +{ 1.308 + m_cols = gralloc<uint16>(m_numGlyphs); 1.309 + if (e.test(!m_cols, E_OUTOFMEM)) return false; 1.310 + memset(m_cols, 0xFF, m_numGlyphs * sizeof(uint16)); 1.311 + for (size_t n = num_ranges; n; --n) 1.312 + { 1.313 + uint16 * ci = m_cols + be::read<uint16>(ranges), 1.314 + * ci_end = m_cols + be::read<uint16>(ranges) + 1, 1.315 + col = be::read<uint16>(ranges); 1.316 + 1.317 + if (e.test(ci >= ci_end || ci_end > m_cols+m_numGlyphs || col >= m_numColumns, E_BADRANGE)) 1.318 + return false; 1.319 + 1.320 + // A glyph must only belong to one column at a time 1.321 + while (ci != ci_end && *ci == 0xffff) 1.322 + *ci++ = col; 1.323 + 1.324 + if (e.test(ci != ci_end, E_BADRANGE)) 1.325 + return false; 1.326 + } 1.327 + return true; 1.328 +} 1.329 + 1.330 + 1.331 +void Pass::runGraphite(Machine & m, FiniteStateMachine & fsm) const 1.332 +{ 1.333 + Slot *s = m.slotMap().segment.first(); 1.334 + if (!s || !testPassConstraint(m)) return; 1.335 + Slot *currHigh = s->next(); 1.336 + 1.337 +#if !defined GRAPHITE2_NTRACING 1.338 + if (fsm.dbgout) *fsm.dbgout << "rules" << json::array; 1.339 + json::closer rules_array_closer(fsm.dbgout); 1.340 +#endif 1.341 + 1.342 + m.slotMap().highwater(currHigh); 1.343 + int lc = m_iMaxLoop; 1.344 + do 1.345 + { 1.346 + findNDoRule(s, m, fsm); 1.347 + if (s && (m.slotMap().highpassed() || s == m.slotMap().highwater() || --lc == 0)) { 1.348 + if (!lc) 1.349 + { 1.350 +// if (dbgout) *dbgout << json::item << json::flat << rule_event(-1, s, 1); 1.351 + s = m.slotMap().highwater(); 1.352 + } 1.353 + lc = m_iMaxLoop; 1.354 + if (s) 1.355 + m.slotMap().highwater(s->next()); 1.356 + } 1.357 + } while (s); 1.358 +} 1.359 + 1.360 +bool Pass::runFSM(FiniteStateMachine& fsm, Slot * slot) const 1.361 +{ 1.362 + fsm.reset(slot, m_maxPreCtxt); 1.363 + if (fsm.slots.context() < m_minPreCtxt) 1.364 + return false; 1.365 + 1.366 + uint16 state = m_startStates[m_maxPreCtxt - fsm.slots.context()]; 1.367 + uint8 free_slots = SlotMap::MAX_SLOTS; 1.368 + do 1.369 + { 1.370 + fsm.slots.pushSlot(slot); 1.371 + if (--free_slots == 0 1.372 + || slot->gid() >= m_numGlyphs 1.373 + || m_cols[slot->gid()] == 0xffffU 1.374 + || state >= m_numTransition) 1.375 + return free_slots != 0; 1.376 + 1.377 + const uint16 * transitions = m_transitions + state*m_numColumns; 1.378 + state = transitions[m_cols[slot->gid()]]; 1.379 + if (state >= m_successStart) 1.380 + fsm.rules.accumulate_rules(m_states[state]); 1.381 + 1.382 + slot = slot->next(); 1.383 + } while (state != 0 && slot); 1.384 + 1.385 + fsm.slots.pushSlot(slot); 1.386 + return true; 1.387 +} 1.388 + 1.389 +#if !defined GRAPHITE2_NTRACING 1.390 + 1.391 +inline 1.392 +Slot * input_slot(const SlotMap & slots, const int n) 1.393 +{ 1.394 + Slot * s = slots[slots.context() + n]; 1.395 + if (!s->isCopied()) return s; 1.396 + 1.397 + return s->prev() ? s->prev()->next() : (s->next() ? s->next()->prev() : slots.segment.last()); 1.398 +} 1.399 + 1.400 +inline 1.401 +Slot * output_slot(const SlotMap & slots, const int n) 1.402 +{ 1.403 + Slot * s = slots[slots.context() + n - 1]; 1.404 + return s ? s->next() : slots.segment.first(); 1.405 +} 1.406 + 1.407 +#endif //!defined GRAPHITE2_NTRACING 1.408 + 1.409 +void Pass::findNDoRule(Slot * & slot, Machine &m, FiniteStateMachine & fsm) const 1.410 +{ 1.411 + assert(slot); 1.412 + 1.413 + if (runFSM(fsm, slot)) 1.414 + { 1.415 + // Search for the first rule which passes the constraint 1.416 + const RuleEntry * r = fsm.rules.begin(), 1.417 + * const re = fsm.rules.end(); 1.418 + while (r != re && !testConstraint(*r->rule, m)) ++r; 1.419 + 1.420 +#if !defined GRAPHITE2_NTRACING 1.421 + if (fsm.dbgout) 1.422 + { 1.423 + if (fsm.rules.size() != 0) 1.424 + { 1.425 + *fsm.dbgout << json::item << json::object; 1.426 + dumpRuleEventConsidered(fsm, *r); 1.427 + if (r != re) 1.428 + { 1.429 + const int adv = doAction(r->rule->action, slot, m); 1.430 + dumpRuleEventOutput(fsm, *r->rule, slot); 1.431 + if (r->rule->action->deletes()) fsm.slots.collectGarbage(); 1.432 + adjustSlot(adv, slot, fsm.slots); 1.433 + *fsm.dbgout << "cursor" << objectid(dslot(&fsm.slots.segment, slot)) 1.434 + << json::close; // Close RuelEvent object 1.435 + 1.436 + return; 1.437 + } 1.438 + else 1.439 + { 1.440 + *fsm.dbgout << json::close // close "considered" array 1.441 + << "output" << json::null 1.442 + << "cursor" << objectid(dslot(&fsm.slots.segment, slot->next())) 1.443 + << json::close; 1.444 + } 1.445 + } 1.446 + } 1.447 + else 1.448 +#endif 1.449 + { 1.450 + if (r != re) 1.451 + { 1.452 + const int adv = doAction(r->rule->action, slot, m); 1.453 + if (r->rule->action->deletes()) fsm.slots.collectGarbage(); 1.454 + adjustSlot(adv, slot, fsm.slots); 1.455 + return; 1.456 + } 1.457 + } 1.458 + } 1.459 + 1.460 + slot = slot->next(); 1.461 +} 1.462 + 1.463 +#if !defined GRAPHITE2_NTRACING 1.464 + 1.465 +void Pass::dumpRuleEventConsidered(const FiniteStateMachine & fsm, const RuleEntry & re) const 1.466 +{ 1.467 + *fsm.dbgout << "considered" << json::array; 1.468 + for (const RuleEntry *r = fsm.rules.begin(); r != &re; ++r) 1.469 + { 1.470 + if (r->rule->preContext > fsm.slots.context()) continue; 1.471 + *fsm.dbgout << json::flat << json::object 1.472 + << "id" << r->rule - m_rules 1.473 + << "failed" << true 1.474 + << "input" << json::flat << json::object 1.475 + << "start" << objectid(dslot(&fsm.slots.segment, input_slot(fsm.slots, -r->rule->preContext))) 1.476 + << "length" << r->rule->sort 1.477 + << json::close // close "input" 1.478 + << json::close; // close Rule object 1.479 + } 1.480 +} 1.481 + 1.482 + 1.483 +void Pass::dumpRuleEventOutput(const FiniteStateMachine & fsm, const Rule & r, Slot * const last_slot) const 1.484 +{ 1.485 + *fsm.dbgout << json::item << json::flat << json::object 1.486 + << "id" << &r - m_rules 1.487 + << "failed" << false 1.488 + << "input" << json::flat << json::object 1.489 + << "start" << objectid(dslot(&fsm.slots.segment, input_slot(fsm.slots, 0))) 1.490 + << "length" << r.sort - r.preContext 1.491 + << json::close // close "input" 1.492 + << json::close // close Rule object 1.493 + << json::close // close considered array 1.494 + << "output" << json::object 1.495 + << "range" << json::flat << json::object 1.496 + << "start" << objectid(dslot(&fsm.slots.segment, input_slot(fsm.slots, 0))) 1.497 + << "end" << objectid(dslot(&fsm.slots.segment, last_slot)) 1.498 + << json::close // close "input" 1.499 + << "slots" << json::array; 1.500 + const Position rsb_prepos = last_slot ? last_slot->origin() : fsm.slots.segment.advance(); 1.501 + fsm.slots.segment.positionSlots(0); 1.502 + 1.503 + for(Slot * slot = output_slot(fsm.slots, 0); slot != last_slot; slot = slot->next()) 1.504 + *fsm.dbgout << dslot(&fsm.slots.segment, slot); 1.505 + *fsm.dbgout << json::close // close "slots" 1.506 + << "postshift" << (last_slot ? last_slot->origin() : fsm.slots.segment.advance()) - rsb_prepos 1.507 + << json::close; // close "output" object 1.508 + 1.509 +} 1.510 + 1.511 +#endif 1.512 + 1.513 + 1.514 +inline 1.515 +bool Pass::testPassConstraint(Machine & m) const 1.516 +{ 1.517 + if (!m_cPConstraint) return true; 1.518 + 1.519 + assert(m_cPConstraint.constraint()); 1.520 + 1.521 + m.slotMap().reset(*m.slotMap().segment.first(), 0); 1.522 + m.slotMap().pushSlot(m.slotMap().segment.first()); 1.523 + vm::slotref * map = m.slotMap().begin(); 1.524 + const uint32 ret = m_cPConstraint.run(m, map); 1.525 + 1.526 +#if !defined GRAPHITE2_NTRACING 1.527 + json * const dbgout = m.slotMap().segment.getFace()->logger(); 1.528 + if (dbgout) 1.529 + *dbgout << "constraint" << (ret && m.status() == Machine::finished); 1.530 +#endif 1.531 + 1.532 + return ret && m.status() == Machine::finished; 1.533 +} 1.534 + 1.535 + 1.536 +bool Pass::testConstraint(const Rule & r, Machine & m) const 1.537 +{ 1.538 + const uint16 curr_context = m.slotMap().context(); 1.539 + if (unsigned(r.sort - r.preContext) > m.slotMap().size() - curr_context 1.540 + || curr_context - r.preContext < 0) return false; 1.541 + if (!*r.constraint) return true; 1.542 + assert(r.constraint->constraint()); 1.543 + 1.544 + vm::slotref * map = m.slotMap().begin() + curr_context - r.preContext; 1.545 + for (int n = r.sort; n && map; --n, ++map) 1.546 + { 1.547 + if (!*map) continue; 1.548 + const int32 ret = r.constraint->run(m, map); 1.549 + if (!ret || m.status() != Machine::finished) 1.550 + return false; 1.551 + } 1.552 + 1.553 + return true; 1.554 +} 1.555 + 1.556 + 1.557 +void SlotMap::collectGarbage() 1.558 +{ 1.559 + for(Slot **s = begin(), *const *const se = end() - 1; s != se; ++s) { 1.560 + Slot *& slot = *s; 1.561 + if(slot->isDeleted() || slot->isCopied()) 1.562 + segment.freeSlot(slot); 1.563 + } 1.564 +} 1.565 + 1.566 + 1.567 + 1.568 +int Pass::doAction(const Code *codeptr, Slot * & slot_out, vm::Machine & m) const 1.569 +{ 1.570 + assert(codeptr); 1.571 + if (!*codeptr) return 0; 1.572 + SlotMap & smap = m.slotMap(); 1.573 + vm::slotref * map = &smap[smap.context()]; 1.574 + smap.highpassed(false); 1.575 + 1.576 + int32 ret = codeptr->run(m, map); 1.577 + 1.578 + if (m.status() != Machine::finished) 1.579 + { 1.580 + slot_out = NULL; 1.581 + smap.highwater(0); 1.582 + return 0; 1.583 + } 1.584 + 1.585 + slot_out = *map; 1.586 + return ret; 1.587 +} 1.588 + 1.589 + 1.590 +void Pass::adjustSlot(int delta, Slot * & slot_out, SlotMap & smap) const 1.591 +{ 1.592 + if (delta < 0) 1.593 + { 1.594 + if (!slot_out) 1.595 + { 1.596 + slot_out = smap.segment.last(); 1.597 + ++delta; 1.598 + if (smap.highpassed() && !smap.highwater()) 1.599 + smap.highpassed(false); 1.600 + } 1.601 + while (++delta <= 0 && slot_out) 1.602 + { 1.603 + if (smap.highpassed() && smap.highwater() == slot_out) 1.604 + smap.highpassed(false); 1.605 + slot_out = slot_out->prev(); 1.606 + } 1.607 + } 1.608 + else if (delta > 0) 1.609 + { 1.610 + if (!slot_out) 1.611 + { 1.612 + slot_out = smap.segment.first(); 1.613 + --delta; 1.614 + } 1.615 + while (--delta >= 0 && slot_out) 1.616 + { 1.617 + slot_out = slot_out->next(); 1.618 + if (slot_out == smap.highwater() && slot_out) 1.619 + smap.highpassed(true); 1.620 + } 1.621 + } 1.622 +} 1.623 +