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:
4 * ***** BEGIN LICENSE BLOCK *****
5 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
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/
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
17 * The Original Code is Mozilla SpiderMonkey JavaScript 1.9 code, released
20 * The Initial Developer of the Original Code is
21 * the Mozilla Corporation.
24 * Nicholas Nethercote <nnethercote@mozilla.com>
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.
38 * ***** END LICENSE BLOCK ***** */
40 #ifndef tracejit_Writer_h___
41 #define tracejit_Writer_h___
46 #include "jstypedarray.h"
52 namespace nj = nanojit;
54 #if defined(DEBUG) && !defined(JS_JIT_SPEW)
58 #if defined(JS_JIT_SPEW) || defined(NJ_NO_VARIADIC_MACROS)
62 * Output control bits for all non-Nanojit code. Only use bits 16 and
63 * above, since Nanojit uses 0 .. 15 itself.
67 LC_TMRecorder = 1<<18,
77 * See LIR.h for the definition of the AccSet type.
79 * *** WARNING WARNING WARNING ***
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
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.
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.
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.
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.
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);
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
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);
163 static const uint8_t TM_NUM_USED_ACCS = 28; // number of access regions used by TraceMonkey
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.
180 Address(nj::LIns *base, int32 offset, nj::AccSet accSet)
181 : base(base), offset(offset), accSet(accSet) {}
183 Address(Address addr, int32 offset)
184 : base(addr.base), offset(addr.offset + offset), accSet(addr.accSet) {}
191 /* Addresses, ordered by AccSet. */
193 struct StackAddress : Address
195 StackAddress(nj::LIns *base, int32 offset)
196 : Address(base, offset, ACCSET_STACK) {}
199 struct CxAddress : Address
201 CxAddress(nj::LIns *base, int32 offset)
202 : Address(base, offset, ACCSET_CX) {}
204 #define CxAddress(fieldname) \
205 CxAddress(cx_ins, offsetof(JSContext, fieldname))
207 struct EosAddress : Address
209 EosAddress(nj::LIns *base, int32 offset)
210 : Address(base, offset, ACCSET_EOS) {}
213 struct AllocSlotsAddress : Address
215 AllocSlotsAddress(nj::LIns *base, unsigned slot = 0)
216 : Address(base, slot * sizeof(Value), ACCSET_ALLOC) {}
219 struct StackFrameAddress : Address
221 StackFrameAddress(nj::LIns *base, int32 offset)
222 : Address(base, offset, ACCSET_STACKFRAME) {}
225 struct FSlotsAddress : Address
227 FSlotsAddress(nj::LIns *base, unsigned slot)
228 : Address(base, JSObject::getFixedSlotOffset(slot), ACCSET_SLOTS) {}
231 struct DSlotsAddress : Address
233 DSlotsAddress(nj::LIns *base, unsigned slot = 0)
234 : Address(base, slot * sizeof(Value), ACCSET_SLOTS) {}
237 struct IterPropsAddress : Address
239 IterPropsAddress(nj::LIns *base)
240 : Address(base, 0, ACCSET_ITER_PROPS) {}
243 struct FCSlotsAddress : Address
245 FCSlotsAddress(nj::LIns *base, unsigned slot = 0)
246 : Address(base, slot * sizeof(Value), ACCSET_FCSLOTS) {}
249 struct ArgsSlotOffsetAddress : Address
251 ArgsSlotOffsetAddress(nj::LIns *base, unsigned offset = 0)
252 : Address(base, offset, ACCSET_ARGS_DATA) {}
255 struct AnyAddress : Address
257 AnyAddress(nj::LIns *base, int32 offset = 0)
258 : Address(base, offset, nj::ACCSET_ALL)
260 JS_ASSERT(nj::ACCSET_LOAD_ANY == nj::ACCSET_STORE_ANY &&
261 nj::ACCSET_LOAD_ANY == nj::ACCSET_ALL);
265 /* An offset from a previous Address. */
266 struct OffsetAddress : Address
268 OffsetAddress(Address addr, int32 offset)
269 : Address(addr, offset) {}
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);
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);
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;
298 * This class provides a layer above Nanojit's basic LirWriter interface.
299 * The goals of this layer are as follows.
301 * - More concise than the vanilla NJ interface, to promote readability.
303 * - But still a relatively thin layer.
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).
311 * - Requires only basic Nanojit state (eg. LirBuffer); doesn't rely on state
312 * from TraceRecorder.
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.
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.
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.
327 * The only place where AccSets need to be used directly is when specifying
328 * the .storeAccSet of a CallInfo.
330 * - Functions that insert moderately complex LIR sequences (eg. multiple
331 * loads) have a 'get' prefix in their name.
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
341 nj::LogControl *logc; // passed in from outside
344 Writer(nj::Allocator *alloc, nj::LirBuffer *lirbuf)
345 : alloc(alloc), lirbuf(lirbuf), lir(NULL), cse(NULL), logc(NULL) {}
347 void init(nj::LogControl *logc);
349 nj::LIns *name(nj::LIns *ins, const char *name) const {
351 /* No point adding names unless .lcbits > 0. */
352 if (logc->lcbits > 0)
353 lirbuf->printer->lirNameMap->addName(ins, name);
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.
367 void pauseAddingCSEValues() { if (cse) cse->suspend(); }
368 void resumeAddingCSEValues() { if (cse) cse->resume(); }
370 /* Miscellaneous operations */
372 nj::LIns *start() const {
373 return lir->ins0(nj::LIR_start);
376 nj::LIns *paramp(int32 arg, int32 kind) const {
377 return lir->insParam(arg, kind);
380 nj::LIns *allocp(int32 size) const {
381 return lir->insAlloc(size);
384 nj::LIns *livep(nj::LIns *x) const {
385 return lir->ins1(nj::LIR_livep, x);
388 void comment(const char *str) {
390 lir->insComment(str);
394 /* Specific loads and stores (those not taking an Address argument). Ordered by AccSets.*/
396 nj::LIns *ldStateFieldHelper(nj::LOpcode op, nj::LIns *state, int32 offset) const {
397 return lir->insLoad(op, state, offset, ACCSET_STATE);
399 #define ldiStateField(fieldname) \
400 name(w.ldStateFieldHelper(LIR_ldi, lirbuf->state, offsetof(TracerState, fieldname)), \
402 #define ldpStateField(fieldname) \
403 name(w.ldStateFieldHelper(LIR_ldp, lirbuf->state, offsetof(TracerState, fieldname)), \
406 nj::LIns *stStateFieldHelper(nj::LIns *value, nj::LIns *state, int32 offset) const {
407 return lir->insStore(value, state, offset, ACCSET_STATE);
409 #define stStateField(value, fieldname) \
410 stStateFieldHelper(value, lirbuf->state, offsetof(TracerState, fieldname))
412 nj::LIns *ldpRstack(nj::LIns *rp, int32 offset) const {
413 return lir->insLoad(nj::LIR_ldp, rp, offset, ACCSET_RSTACK);
416 nj::LIns *stRstack(nj::LIns *value, nj::LIns *rp, int32 offset) const {
417 return lir->insStore(value, rp, offset, ACCSET_RSTACK);
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);
423 #define ldpContextField(fieldname) \
424 name(w.ldpContextFieldHelper(cx_ins, offsetof(JSContext, fieldname), LOAD_NORMAL), \
426 #define ldpConstContextField(fieldname) \
427 name(w.ldpContextFieldHelper(cx_ins, offsetof(JSContext, fieldname), LOAD_CONST), \
430 nj::LIns *stContextField(nj::LIns *value, nj::LIns *cx, int32 offset) const {
431 return lir->insStore(value, cx, offset, ACCSET_CX);
433 #define stContextField(value, fieldname) \
434 stContextField((value), cx_ins, offsetof(JSContext, fieldname))
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);
439 #define stTraceMonitorField(value, fieldname) \
440 stTraceMonitorField(value, &traceMonitor->fieldname, #fieldname)
442 nj::LIns *ldiAlloc(nj::LIns *alloc) const {
443 return lir->insLoad(nj::LIR_ldi, alloc, 0, ACCSET_ALLOC);
446 nj::LIns *ldpAlloc(nj::LIns *alloc) const {
447 return lir->insLoad(nj::LIR_ldp, alloc, 0, ACCSET_ALLOC);
450 nj::LIns *lddAlloc(nj::LIns *alloc) const {
451 return lir->insLoad(nj::LIR_ldd, alloc, 0, ACCSET_ALLOC);
454 nj::LIns *stAlloc(nj::LIns *value, nj::LIns *alloc) const {
455 return lir->insStore(value, alloc, 0, ACCSET_ALLOC);
458 nj::LIns *ldpFrameFp(nj::LIns *regs) const {
459 return lir->insLoad(nj::LIR_ldp, regs, offsetof(JSFrameRegs, fp), ACCSET_FRAMEREGS);
462 nj::LIns *ldpStackFrameScopeChain(nj::LIns *frame) const {
463 return lir->insLoad(nj::LIR_ldp, frame, JSStackFrame::offsetOfScopeChain(),
467 nj::LIns *ldiRuntimeProtoHazardShape(nj::LIns *runtime) const {
468 return name(lir->insLoad(nj::LIR_ldi, runtime, offsetof(JSRuntime, protoHazardShape),
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,
479 nj::LIns *ldiObjFlags(nj::LIns *obj) const {
480 return name(lir->insLoad(nj::LIR_ldi, obj, offsetof(JSObject, flags), ACCSET_OBJ_FLAGS),
484 nj::LIns *ldiObjShape(nj::LIns *obj) const {
485 return name(lir->insLoad(nj::LIR_ldi, obj, offsetof(JSObject, objShape), ACCSET_OBJ_SHAPE),
489 nj::LIns *ldpObjProto(nj::LIns *obj) const {
490 return name(lir->insLoad(nj::LIR_ldp, obj, offsetof(JSObject, proto), ACCSET_OBJ_PROTO),
494 nj::LIns *ldpObjParent(nj::LIns *obj) const {
495 return name(lir->insLoad(nj::LIR_ldp, obj, offsetof(JSObject, parent), ACCSET_OBJ_PARENT),
499 nj::LIns *ldpObjPrivate(nj::LIns *obj) const {
500 return name(lir->insLoad(nj::LIR_ldp, obj, offsetof(JSObject, privateData),
505 nj::LIns *lduiObjPrivate(nj::LIns *obj) const {
506 return name(lir->insLoad(nj::LIR_ldi, obj, offsetof(JSObject, privateData),
511 nj::LIns *stuiObjPrivate(nj::LIns *obj, nj::LIns *value) const {
512 return name(lir->insStore(nj::LIR_sti, value, obj, offsetof(JSObject, privateData),
517 nj::LIns *ldiDenseArrayCapacity(nj::LIns *array) const {
518 return name(lir->insLoad(nj::LIR_ldi, array, offsetof(JSObject, capacity),
519 ACCSET_OBJ_CAPACITY),
523 nj::LIns *ldpObjSlots(nj::LIns *obj) const {
524 return name(lir->insLoad(nj::LIR_ldp, obj, offsetof(JSObject, slots), ACCSET_OBJ_SLOTS),
528 nj::LIns *ldiConstTypedArrayLength(nj::LIns *array) const {
529 return name(lir->insLoad(nj::LIR_ldi, array, js::TypedArray::lengthOffset(), ACCSET_TARRAY,
534 nj::LIns *ldpConstTypedArrayData(nj::LIns *array) const {
535 return name(lir->insLoad(nj::LIR_ldp, array, js::TypedArray::dataOffset(), ACCSET_TARRAY,
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);
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);
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);
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);
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);
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);
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);
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);
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,
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,
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,
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,
592 nj::LIns *ldpIterCursor(nj::LIns *iter) const {
593 return name(lir->insLoad(nj::LIR_ldp, iter, offsetof(NativeIterator, props_cursor),
598 nj::LIns *ldpIterEnd(nj::LIns *iter) const {
599 return name(lir->insLoad(nj::LIR_ldp, iter, offsetof(NativeIterator, props_end),
604 nj::LIns *stpIterCursor(nj::LIns *cursor, nj::LIns *iter) const {
605 return lir->insStore(nj::LIR_stp, cursor, iter, offsetof(NativeIterator, props_cursor),
609 nj::LIns *ldpStringLengthAndFlags(nj::LIns *str) const {
610 return name(lir->insLoad(nj::LIR_ldp, str, JSString::offsetOfLengthAndFlags(),
615 nj::LIns *ldpStringChars(nj::LIns *str) const {
616 return name(lir->insLoad(nj::LIR_ldp, str, JSString::offsetOfChars(), ACCSET_STRING),
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);
626 nj::LIns *ldiVolatile(nj::LIns *base) const {
627 return lir->insLoad(nj::LIR_ldi, base, 0, nj::ACCSET_LOAD_ANY, nj::LOAD_VOLATILE);
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);
634 nj::LIns *ldiVMSideExitFieldHelper(nj::LIns *lr, int32 offset) const {
635 return lir->insLoad(nj::LIR_ldi, lr, offset, nj::ACCSET_LOAD_ANY);
637 #define ldiVMSideExitField(lr, fieldname) \
638 name(w.ldiVMSideExitFieldHelper((lr), offsetof(VMSideExit, fieldname)), #fieldname)
640 nj::LIns *ldpGuardRecordExit(nj::LIns *gr) const {
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.
646 return name(lir->insLoad(nj::LIR_ldp, gr, offsetof(nj::GuardRecord, exit),
647 nj::ACCSET_LOAD_ANY),
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);
657 /* Generic loads and stores (those taking an Address argument). */
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),
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);
670 nj::LIns *ldiValuePayload(Address addr) const {
671 return name(lir->insLoad(nj::LIR_ldi, addr.base, addr.offset + sPayloadOffset,
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);
680 #endif // JS_BITS_PER_WORD == 32
682 nj::LIns *ldi(Address addr) const {
683 return lir->insLoad(nj::LIR_ldi, addr.base, addr.offset, addr.accSet);
687 nj::LIns *ldq(Address addr) const {
688 return lir->insLoad(nj::LIR_ldq, addr.base, addr.offset, addr.accSet);
691 nj::LIns *stq(nj::LIns *value, Address addr) const {
692 return lir->insStore(nj::LIR_stq, value, addr.base, addr.offset, addr.accSet);
696 nj::LIns *ldp(Address addr) const {
697 return lir->insLoad(nj::LIR_ldp, addr.base, addr.offset, addr.accSet);
700 nj::LIns *ldd(Address addr) const {
701 return lir->insLoad(nj::LIR_ldd, addr.base, addr.offset, addr.accSet);
704 nj::LIns *std(nj::LIns *value, Address addr) const {
705 return lir->insStore(nj::LIR_std, value, addr.base, addr.offset, addr.accSet);
708 nj::LIns *st(nj::LIns *value, Address addr) const {
709 return lir->insStore(value, addr.base, addr.offset, addr.accSet);
714 nj::LIns *call(const nj::CallInfo *call, nj::LIns *args[]) const {
715 return lir->insCall(call, args);
718 /* Branches and labels */
720 nj::LIns *j(nj::LIns *target) const {
721 return lir->insBranch(nj::LIR_j, /* cond = */NULL, target);
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
730 MaybeBranch jt(nj::LIns *cond) {
732 return MaybeBranch(); /* branch is always taken */
733 return MaybeBranch(lir->insBranch(nj::LIR_jt, cond, NULL)); /* NULL if never taken */
737 MaybeBranch jf(nj::LIns *cond) {
739 return MaybeBranch(); /* branch is always taken */
740 return MaybeBranch(lir->insBranch(nj::LIR_jf, cond, NULL)); /* NULL if never taken */
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.
748 nj::LIns *jfUnoptimizable(nj::LIns *cond) const {
749 JS_ASSERT(!cond->isImmI());
750 return lir->insBranch(nj::LIR_jf, cond, /* target = */NULL);
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);
759 nj::LIns *label() const {
760 return lir->ins0(nj::LIR_label);
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.)
768 void label(nj::LIns *br) {
770 JS_ASSERT(br->isop(nj::LIR_j) || br->isop(nj::LIR_jt) || br->isop(nj::LIR_jf));
771 br->setTarget(label());
775 /* Similar to label(LIns *), but for two branches. */
776 void label(nj::LIns *br1, nj::LIns *br2) {
778 nj::LIns *label_ = label();
780 JS_ASSERT(br1->isop(nj::LIR_j) || br1->isop(nj::LIR_jt) || br1->isop(nj::LIR_jf));
781 br1->setTarget(label_);
784 JS_ASSERT(br2->isop(nj::LIR_j) || br2->isop(nj::LIR_jt) || br2->isop(nj::LIR_jf));
785 br2->setTarget(label_);
792 nj::LIns *x(nj::GuardRecord *gr) const {
793 return lir->insGuard(nj::LIR_x, /* cond = */NULL, gr);
796 nj::LIns *xf(nj::LIns *cond, nj::GuardRecord *gr) const {
797 return lir->insGuard(nj::LIR_xf, cond, gr);
800 nj::LIns *xt(nj::LIns *cond, nj::GuardRecord *gr) const {
801 return lir->insGuard(nj::LIR_xt, cond, gr);
804 nj::LIns *xtbl(nj::LIns *index, nj::GuardRecord *gr) const {
805 return lir->insGuard(nj::LIR_xtbl, index, gr);
808 nj::LIns *xbarrier(nj::GuardRecord *gr) const {
809 return lir->insGuard(nj::LIR_xbarrier, /* cond = */NULL, gr);
814 nj::LIns *immi(int32 i) const {
815 return lir->insImmI(i);
818 nj::LIns *immiUndefined() const {
819 return name(immi(0), "undefined");
823 * These must be macros because they stringify their argument. Likewise
824 * with similar 'nameXYZ' operations below,
826 * These nameXYZ() macros have the 'name' prefix to distinguish them from the
827 * non-naming XYZ() functions.
829 #define nameImmi(i) name(w.immi(i), #i)
830 #define nameImmui(ui) name(w.immi((uint32_t)ui), #ui)
833 nj::LIns *immq(uint64 q) const {
834 return lir->insImmQ(q);
837 #define nameImmq(q) name(w.immq(q), #q)
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.
848 nj::LIns *immpNonGC(const void *p) const {
849 return lir->insImmP(p);
852 nj::LIns *immw(intptr_t i) const {
853 return lir->insImmP((void *)i);
856 #define nameImmpNonGC(p) name(w.immpNonGC(p), #p)
857 #define nameImmw(ww) name(w.immpNonGC((void *) (ww)), #ww)
859 nj::LIns *immpNull() const {
860 return name(immpNonGC(NULL), "NULL");
863 #define immpMagicWhy(why) name(w.immpNonGC((void *)(size_t)(why)), #why)
865 nj::LIns *immpMagicNull() const {
866 return name(immpNonGC(NULL), "MAGIC_NULL");
869 nj::LIns *immd(double d) const {
870 return lir->insImmD(d);
875 nj::LIns *eqi(nj::LIns *x, nj::LIns *y) const {
876 return lir->ins2(nj::LIR_eqi, x, y);
879 nj::LIns *eqi0(nj::LIns *x) const {
880 return lir->insEqI_0(x);
883 nj::LIns *eqiN(nj::LIns *x, int32 imm) const {
884 return lir->ins2ImmI(nj::LIR_eqi, x, imm);
887 nj::LIns *lti(nj::LIns *x, nj::LIns *y) const {
888 return lir->ins2(nj::LIR_lti, x, y);
891 nj::LIns *ltiN(nj::LIns *x, int32 imm) const {
892 return lir->ins2ImmI(nj::LIR_lti, x, imm);
895 nj::LIns *gti(nj::LIns *x, nj::LIns *y) const {
896 return lir->ins2(nj::LIR_gti, x, y);
899 nj::LIns *gtiN(nj::LIns *x, int32 imm) const {
900 return lir->ins2ImmI(nj::LIR_gti, x, imm);
903 nj::LIns *geiN(nj::LIns *x, int32 imm) const {
904 return lir->ins2ImmI(nj::LIR_gei, x, imm);
907 nj::LIns *ltui(nj::LIns *x, nj::LIns *y) const {
908 return lir->ins2(nj::LIR_ltui, x, y);
911 nj::LIns *ltuiN(nj::LIns *x, int32 imm) const {
912 return lir->ins2ImmI(nj::LIR_ltui, x, imm);
915 nj::LIns *gtui(nj::LIns *x, nj::LIns *y) const {
916 return lir->ins2(nj::LIR_gtui, x, y);
919 nj::LIns *leui(nj::LIns *x, nj::LIns *y) const {
920 return lir->ins2(nj::LIR_leui, x, y);
923 nj::LIns *geui(nj::LIns *x, nj::LIns *y) const {
924 return lir->ins2(nj::LIR_geui, x, y);
928 nj::LIns *eqq(nj::LIns *x, nj::LIns *y) const {
929 return lir->ins2(nj::LIR_eqq, x, y);
932 nj::LIns *ltuq(nj::LIns *x, nj::LIns *y) const {
933 return lir->ins2(nj::LIR_ltuq, x, y);
936 nj::LIns *leuq(nj::LIns *x, nj::LIns *y) const {
937 return lir->ins2(nj::LIR_leuq, x, y);
940 nj::LIns *geuq(nj::LIns *x, nj::LIns *y) const {
941 return lir->ins2(nj::LIR_geuq, x, y);
945 nj::LIns *eqp(nj::LIns *x, nj::LIns *y) const {
946 return lir->ins2(nj::LIR_eqp, x, y);
949 nj::LIns *eqp0(nj::LIns *x) const {
950 return lir->insEqP_0(x);
953 nj::LIns *ltp(nj::LIns *x, nj::LIns *y) const {
954 return lir->ins2(nj::LIR_ltp, x, y);
957 nj::LIns *ltup(nj::LIns *x, nj::LIns *y) const {
958 return lir->ins2(nj::LIR_ltup, x, y);
961 nj::LIns *eqd(nj::LIns *x, nj::LIns *y) const {
962 return lir->ins2(nj::LIR_eqd, x, y);
965 nj::LIns *eqd0(nj::LIns *x) const {
966 return lir->ins2(nj::LIR_eqd, x, immd(0));
969 nj::LIns *ltdN(nj::LIns *x, jsdouble imm) const {
970 return lir->ins2(nj::LIR_ltd, x, immd(imm));
975 nj::LIns *negi(nj::LIns *x) const {
976 return lir->ins1(nj::LIR_negi, x);
979 nj::LIns *addi(nj::LIns *x, nj::LIns *y) const {
980 return lir->ins2(nj::LIR_addi, x, y);
983 nj::LIns *addiN(nj::LIns *x, int32 imm) const {
984 return lir->ins2ImmI(nj::LIR_addi, x, imm);
987 nj::LIns *subi(nj::LIns *x, nj::LIns *y) const {
988 return lir->ins2(nj::LIR_subi, x, y);
991 nj::LIns *muli(nj::LIns *x, nj::LIns *y) const {
992 return lir->ins2(nj::LIR_muli, x, y);
995 nj::LIns *muliN(nj::LIns *x, int32 imm) const {
996 return lir->ins2ImmI(nj::LIR_muli, x, imm);
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);
1004 nj::LIns *modi(nj::LIns *x) const {
1005 return lir->ins1(nj::LIR_modi, x);
1009 nj::LIns *andi(nj::LIns *x, nj::LIns *y) const {
1010 return lir->ins2(nj::LIR_andi, x, y);
1013 nj::LIns *andiN(nj::LIns *x, int32 imm) const {
1014 return lir->ins2ImmI(nj::LIR_andi, x, imm);
1017 nj::LIns *ori(nj::LIns *x, nj::LIns *y) const {
1018 return lir->ins2(nj::LIR_ori, x, y);
1021 nj::LIns *xoriN(nj::LIns *x, int32 imm) const {
1022 return lir->ins2ImmI(nj::LIR_xori, x, imm);
1025 nj::LIns *lshiN(nj::LIns *x, int32 imm) const {
1026 return lir->ins2ImmI(nj::LIR_lshi, x, imm);
1029 nj::LIns *rshiN(nj::LIns *x, int32 imm) const {
1030 return lir->ins2ImmI(nj::LIR_rshi, x, imm);
1033 #ifdef NANOJIT_64BIT
1034 nj::LIns *andq(nj::LIns *x, nj::LIns *y) const {
1035 return lir->ins2(nj::LIR_andq, x, y);
1038 nj::LIns *orq(nj::LIns *x, nj::LIns *y) const {
1039 return lir->ins2(nj::LIR_orq, x, y);
1042 nj::LIns *lshqN(nj::LIns *x, int32 imm) const {
1043 return lir->ins2ImmI(nj::LIR_lshq, x, imm);
1046 nj::LIns *rshuqN(nj::LIns *x, int32 imm) const {
1047 return lir->ins2ImmI(nj::LIR_rshuq, x, imm);
1051 nj::LIns *addp(nj::LIns *x, nj::LIns *y) const {
1052 return lir->ins2(nj::LIR_addp, x, y);
1055 nj::LIns *andp(nj::LIns *x, nj::LIns *y) const {
1056 return lir->ins2(nj::LIR_andp, x, y);
1059 nj::LIns *lshpN(nj::LIns *x, int32 imm) const {
1060 return lir->ins2ImmI(nj::LIR_lshp, x, imm);
1063 nj::LIns *rshupN(nj::LIns *x, int32 imm) const {
1064 return lir->ins2ImmI(nj::LIR_rshup, x, imm);
1067 nj::LIns *negd(nj::LIns *x) const {
1068 return lir->ins1(nj::LIR_negd, x);
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());
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());
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);
1091 #ifdef NANOJIT_64BIT
1092 nj::LIns *ui2uq(nj::LIns *ins) const {
1093 return lir->ins1(nj::LIR_ui2uq, ins);
1096 nj::LIns *q2i(nj::LIns *ins) const {
1097 return lir->ins1(nj::LIR_q2i, ins);
1101 nj::LIns *i2p(nj::LIns *x) const {
1102 return lir->insI2P(x);
1105 nj::LIns *ui2p(nj::LIns *x) const {
1106 return lir->insUI2P(x);
1109 nj::LIns *p2i(nj::LIns *x) const {
1110 #ifdef NANOJIT_64BIT
1111 return lir->ins1(nj::LIR_q2i, x);
1117 nj::LIns *i2d(nj::LIns *ins) const {
1118 return lir->ins1(nj::LIR_i2d, ins);
1121 nj::LIns *ui2d(nj::LIns *ins) const {
1122 return lir->ins1(nj::LIR_ui2d, ins);
1126 * This is not called d2i() because that could be easily confused with
1127 * TraceRecorder::d2i(), which is usually what should be used.
1129 nj::LIns *rawD2i(nj::LIns *ins) const {
1130 return lir->ins1(nj::LIR_d2i, ins);
1133 #ifdef NANOJIT_64BIT
1134 nj::LIns *dasq(nj::LIns *ins) const {
1135 return lir->ins1(nj::LIR_dasq, ins);
1138 nj::LIns *qasd(nj::LIns *ins) const {
1139 return lir->ins1(nj::LIR_qasd, ins);
1143 nj::LIns *demoteToInt32(nj::LIns *ins) const {
1144 return DemoteToInt32(lir, ins);
1147 nj::LIns *demoteToUint32(nj::LIns *ins) const {
1148 return DemoteToUint32(lir, ins);
1151 /* Overflow arithmetic */
1153 nj::LIns *addxovi(nj::LIns *x, nj::LIns *y, nj::GuardRecord *gr) const {
1154 return lir->insGuardXov(nj::LIR_addxovi, x, y, gr);
1157 nj::LIns *subxovi(nj::LIns *x, nj::LIns *y, nj::GuardRecord *gr) const {
1158 return lir->insGuardXov(nj::LIR_subxovi, x, y, gr);
1161 nj::LIns *mulxovi(nj::LIns *x, nj::LIns *y, nj::GuardRecord *gr) const {
1162 return lir->insGuardXov(nj::LIR_mulxovi, x, y, gr);
1166 * Ones not specific to a single opcode. These should not be used if an
1167 * opcode-specific function can be used instead.
1170 nj::LIns *ins1(nj::LOpcode op, nj::LIns *x) const {
1171 return lir->ins1(op, x);
1174 nj::LIns *ins2(nj::LOpcode op, nj::LIns *x, nj::LIns *y) const {
1175 return lir->ins2(op, x, y);
1178 /* Operations involving non-trivial combinations of multiple instructions. */
1181 * Nb: this "Privatized" refers to the Private API in jsvalue.h. It
1182 * doesn't refer to the JSObj::privateData slot! Confusing.
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);
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);
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);
1207 nj::LIns *getStringLength(nj::LIns *str) const {
1208 return name(rshupN(ldpStringLengthAndFlags(str), JSString::LENGTH_SHIFT),
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),
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,
1228 } /* namespace tjit */
1229 } /* namespace js */
1231 #endif /* tracejit_Writer_h___ */