PageRenderTime 91ms CodeModel.GetById 12ms app.highlight 68ms RepoModel.GetById 1ms app.codeStats 1ms

/js/src/tracejit/Writer.cpp

http://github.com/zpao/v8monkey
C++ | 592 lines | 341 code | 67 blank | 184 comment | 109 complexity | f978b4d3c7cbbabab336e0ca8740973f MD5 | raw file
  1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
  2 * vim: set ts=4 sw=4 et tw=99 ft=cpp:
  3 *
  4 * ***** BEGIN LICENSE BLOCK *****
  5 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
  6 *
  7 * The contents of this file are subject to the Mozilla Public License Version
  8 * 1.1 (the "License"); you may not use this file except in compliance with
  9 * the License. You may obtain a copy of the License at
 10 * http://www.mozilla.org/MPL/
 11 *
 12 * Software distributed under the License is distributed on an "AS IS" basis,
 13 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
 14 * for the specific language governing rights and limitations under the
 15 * License.
 16 *
 17 * The Original Code is Mozilla SpiderMonkey JavaScript 1.9 code, released
 18 * May 28, 2008.
 19 *
 20 * The Initial Developer of the Original Code is
 21 *   the Mozilla Corporation.
 22 *
 23 * Contributor(s):
 24 *   Nicholas Nethercote <nnethercote@mozilla.com>
 25 *
 26 * Alternatively, the contents of this file may be used under the terms of
 27 * either of the GNU General Public License Version 2 or later (the "GPL"),
 28 * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
 29 * in which case the provisions of the GPL or the LGPL are applicable instead
 30 * of those above. If you wish to allow use of your version of this file only
 31 * under the terms of either the GPL or the LGPL, and not to allow others to
 32 * use your version of this file under the terms of the MPL, indicate your
 33 * decision by deleting the provisions above and replace them with the notice
 34 * and other provisions required by the GPL or the LGPL. If you do not delete
 35 * the provisions above, a recipient may use your version of this file under
 36 * the terms of any one of the MPL, the GPL or the LGPL.
 37 *
 38 * ***** END LICENSE BLOCK ***** */
 39
 40#include "jsprf.h"
 41
 42#include "jscompartment.h"
 43#include "jsiter.h"
 44#include "Writer.h"
 45#include "nanojit.h"
 46#include "jsobjinlines.h"
 47
 48#include "vm/ArgumentsObject.h"
 49
 50namespace js {
 51namespace tjit {
 52
 53using namespace nanojit;
 54
 55class FuncFilter : public LirWriter
 56{
 57public:
 58    FuncFilter(LirWriter *out):
 59        LirWriter(out)
 60    {
 61    }
 62
 63    LIns *ins2(LOpcode v, LIns *s0, LIns *s1)
 64    {
 65        if (s0 == s1 && v == LIR_eqd) {
 66            // 'eqd x, x' will always succeed if 'x' cannot be NaN
 67            if (IsPromotedInt32OrUint32(s0)) {
 68                // x = <a number that fits in int32 or uint32>      # cannot be NaN
 69                // c = eqd x, x
 70                return insImmI(1);
 71            }
 72            if (s0->isop(LIR_addd) || s0->isop(LIR_subd) || s0->isop(LIR_muld)) {
 73                LIns *lhs = s0->oprnd1();
 74                LIns *rhs = s0->oprnd2();
 75                if (IsPromotedInt32OrUint32(lhs) && IsPromotedInt32OrUint32(rhs)) {
 76                    // a = <a number that fits in int32 or uint32>  # cannot be NaN
 77                    // b = <a number that fits in int32 or uint32>  # cannot be NaN
 78                    // x = addd/subd/muld a, b                      # cannot be NaN
 79                    // c = eqd x, x
 80                    return insImmI(1);
 81                }
 82            }
 83        } else if (isCmpDOpcode(v)) {
 84            if (IsPromotedInt32(s0) && IsPromotedInt32(s1)) {
 85                v = cmpOpcodeD2I(v);
 86                return out->ins2(v, DemoteToInt32(out, s0), DemoteToInt32(out, s1));
 87            } else if (IsPromotedUint32(s0) && IsPromotedUint32(s1)) {
 88                // uint compare
 89                v = cmpOpcodeD2UI(v);
 90                return out->ins2(v, DemoteToUint32(out, s0), DemoteToUint32(out, s1));
 91            }
 92        }
 93        return out->ins2(v, s0, s1);
 94    }
 95};
 96
 97void
 98Writer::init(LogControl *logc_, Config *njConfig_)
 99{
100    JS_ASSERT(logc_ && njConfig_);
101    logc = logc_;
102    njConfig = njConfig_;
103
104    LirWriter *&lir = InitConst(this->lir);
105    CseFilter *&cse = InitConst(this->cse);
106    lir = new (alloc) LirBufWriter(lirbuf, *njConfig);
107#ifdef DEBUG
108    ValidateWriter *validate2;
109    lir = validate2 =
110        new (alloc) ValidateWriter(lir, lirbuf->printer, "end of writer pipeline");
111#endif
112#ifdef JS_JIT_SPEW
113    if (logc->lcbits & LC_TMRecorder)
114       lir = new (alloc) VerboseWriter(*alloc, lir, lirbuf->printer, logc);
115#endif
116    // CseFilter must be downstream of SoftFloatFilter (see bug 527754 for why).
117    if (njConfig->cseopt)
118        cse = new (alloc) CseFilter(lir, TM_NUM_USED_ACCS, *alloc);
119        if (!cse->initOOM)
120            lir = cse;      // Skip CseFilter if we OOM'd when creating it.
121    lir = new (alloc) ExprFilter(lir);
122    lir = new (alloc) FuncFilter(lir);
123#ifdef DEBUG
124    ValidateWriter *validate1 =
125        new (alloc) ValidateWriter(lir, lirbuf->printer, "start of writer pipeline");
126    lir = validate1;
127#endif
128}
129
130bool
131IsPromotedInt32(LIns* ins)
132{
133    if (ins->isop(LIR_i2d))
134        return true;
135    if (ins->isImmD()) {
136        jsdouble d = ins->immD();
137        return d == jsdouble(jsint(d)) && !JSDOUBLE_IS_NEGZERO(d);
138    }
139    return false;
140}
141
142bool
143IsPromotedUint32(LIns* ins)
144{
145    if (ins->isop(LIR_ui2d))
146        return true;
147    if (ins->isImmD()) {
148        jsdouble d = ins->immD();
149        return d == jsdouble(jsuint(d)) && !JSDOUBLE_IS_NEGZERO(d);
150    }
151    return false;
152}
153
154bool
155IsPromotedInt32OrUint32(LIns* ins)
156{
157    return IsPromotedInt32(ins) || IsPromotedUint32(ins);
158}
159
160LIns *
161DemoteToInt32(LirWriter *out, LIns *ins)
162{
163    JS_ASSERT(IsPromotedInt32(ins));
164    if (ins->isop(LIR_i2d))
165        return ins->oprnd1();
166    JS_ASSERT(ins->isImmD());
167    return out->insImmI(int32_t(ins->immD()));
168}
169
170LIns *
171DemoteToUint32(LirWriter *out, LIns *ins)
172{
173    JS_ASSERT(IsPromotedUint32(ins));
174    if (ins->isop(LIR_ui2d))
175        return ins->oprnd1();
176    JS_ASSERT(ins->isImmD());
177    return out->insImmI(uint32_t(ins->immD()));
178}
179
180}   /* namespace tjit */
181}   /* namespace js */
182
183#ifdef DEBUG
184namespace nanojit {
185
186using namespace js;
187using namespace js::tjit;
188
189static bool
190match(LIns *base, LOpcode opcode, AccSet accSet, int32_t disp)
191{
192    return base->isop(opcode) &&
193           base->accSet() == accSet &&
194           base->disp() == disp;
195}
196
197static bool
198match(LIns *base, LOpcode opcode, AccSet accSet, LoadQual loadQual, int32_t disp)
199{
200    return base->isop(opcode) &&
201           base->accSet() == accSet &&
202           base->loadQual() == loadQual &&
203           base->disp() == disp;
204}
205
206static bool
207couldBeObjectOrString(LIns *ins)
208{
209    bool ret = false;
210
211    if (ins->isop(LIR_callp)) {
212        // ins = callp ...      # could be a call to an object-creating function
213        ret = true;
214
215    } else if (ins->isop(LIR_ldp)) {
216        // ins = ldp ...        # could be an object, eg. loaded from the stack
217        ret = true;
218
219    } else if (ins->isImmP()) {
220        // ins = immp ...       # could be a pointer to an object
221        uintptr_t val = uintptr_t(ins->immP());
222        if (val == 0 || val > 4096)
223            ret = true;         // Looks like a pointer
224
225    } else if (ins->isop(LIR_cmovp)) {
226        // ins = cmovp <JSObject>, <JSObject>
227        ret = couldBeObjectOrString(ins->oprnd2()) &&
228              couldBeObjectOrString(ins->oprnd3());
229
230    } else if (ins->isop(LIR_ori) &&
231               ins->oprnd1()->isop(LIR_andi) &&
232               ins->oprnd2()->isop(LIR_andi))
233    {
234        // This is a partial check for the insChoose() code that only occurs
235        // is use_cmov() is false.
236        //
237        // ins_oprnd1 = andi ...
238        // ins_oprnd2 = andi ...
239        // ins = ori ins_oprnd1, ins_oprnd2
240        ret = true;
241
242#if JS_BITS_PER_WORD == 64
243    } else if (ins->isop(LIR_andq) &&
244               ins->oprnd1()->isop(LIR_ldq) &&
245               ins->oprnd2()->isImmQ() &&
246               uintptr_t(ins->oprnd2()->immQ()) == JSVAL_PAYLOAD_MASK)
247    {
248        // ins_oprnd1 = ldq ...
249        // ins_oprnd2 = immq JSVAL_PAYLOAD_MASK
250        // ins = andq ins_oprnd1, ins_oprnd2
251        ret = true;
252#endif
253    }
254#ifdef JS_HAS_STATIC_STRINGS
255    else if (ins->isop(LIR_addp) &&
256               ((ins->oprnd1()->isImmP() &&
257                 (void *)ins->oprnd1()->immP() == JSAtom::unitStaticTable) ||
258                (ins->oprnd2()->isImmP() &&
259                 (void *)ins->oprnd2()->immP() == JSAtom::unitStaticTable)))
260    {
261        // (String only)
262        // ins = addp ..., JSString::unitStringTable
263        //   OR
264        // ins = addp JSString::unitStringTable, ...
265        ret = true;
266    }
267#endif
268
269    return ret;
270}
271
272static bool
273isConstPrivatePtr(LIns *ins, unsigned slot)
274{
275    uint32 offset = JSObject::getFixedSlotOffset(slot) + sPayloadOffset;
276
277#if JS_BITS_PER_WORD == 32
278    // ins = ldp.slots/c ...[<offset of slot>]
279    return match(ins, LIR_ldp, ACCSET_SLOTS, LOAD_CONST, offset);
280#elif JS_BITS_PER_WORD == 64
281    // ins_oprnd1 = ldp.slots/c ...[<offset of slot>]
282    // ins_oprnd2 = immi 1
283    // ins = lshq ins_oprnd1, ins_oprnd2
284    return ins->isop(LIR_lshq) &&
285           match(ins->oprnd1(), LIR_ldp, ACCSET_SLOTS, LOAD_CONST, offset) &&
286           ins->oprnd2()->isImmI(1);
287#endif
288}
289
290/*
291 * Any time you use an AccSet annotation other than ACCSET_ALL, you are making
292 * a promise to Nanojit about the properties of the annotated load/store/call.
293 * If that annotation is wrong, it could cause rare and subtle bugs.  So this
294 * function does its damnedest to prevent such bugs occurring by carefully
295 * checking every load and store.
296 *
297 * For some access regions, we can check perfectly -- eg. for an ACCSET_STATE
298 * load/store, the base pointer must be 'state'.  For others, we can only
299 * check imperfectly -- eg. for an ACCSET_OBJ_CLASP load/store, we can check that
300 * the base pointer has one of several forms, but it's possible that a
301 * non-object has that form as well.  This imperfect checking is unfortunate
302 * but unavoidable.  Also, multi-region load/store AccSets are not checked,
303 * and so are best avoided (they're rarely needed).  Finally, the AccSet
304 * annotations on calls cannot be checked here;  in some cases they can be
305 * partially checked via assertions (eg. by checking that certain values
306 * are not changed by the function).
307 */
308void ValidateWriter::checkAccSet(LOpcode op, LIns *base, int32_t disp, AccSet accSet)
309{
310    bool ok;
311
312    NanoAssert(accSet != ACCSET_NONE);
313
314    #define dispWithin(Struct) \
315        (0 <= disp && disp < int32_t(sizeof(Struct)))
316
317    switch (accSet) {
318      case ACCSET_STATE:
319        // base = paramp 0 0
320        // ins  = {ld,st}X.state base[<disp within TracerState>]
321        ok = dispWithin(TracerState) && 
322             base->isop(LIR_paramp) &&
323             base->paramKind() == 0 &&
324             base->paramArg() == 0;
325        break;
326
327      case ACCSET_STACK:
328        // base = ldp.state ...[offsetof(TracerState, sp)]
329        // ins  = {ld,st}X.sp base[...]
330        //   OR
331        // base_oprnd1 = ldp.state ...[offsetof(TraceState, sp)]
332        // base        = addp base_oprnd1, ...
333        // ins         = {ld,st}X.sp base[...]
334        ok = match(base, LIR_ldp, ACCSET_STATE, offsetof(TracerState, sp)) ||
335             (base->isop(LIR_addp) &&
336              match(base->oprnd1(), LIR_ldp, ACCSET_STATE, offsetof(TracerState, sp)));
337        break;
338
339      case ACCSET_RSTACK:
340        // base = ldp.state ...[offsetof(TracerState, rp)]
341        // ins  = {ld,st}p.rp base[...]
342        //   OR
343        // base = ldp.state ...[offsetof(TracerState, callstackBaseOffset)]
344        // ins  = {ld,st}p.rp base[...]
345        ok = (op == LIR_ldp || op == LIR_stp) &&
346             (match(base, LIR_ldp, ACCSET_STATE, offsetof(TracerState, rp)) ||
347              match(base, LIR_ldp, ACCSET_STATE, offsetof(TracerState, callstackBase)));
348        break;
349
350      case ACCSET_CX:
351        // base = ldp.state ...[offsetof(TracerState, cx)]
352        // ins  = {ld,st}X.cx base[<disp within JSContext>]
353        ok = dispWithin(JSContext) &&
354             match(base, LIR_ldp, ACCSET_STATE, offsetof(TracerState, cx));
355        break;
356
357      case ACCSET_TM:
358          // base = immp
359          ok = base->isImmP() && disp == 0;
360          break;
361
362      case ACCSET_EOS:
363        // base = ldp.state ...[offsetof(TracerState, eos)]
364        // ins  = {ld,st}X.eos base[...]
365        ok = match(base, LIR_ldp, ACCSET_STATE, offsetof(TracerState, eos));
366        break;
367
368      case ACCSET_ALLOC:
369        // base = allocp ...
370        // ins  = {ld,st}X.alloc base[...]
371        //   OR
372        // base_oprnd1 = allocp ...
373        // base        = addp base_oprnd1, ...
374        // ins         = {ld,st}X.alloc base[...]
375        ok = base->isop(LIR_allocp) ||
376             (base->isop(LIR_addp) &&
377              base->oprnd1()->isop(LIR_allocp));
378        break;
379
380      case ACCSET_FRAMEREGS:
381        // base = ldp.cx ...[offsetof(JSContext, regs)]
382        // ins  = ldp.regs base[<disp within FrameRegs>]
383        ok = op == LIR_ldp &&
384             dispWithin(FrameRegs) && 
385             match(base, LIR_ldp, ACCSET_SEG, StackSegment::offsetOfRegs());
386        break;
387
388      case ACCSET_STACKFRAME:
389        // base = ldp.regs ...[offsetof(FrameRegs, fp)]
390        // ins  = {ld,st}X.sf base[<disp within StackFrame>]
391        ok = dispWithin(StackFrame) && 
392             match(base, LIR_ldp, ACCSET_FRAMEREGS, FrameRegs::offsetOfFp);
393        break;
394
395      case ACCSET_RUNTIME:
396        // base = ldp.cx ...[offsetof(JSContext, runtime)]
397        // ins  = ldp.rt base[<disp within JSRuntime>]
398        ok = dispWithin(JSRuntime) &&
399             match(base, LIR_ldp, ACCSET_CX, offsetof(JSContext, runtime));
400        break;
401
402      // This check is imperfect.
403      //
404      // base = <JSObject>
405      // ins  = ldp.obj<field> base[offsetof(JSObject, <field>)]
406      #define OK_OBJ_FIELD(ldop, field) \
407            ((op == (ldop)) && \
408            (disp == offsetof(JSObject, field)) && \
409            couldBeObjectOrString(base))
410
411      case ACCSET_OBJ_CLASP:
412        ok = OK_OBJ_FIELD(LIR_ldp, clasp);
413        break;
414
415      case ACCSET_OBJ_FLAGS:
416        ok = OK_OBJ_FIELD(LIR_ldi, flags);
417        break;
418
419      case ACCSET_OBJ_SHAPE:
420        ok = OK_OBJ_FIELD(LIR_ldi, objShape);
421        break;
422
423      case ACCSET_OBJ_TYPE:
424        ok = ((op == LIR_ldp) &&
425              disp == (int)JSObject::offsetOfType() &&
426              couldBeObjectOrString(base)) ||
427            (op == LIR_ldp && disp == offsetof(types::TypeObject, proto));
428        break;
429
430      case ACCSET_OBJ_PARENT:
431        ok = OK_OBJ_FIELD(LIR_ldp, parent);
432        break;
433
434      case ACCSET_OBJ_PRIVATE:
435        // base = <JSObject>
436        // ins  = {ld,st}p.objprivate base[offsetof(JSObject, privateData)]
437        ok = (op == LIR_ldi || op == LIR_ldp ||
438              op == LIR_sti || op == LIR_stp) &&
439             disp == offsetof(JSObject, privateData) &&
440             couldBeObjectOrString(base);
441        break;
442
443      case ACCSET_OBJ_CAPACITY:
444        ok = OK_OBJ_FIELD(LIR_ldi, capacity) || OK_OBJ_FIELD(LIR_ldi, initializedLength);
445        break;
446
447      case ACCSET_OBJ_SLOTS:
448        ok = OK_OBJ_FIELD(LIR_ldp, slots);
449        break;
450
451      case ACCSET_SLOTS:
452        // This check is imperfect.
453        //
454        // base = <JSObject>                                          # direct slot access
455        // ins  = {ld,st}X.slots base[...]
456        //   OR
457        // base = ldp.objslots ...[offsetof(JSObject, slots)]         # indirect slot access
458        // ins  = {ld,st}X.slots base[...]
459        //   OR
460        // base_oprnd1 = ldp.objslots ...[offsetof(JSObject, slots)]  # indirect scaled slot access
461        // base        = addp base_oprnd1, ...
462        // ins         = {ld,st}X.slots base[...]
463        ok = couldBeObjectOrString(base) ||
464             match(base, LIR_ldp, ACCSET_OBJ_SLOTS, offsetof(JSObject, slots)) ||
465             (base->isop(LIR_addp) &&
466              match(base->oprnd1(), LIR_ldp, ACCSET_OBJ_SLOTS, offsetof(JSObject, slots)));
467        break;
468
469      case ACCSET_TARRAY:
470        // we actually just want the JSObject itself
471        // This check is imperfect.
472        //
473        // base = ldp.objprivate ...[offsetof(JSObject, privateData)]
474        // ins = ld{i,p}.tarray base[<disp within TypedArray>]
475        ok = (op == LIR_ldi || op == LIR_ldp); /*&&*/
476             //match(base, LIR_ldp, ACCSET_OBJ_SLOTS, offsetof(JSObject, slots));
477        break;
478
479      case ACCSET_TARRAY_DATA:
480        // base = ldp.tarray/c ...[TypedArray::dataOffset()]
481        // ins  = {ld,st}X.tdata base[...]
482        //   OR
483        // base_oprnd1 = ldp.tarray/c ...[TypedArray::dataOffset()]
484        // base        = addp base_oprnd1, ...
485        // ins         = {ld,st}X.tdata base[...]
486        ok = true;
487        //ok = isConstPrivatePtr(base, TypedArray::FIELD_DATA);
488        JS_ASSERT(ok);
489        //ok = match(base, LIR_ldp, ACCSET_TARRAY, LOAD_CONST,  sizeof(js::Value) * js::TypedArray::FIELD_DATA) ||
490                //((base->isop(LIR_addp) &&
491                //match(base->oprnd1(), LIR_ldp, ACCSET_TARRAY, sizeof(js::Value) * js::TypedArray::FIELD_DATA)));
492        break;
493
494      case ACCSET_ITER:
495        // base = ldp.objprivate ...[offsetof(JSObject, privateData)]
496        // ins = {ld,st}p.iter base[<disp within NativeIterator>]
497        ok = (op == LIR_ldp || op == LIR_stp) &&
498             dispWithin(NativeIterator) &&
499             match(base, LIR_ldp, ACCSET_OBJ_PRIVATE, offsetof(JSObject, privateData));
500        break;
501
502      case ACCSET_ITER_PROPS:
503        // base = ldp.iter ...[offsetof(NativeIterator, props_cursor)]
504        // ins  = ld{i,p,d}.iterprops base[0|4]
505        ok = (op == LIR_ldi || op == LIR_ldp || op == LIR_ldd) &&
506             (disp == 0 || disp == 4) &&
507             match(base, LIR_ldp, ACCSET_ITER, offsetof(NativeIterator, props_cursor));
508        break;
509
510      case ACCSET_STRING:
511        // This check is imperfect.
512        //
513        // base = <JSString>
514        // ins  = {ld,st}X.str base[<disp within JSString>]
515        ok = dispWithin(JSString) &&
516             couldBeObjectOrString(base);
517        break;
518
519      case ACCSET_STRING_MCHARS:
520        // base = ldp.string ...[offsetof(JSString, chars)]
521        // ins  = ldus2ui.strchars/c base[0]
522        //   OR
523        // base_oprnd1 = ldp.string ...[offsetof(JSString, chars)]
524        // base        = addp base_oprnd1, ...
525        // ins         = ldus2ui.strchars/c base[0]
526        ok = op == LIR_ldus2ui &&
527             disp == 0 &&
528             (match(base, LIR_ldp, ACCSET_STRING, JSString::offsetOfChars()) ||
529              (base->isop(LIR_addp) &&
530               match(base->oprnd1(), LIR_ldp, ACCSET_STRING, JSString::offsetOfChars())));
531        break;
532
533      case ACCSET_TYPEMAP:
534        // This check is imperfect, things get complicated once you get back
535        // farther than 'base'.  But the parts we check are pretty distinctive
536        // and should be good enough.
537        //
538        // base = addp base_oprnd1, ...
539        // ins  = lduc2ui.typemap/c base[0]
540        ok = op == LIR_lduc2ui &&
541             disp == 0 &&
542             base->isop(LIR_addp);
543        break;
544
545      case ACCSET_FCSLOTS:
546        // This check is imperfect.
547        //
548        // base = <const private ptr slots[JSSLOT_FLAT_CLOSURE_UPVARS]>
549        // ins = {ld,st}X.fcslots base[...]
550        ok = isConstPrivatePtr(base, JSObject::JSSLOT_FLAT_CLOSURE_UPVARS);
551        break;
552
553      case ACCSET_ARGS_DATA:
554        // This check is imperfect.
555        //
556        // base = <const private ptr slots[JSSLOT_ARGS_DATA]>
557        // ins = st{i,p,d}.argsdata base[...]
558        //   OR
559        // base_oprnd1 = <const private ptr slots[JSSLOT_ARGS_DATA]>
560        // base        = addp base_oprnd1, ...
561        // ins         = {ld,st}X.argsdata base[...]
562        ok = (isConstPrivatePtr(base, ArgumentsObject::DATA_SLOT) ||
563              (base->isop(LIR_addp) &&
564               isConstPrivatePtr(base->oprnd1(), ArgumentsObject::DATA_SLOT)));
565        break;
566
567      case ACCSET_SEG:
568        // Match the ACCSET_SEG load that comes out of ldpContextRegs
569        ok = dispWithin(StackSegment) &&
570             match(base, LIR_ldp, ACCSET_CX, offsetof(JSContext, stack) + ContextStack::offsetOfSeg());
571        break;
572
573      default:
574        // This assertion will fail if any single-region AccSets aren't covered
575        // by the switch -- only multi-region AccSets should be handled here.
576        JS_ASSERT(!isSingletonAccSet(accSet));
577        ok = true;
578        break;
579    }
580
581    if (!ok) {
582        InsBuf b1, b2;
583        printer->formatIns(&b1, base);
584        JS_snprintf(b2.buf, b2.len, "base = (%s); disp = %d", b1.buf, disp);
585        errorAccSet(lirNames[op], accSet, b2.buf);
586    }
587}
588
589} // namespace nanojit
590
591#endif
592