gfx/graphite2/src/Pass.cpp

changeset 0
6474c204b198
     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 +

mercurial