gfx/graphite2/src/Pass.cpp

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

     1 /*  GRAPHITE2 LICENSING
     3     Copyright 2010, SIL International
     4     All rights reserved.
     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.
    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.
    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.
    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 #include "inc/Main.h"
    28 #include "inc/debug.h"
    29 #include "inc/Endian.h"
    30 #include "inc/Pass.h"
    31 #include <cstring>
    32 #include <cstdlib>
    33 #include <cassert>
    34 #include "inc/Segment.h"
    35 #include "inc/Code.h"
    36 #include "inc/Rule.h"
    37 #include "inc/Error.h"
    39 using namespace graphite2;
    40 using vm::Machine;
    41 typedef Machine::Code  Code;
    44 Pass::Pass()
    45 : m_silf(0),
    46   m_cols(0),
    47   m_rules(0),
    48   m_ruleMap(0),
    49   m_startStates(0),
    50   m_transitions(0),
    51   m_states(0),
    52   m_flags(0),
    53   m_iMaxLoop(0),
    54   m_numGlyphs(0),
    55   m_numRules(0),
    56   m_numStates(0),
    57   m_numTransition(0),
    58   m_numSuccess(0),
    59   m_numColumns(0),
    60   m_minPreCtxt(0),
    61   m_maxPreCtxt(0)
    62 {
    63 }
    65 Pass::~Pass()
    66 {
    67     free(m_cols);
    68     free(m_startStates);
    69     free(m_transitions);
    70     free(m_states);
    71     free(m_ruleMap);
    73     delete [] m_rules;
    74 }
    76 bool Pass::readPass(const byte * const pass_start, size_t pass_length, size_t subtable_base, GR_MAYBE_UNUSED Face & face, Error &e)
    77 {
    78     const byte *                p = pass_start,
    79                * const pass_end   = p + pass_length;
    80     size_t numRanges;
    82     if (e.test(pass_length < 40, E_BADPASSLENGTH)) return face.error(e); 
    83     // Read in basic values
    84     m_flags = be::read<byte>(p);
    85     m_iMaxLoop = be::read<byte>(p);
    86     be::skip<byte>(p,2); // skip maxContext & maxBackup
    87     m_numRules = be::read<uint16>(p);
    88     be::skip<uint16>(p);   // fsmOffset - not sure why we would want this
    89     const byte * const pcCode = pass_start + be::read<uint32>(p) - subtable_base,
    90                * const rcCode = pass_start + be::read<uint32>(p) - subtable_base,
    91                * const aCode  = pass_start + be::read<uint32>(p) - subtable_base;
    92     be::skip<uint32>(p);
    93     m_numStates = be::read<uint16>(p);
    94     m_numTransition = be::read<uint16>(p);
    95     m_numSuccess = be::read<uint16>(p);
    96     m_numColumns = be::read<uint16>(p);
    97     numRanges = be::read<uint16>(p);
    98     be::skip<uint16>(p, 3); // skip searchRange, entrySelector & rangeShift.
    99     assert(p - pass_start == 40);
   100     // Perform some sanity checks.
   101     if ( e.test(m_numTransition > m_numStates, E_BADNUMTRANS)
   102             || e.test(m_numSuccess > m_numStates, E_BADNUMSUCCESS)
   103             || e.test(m_numSuccess + m_numTransition < m_numStates, E_BADNUMSTATES)
   104             || e.test(numRanges == 0, E_NORANGES))
   105         return face.error(e);
   107     m_successStart = m_numStates - m_numSuccess;
   108     if (e.test(p + numRanges * 6 - 4 > pass_end, E_BADPASSLENGTH)) return face.error(e);
   109     m_numGlyphs = be::peek<uint16>(p + numRanges * 6 - 4) + 1;
   110     // Calculate the start of various arrays.
   111     const byte * const ranges = p;
   112     be::skip<uint16>(p, numRanges*3);
   113     const byte * const o_rule_map = p;
   114     be::skip<uint16>(p, m_numSuccess + 1);
   116     // More sanity checks
   117     if (e.test(reinterpret_cast<const byte *>(o_rule_map + m_numSuccess*sizeof(uint16)) > pass_end
   118             || p > pass_end, E_BADRULEMAPLEN))
   119         return face.error(e);
   120     const size_t numEntries = be::peek<uint16>(o_rule_map + m_numSuccess*sizeof(uint16));
   121     const byte * const   rule_map = p;
   122     be::skip<uint16>(p, numEntries);
   124     if (e.test(p + 2*sizeof(uint8) > pass_end, E_BADPASSLENGTH)) return face.error(e);
   125     m_minPreCtxt = be::read<uint8>(p);
   126     m_maxPreCtxt = be::read<uint8>(p);
   127     if (e.test(m_minPreCtxt > m_maxPreCtxt, E_BADCTXTLENBOUNDS)) return face.error(e);
   128     const byte * const start_states = p;
   129     be::skip<int16>(p, m_maxPreCtxt - m_minPreCtxt + 1);
   130     const uint16 * const sort_keys = reinterpret_cast<const uint16 *>(p);
   131     be::skip<uint16>(p, m_numRules);
   132     const byte * const precontext = p;
   133     be::skip<byte>(p, m_numRules);
   134     be::skip<byte>(p);     // skip reserved byte
   136     if (e.test(p + sizeof(uint16) > pass_end, E_BADCTXTLENS)) return face.error(e);
   137     const size_t pass_constraint_len = be::read<uint16>(p);
   138     const uint16 * const o_constraint = reinterpret_cast<const uint16 *>(p);
   139     be::skip<uint16>(p, m_numRules + 1);
   140     const uint16 * const o_actions = reinterpret_cast<const uint16 *>(p);
   141     be::skip<uint16>(p, m_numRules + 1);
   142     const byte * const states = p;
   143     be::skip<int16>(p, m_numTransition*m_numColumns);
   144     be::skip<byte>(p);          // skip reserved byte
   145     if (e.test(p != pcCode, E_BADPASSCCODEPTR) || e.test(p >= pass_end, E_BADPASSLENGTH)) return face.error(e);
   146     be::skip<byte>(p, pass_constraint_len);
   147     if (e.test(p != rcCode, E_BADRULECCODEPTR) || e.test(p >= pass_end, E_BADPASSLENGTH)
   148         || e.test(size_t(rcCode - pcCode) != pass_constraint_len, E_BADCCODELEN)) return face.error(e);
   149     be::skip<byte>(p, be::peek<uint16>(o_constraint + m_numRules));
   150     if (e.test(p != aCode, E_BADACTIONCODEPTR) || e.test(p >= pass_end, E_BADPASSLENGTH)) return face.error(e);
   151     be::skip<byte>(p, be::peek<uint16>(o_actions + m_numRules));
   153     // We should be at the end or within the pass
   154     if (e.test(p > pass_end, E_BADPASSLENGTH)) return face.error(e);
   156     // Load the pass constraint if there is one.
   157     if (pass_constraint_len)
   158     {
   159         face.error_context(face.error_context() + 1);
   160         m_cPConstraint = vm::Machine::Code(true, pcCode, pcCode + pass_constraint_len, 
   161                                   precontext[0], be::peek<uint16>(sort_keys), *m_silf, face);
   162         if (e.test(!m_cPConstraint, E_OUTOFMEM)
   163                 || e.test(m_cPConstraint.status(), m_cPConstraint.status() + E_CODEFAILURE))
   164             return face.error(e);
   165         face.error_context(face.error_context() - 1);
   166     }
   167     if (!readRanges(ranges, numRanges, e)) return face.error(e);
   168     if (!readRules(rule_map, numEntries,  precontext, sort_keys,
   169                    o_constraint, rcCode, o_actions, aCode, face, e)) return false;
   170 #ifdef GRAPHITE2_TELEMETRY
   171     telemetry::category _states_cat(face.tele.states);
   172 #endif
   173     return readStates(start_states, states, o_rule_map, face, e);
   174 }
   177 bool Pass::readRules(const byte * rule_map, const size_t num_entries,
   178                      const byte *precontext, const uint16 * sort_key,
   179                      const uint16 * o_constraint, const byte *rc_data,
   180                      const uint16 * o_action,     const byte * ac_data,
   181                      Face & face, Error &e)
   182 {
   183     const byte * const ac_data_end = ac_data + be::peek<uint16>(o_action + m_numRules);
   184     const byte * const rc_data_end = rc_data + be::peek<uint16>(o_constraint + m_numRules);
   186     if (e.test(!(m_rules = new Rule [m_numRules]), E_OUTOFMEM)) return face.error(e);
   187     precontext += m_numRules;
   188     sort_key   += m_numRules;
   189     o_constraint += m_numRules;
   190     o_action += m_numRules;
   192     // Load rules.
   193     const byte * ac_begin = 0, * rc_begin = 0,
   194                * ac_end = ac_data + be::peek<uint16>(o_action),
   195                * rc_end = rc_data + be::peek<uint16>(o_constraint);
   196     Rule * r = m_rules + m_numRules - 1;
   197     for (size_t n = m_numRules; n; --n, --r, ac_end = ac_begin, rc_end = rc_begin)
   198     {
   199         face.error_context((face.error_context() & 0xFFFF00) + EC_ARULE + ((n - 1) << 24));
   200         r->preContext = *--precontext;
   201         r->sort       = be::peek<uint16>(--sort_key);
   202 #ifndef NDEBUG
   203         r->rule_idx   = n - 1;
   204 #endif
   205         if (r->sort > 63 || r->preContext >= r->sort || r->preContext > m_maxPreCtxt || r->preContext < m_minPreCtxt)
   206             return false;
   207         ac_begin      = ac_data + be::peek<uint16>(--o_action);
   208         --o_constraint;
   209         rc_begin      = be::peek<uint16>(o_constraint) ? rc_data + be::peek<uint16>(o_constraint) : rc_end;
   211         if (ac_begin > ac_end || ac_begin > ac_data_end || ac_end > ac_data_end
   212                 || rc_begin > rc_end || rc_begin > rc_data_end || rc_end > rc_data_end)
   213             return false;
   214         r->action     = new vm::Machine::Code(false, ac_begin, ac_end, r->preContext, r->sort, *m_silf, face);
   215         r->constraint = new vm::Machine::Code(true,  rc_begin, rc_end, r->preContext, r->sort, *m_silf, face);
   217         if (e.test(!r->action || !r->constraint, E_OUTOFMEM)
   218                 || e.test(r->action->status() != Code::loaded, r->action->status() + E_CODEFAILURE)
   219                 || e.test(r->constraint->status() != Code::loaded, r->constraint->status() + E_CODEFAILURE)
   220                 || e.test(!r->constraint->immutable(), E_MUTABLECCODE))
   221             return face.error(e);
   222     }
   224     // Load the rule entries map
   225     face.error_context((face.error_context() & 0xFFFF00) + EC_APASS);
   226     RuleEntry * re = m_ruleMap = gralloc<RuleEntry>(num_entries);
   227     if (e.test(!re, E_OUTOFMEM)) return face.error(e);
   228     for (size_t n = num_entries; n; --n, ++re)
   229     {
   230         const ptrdiff_t rn = be::read<uint16>(rule_map);
   231         if (e.test(rn >= m_numRules, E_BADRULENUM))  return face.error(e);
   232         re->rule = m_rules + rn;
   233     }
   235     return true;
   236 }
   238 static int cmpRuleEntry(const void *a, const void *b) { return (*(RuleEntry *)a < *(RuleEntry *)b ? -1 :
   239                                                                 (*(RuleEntry *)b < *(RuleEntry *)a ? 1 : 0)); }
   241 bool Pass::readStates(const byte * starts, const byte *states, const byte * o_rule_map, GR_MAYBE_UNUSED Face & face, Error &e)
   242 {
   243 #ifdef GRAPHITE2_TELEMETRY
   244     telemetry::category _states_cat(face.tele.starts);
   245 #endif
   246     m_startStates = gralloc<uint16>(m_maxPreCtxt - m_minPreCtxt + 1);
   247 #ifdef GRAPHITE2_TELEMETRY
   248     telemetry::set_category(face.tele.states);
   249 #endif
   250     m_states      = gralloc<State>(m_numStates);
   251 #ifdef GRAPHITE2_TELEMETRY
   252     telemetry::set_category(face.tele.transitions);
   253 #endif
   254     m_transitions      = gralloc<uint16>(m_numTransition * m_numColumns);
   256     if (e.test(!m_startStates || !m_states || !m_transitions, E_OUTOFMEM)) return face.error(e);
   257     // load start states
   258     for (uint16 * s = m_startStates,
   259                 * const s_end = s + m_maxPreCtxt - m_minPreCtxt + 1; s != s_end; ++s)
   260     {
   261         *s = be::read<uint16>(starts);
   262         if (e.test(*s >= m_numStates, E_BADSTATE))
   263         {
   264             face.error_context((face.error_context() & 0xFFFF00) + EC_ASTARTS + ((s - m_startStates) << 24));
   265             return face.error(e); // true;
   266         }
   267     }
   269     // load state transition table.
   270     for (uint16 * t = m_transitions,
   271                 * const t_end = t + m_numTransition*m_numColumns; t != t_end; ++t)
   272     {
   273         *t = be::read<uint16>(states);
   274         if (e.test(*t >= m_numStates, E_BADSTATE))
   275         {
   276             face.error_context((face.error_context() & 0xFFFF00) + EC_ATRANS + (((t - m_transitions) / m_numColumns) << 24));
   277             return face.error(e);
   278         }
   279     }
   281     State * s = m_states,
   282           * const success_begin = m_states + m_numStates - m_numSuccess;
   283     const RuleEntry * rule_map_end = m_ruleMap + be::peek<uint16>(o_rule_map + m_numSuccess*sizeof(uint16));
   284     for (size_t n = m_numStates; n; --n, ++s)
   285     {
   286         RuleEntry * const begin = s < success_begin ? 0 : m_ruleMap + be::read<uint16>(o_rule_map),
   287                   * const end   = s < success_begin ? 0 : m_ruleMap + be::peek<uint16>(o_rule_map);
   289         if (e.test(begin >= rule_map_end || end > rule_map_end || begin > end, E_BADRULEMAPPING))
   290         {
   291             face.error_context((face.error_context() & 0xFFFF00) + EC_ARULEMAP + (n << 24));
   292             return face.error(e);
   293         }
   294         s->rules = begin;
   295         s->rules_end = (end - begin <= FiniteStateMachine::MAX_RULES)? end :
   296             begin + FiniteStateMachine::MAX_RULES;
   297         qsort(begin, end - begin, sizeof(RuleEntry), &cmpRuleEntry);
   298     }
   300     return true;
   301 }
   303 bool Pass::readRanges(const byte * ranges, size_t num_ranges, Error &e)
   304 {
   305     m_cols = gralloc<uint16>(m_numGlyphs);
   306     if (e.test(!m_cols, E_OUTOFMEM)) return false;
   307     memset(m_cols, 0xFF, m_numGlyphs * sizeof(uint16));
   308     for (size_t n = num_ranges; n; --n)
   309     {
   310         uint16     * ci     = m_cols + be::read<uint16>(ranges),
   311                    * ci_end = m_cols + be::read<uint16>(ranges) + 1,
   312                      col    = be::read<uint16>(ranges);
   314         if (e.test(ci >= ci_end || ci_end > m_cols+m_numGlyphs || col >= m_numColumns, E_BADRANGE))
   315             return false;
   317         // A glyph must only belong to one column at a time
   318         while (ci != ci_end && *ci == 0xffff)
   319             *ci++ = col;
   321         if (e.test(ci != ci_end, E_BADRANGE))
   322             return false;
   323     }
   324     return true;
   325 }
   328 void Pass::runGraphite(Machine & m, FiniteStateMachine & fsm) const
   329 {
   330     Slot *s = m.slotMap().segment.first();
   331     if (!s || !testPassConstraint(m)) return;
   332     Slot *currHigh = s->next();
   334 #if !defined GRAPHITE2_NTRACING
   335     if (fsm.dbgout)  *fsm.dbgout << "rules" << json::array;
   336     json::closer rules_array_closer(fsm.dbgout);
   337 #endif
   339     m.slotMap().highwater(currHigh);
   340     int lc = m_iMaxLoop;
   341     do
   342     {
   343         findNDoRule(s, m, fsm);
   344         if (s && (m.slotMap().highpassed() || s == m.slotMap().highwater() || --lc == 0)) {
   345             if (!lc)
   346             {
   347 //              if (dbgout) *dbgout << json::item << json::flat << rule_event(-1, s, 1);
   348                 s = m.slotMap().highwater();
   349             }
   350             lc = m_iMaxLoop;
   351             if (s)
   352                 m.slotMap().highwater(s->next());
   353         }
   354     } while (s);
   355 }
   357 bool Pass::runFSM(FiniteStateMachine& fsm, Slot * slot) const
   358 {
   359     fsm.reset(slot, m_maxPreCtxt);
   360     if (fsm.slots.context() < m_minPreCtxt)
   361         return false;
   363     uint16 state = m_startStates[m_maxPreCtxt - fsm.slots.context()];
   364     uint8  free_slots = SlotMap::MAX_SLOTS;
   365     do
   366     {
   367         fsm.slots.pushSlot(slot);
   368         if (--free_slots == 0
   369          || slot->gid() >= m_numGlyphs
   370          || m_cols[slot->gid()] == 0xffffU
   371          || state >= m_numTransition)
   372             return free_slots != 0;
   374         const uint16 * transitions = m_transitions + state*m_numColumns;
   375         state = transitions[m_cols[slot->gid()]];
   376         if (state >= m_successStart)
   377             fsm.rules.accumulate_rules(m_states[state]);
   379         slot = slot->next();
   380     } while (state != 0 && slot);
   382     fsm.slots.pushSlot(slot);
   383     return true;
   384 }
   386 #if !defined GRAPHITE2_NTRACING
   388 inline
   389 Slot * input_slot(const SlotMap &  slots, const int n)
   390 {
   391     Slot * s = slots[slots.context() + n];
   392     if (!s->isCopied())     return s;
   394     return s->prev() ? s->prev()->next() : (s->next() ? s->next()->prev() : slots.segment.last());
   395 }
   397 inline
   398 Slot * output_slot(const SlotMap &  slots, const int n)
   399 {
   400     Slot * s = slots[slots.context() + n - 1];
   401     return s ? s->next() : slots.segment.first();
   402 }
   404 #endif //!defined GRAPHITE2_NTRACING
   406 void Pass::findNDoRule(Slot * & slot, Machine &m, FiniteStateMachine & fsm) const
   407 {
   408     assert(slot);
   410     if (runFSM(fsm, slot))
   411     {
   412         // Search for the first rule which passes the constraint
   413         const RuleEntry *        r = fsm.rules.begin(),
   414                         * const re = fsm.rules.end();
   415         while (r != re && !testConstraint(*r->rule, m)) ++r;
   417 #if !defined GRAPHITE2_NTRACING
   418         if (fsm.dbgout)
   419         {
   420             if (fsm.rules.size() != 0)
   421             {
   422                 *fsm.dbgout << json::item << json::object;
   423                 dumpRuleEventConsidered(fsm, *r);
   424                 if (r != re)
   425                 {
   426                     const int adv = doAction(r->rule->action, slot, m);
   427                     dumpRuleEventOutput(fsm, *r->rule, slot);
   428                     if (r->rule->action->deletes()) fsm.slots.collectGarbage();
   429                     adjustSlot(adv, slot, fsm.slots);
   430                     *fsm.dbgout << "cursor" << objectid(dslot(&fsm.slots.segment, slot))
   431                             << json::close; // Close RuelEvent object
   433                     return;
   434                 }
   435                 else
   436                 {
   437                     *fsm.dbgout << json::close  // close "considered" array
   438                             << "output" << json::null
   439                             << "cursor" << objectid(dslot(&fsm.slots.segment, slot->next()))
   440                             << json::close;
   441                 }
   442             }
   443         }
   444         else
   445 #endif
   446         {
   447             if (r != re)
   448             {
   449                 const int adv = doAction(r->rule->action, slot, m);
   450                 if (r->rule->action->deletes()) fsm.slots.collectGarbage();
   451                 adjustSlot(adv, slot, fsm.slots);
   452                 return;
   453             }
   454         }
   455     }
   457     slot = slot->next();
   458 }
   460 #if !defined GRAPHITE2_NTRACING
   462 void Pass::dumpRuleEventConsidered(const FiniteStateMachine & fsm, const RuleEntry & re) const
   463 {
   464     *fsm.dbgout << "considered" << json::array;
   465     for (const RuleEntry *r = fsm.rules.begin(); r != &re; ++r)
   466     {
   467         if (r->rule->preContext > fsm.slots.context())  continue;
   468     *fsm.dbgout << json::flat << json::object
   469                     << "id"     << r->rule - m_rules
   470                     << "failed" << true
   471                     << "input" << json::flat << json::object
   472                         << "start" << objectid(dslot(&fsm.slots.segment, input_slot(fsm.slots, -r->rule->preContext)))
   473                         << "length" << r->rule->sort
   474                         << json::close  // close "input"
   475                     << json::close; // close Rule object
   476     }
   477 }
   480 void Pass::dumpRuleEventOutput(const FiniteStateMachine & fsm, const Rule & r, Slot * const last_slot) const
   481 {
   482     *fsm.dbgout     << json::item << json::flat << json::object
   483                         << "id"     << &r - m_rules
   484                         << "failed" << false
   485                         << "input" << json::flat << json::object
   486                             << "start" << objectid(dslot(&fsm.slots.segment, input_slot(fsm.slots, 0)))
   487                             << "length" << r.sort - r.preContext
   488                             << json::close // close "input"
   489                         << json::close  // close Rule object
   490                 << json::close // close considered array
   491                 << "output" << json::object
   492                     << "range" << json::flat << json::object
   493                         << "start"  << objectid(dslot(&fsm.slots.segment, input_slot(fsm.slots, 0)))
   494                         << "end"    << objectid(dslot(&fsm.slots.segment, last_slot))
   495                     << json::close // close "input"
   496                     << "slots"  << json::array;
   497     const Position rsb_prepos = last_slot ? last_slot->origin() : fsm.slots.segment.advance();
   498     fsm.slots.segment.positionSlots(0);
   500     for(Slot * slot = output_slot(fsm.slots, 0); slot != last_slot; slot = slot->next())
   501         *fsm.dbgout     << dslot(&fsm.slots.segment, slot);
   502     *fsm.dbgout         << json::close  // close "slots"
   503                     << "postshift"  << (last_slot ? last_slot->origin() : fsm.slots.segment.advance()) - rsb_prepos
   504                 << json::close;         // close "output" object
   506 }
   508 #endif
   511 inline
   512 bool Pass::testPassConstraint(Machine & m) const
   513 {
   514     if (!m_cPConstraint) return true;
   516     assert(m_cPConstraint.constraint());
   518     m.slotMap().reset(*m.slotMap().segment.first(), 0);
   519     m.slotMap().pushSlot(m.slotMap().segment.first());
   520     vm::slotref * map = m.slotMap().begin();
   521     const uint32 ret = m_cPConstraint.run(m, map);
   523 #if !defined GRAPHITE2_NTRACING
   524     json * const dbgout = m.slotMap().segment.getFace()->logger();
   525     if (dbgout)
   526         *dbgout << "constraint" << (ret && m.status() == Machine::finished);
   527 #endif
   529     return ret && m.status() == Machine::finished;
   530 }
   533 bool Pass::testConstraint(const Rule & r, Machine & m) const
   534 {
   535     const uint16 curr_context = m.slotMap().context();
   536     if (unsigned(r.sort - r.preContext) > m.slotMap().size() - curr_context
   537         || curr_context - r.preContext < 0) return false;
   538     if (!*r.constraint) return true;
   539     assert(r.constraint->constraint());
   541     vm::slotref * map = m.slotMap().begin() + curr_context - r.preContext;
   542     for (int n = r.sort; n && map; --n, ++map)
   543     {
   544         if (!*map) continue;
   545         const int32 ret = r.constraint->run(m, map);
   546         if (!ret || m.status() != Machine::finished)
   547             return false;
   548     }
   550     return true;
   551 }
   554 void SlotMap::collectGarbage()
   555 {
   556     for(Slot **s = begin(), *const *const se = end() - 1; s != se; ++s) {
   557         Slot *& slot = *s;
   558         if(slot->isDeleted() || slot->isCopied())
   559             segment.freeSlot(slot);
   560     }
   561 }
   565 int Pass::doAction(const Code *codeptr, Slot * & slot_out, vm::Machine & m) const
   566 {
   567     assert(codeptr);
   568     if (!*codeptr) return 0;
   569     SlotMap   & smap = m.slotMap();
   570     vm::slotref * map = &smap[smap.context()];
   571     smap.highpassed(false);
   573     int32 ret = codeptr->run(m, map);
   575     if (m.status() != Machine::finished)
   576     {
   577         slot_out = NULL;
   578         smap.highwater(0);
   579         return 0;
   580     }
   582     slot_out = *map;
   583     return ret;
   584 }
   587 void Pass::adjustSlot(int delta, Slot * & slot_out, SlotMap & smap) const
   588 {
   589     if (delta < 0)
   590     {
   591         if (!slot_out)
   592         {
   593             slot_out = smap.segment.last();
   594             ++delta;
   595             if (smap.highpassed() && !smap.highwater())
   596                 smap.highpassed(false);
   597         }
   598         while (++delta <= 0 && slot_out)
   599         {
   600             if (smap.highpassed() && smap.highwater() == slot_out)
   601                 smap.highpassed(false);
   602             slot_out = slot_out->prev();
   603         }
   604     }
   605     else if (delta > 0)
   606     {
   607         if (!slot_out)
   608         {
   609             slot_out = smap.segment.first();
   610             --delta;
   611         }
   612         while (--delta >= 0 && slot_out)
   613         {
   614             slot_out = slot_out->next();
   615             if (slot_out == smap.highwater() && slot_out)
   616                 smap.highpassed(true);
   617         }
   618     }
   619 }

mercurial