Imported Upstream version 1.0.0
[platform/upstream/js.git] / js / src / tracejit / Writer.h
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 #ifndef tracejit_Writer_h___
41 #define tracejit_Writer_h___
42
43 #include "jsiter.h"
44 #include "jsobj.h"
45 #include "jsstr.h"
46 #include "jstypedarray.h"
47 #include "nanojit.h"
48
49 namespace js {
50 namespace tjit {
51
52 namespace nj = nanojit;
53
54 #if defined(DEBUG) && !defined(JS_JIT_SPEW)
55 #define JS_JIT_SPEW
56 #endif
57
58 #if defined(JS_JIT_SPEW) || defined(NJ_NO_VARIADIC_MACROS)
59
60 enum LC_TMBits {
61     /*
62      * Output control bits for all non-Nanojit code.  Only use bits 16 and
63      * above, since Nanojit uses 0 .. 15 itself.
64      */
65     LC_TMMinimal  = 1<<16,
66     LC_TMTracer   = 1<<17,
67     LC_TMRecorder = 1<<18,
68     LC_TMAbort    = 1<<19,
69     LC_TMStats    = 1<<20,
70     LC_TMTreeVis  = 1<<21,
71     LC_TMProfiler = 1<<22
72 };
73
74 #endif
75
76 /*
77  * See LIR.h for the definition of the AccSet type.
78  *
79  * *** WARNING WARNING WARNING ***
80  *
81  * Any incorrect access region annotations on loads/stores/calls could lead to
82  * subtle bugs that manifest rarely, eg. when two loads are CSE'd that
83  * shouldn't be.
84  *
85  * If you add a new access region you will need to add some sanity checking to
86  * ValidateWriter::checkAccSet().  Do not skimp on this checking!  Make it as
87  * strong as you can.  Look at the existing cases for inspiration.  This
88  * checking helps prevent these subtle bugs.
89  *
90  * Furthermore, do not add a "catch-all" region such as "ACCSET_OTHER".  There
91  * are two reasons for this.  First, no checking could be done on loads/stores
92  * bearing it.  Second, it would be too easy for someone in the future who
93  * doesn't understand how AccSets work to use it inappropriately.  Only
94  * ACCSET_ALL (the union of all access regions) should be used as a catch-all,
95  * it can always be used safely, but it reduces optimization possibilities.
96  *
97  * Most of the access regions are type-based, ie. all structs of a particular
98  * type combined together form a region.  This is less precise than
99  * considering each struct separately, but also much simpler.
100  *
101  * - ACCSET_STATE:         The TracerState struct.
102  * - ACCSET_STACK:         The stack.
103  * - ACCSET_RSTACK:        The return stack.
104  * - ACCSET_CX:            All JSContext structs.
105  * - ACCSET_TM:            All TraceMonitor structs.
106  * - ACCSET_EOS:           The globals area.
107  * - ACCSET_ALLOC:         All memory blocks allocated with LIR_allocp (in
108  *                         other words, this region is the AR space).
109  * - ACCSET_FRAMEREGS:     All JSFrameRegs structs.
110  * - ACCSET_STACKFRAME:    All JSStackFrame objects.
111  * - ACCSET_RUNTIME:       The JSRuntime object.
112  * - ACCSET_OBJ_CLASP:     The 'clasp'    field of all JSObjects.
113  * - ACCSET_OBJ_FLAGS:     The 'flags'    field of all JSObjects.
114  * - ACCSET_OBJ_SHAPE:     The 'shape'    field of all JSObjects.
115  * - ACCSET_OBJ_PROTO:     The 'proto'    field of all JSObjects.
116  * - ACCSET_OBJ_PARENT:    The 'parent'   field of all JSObjects.
117  * - ACCSET_OBJ_PRIVATE:   The 'private'  field of all JSObjects.
118  * - ACCSET_OBJ_CAPACITY:  The 'capacity' field of all JSObjects.
119  * - ACCSET_OBJ_SLOTS:     The 'slots'    field of all JSObjects.
120  * - ACCSET_SLOTS:         The slots (be they fixed or dynamic) of all JSObjects.
121  * - ACCSET_TARRAY:        All TypedArray structs.
122  * - ACCSET_TARRAY_DATA:   All TypedArray data arrays.
123  * - ACCSET_ITER:          All NativeIterator structs.
124  * - ACCSET_ITER_PROPS:    The props_arrays of all NativeIterator structs.
125  * - ACCSET_STRING:        All JSString structs.
126  * - ACCSET_STRING_MCHARS: All JSString mchars arrays.
127  * - ACCSET_TYPEMAP:       All typemaps form a single region.
128  * - ACCSET_FCSLOTS:       All fcslots arrays form a single region.
129  * - ACCSET_ARGS_DATA:     All Arguments data arrays form a single region.
130  */
131 static const nanojit::AccSet ACCSET_STATE         = (1 <<  0);
132 static const nanojit::AccSet ACCSET_STACK         = (1 <<  1);
133 static const nanojit::AccSet ACCSET_RSTACK        = (1 <<  2);
134 static const nanojit::AccSet ACCSET_CX            = (1 <<  3);
135 static const nanojit::AccSet ACCSET_TM            = (1 <<  4);
136 static const nanojit::AccSet ACCSET_EOS           = (1 <<  5);
137 static const nanojit::AccSet ACCSET_ALLOC         = (1 <<  6);
138 static const nanojit::AccSet ACCSET_FRAMEREGS     = (1 <<  7);
139 static const nanojit::AccSet ACCSET_STACKFRAME    = (1 <<  8);
140 static const nanojit::AccSet ACCSET_RUNTIME       = (1 <<  9);
141
142 // Nb: JSObject::{lastProp,map,flags} don't have an AccSet because they are never accessed on trace
143 static const nanojit::AccSet ACCSET_OBJ_CLASP     = (1 << 10);
144 static const nanojit::AccSet ACCSET_OBJ_FLAGS     = (1 << 11);
145 static const nanojit::AccSet ACCSET_OBJ_SHAPE     = (1 << 12);
146 static const nanojit::AccSet ACCSET_OBJ_PROTO     = (1 << 13);
147 static const nanojit::AccSet ACCSET_OBJ_PARENT    = (1 << 14);
148 static const nanojit::AccSet ACCSET_OBJ_PRIVATE   = (1 << 15);
149 static const nanojit::AccSet ACCSET_OBJ_CAPACITY  = (1 << 16);
150 static const nanojit::AccSet ACCSET_OBJ_SLOTS     = (1 << 17);  // the pointer to the slots
151
152 static const nanojit::AccSet ACCSET_SLOTS         = (1 << 18);  // the slots themselves
153 static const nanojit::AccSet ACCSET_TARRAY        = (1 << 19);
154 static const nanojit::AccSet ACCSET_TARRAY_DATA   = (1 << 20);
155 static const nanojit::AccSet ACCSET_ITER          = (1 << 21);
156 static const nanojit::AccSet ACCSET_ITER_PROPS    = (1 << 22);
157 static const nanojit::AccSet ACCSET_STRING        = (1 << 23);
158 static const nanojit::AccSet ACCSET_STRING_MCHARS = (1 << 24);
159 static const nanojit::AccSet ACCSET_TYPEMAP       = (1 << 25);
160 static const nanojit::AccSet ACCSET_FCSLOTS       = (1 << 26);
161 static const nanojit::AccSet ACCSET_ARGS_DATA     = (1 << 27);
162
163 static const uint8_t TM_NUM_USED_ACCS = 28; // number of access regions used by TraceMonkey
164
165 /*
166  * An Address describes everything about a loaded/stored memory location.  One
167  * only be created via the sub-classes below and only accessed via class
168  * Writer;  this is so that AccSets are encapsulated as much as possible.
169  */
170 struct Address
171 {
172   friend class Writer;
173
174   private:
175     nj::LIns *base;
176     int32 offset;
177     nj::AccSet accSet;
178
179   protected:
180     Address(nj::LIns *base, int32 offset, nj::AccSet accSet)
181       : base(base), offset(offset), accSet(accSet) {}
182
183     Address(Address addr, int32 offset)
184       : base(addr.base), offset(addr.offset + offset), accSet(addr.accSet) {}
185
186   public:
187     Address() {}
188 };
189
190
191 /* Addresses, ordered by AccSet. */
192
193 struct StackAddress : Address 
194 {
195     StackAddress(nj::LIns *base, int32 offset)
196       : Address(base, offset, ACCSET_STACK) {}
197 };
198
199 struct CxAddress : Address
200 {
201     CxAddress(nj::LIns *base, int32 offset)
202       : Address(base, offset, ACCSET_CX) {}
203 };
204 #define CxAddress(fieldname) \
205     CxAddress(cx_ins, offsetof(JSContext, fieldname))
206
207 struct EosAddress : Address
208 {
209     EosAddress(nj::LIns *base, int32 offset)
210       : Address(base, offset, ACCSET_EOS) {}
211 };
212
213 struct AllocSlotsAddress : Address
214 {
215     AllocSlotsAddress(nj::LIns *base, unsigned slot = 0)
216       : Address(base, slot * sizeof(Value), ACCSET_ALLOC) {}
217 };
218
219 struct StackFrameAddress : Address
220 {
221     StackFrameAddress(nj::LIns *base, int32 offset)
222       : Address(base, offset, ACCSET_STACKFRAME) {}
223 };
224
225 struct FSlotsAddress : Address
226 {
227     FSlotsAddress(nj::LIns *base, unsigned slot)
228       : Address(base, JSObject::getFixedSlotOffset(slot), ACCSET_SLOTS) {}
229 };
230
231 struct DSlotsAddress : Address
232 {
233     DSlotsAddress(nj::LIns *base, unsigned slot = 0)
234       : Address(base, slot * sizeof(Value), ACCSET_SLOTS) {}
235 };
236
237 struct IterPropsAddress : Address
238 {
239     IterPropsAddress(nj::LIns *base)
240       : Address(base, 0, ACCSET_ITER_PROPS) {}
241 };
242
243 struct FCSlotsAddress : Address
244 {
245     FCSlotsAddress(nj::LIns *base, unsigned slot = 0)
246       : Address(base, slot * sizeof(Value), ACCSET_FCSLOTS) {}
247 };
248
249 struct ArgsSlotOffsetAddress : Address
250 {
251     ArgsSlotOffsetAddress(nj::LIns *base, unsigned offset = 0)
252       : Address(base, offset, ACCSET_ARGS_DATA) {}
253 };
254
255 struct AnyAddress : Address
256 {
257     AnyAddress(nj::LIns *base, int32 offset = 0)
258       : Address(base, offset, nj::ACCSET_ALL)
259     {
260         JS_ASSERT(nj::ACCSET_LOAD_ANY == nj::ACCSET_STORE_ANY &&
261                   nj::ACCSET_LOAD_ANY == nj::ACCSET_ALL);
262     }
263 };
264
265 /* An offset from a previous Address. */
266 struct OffsetAddress : Address
267 {
268     OffsetAddress(Address addr, int32 offset)
269       : Address(addr, offset) {}
270 };
271
272 bool IsPromotedInt32(nj::LIns *ins);
273 bool IsPromotedUint32(nj::LIns *ins);
274 bool IsPromotedInt32OrUint32(nj::LIns *ins);
275 nj::LIns *DemoteToInt32(nj::LirWriter *out, nj::LIns *ins);
276 nj::LIns *DemoteToUint32(nj::LirWriter *out, nj::LIns *ins);
277
278 /* These would be private to class Writer if they weren't used in AccSet checking. */
279 static const size_t sPayloadOffset = offsetof(jsval_layout, s.payload);
280 #if JS_BITS_PER_WORD == 32
281 static const size_t sTagOffset = offsetof(jsval_layout, s.tag);
282 #endif
283
284 struct MaybeBranch {
285     bool set;
286     nj::LIns *br;
287     MaybeBranch() : set(false), br(NULL) {}
288     MaybeBranch(nj::LIns *ins) : set(true), br(ins) {}
289     operator bool() { return set; }
290     typedef nj::LIns* LInsp;
291     operator LInsp() {
292         JS_ASSERT(set);
293         return br;
294     }
295 };
296
297 /*
298  * This class provides a layer above Nanojit's basic LirWriter interface.
299  * The goals of this layer are as follows.
300  *
301  * - More concise than the vanilla NJ interface, to promote readability. 
302  *
303  * - But still a relatively thin layer.
304  *
305  * - Completely occludes NJ's interface so that there is no possibility of
306  *   using a combination of both interfaces.  This is good because there are
307  *   some cases where the NJ interface is error-prone when used with
308  *   TraceMonkey (eg. when using the NJ interface it's easy to forget to
309  *   handle the cases where a conditional branch is always or never taken).
310  *
311  * - Requires only basic Nanojit state (eg. LirBuffer);  doesn't rely on state
312  *   from TraceRecorder.
313  *
314  * - There should be one or more functions for every opcode that's used (if
315  *   one is missing, please add it), plus minimal generic ones (eg. ins2()).
316  *   This makes for a lot of functions, but promotes readability.
317  *
318  * - Loads/stores get special treatment, due to AccSets.  AccSets aren't
319  *   exposed at all, although someone using the interface will still need to
320  *   understand them;  the goal is not to completely hide their presence but
321  *   to make their use indirect so that it is difficult to get them wrong.
322  *
323  *   Type/field-specific load/store functions are used where possible.  When
324  *   this isn't possible, details about memory locations are abstracted in the
325  *   Address type, which encapsulates a base pointer, an offset and an AccSet.
326  *
327  *   The only place where AccSets need to be used directly is when specifying
328  *   the .storeAccSet of a CallInfo.
329  *
330  * - Functions that insert moderately complex LIR sequences (eg. multiple
331  *   loads) have a 'get' prefix in their name.
332  */
333 class Writer
334 {
335   private:
336     nj::Allocator *alloc;
337     nj::LirBuffer *lirbuf;      // passed in from outside
338     nj::LirWriter *const lir;   // created in this class
339     nj::CseFilter *const cse;   // created in this class
340
341     nj::LogControl *logc;       // passed in from outside
342
343   public:
344     Writer(nj::Allocator *alloc, nj::LirBuffer *lirbuf)
345       : alloc(alloc), lirbuf(lirbuf), lir(NULL), cse(NULL), logc(NULL) {}
346
347     void init(nj::LogControl *logc); 
348
349     nj::LIns *name(nj::LIns *ins, const char *name) const {
350 #ifdef JS_JIT_SPEW
351         /* No point adding names unless .lcbits > 0. */
352         if (logc->lcbits > 0)
353             lirbuf->printer->lirNameMap->addName(ins, name);
354 #endif
355         return ins;
356     }
357
358     /* 
359      * These two don't generate any code, they control the internal state of
360      * the CseFilter.  They can be put around a control-flow diamond if it's
361      * important that CSE work across the diamond.  (If they aren't used, the
362      * diamond will reset all CSE state.)  Duplicated expressions within the
363      * diamond will be CSE'd, but expressions defined within the diamond won't
364      * be added to the tables of CSEable expressions.  Loads are still
365      * invalidated if they alias any stores that occur within diamonds.
366      */
367     void pauseAddingCSEValues()     { if (cse) cse->suspend(); }
368     void resumeAddingCSEValues()    { if (cse) cse->resume();  }
369
370     /* Miscellaneous operations */
371
372     nj::LIns *start() const {
373         return lir->ins0(nj::LIR_start);
374     }
375
376     nj::LIns *paramp(int32 arg, int32 kind) const {
377         return lir->insParam(arg, kind);
378     }
379
380     nj::LIns *allocp(int32 size) const {
381         return lir->insAlloc(size);
382     }
383
384     nj::LIns *livep(nj::LIns *x) const {
385         return lir->ins1(nj::LIR_livep, x);
386     }
387
388     void comment(const char *str) {
389     #ifdef JS_JIT_SPEW
390         lir->insComment(str);  
391     #endif
392     }
393
394     /* Specific loads and stores (those not taking an Address argument).  Ordered by AccSets.*/
395
396     nj::LIns *ldStateFieldHelper(nj::LOpcode op, nj::LIns *state, int32 offset) const {
397         return lir->insLoad(op, state, offset, ACCSET_STATE);
398     }
399     #define ldiStateField(fieldname) \
400         name(w.ldStateFieldHelper(LIR_ldi, lirbuf->state, offsetof(TracerState, fieldname)), \
401              #fieldname)
402     #define ldpStateField(fieldname) \
403         name(w.ldStateFieldHelper(LIR_ldp, lirbuf->state, offsetof(TracerState, fieldname)), \
404              #fieldname)
405
406     nj::LIns *stStateFieldHelper(nj::LIns *value, nj::LIns *state, int32 offset) const {
407         return lir->insStore(value, state, offset, ACCSET_STATE);
408     }
409     #define stStateField(value, fieldname) \
410         stStateFieldHelper(value, lirbuf->state, offsetof(TracerState, fieldname))
411
412     nj::LIns *ldpRstack(nj::LIns *rp, int32 offset) const {
413         return lir->insLoad(nj::LIR_ldp, rp, offset, ACCSET_RSTACK);
414     }
415
416     nj::LIns *stRstack(nj::LIns *value, nj::LIns *rp, int32 offset) const {
417         return lir->insStore(value, rp, offset, ACCSET_RSTACK);
418     }
419
420     nj::LIns *ldpContextFieldHelper(nj::LIns *cx, int32 offset, nj::LoadQual loadQual) const {
421         return lir->insLoad(nj::LIR_ldp, cx, offset, ACCSET_CX, loadQual);
422     }
423     #define ldpContextField(fieldname) \
424         name(w.ldpContextFieldHelper(cx_ins, offsetof(JSContext, fieldname), LOAD_NORMAL), \
425              #fieldname)
426     #define ldpConstContextField(fieldname) \
427         name(w.ldpContextFieldHelper(cx_ins, offsetof(JSContext, fieldname), LOAD_CONST), \
428              #fieldname)
429
430     nj::LIns *stContextField(nj::LIns *value, nj::LIns *cx, int32 offset) const {
431         return lir->insStore(value, cx, offset, ACCSET_CX);
432     }
433     #define stContextField(value, fieldname) \
434         stContextField((value), cx_ins, offsetof(JSContext, fieldname))
435
436     nj::LIns *stTraceMonitorField(nj::LIns *value, void *dest, const char *destName) const {
437         return lir->insStore(value, name(lir->insImmP(dest), destName), 0, ACCSET_TM);
438     }
439     #define stTraceMonitorField(value, fieldname) \
440         stTraceMonitorField(value, &traceMonitor->fieldname, #fieldname)
441
442     nj::LIns *ldiAlloc(nj::LIns *alloc) const {
443         return lir->insLoad(nj::LIR_ldi, alloc, 0, ACCSET_ALLOC);
444     }
445
446     nj::LIns *ldpAlloc(nj::LIns *alloc) const {
447         return lir->insLoad(nj::LIR_ldp, alloc, 0, ACCSET_ALLOC);
448     }
449
450     nj::LIns *lddAlloc(nj::LIns *alloc) const {
451         return lir->insLoad(nj::LIR_ldd, alloc, 0, ACCSET_ALLOC);
452     }
453
454     nj::LIns *stAlloc(nj::LIns *value, nj::LIns *alloc) const {
455         return lir->insStore(value, alloc, 0, ACCSET_ALLOC);
456     }
457
458     nj::LIns *ldpFrameFp(nj::LIns *regs) const {
459         return lir->insLoad(nj::LIR_ldp, regs, offsetof(JSFrameRegs, fp), ACCSET_FRAMEREGS);
460     }
461
462     nj::LIns *ldpStackFrameScopeChain(nj::LIns *frame) const {
463         return lir->insLoad(nj::LIR_ldp, frame, JSStackFrame::offsetOfScopeChain(),
464                             ACCSET_STACKFRAME);
465     }
466
467     nj::LIns *ldiRuntimeProtoHazardShape(nj::LIns *runtime) const {
468         return name(lir->insLoad(nj::LIR_ldi, runtime, offsetof(JSRuntime, protoHazardShape),
469                                  ACCSET_RUNTIME),
470                     "protoHazardShape");
471     }
472
473     nj::LIns *ldpObjClasp(nj::LIns *obj, nj::LoadQual loadQual) const {
474         return name(lir->insLoad(nj::LIR_ldp, obj, offsetof(JSObject, clasp), ACCSET_OBJ_CLASP,
475                                  loadQual),
476                     "clasp");
477     }
478
479     nj::LIns *ldiObjFlags(nj::LIns *obj) const {
480         return name(lir->insLoad(nj::LIR_ldi, obj, offsetof(JSObject, flags), ACCSET_OBJ_FLAGS),
481                     "flags");
482     }
483
484     nj::LIns *ldiObjShape(nj::LIns *obj) const {
485         return name(lir->insLoad(nj::LIR_ldi, obj, offsetof(JSObject, objShape), ACCSET_OBJ_SHAPE),
486                     "objShape");
487     }
488
489     nj::LIns *ldpObjProto(nj::LIns *obj) const {
490         return name(lir->insLoad(nj::LIR_ldp, obj, offsetof(JSObject, proto), ACCSET_OBJ_PROTO),
491                     "proto");
492     }
493
494     nj::LIns *ldpObjParent(nj::LIns *obj) const {
495         return name(lir->insLoad(nj::LIR_ldp, obj, offsetof(JSObject, parent), ACCSET_OBJ_PARENT),
496                     "parent");
497     }
498
499     nj::LIns *ldpObjPrivate(nj::LIns *obj) const {
500         return name(lir->insLoad(nj::LIR_ldp, obj, offsetof(JSObject, privateData),
501                                  ACCSET_OBJ_PRIVATE),
502                     "private");
503     }
504
505     nj::LIns *lduiObjPrivate(nj::LIns *obj) const {
506         return name(lir->insLoad(nj::LIR_ldi, obj, offsetof(JSObject, privateData),
507                                  ACCSET_OBJ_PRIVATE),
508                     "private_uint32");
509     }
510
511     nj::LIns *stuiObjPrivate(nj::LIns *obj, nj::LIns *value) const {
512         return name(lir->insStore(nj::LIR_sti, value, obj, offsetof(JSObject, privateData),
513                                   ACCSET_OBJ_PRIVATE),
514                     "private_uint32");
515     }
516
517     nj::LIns *ldiDenseArrayCapacity(nj::LIns *array) const {
518         return name(lir->insLoad(nj::LIR_ldi, array, offsetof(JSObject, capacity),
519                                  ACCSET_OBJ_CAPACITY),
520                     "capacity");
521     }
522
523     nj::LIns *ldpObjSlots(nj::LIns *obj) const {
524         return name(lir->insLoad(nj::LIR_ldp, obj, offsetof(JSObject, slots), ACCSET_OBJ_SLOTS),
525                     "slots");
526     }
527
528     nj::LIns *ldiConstTypedArrayLength(nj::LIns *array) const {
529         return name(lir->insLoad(nj::LIR_ldi, array, js::TypedArray::lengthOffset(), ACCSET_TARRAY,
530                                  nj::LOAD_CONST),
531                     "typedArrayLength");
532     }
533
534     nj::LIns *ldpConstTypedArrayData(nj::LIns *array) const {
535         return name(lir->insLoad(nj::LIR_ldp, array, js::TypedArray::dataOffset(), ACCSET_TARRAY,
536                                  nj::LOAD_CONST),
537                     "typedElems");
538     }
539
540     nj::LIns *ldc2iTypedArrayElement(nj::LIns *elems, nj::LIns *index) const {
541         return lir->insLoad(nj::LIR_ldc2i, addp(elems, index), 0, ACCSET_TARRAY_DATA);
542     }
543
544     nj::LIns *lduc2uiTypedArrayElement(nj::LIns *elems, nj::LIns *index) const {
545         return lir->insLoad(nj::LIR_lduc2ui, addp(elems, index), 0, ACCSET_TARRAY_DATA);
546     }
547
548     nj::LIns *lds2iTypedArrayElement(nj::LIns *elems, nj::LIns *index) const {
549         return lir->insLoad(nj::LIR_lds2i, addp(elems, lshpN(index, 1)), 0, ACCSET_TARRAY_DATA);
550     }
551
552     nj::LIns *ldus2uiTypedArrayElement(nj::LIns *elems, nj::LIns *index) const {
553         return lir->insLoad(nj::LIR_ldus2ui, addp(elems, lshpN(index, 1)), 0, ACCSET_TARRAY_DATA);
554     }
555
556     nj::LIns *ldiTypedArrayElement(nj::LIns *elems, nj::LIns *index) const {
557         return lir->insLoad(nj::LIR_ldi, addp(elems, lshpN(index, 2)), 0, ACCSET_TARRAY_DATA);
558     }
559
560     nj::LIns *ldf2dTypedArrayElement(nj::LIns *elems, nj::LIns *index) const {
561         return lir->insLoad(nj::LIR_ldf2d, addp(elems, lshpN(index, 2)), 0, ACCSET_TARRAY_DATA);
562     }
563
564     nj::LIns *lddTypedArrayElement(nj::LIns *elems, nj::LIns *index) const {
565         return lir->insLoad(nj::LIR_ldd, addp(elems, lshpN(index, 3)), 0, ACCSET_TARRAY_DATA);
566     }
567
568     nj::LIns *sti2cTypedArrayElement(nj::LIns *value, nj::LIns *elems, nj::LIns *index) const {
569         return lir->insStore(nj::LIR_sti2c, value, addp(elems, index), 0, ACCSET_TARRAY_DATA);
570     }
571
572     nj::LIns *sti2sTypedArrayElement(nj::LIns *value, nj::LIns *elems, nj::LIns *index) const {
573         return lir->insStore(nj::LIR_sti2s, value, addp(elems, lshpN(index, 1)), 0,
574                              ACCSET_TARRAY_DATA);
575     }
576
577     nj::LIns *stiTypedArrayElement(nj::LIns *value, nj::LIns *elems, nj::LIns *index) const {
578         return lir->insStore(nj::LIR_sti, value, addp(elems, lshpN(index, 2)), 0,
579                              ACCSET_TARRAY_DATA);
580     }
581
582     nj::LIns *std2fTypedArrayElement(nj::LIns *value, nj::LIns *elems, nj::LIns *index) const {
583         return lir->insStore(nj::LIR_std2f, value, addp(elems, lshpN(index, 2)), 0,
584                              ACCSET_TARRAY_DATA);
585     }
586
587     nj::LIns *stdTypedArrayElement(nj::LIns *value, nj::LIns *elems, nj::LIns *index) const {
588         return lir->insStore(nj::LIR_std, value, addp(elems, lshpN(index, 3)), 0,
589                              ACCSET_TARRAY_DATA);
590     }
591
592     nj::LIns *ldpIterCursor(nj::LIns *iter) const {
593         return name(lir->insLoad(nj::LIR_ldp, iter, offsetof(NativeIterator, props_cursor),
594                                  ACCSET_ITER),
595                     "cursor");
596     }
597
598     nj::LIns *ldpIterEnd(nj::LIns *iter) const {
599         return name(lir->insLoad(nj::LIR_ldp, iter, offsetof(NativeIterator, props_end),
600                                  ACCSET_ITER),
601                     "end");
602     }
603
604     nj::LIns *stpIterCursor(nj::LIns *cursor, nj::LIns *iter) const {
605         return lir->insStore(nj::LIR_stp, cursor, iter, offsetof(NativeIterator, props_cursor),
606                              ACCSET_ITER);
607     }
608
609     nj::LIns *ldpStringLengthAndFlags(nj::LIns *str) const {
610         return name(lir->insLoad(nj::LIR_ldp, str, JSString::offsetOfLengthAndFlags(),
611                                  ACCSET_STRING),
612                     "lengthAndFlags");
613     }
614
615     nj::LIns *ldpStringChars(nj::LIns *str) const {
616         return name(lir->insLoad(nj::LIR_ldp, str, JSString::offsetOfChars(), ACCSET_STRING),
617                     "chars");
618     }
619
620     nj::LIns *lduc2uiConstTypeMapEntry(nj::LIns *typemap, nj::LIns *index) const {
621         nj::LIns *entry = addp(typemap, ui2p(muli(index, name(immi(sizeof(JSValueType)),
622                                                               "sizeof(JSValueType)"))));
623         return lir->insLoad(nj::LIR_lduc2ui, entry, 0, ACCSET_TYPEMAP, nj::LOAD_CONST);
624     }
625
626     nj::LIns *ldiVolatile(nj::LIns *base) const {
627         return lir->insLoad(nj::LIR_ldi, base, 0, nj::ACCSET_LOAD_ANY, nj::LOAD_VOLATILE);
628     }
629
630     nj::LIns *stiVolatile(nj::LIns *value, nj::LIns *base) const {
631         return lir->insStore(nj::LIR_sti, value, base, 0, nj::ACCSET_STORE_ANY);
632     }
633
634     nj::LIns *ldiVMSideExitFieldHelper(nj::LIns *lr, int32 offset) const {
635         return lir->insLoad(nj::LIR_ldi, lr, offset, nj::ACCSET_LOAD_ANY);
636     }
637     #define ldiVMSideExitField(lr, fieldname) \
638         name(w.ldiVMSideExitFieldHelper((lr), offsetof(VMSideExit, fieldname)), #fieldname)
639
640     nj::LIns *ldpGuardRecordExit(nj::LIns *gr) const {
641         /*
642          * We use ACCSET_LOAD_ANY for the GuardRecord and VMSideExit loads;
643          * they're immediately after a fragment call, and so won't be
644          * optimizable anyway.
645          */
646         return name(lir->insLoad(nj::LIR_ldp, gr, offsetof(nj::GuardRecord, exit),
647                                  nj::ACCSET_LOAD_ANY),
648                     "exit");
649     }
650
651     nj::LIns *stTprintArg(nj::LIns *insa[], nj::LIns *args, int index) const {
652         JS_ASSERT(insa[index]);
653         /* The AccSet doesn't matter much here, this is debug-only code. */
654         return lir->insStore(insa[index], args, sizeof(double) * index, nj::ACCSET_STORE_ANY);
655     }
656
657     /* Generic loads and stores (those taking an Address argument). */
658
659 #if JS_BITS_PER_WORD == 32
660     nj::LIns *ldiValueTag(Address addr) const {
661         return name(lir->insLoad(nj::LIR_ldi, addr.base, addr.offset + sTagOffset, addr.accSet),
662                     "tag");
663     }
664
665     nj::LIns *stiValueTag(nj::LIns *tag, Address addr) const {
666         JS_ASSERT(tag->isI());
667         return lir->insStore(tag, addr.base, addr.offset + sTagOffset, addr.accSet);
668     }
669
670     nj::LIns *ldiValuePayload(Address addr) const {
671         return name(lir->insLoad(nj::LIR_ldi, addr.base, addr.offset + sPayloadOffset,
672                                  addr.accSet),
673                     "payload");
674     }
675
676     nj::LIns *stiValuePayload(nj::LIns *payload, Address addr) const {
677         JS_ASSERT(payload->isI());
678         return lir->insStore(payload, addr.base, addr.offset + sPayloadOffset, addr.accSet);
679     }
680 #endif  // JS_BITS_PER_WORD == 32
681
682     nj::LIns *ldi(Address addr) const {
683         return lir->insLoad(nj::LIR_ldi, addr.base, addr.offset, addr.accSet);
684     }
685
686 #ifdef NANOJIT_64BIT
687     nj::LIns *ldq(Address addr) const {
688         return lir->insLoad(nj::LIR_ldq, addr.base, addr.offset, addr.accSet);
689     }
690
691     nj::LIns *stq(nj::LIns *value, Address addr) const {
692         return lir->insStore(nj::LIR_stq, value, addr.base, addr.offset, addr.accSet);
693     }
694 #endif
695
696     nj::LIns *ldp(Address addr) const {
697         return lir->insLoad(nj::LIR_ldp, addr.base, addr.offset, addr.accSet);
698     }
699
700     nj::LIns *ldd(Address addr) const {
701         return lir->insLoad(nj::LIR_ldd, addr.base, addr.offset, addr.accSet);
702     }
703
704     nj::LIns *std(nj::LIns *value, Address addr) const {
705         return lir->insStore(nj::LIR_std, value, addr.base, addr.offset, addr.accSet);
706     }
707
708     nj::LIns *st(nj::LIns *value, Address addr) const {
709         return lir->insStore(value, addr.base, addr.offset, addr.accSet);
710     }
711
712     /* Calls */
713
714     nj::LIns *call(const nj::CallInfo *call, nj::LIns *args[]) const {
715         return lir->insCall(call, args);
716     }
717
718     /* Branches and labels */
719
720     nj::LIns *j(nj::LIns *target) const {
721         return lir->insBranch(nj::LIR_j, /* cond = */NULL, target);
722     }
723
724     /*
725      * If the branch is always taken, return false;  the code jumped over by the
726      * branch need not be generated.  If the branch is never taken, return true
727      * and put NULL in *brOut.  Otherwise, return true and put the branch in
728      * *brOut.
729      */
730     MaybeBranch jt(nj::LIns *cond) {
731         if (cond->isImmI(1))
732             return MaybeBranch();                                   /* branch is always taken */
733         return MaybeBranch(lir->insBranch(nj::LIR_jt, cond, NULL)); /* NULL if never taken */
734     }
735
736     /* Like jt(). */
737     MaybeBranch jf(nj::LIns *cond) {
738         if (cond->isImmI(0))
739             return MaybeBranch();                                   /* branch is always taken */
740         return MaybeBranch(lir->insBranch(nj::LIR_jf, cond, NULL)); /* NULL if never taken */
741     }
742
743     /*
744      * Like jf(), but for when we know the branch condition cannot be
745      * optimized to a constant, eg. because one of the operands is the result
746      * of a volatile load.
747      */
748     nj::LIns *jfUnoptimizable(nj::LIns *cond) const {
749         JS_ASSERT(!cond->isImmI());
750         return lir->insBranch(nj::LIR_jf, cond, /* target = */NULL);
751     }
752
753     /* Like jfUnoptimizable(). */
754     nj::LIns *jtUnoptimizable(nj::LIns *cond) const {
755         JS_ASSERT(!cond->isImmI());
756         return lir->insBranch(nj::LIR_jt, cond, /* target = */NULL);
757     }
758
759     nj::LIns *label() const {
760         return lir->ins0(nj::LIR_label);
761     }
762
763     /*
764      * Inserts a label and updates 'branch' to branch to it, if 'branch' is non-NULL.
765      * ('branch' may be NULL if it was a conditional branch and its condition was
766      * a constant value that resulted in the branch never being taken.)
767      */
768     void label(nj::LIns *br) {
769         if (br) {
770             JS_ASSERT(br->isop(nj::LIR_j) || br->isop(nj::LIR_jt) || br->isop(nj::LIR_jf));
771             br->setTarget(label());
772         }
773     }
774
775     /* Similar to label(LIns *), but for two branches. */
776     void label(nj::LIns *br1, nj::LIns *br2) {
777         if (br1 || br2) {
778             nj::LIns *label_ = label();
779             if (br1) {
780                 JS_ASSERT(br1->isop(nj::LIR_j) || br1->isop(nj::LIR_jt) || br1->isop(nj::LIR_jf));
781                 br1->setTarget(label_);
782             }
783             if (br2) {
784                 JS_ASSERT(br2->isop(nj::LIR_j) || br2->isop(nj::LIR_jt) || br2->isop(nj::LIR_jf));
785                 br2->setTarget(label_);
786             }
787         }
788     }
789
790     /* Guards */
791
792     nj::LIns *x(nj::GuardRecord *gr) const {
793         return lir->insGuard(nj::LIR_x, /* cond = */NULL, gr);
794     }
795
796     nj::LIns *xf(nj::LIns *cond, nj::GuardRecord *gr) const {
797         return lir->insGuard(nj::LIR_xf, cond, gr);
798     }
799
800     nj::LIns *xt(nj::LIns *cond, nj::GuardRecord *gr) const {
801         return lir->insGuard(nj::LIR_xt, cond, gr);
802     }
803
804     nj::LIns *xtbl(nj::LIns *index, nj::GuardRecord *gr) const {
805         return lir->insGuard(nj::LIR_xtbl, index, gr);
806     }
807
808     nj::LIns *xbarrier(nj::GuardRecord *gr) const {
809         return lir->insGuard(nj::LIR_xbarrier, /* cond = */NULL, gr);
810     }
811
812     /* Immediates */
813
814     nj::LIns *immi(int32 i) const {
815         return lir->insImmI(i);
816     }
817
818     nj::LIns *immiUndefined() const {
819         return name(immi(0), "undefined");
820     }
821
822     /*
823      * These must be macros because they stringify their argument.  Likewise
824      * with similar 'nameXYZ' operations below, 
825      *
826      * These nameXYZ() macros have the 'name' prefix to distinguish them from the
827      * non-naming XYZ() functions.
828      */
829     #define nameImmi(i)         name(w.immi(i), #i)
830     #define nameImmui(ui)       name(w.immi((uint32_t)ui), #ui)
831
832 #ifdef NANOJIT_64BIT
833     nj::LIns *immq(uint64 q) const {
834         return lir->insImmQ(q);
835     }
836
837     #define nameImmq(q)         name(w.immq(q), #q)
838 #endif
839
840     /*
841      * immpNonGC() can be used to embed arbitrary pointers into the native
842      * code.  It should not be used directly to embed GC thing pointers unless
843      * they've already been rooted(hence the name).  Instead, the
844      * TraceRecorder::immpXyzGC() variants should be used because they ensure
845      * that the embedded pointer will be kept alive across GCs.  These types
846      * make it difficult to inadvertently get this wrong.
847      */
848     nj::LIns *immpNonGC(const void *p) const {
849         return lir->insImmP(p);
850     }
851
852     nj::LIns *immw(intptr_t i) const {
853         return lir->insImmP((void *)i);
854     }
855
856     #define nameImmpNonGC(p)    name(w.immpNonGC(p), #p)
857     #define nameImmw(ww)        name(w.immpNonGC((void *) (ww)), #ww)
858
859     nj::LIns *immpNull() const {
860         return name(immpNonGC(NULL), "NULL");
861     }
862
863     #define immpMagicWhy(why)   name(w.immpNonGC((void *)(size_t)(why)), #why)
864
865     nj::LIns *immpMagicNull() const {
866         return name(immpNonGC(NULL), "MAGIC_NULL");
867     }
868
869     nj::LIns *immd(double d) const {
870         return lir->insImmD(d);
871     }
872
873     /* Comparisons */
874
875     nj::LIns *eqi(nj::LIns *x, nj::LIns *y) const {
876         return lir->ins2(nj::LIR_eqi, x, y);
877     }
878
879     nj::LIns *eqi0(nj::LIns *x) const {
880         return lir->insEqI_0(x);
881     }
882
883     nj::LIns *eqiN(nj::LIns *x, int32 imm) const {
884         return lir->ins2ImmI(nj::LIR_eqi, x, imm);
885     }
886
887     nj::LIns *lti(nj::LIns *x, nj::LIns *y) const {
888         return lir->ins2(nj::LIR_lti, x, y);
889     }
890
891     nj::LIns *ltiN(nj::LIns *x, int32 imm) const {
892         return lir->ins2ImmI(nj::LIR_lti, x, imm);
893     }
894
895     nj::LIns *gti(nj::LIns *x, nj::LIns *y) const {
896         return lir->ins2(nj::LIR_gti, x, y);
897     }
898
899     nj::LIns *gtiN(nj::LIns *x, int32 imm) const {
900         return lir->ins2ImmI(nj::LIR_gti, x, imm);
901     }
902
903     nj::LIns *geiN(nj::LIns *x, int32 imm) const {
904         return lir->ins2ImmI(nj::LIR_gei, x, imm);
905     }
906
907     nj::LIns *ltui(nj::LIns *x, nj::LIns *y) const {
908         return lir->ins2(nj::LIR_ltui, x, y);
909     }
910
911     nj::LIns *ltuiN(nj::LIns *x, int32 imm) const {
912         return lir->ins2ImmI(nj::LIR_ltui, x, imm);
913     }
914
915     nj::LIns *gtui(nj::LIns *x, nj::LIns *y) const {
916         return lir->ins2(nj::LIR_gtui, x, y);
917     }
918
919     nj::LIns *leui(nj::LIns *x, nj::LIns *y) const {
920         return lir->ins2(nj::LIR_leui, x, y);
921     }
922
923     nj::LIns *geui(nj::LIns *x, nj::LIns *y) const {
924         return lir->ins2(nj::LIR_geui, x, y);
925     }
926
927 #ifdef NANOJIT_64BIT
928     nj::LIns *eqq(nj::LIns *x, nj::LIns *y) const {
929         return lir->ins2(nj::LIR_eqq, x, y);
930     }
931
932     nj::LIns *ltuq(nj::LIns *x, nj::LIns *y) const {
933         return lir->ins2(nj::LIR_ltuq, x, y);
934     }
935
936     nj::LIns *leuq(nj::LIns *x, nj::LIns *y) const {
937         return lir->ins2(nj::LIR_leuq, x, y);
938     }
939
940     nj::LIns *geuq(nj::LIns *x, nj::LIns *y) const {
941         return lir->ins2(nj::LIR_geuq, x, y);
942     }
943 #endif
944
945     nj::LIns *eqp(nj::LIns *x, nj::LIns *y) const {
946         return lir->ins2(nj::LIR_eqp, x, y);
947     }
948
949     nj::LIns *eqp0(nj::LIns *x) const {
950         return lir->insEqP_0(x);
951     }
952
953     nj::LIns *ltp(nj::LIns *x, nj::LIns *y) const {
954         return lir->ins2(nj::LIR_ltp, x, y);
955     }
956
957     nj::LIns *ltup(nj::LIns *x, nj::LIns *y) const {
958         return lir->ins2(nj::LIR_ltup, x, y);
959     }
960
961     nj::LIns *eqd(nj::LIns *x, nj::LIns *y) const {
962         return lir->ins2(nj::LIR_eqd, x, y);
963     }
964
965     nj::LIns *eqd0(nj::LIns *x) const {
966         return lir->ins2(nj::LIR_eqd, x, immd(0));
967     }
968
969     nj::LIns *ltdN(nj::LIns *x, jsdouble imm) const {
970         return lir->ins2(nj::LIR_ltd, x, immd(imm));
971     }
972
973     /* Arithmetic */
974
975     nj::LIns *negi(nj::LIns *x) const {
976         return lir->ins1(nj::LIR_negi, x);
977     }
978
979     nj::LIns *addi(nj::LIns *x, nj::LIns *y) const {
980         return lir->ins2(nj::LIR_addi, x, y);
981     }
982
983     nj::LIns *addiN(nj::LIns *x, int32 imm) const {
984         return lir->ins2ImmI(nj::LIR_addi, x, imm);
985     }
986
987     nj::LIns *subi(nj::LIns *x, nj::LIns *y) const {
988         return lir->ins2(nj::LIR_subi, x, y);
989     }
990
991     nj::LIns *muli(nj::LIns *x, nj::LIns *y) const {
992         return lir->ins2(nj::LIR_muli, x, y);
993     }
994
995     nj::LIns *muliN(nj::LIns *x, int32 imm) const {
996         return lir->ins2ImmI(nj::LIR_muli, x, imm);
997     }
998
999 #if defined NANOJIT_IA32 || defined NANOJIT_X64
1000     nj::LIns *divi(nj::LIns *x, nj::LIns *y) const {
1001         return lir->ins2(nj::LIR_divi, x, y);
1002     }
1003
1004     nj::LIns *modi(nj::LIns *x) const {
1005         return lir->ins1(nj::LIR_modi, x);
1006     }
1007 #endif
1008
1009     nj::LIns *andi(nj::LIns *x, nj::LIns *y) const {
1010         return lir->ins2(nj::LIR_andi, x, y);
1011     }
1012
1013     nj::LIns *andiN(nj::LIns *x, int32 imm) const {
1014         return lir->ins2ImmI(nj::LIR_andi, x, imm);
1015     }
1016
1017     nj::LIns *ori(nj::LIns *x, nj::LIns *y) const {
1018         return lir->ins2(nj::LIR_ori, x, y);
1019     }
1020
1021     nj::LIns *xoriN(nj::LIns *x, int32 imm) const {
1022         return lir->ins2ImmI(nj::LIR_xori, x, imm);
1023     }
1024
1025     nj::LIns *lshiN(nj::LIns *x, int32 imm) const {
1026         return lir->ins2ImmI(nj::LIR_lshi, x, imm);
1027     }
1028
1029     nj::LIns *rshiN(nj::LIns *x, int32 imm) const {
1030         return lir->ins2ImmI(nj::LIR_rshi, x, imm);
1031     }
1032
1033 #ifdef NANOJIT_64BIT
1034     nj::LIns *andq(nj::LIns *x, nj::LIns *y) const {
1035         return lir->ins2(nj::LIR_andq, x, y);
1036     }
1037
1038     nj::LIns *orq(nj::LIns *x, nj::LIns *y) const {
1039         return lir->ins2(nj::LIR_orq, x, y);
1040     }
1041
1042     nj::LIns *lshqN(nj::LIns *x, int32 imm) const {
1043         return lir->ins2ImmI(nj::LIR_lshq, x, imm);
1044     }
1045
1046     nj::LIns *rshuqN(nj::LIns *x, int32 imm) const {
1047         return lir->ins2ImmI(nj::LIR_rshuq, x, imm);
1048     }
1049 #endif
1050
1051     nj::LIns *addp(nj::LIns *x, nj::LIns *y) const {
1052         return lir->ins2(nj::LIR_addp, x, y);
1053     }
1054
1055     nj::LIns *andp(nj::LIns *x, nj::LIns *y) const {
1056         return lir->ins2(nj::LIR_andp, x, y);
1057     }
1058
1059     nj::LIns *lshpN(nj::LIns *x, int32 imm) const {
1060         return lir->ins2ImmI(nj::LIR_lshp, x, imm);
1061     }
1062
1063     nj::LIns *rshupN(nj::LIns *x, int32 imm) const {
1064         return lir->ins2ImmI(nj::LIR_rshup, x, imm);
1065     }
1066
1067     nj::LIns *negd(nj::LIns *x) const {
1068         return lir->ins1(nj::LIR_negd, x);
1069     }
1070
1071     nj::LIns *cmovi(nj::LIns *cond, nj::LIns *t, nj::LIns *f) const {
1072         /* We can only use cmovi if the configuration says we can. */
1073         NanoAssert(t->isI() && f->isI());
1074         return lir->insChoose(cond, t, f, avmplus::AvmCore::use_cmov());
1075     }
1076
1077     nj::LIns *cmovp(nj::LIns *cond, nj::LIns *t, nj::LIns *f) const {
1078         /* We can only use cmovp if the configuration says we can. */
1079         NanoAssert(t->isP() && f->isP());
1080         return lir->insChoose(cond, t, f, avmplus::AvmCore::use_cmov());
1081     }
1082
1083     nj::LIns *cmovd(nj::LIns *cond, nj::LIns *t, nj::LIns *f) const {
1084         /* We can always use cmovd. */
1085         NanoAssert(t->isD() && f->isD());
1086         return lir->insChoose(cond, t, f, /* use_cmov = */true);
1087     }
1088
1089     /* Conversions */
1090
1091 #ifdef NANOJIT_64BIT
1092     nj::LIns *ui2uq(nj::LIns *ins) const {
1093         return lir->ins1(nj::LIR_ui2uq, ins);
1094     }
1095
1096     nj::LIns *q2i(nj::LIns *ins) const {
1097         return lir->ins1(nj::LIR_q2i, ins);
1098     }
1099 #endif
1100
1101     nj::LIns *i2p(nj::LIns *x) const {
1102         return lir->insI2P(x);
1103     }
1104
1105     nj::LIns *ui2p(nj::LIns *x) const {
1106         return lir->insUI2P(x);
1107     }
1108
1109     nj::LIns *p2i(nj::LIns *x) const {
1110     #ifdef NANOJIT_64BIT
1111         return lir->ins1(nj::LIR_q2i, x);
1112     #else
1113         return x;
1114     #endif
1115     }
1116
1117     nj::LIns *i2d(nj::LIns *ins) const {
1118         return lir->ins1(nj::LIR_i2d, ins);
1119     }
1120
1121     nj::LIns *ui2d(nj::LIns *ins) const {
1122         return lir->ins1(nj::LIR_ui2d, ins);
1123     }
1124
1125     /*
1126      * This is not called d2i() because that could be easily confused with
1127      * TraceRecorder::d2i(), which is usually what should be used.
1128      */
1129     nj::LIns *rawD2i(nj::LIns *ins) const {
1130         return lir->ins1(nj::LIR_d2i, ins);
1131     }
1132
1133 #ifdef NANOJIT_64BIT
1134     nj::LIns *dasq(nj::LIns *ins) const {
1135         return lir->ins1(nj::LIR_dasq, ins);
1136     }
1137
1138     nj::LIns *qasd(nj::LIns *ins) const {
1139         return lir->ins1(nj::LIR_qasd, ins);
1140     }
1141 #endif
1142
1143     nj::LIns *demoteToInt32(nj::LIns *ins) const {
1144         return DemoteToInt32(lir, ins);
1145     }
1146
1147     nj::LIns *demoteToUint32(nj::LIns *ins) const {
1148         return DemoteToUint32(lir, ins);
1149     }
1150
1151     /* Overflow arithmetic */
1152
1153     nj::LIns *addxovi(nj::LIns *x, nj::LIns *y, nj::GuardRecord *gr) const {
1154         return lir->insGuardXov(nj::LIR_addxovi, x, y, gr);
1155     }
1156
1157     nj::LIns *subxovi(nj::LIns *x, nj::LIns *y, nj::GuardRecord *gr) const {
1158         return lir->insGuardXov(nj::LIR_subxovi, x, y, gr);
1159     }
1160
1161     nj::LIns *mulxovi(nj::LIns *x, nj::LIns *y, nj::GuardRecord *gr) const {
1162         return lir->insGuardXov(nj::LIR_mulxovi, x, y, gr);
1163     }
1164
1165     /*
1166      * Ones not specific to a single opcode.  These should not be used if an
1167      * opcode-specific function can be used instead.
1168      */
1169
1170     nj::LIns *ins1(nj::LOpcode op, nj::LIns *x) const {
1171         return lir->ins1(op, x);
1172     }
1173
1174     nj::LIns *ins2(nj::LOpcode op, nj::LIns *x, nj::LIns *y) const {
1175         return lir->ins2(op, x, y);
1176     }
1177
1178     /* Operations involving non-trivial combinations of multiple instructions. */
1179
1180     /*
1181      * Nb: this "Privatized" refers to the Private API in jsvalue.h.  It
1182      * doesn't refer to the JSObj::privateData slot!  Confusing.
1183      */
1184     nj::LIns *getObjPrivatizedSlot(nj::LIns *obj, uint32 slot) const {
1185 #if JS_BITS_PER_WORD == 32
1186         nj::LIns *vaddr_ins = ldpObjSlots(obj);
1187         return lir->insLoad(nj::LIR_ldi, vaddr_ins,
1188                             slot * sizeof(Value) + sPayloadOffset, ACCSET_SLOTS, nj::LOAD_CONST);
1189
1190 #elif JS_BITS_PER_WORD == 64
1191         /* N.B. On 64-bit, privatized value are encoded differently from other pointers. */
1192         nj::LIns *vaddr_ins = ldpObjSlots(obj);
1193         nj::LIns *v_ins = lir->insLoad(nj::LIR_ldq, vaddr_ins,
1194                                        slot * sizeof(Value) + sPayloadOffset,
1195                                        ACCSET_SLOTS, nj::LOAD_CONST);
1196         return lshqN(v_ins, 1);
1197 #endif
1198     }
1199
1200     nj::LIns *getDslotAddress(nj::LIns *obj, nj::LIns *idx) const {
1201         JS_ASSERT(sizeof(Value) == 8); // The |3| in the following statement requires this.
1202         nj::LIns *offset = lshpN(ui2p(idx), 3);
1203         nj::LIns *slots = ldpObjSlots(obj);
1204         return addp(slots, offset);
1205     }
1206
1207     nj::LIns *getStringLength(nj::LIns *str) const {
1208         return name(rshupN(ldpStringLengthAndFlags(str), JSString::LENGTH_SHIFT),
1209                     "strLength");
1210     }
1211
1212     nj::LIns *getStringChar(nj::LIns *str, nj::LIns *idx) const {
1213         nj::LIns *chars = ldpStringChars(str);
1214         return name(lir->insLoad(nj::LIR_ldus2ui, addp(chars, lshpN(idx, 1)), 0,
1215                                  ACCSET_STRING_MCHARS, nj::LOAD_CONST),
1216                     "strChar");
1217     }
1218
1219     nj::LIns *getArgsLength(nj::LIns *args) const {
1220         uint32 slot = JSObject::JSSLOT_ARGS_LENGTH;
1221         nj::LIns *vaddr_ins = ldpObjSlots(args);
1222         return name(lir->insLoad(nj::LIR_ldi, vaddr_ins, slot * sizeof(Value) + sPayloadOffset,
1223                                  ACCSET_SLOTS),
1224                     "argsLength");
1225     }
1226 };
1227
1228 }   /* namespace tjit */
1229 }   /* namespace js */
1230
1231 #endif /* tracejit_Writer_h___ */
1232