Imported Upstream version 1.0.0
[platform/upstream/js.git] / js / src / jstracer.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  *   Brendan Eich <brendan@mozilla.org>
22  *
23  * Contributor(s):
24  *   Andreas Gal <gal@mozilla.com>
25  *   Mike Shaver <shaver@mozilla.org>
26  *   David Anderson <danderson@mozilla.com>
27  *
28  * Alternatively, the contents of this file may be used under the terms of
29  * either of the GNU General Public License Version 2 or later (the "GPL"),
30  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
31  * in which case the provisions of the GPL or the LGPL are applicable instead
32  * of those above. If you wish to allow use of your version of this file only
33  * under the terms of either the GPL or the LGPL, and not to allow others to
34  * use your version of this file under the terms of the MPL, indicate your
35  * decision by deleting the provisions above and replace them with the notice
36  * and other provisions required by the GPL or the LGPL. If you do not delete
37  * the provisions above, a recipient may use your version of this file under
38  * the terms of any one of the MPL, the GPL or the LGPL.
39  *
40  * ***** END LICENSE BLOCK ***** */
41
42 #ifndef jstracer_h___
43 #define jstracer_h___
44
45 #ifdef JS_TRACER
46
47 #include "jstypes.h"
48 #include "jsbuiltins.h"
49 #include "jscntxt.h"
50 #include "jsdhash.h"
51 #include "jsinterp.h"
52 #include "jslock.h"
53 #include "jsnum.h"
54 #include "jsvector.h"
55 #include "jscompartment.h"
56 #include "Writer.h"
57
58 namespace js {
59
60 template <typename T>
61 class Queue {
62     T* _data;
63     unsigned _len;
64     unsigned _max;
65     nanojit::Allocator* alloc;
66
67 public:
68     void ensure(unsigned size) {
69         if (_max > size)
70             return;
71         if (!_max)
72             _max = 8;
73         _max = JS_MAX(_max * 2, size);
74         if (alloc) {
75             T* tmp = new (*alloc) T[_max];
76             memcpy(tmp, _data, _len * sizeof(T));
77             _data = tmp;
78         } else {
79             _data = (T*)js_realloc(_data, _max * sizeof(T));
80         }
81 #if defined(DEBUG)
82         memset(&_data[_len], 0xcd, _max - _len);
83 #endif
84     }
85
86     Queue(nanojit::Allocator* alloc)
87         : alloc(alloc)
88     {
89         this->_max =
90         this->_len = 0;
91         this->_data = NULL;
92     }
93
94     ~Queue() {
95         if (!alloc)
96             js_free(_data);
97     }
98
99     bool contains(T a) {
100         for (unsigned n = 0; n < _len; ++n) {
101             if (_data[n] == a)
102                 return true;
103         }
104         return false;
105     }
106
107     void add(T a) {
108         ensure(_len + 1);
109         JS_ASSERT(_len <= _max);
110         _data[_len++] = a;
111     }
112
113     void add(T* chunk, unsigned size) {
114         ensure(_len + size);
115         JS_ASSERT(_len <= _max);
116         memcpy(&_data[_len], chunk, size * sizeof(T));
117         _len += size;
118     }
119
120     void addUnique(T a) {
121         if (!contains(a))
122             add(a);
123     }
124
125     void setLength(unsigned len) {
126         ensure(len + 1);
127         _len = len;
128     }
129
130     void clear() {
131         _len = 0;
132     }
133
134     T & get(unsigned i) {
135         JS_ASSERT(i < length());
136         return _data[i];
137     }
138
139     const T & get(unsigned i) const {
140         JS_ASSERT(i < length());
141         return _data[i];
142     }
143
144     T & operator [](unsigned i) {
145         return get(i);
146     }
147
148     const T & operator [](unsigned i) const {
149         return get(i);
150     }
151
152     unsigned length() const {
153         return _len;
154     }
155
156     T* data() const {
157         return _data;
158     }
159
160     int offsetOf(T slot) {
161         T* p = _data;
162         unsigned n = 0;
163         for (n = 0; n < _len; ++n)
164             if (*p++ == slot)
165                 return n;
166         return -1;
167     }
168
169 };
170
171 /*
172  * Tracker is used to keep track of values being manipulated by the interpreter
173  * during trace recording.  It maps opaque, 4-byte aligned address to LIns pointers.
174  * pointers. To do this efficiently, we observe that the addresses of jsvals
175  * living in the interpreter tend to be aggregated close to each other -
176  * usually on the same page (where a tracker page doesn't have to be the same
177  * size as the OS page size, but it's typically similar).  The Tracker
178  * consists of a linked-list of structures representing a memory page, which
179  * are created on-demand as memory locations are used.
180  *
181  * For every address, first we split it into two parts: upper bits which
182  * represent the "base", and lower bits which represent an offset against the
183  * base.  For the offset, we then right-shift it by two because the bottom two
184  * bits of a 4-byte aligned address are always zero.  The mapping then
185  * becomes:
186  *
187  *   page = page in pagelist such that Base(address) == page->base,
188  *   page->map[Offset(address)]
189  */
190 class Tracker {
191     #define TRACKER_PAGE_SZB        4096
192     #define TRACKER_PAGE_ENTRIES    (TRACKER_PAGE_SZB >> 2)    // each slot is 4 bytes
193     #define TRACKER_PAGE_MASK       jsuword(TRACKER_PAGE_SZB - 1)
194
195     struct TrackerPage {
196         struct TrackerPage* next;
197         jsuword             base;
198         nanojit::LIns*      map[TRACKER_PAGE_ENTRIES];
199     };
200     struct TrackerPage* pagelist;
201
202     jsuword             getTrackerPageBase(const void* v) const;
203     jsuword             getTrackerPageOffset(const void* v) const;
204     struct TrackerPage* findTrackerPage(const void* v) const;
205     struct TrackerPage* addTrackerPage(const void* v);
206 public:
207     Tracker();
208     ~Tracker();
209
210     bool            has(const void* v) const;
211     nanojit::LIns*  get(const void* v) const;
212     void            set(const void* v, nanojit::LIns* ins);
213     void            clear();
214 };
215
216 class VMFragment : public nanojit::Fragment {
217 public:
218     VMFragment(const void* _ip verbose_only(, uint32_t profFragID))
219       : Fragment(_ip verbose_only(, profFragID))
220     {}
221
222     /*
223      * If this is anchored off a TreeFragment, this points to that tree fragment.
224      * Otherwise, it is |this|.
225      */
226     TreeFragment* root;
227
228     TreeFragment* toTreeFragment();
229 };
230
231 #ifdef NJ_NO_VARIADIC_MACROS
232
233 #define debug_only_stmt(action)            /* */
234 static void debug_only_printf(int mask, const char *fmt, ...) JS_BEGIN_MACRO JS_END_MACRO
235 #define debug_only_print0(mask, str)       JS_BEGIN_MACRO JS_END_MACRO
236
237 #elif defined(JS_JIT_SPEW)
238
239 // Top level logging controller object.
240 extern nanojit::LogControl LogController;
241
242 // Top level profiling hook, needed to harvest profile info from Fragments
243 // whose logical lifetime is about to finish
244 extern void FragProfiling_FragFinalizer(nanojit::Fragment* f, TraceMonitor*);
245
246 #define debug_only_stmt(stmt) \
247     stmt
248
249 #define debug_only_printf(mask, fmt, ...)                                      \
250     JS_BEGIN_MACRO                                                             \
251         if ((LogController.lcbits & (mask)) > 0) {                             \
252             LogController.printf(fmt, __VA_ARGS__);                            \
253             fflush(stdout);                                                    \
254         }                                                                      \
255     JS_END_MACRO
256
257 #define debug_only_print0(mask, str)                                           \
258     JS_BEGIN_MACRO                                                             \
259         if ((LogController.lcbits & (mask)) > 0) {                             \
260             LogController.printf("%s", str);                                   \
261             fflush(stdout);                                                    \
262         }                                                                      \
263     JS_END_MACRO
264
265 #else
266
267 #define debug_only_stmt(action)            /* */
268 #define debug_only_printf(mask, fmt, ...)  JS_BEGIN_MACRO JS_END_MACRO
269 #define debug_only_print0(mask, str)       JS_BEGIN_MACRO JS_END_MACRO
270
271 #endif
272
273 /*
274  * The oracle keeps track of hit counts for program counter locations, as
275  * well as slots that should not be demoted to int because we know them to
276  * overflow or they result in type-unstable traces. We are using simple
277  * hash tables.  Collisions lead to loss of optimization (demotable slots
278  * are not demoted, etc.) but have no correctness implications.
279  */
280 #define ORACLE_SIZE 4096
281
282 class Oracle {
283     avmplus::BitSet _stackDontDemote;
284     avmplus::BitSet _globalDontDemote;
285     avmplus::BitSet _pcDontDemote;
286     avmplus::BitSet _pcSlowZeroTest;
287 public:
288     Oracle();
289
290     JS_REQUIRES_STACK void markGlobalSlotUndemotable(JSContext* cx, unsigned slot);
291     JS_REQUIRES_STACK bool isGlobalSlotUndemotable(JSContext* cx, unsigned slot) const;
292     JS_REQUIRES_STACK void markStackSlotUndemotable(JSContext* cx, unsigned slot);
293     JS_REQUIRES_STACK void markStackSlotUndemotable(JSContext* cx, unsigned slot, const void* pc);
294     JS_REQUIRES_STACK bool isStackSlotUndemotable(JSContext* cx, unsigned slot) const;
295     JS_REQUIRES_STACK bool isStackSlotUndemotable(JSContext* cx, unsigned slot, const void* pc) const;
296     void markInstructionUndemotable(jsbytecode* pc);
297     bool isInstructionUndemotable(jsbytecode* pc) const;
298     void markInstructionSlowZeroTest(jsbytecode* pc);
299     bool isInstructionSlowZeroTest(jsbytecode* pc) const;
300
301     void clearDemotability();
302     void clear() {
303         clearDemotability();
304     }
305 };
306
307 typedef Queue<uint16> SlotList;
308
309 class TypeMap : public Queue<JSValueType> {
310     Oracle *oracle;
311 public:
312     TypeMap(nanojit::Allocator* alloc, Oracle *oracle)
313       : Queue<JSValueType>(alloc),
314         oracle(oracle)
315     {}
316     void set(unsigned stackSlots, unsigned ngslots,
317              const JSValueType* stackTypeMap, const JSValueType* globalTypeMap);
318     JS_REQUIRES_STACK void captureTypes(JSContext* cx, JSObject* globalObj, SlotList& slots, unsigned callDepth,
319                                         bool speculate);
320     JS_REQUIRES_STACK void captureMissingGlobalTypes(JSContext* cx, JSObject* globalObj, SlotList& slots,
321                                                      unsigned stackSlots, bool speculate);
322     bool matches(TypeMap& other) const;
323     void fromRaw(JSValueType* other, unsigned numSlots);
324 };
325
326 #define JS_TM_EXITCODES(_)    \
327     /*                                                                          \
328      * An exit at a possible branch-point in the trace at which to attach a     \
329      * future secondary trace. Therefore the recorder must generate different   \
330      * code to handle the other outcome of the branch condition from the        \
331      * primary trace's outcome.                                                 \
332      */                                                                         \
333     _(BRANCH)                                                                   \
334     /*                                                                          \
335      * Exit at a tableswitch via a numbered case.                               \
336      */                                                                         \
337     _(CASE)                                                                     \
338     /*                                                                          \
339      * Exit at a tableswitch via the default case.                              \
340      */                                                                         \
341     _(DEFAULT)                                                                  \
342     _(LOOP)                                                                     \
343     _(NESTED)                                                                   \
344     /*                                                                          \
345      * An exit from a trace because a condition relied upon at recording time   \
346      * no longer holds, where the alternate path of execution is so rare or     \
347      * difficult to address in native code that it is not traced at all, e.g.   \
348      * negative array index accesses, which differ from positive indexes in     \
349      * that they require a string-based property lookup rather than a simple    \
350      * memory access.                                                           \
351      */                                                                         \
352     _(MISMATCH)                                                                 \
353     /*                                                                          \
354      * A specialization of MISMATCH_EXIT to handle allocation failures.         \
355      */                                                                         \
356     _(OOM)                                                                      \
357     _(OVERFLOW)                                                                 \
358     _(MUL_ZERO)                                                                 \
359     _(UNSTABLE_LOOP)                                                            \
360     _(TIMEOUT)                                                                  \
361     _(DEEP_BAIL)                                                                \
362     _(STATUS)
363
364 enum ExitType {
365     #define MAKE_EXIT_CODE(x) x##_EXIT,
366     JS_TM_EXITCODES(MAKE_EXIT_CODE)
367     #undef MAKE_EXIT_CODE
368     TOTAL_EXIT_TYPES
369 };
370
371 struct FrameInfo;
372
373 struct VMSideExit : public nanojit::SideExit
374 {
375     jsbytecode* pc;
376     jsbytecode* imacpc;
377     intptr_t sp_adj;
378     intptr_t rp_adj;
379     int32_t calldepth;
380     uint32 numGlobalSlots;
381     uint32 numStackSlots;
382     uint32 numStackSlotsBelowCurrentFrame;
383     ExitType exitType;
384     uintN lookupFlags;
385     unsigned hitcount;
386
387     inline JSValueType* stackTypeMap() {
388         return (JSValueType*)(this + 1);
389     }
390
391     inline JSValueType& stackType(unsigned i) {
392         JS_ASSERT(i < numStackSlots);
393         return stackTypeMap()[i];
394     }
395
396     inline JSValueType* globalTypeMap() {
397         return (JSValueType*)(this + 1) + this->numStackSlots;
398     }
399
400     inline JSValueType* fullTypeMap() {
401         return stackTypeMap();
402     }
403
404     inline VMFragment* fromFrag() {
405         return (VMFragment*)from;
406     }
407
408     inline TreeFragment* root() {
409         return fromFrag()->root;
410     }
411 };
412
413 class VMAllocator : public nanojit::Allocator
414 {
415
416 public:
417     VMAllocator(char* reserve, size_t reserveSize)
418       : mOutOfMemory(false), mSize(0), mReserve(reserve),
419         mReserveCurr(uintptr_t(reserve)), mReserveLimit(uintptr_t(reserve + reserveSize))
420     {}
421
422     ~VMAllocator() {
423         js_free(mReserve);
424     }
425
426     size_t size() {
427         return mSize;
428     }
429
430     bool outOfMemory() {
431         return mOutOfMemory;
432     }
433
434     struct Mark
435     {
436         VMAllocator& vma;
437         bool committed;
438         nanojit::Allocator::Chunk* saved_chunk;
439         char* saved_top;
440         char* saved_limit;
441         size_t saved_size;
442
443         Mark(VMAllocator& vma) :
444             vma(vma),
445             committed(false),
446             saved_chunk(vma.current_chunk),
447             saved_top(vma.current_top),
448             saved_limit(vma.current_limit),
449             saved_size(vma.mSize)
450         {}
451
452         ~Mark()
453         {
454             if (!committed)
455                 vma.rewind(*this);
456         }
457
458         void commit() { committed = true; }
459     };
460
461     void rewind(const Mark& m) {
462         while (current_chunk != m.saved_chunk) {
463             Chunk *prev = current_chunk->prev;
464             freeChunk(current_chunk);
465             current_chunk = prev;
466         }
467         current_top = m.saved_top;
468         current_limit = m.saved_limit;
469         mSize = m.saved_size;
470         memset(current_top, 0, current_limit - current_top);
471     }
472
473     bool mOutOfMemory;
474     size_t mSize;
475
476     /* See nanojit::Allocator::allocChunk() for details on these. */
477     char* mReserve;
478     uintptr_t mReserveCurr;
479     uintptr_t mReserveLimit;
480 };
481
482 struct FrameInfo {
483     JSObject*       block;      // caller block chain head
484     jsbytecode*     pc;         // caller fp->regs->pc
485     jsbytecode*     imacpc;     // caller fp->imacpc
486     uint32          spdist;     // distance from fp->slots to fp->regs->sp at JSOP_CALL
487
488     /*
489      * Bit  15 (0x8000) is a flag that is set if constructing (called through new).
490      * Bits 0-14 are the actual argument count. This may be less than fun->nargs.
491      * NB: This is argc for the callee, not the caller.
492      */
493     uint32          argc;
494
495     /*
496      * Number of stack slots in the caller, not counting slots pushed when
497      * invoking the callee. That is, slots after JSOP_CALL completes but
498      * without the return value. This is also equal to the number of slots
499      * between fp->prev->argv[-2] (calleR fp->callee) and fp->argv[-2]
500      * (calleE fp->callee).
501      */
502     uint32          callerHeight;
503
504     /* argc of the caller */
505     uint32          callerArgc;
506
507     // Safer accessors for argc.
508     enum { CONSTRUCTING_FLAG = 0x10000 };
509     void   set_argc(uint16 argc, bool constructing) {
510         this->argc = uint32(argc) | (constructing ? CONSTRUCTING_FLAG: 0);
511     }
512     uint16 get_argc() const { return uint16(argc & ~CONSTRUCTING_FLAG); }
513     bool   is_constructing() const { return (argc & CONSTRUCTING_FLAG) != 0; }
514
515     // The typemap just before the callee is called.
516     JSValueType* get_typemap() { return (JSValueType*) (this+1); }
517     const JSValueType* get_typemap() const { return (JSValueType*) (this+1); }
518 };
519
520 struct UnstableExit
521 {
522     VMFragment* fragment;
523     VMSideExit* exit;
524     UnstableExit* next;
525 };
526
527 struct LinkableFragment : public VMFragment
528 {
529     LinkableFragment(const void* _ip, nanojit::Allocator* alloc, Oracle *oracle
530                      verbose_only(, uint32_t profFragID))
531         : VMFragment(_ip verbose_only(, profFragID)), typeMap(alloc, oracle), nStackTypes(0)
532     { }
533
534     uint32                  branchCount;
535     TypeMap                 typeMap;
536     unsigned                nStackTypes;
537     unsigned                spOffsetAtEntry;
538     SlotList*               globalSlots;
539 };
540
541 /*
542  * argc is cx->fp->argc at the trace loop header, i.e., the number of arguments
543  * pushed for the innermost JS frame. This is required as part of the fragment
544  * key because the fragment will write those arguments back to the interpreter
545  * stack when it exits, using its typemap, which implicitly incorporates a
546  * given value of argc. Without this feature, a fragment could be called as an
547  * inner tree with two different values of argc, and entry type checking or
548  * exit frame synthesis could crash.
549  */
550 struct TreeFragment : public LinkableFragment
551 {
552     TreeFragment(const void* _ip, nanojit::Allocator* alloc, Oracle *oracle, JSObject* _globalObj,
553                  uint32 _globalShape, uint32 _argc verbose_only(, uint32_t profFragID)):
554         LinkableFragment(_ip, alloc, oracle verbose_only(, profFragID)),
555         first(NULL),
556         next(NULL),
557         peer(NULL),
558         globalObj(_globalObj),
559         globalShape(_globalShape),
560         argc(_argc),
561         dependentTrees(alloc),
562         linkedTrees(alloc),
563         sideExits(alloc),
564         gcthings(alloc),
565         shapes(alloc)
566     { }
567
568     TreeFragment* first;
569     TreeFragment* next;
570     TreeFragment* peer;
571     JSObject* globalObj;
572     uint32 globalShape;
573     uint32 argc;
574     /* Dependent trees must be trashed if this tree dies, and updated on missing global types */
575     Queue<TreeFragment*>    dependentTrees;
576     /* Linked trees must be updated on missing global types, but are not dependent */
577     Queue<TreeFragment*>    linkedTrees;
578 #ifdef DEBUG
579     const char*             treeFileName;
580     uintN                   treeLineNumber;
581     uintN                   treePCOffset;
582 #endif
583     JSScript*               script;
584     UnstableExit*           unstableExits;
585     Queue<VMSideExit*>      sideExits;
586     ptrdiff_t               nativeStackBase;
587     unsigned                maxCallDepth;
588     /* All embedded GC things are registered here so the GC can scan them. */
589     Queue<Value>            gcthings;
590     Queue<const js::Shape*> shapes;
591     unsigned                maxNativeStackSlots;
592     /* Gives the number of times we have entered this trace. */
593     uintN                   execs;
594     /* Gives the total number of iterations executed by the trace (up to a limit). */
595     uintN                   iters;
596
597     inline unsigned nGlobalTypes() {
598         return typeMap.length() - nStackTypes;
599     }
600     inline JSValueType* globalTypeMap() {
601         return typeMap.data() + nStackTypes;
602     }
603     inline JSValueType* stackTypeMap() {
604         return typeMap.data();
605     }
606
607     JS_REQUIRES_STACK void initialize(JSContext* cx, SlotList *globalSlots, bool speculate);
608     UnstableExit* removeUnstableExit(VMSideExit* exit);
609 };
610
611 inline TreeFragment*
612 VMFragment::toTreeFragment()
613 {
614     JS_ASSERT(root == this);
615     return static_cast<TreeFragment*>(this);
616 }
617
618 enum MonitorResult {
619     MONITOR_RECORDING,
620     MONITOR_NOT_RECORDING,
621     MONITOR_ERROR
622 };
623
624 const uintN PROFILE_MAX_INNER_LOOPS = 8;
625 const uintN PROFILE_MAX_STACK = 6;
626
627 /*
628  * A loop profile keeps track of the instruction mix of a hot loop. We use this
629  * information to predict whether tracing would be beneficial for the loop.
630  */
631 class LoopProfile
632 {
633 public:
634     /* Instructions are divided into a few categories. */
635     enum OpKind {
636         OP_FLOAT, // Floating point arithmetic
637         OP_INT, // Integer arithmetic
638         OP_BIT, // Bit operations
639         OP_EQ, // == and !=
640         OP_EVAL, // Calls to eval()
641         OP_CALL, // JSOP_CALL instructions
642         OP_FWDJUMP, // Jumps with positive delta
643         OP_NEW, // JSOP_NEW instructions
644         OP_RECURSIVE, // Recursive calls
645         OP_ARRAY_READ, // Reads from dense arrays
646         OP_TYPED_ARRAY, // Accesses to typed arrays
647         OP_LIMIT
648     };
649
650     /* The TraceMonitor for which we're profiling. */
651     TraceMonitor *traceMonitor;
652     
653     /* The script in which the loop header lives. */
654     JSScript *entryScript;
655
656     /* The stack frame where we started profiling. Only valid while profiling! */
657     JSStackFrame *entryfp;
658
659     /* The bytecode locations of the loop header and the back edge. */
660     jsbytecode *top, *bottom;
661
662     /* Number of times we have seen this loop executed; used to decide when to profile. */
663     uintN hits;
664
665     /* Whether we have run a complete profile of the loop. */
666     bool profiled;
667
668     /* Sometimes we can't decide in one profile run whether to trace, so we set undecided. */
669     bool undecided;
670
671     /* If we have profiled the loop, this saves the decision of whether to trace it. */
672     bool traceOK;
673
674     /* Memoized value of isCompilationUnprofitable. */
675     bool unprofitable;
676
677     /*
678      * Sometimes loops are not good tracing opportunities, but they are nested inside
679      * loops that we want to trace. In that case, we set their traceOK flag to true,
680      * but we set execOK to false. That way, the loop is traced so that it can be
681      * integrated into the outer trace. But we never execute the trace on its only.
682      */
683     bool execOK;
684
685     /* Instruction mix for the loop and total number of instructions. */
686     uintN allOps[OP_LIMIT];
687     uintN numAllOps;
688
689     /* Instruction mix and total for the loop, excluding nested inner loops. */
690     uintN selfOps[OP_LIMIT];
691     uintN numSelfOps;
692
693     /*
694      * A prediction of the number of instructions we would have to compile
695      * for the loop. This takes into account the fact that a branch may cause us to
696      * compile every instruction after it twice. Polymorphic calls are
697      * treated as n-way branches.
698      */
699     double numSelfOpsMult;
700
701     /*
702      * This keeps track of the number of times that every succeeding instruction
703      * in the trace will have to be compiled. Every time we hit a branch, we
704      * double this number. Polymorphic calls multiply it by n (for n-way
705      * polymorphism).
706      */
707     double branchMultiplier;
708
709     /* Set to true if the loop is short (i.e., has fewer than 8 iterations). */
710     bool shortLoop;
711
712     /* Set to true if the loop may be short (has few iterations at profiling time). */
713     bool maybeShortLoop;
714
715     /*
716      * When we hit a nested loop while profiling, we record where it occurs
717      * and how many iterations we execute it.
718      */
719     struct InnerLoop {
720         JSStackFrame *entryfp;
721         jsbytecode *top, *bottom;
722         uintN iters;
723
724         InnerLoop() {}
725         InnerLoop(JSStackFrame *entryfp, jsbytecode *top, jsbytecode *bottom)
726             : entryfp(entryfp), top(top), bottom(bottom), iters(0) {}
727     };
728
729     /* These two variables track all the inner loops seen while profiling (up to a limit). */
730     InnerLoop innerLoops[PROFILE_MAX_INNER_LOOPS];
731     uintN numInnerLoops;
732
733     /*
734      * These two variables track the loops that we are currently nested
735      * inside while profiling. Loops get popped off here when they exit.
736      */
737     InnerLoop loopStack[PROFILE_MAX_INNER_LOOPS];
738     uintN loopStackDepth;
739
740     /*
741      * These fields keep track of values on the JS stack. If the stack grows larger
742      * than PROFILE_MAX_STACK, we continue to track sp, but we return conservative results
743      * for stackTop().
744      */
745     struct StackValue {
746         bool isConst;
747         bool hasValue;
748         int value;
749
750         StackValue() : isConst(false), hasValue(false) {}
751         StackValue(bool isConst) : isConst(isConst), hasValue(false) {}
752         StackValue(bool isConst, int value) : isConst(isConst), hasValue(true), value(value) {}
753     };
754     StackValue stack[PROFILE_MAX_STACK];
755     uintN sp;
756
757     inline void stackClear() { sp = 0; }
758     
759     inline void stackPush(const StackValue &v) {
760         if (sp < PROFILE_MAX_STACK)
761             stack[sp++] = v;
762         else
763             stackClear();
764     }
765
766     inline void stackPop() { if (sp > 0) sp--; }
767
768     inline StackValue stackAt(int pos) {
769         pos += sp;
770         if (pos >= 0 && uintN(pos) < PROFILE_MAX_STACK)
771             return stack[pos];
772         else
773             return StackValue(false);
774     }
775     
776     LoopProfile(TraceMonitor *tm, JSStackFrame *entryfp, jsbytecode *top, jsbytecode *bottom);
777
778     void reset();
779
780     enum ProfileAction {
781         ProfContinue,
782         ProfComplete
783     };
784
785     /* These two functions track the instruction mix. */
786     inline void increment(OpKind kind)
787     {
788         allOps[kind]++;
789         if (loopStackDepth == 0)
790             selfOps[kind]++;
791     }
792
793     inline uintN count(OpKind kind) { return allOps[kind]; }
794
795     /* Called for every back edge being profiled. */
796     MonitorResult profileLoopEdge(JSContext* cx, uintN& inlineCallCount);
797     
798     /* Called for every instruction being profiled. */
799     ProfileAction profileOperation(JSContext *cx, JSOp op);
800
801     /* Once a loop's profile is done, these decide whether it should be traced. */
802     bool isCompilationExpensive(JSContext *cx, uintN depth);
803     bool isCompilationUnprofitable(JSContext *cx, uintN goodOps);
804     void decide(JSContext *cx);
805
806     void stopProfiling(JSContext *cx);
807 };
808
809 /*
810  * BUILTIN_NO_FIXUP_NEEDED indicates that after the initial LeaveTree of a deep
811  * bail, the builtin call needs no further fixup when the trace exits and calls
812  * LeaveTree the second time.
813  */
814 typedef enum BuiltinStatus {
815     BUILTIN_BAILED = 1,
816     BUILTIN_ERROR = 2
817 } BuiltinStatus;
818
819 static JS_INLINE void
820 SetBuiltinError(TraceMonitor *tm)
821 {
822     tm->tracerState->builtinStatus |= BUILTIN_ERROR;
823 }
824
825 static JS_INLINE bool
826 WasBuiltinSuccessful(TraceMonitor *tm)
827 {
828     return tm->tracerState->builtinStatus == 0;
829 }
830
831 #ifdef DEBUG_RECORDING_STATUS_NOT_BOOL
832 /* #define DEBUG_RECORDING_STATUS_NOT_BOOL to detect misuses of RecordingStatus */
833 struct RecordingStatus {
834     int code;
835     bool operator==(RecordingStatus &s) { return this->code == s.code; };
836     bool operator!=(RecordingStatus &s) { return this->code != s.code; };
837 };
838 enum RecordingStatusCodes {
839     RECORD_ERROR_code     = 0,
840     RECORD_STOP_code      = 1,
841
842     RECORD_CONTINUE_code  = 3,
843     RECORD_IMACRO_code    = 4
844 };
845 RecordingStatus RECORD_CONTINUE = { RECORD_CONTINUE_code };
846 RecordingStatus RECORD_STOP     = { RECORD_STOP_code };
847 RecordingStatus RECORD_IMACRO   = { RECORD_IMACRO_code };
848 RecordingStatus RECORD_ERROR    = { RECORD_ERROR_code };
849
850 struct AbortableRecordingStatus {
851     int code;
852     bool operator==(AbortableRecordingStatus &s) { return this->code == s.code; };
853     bool operator!=(AbortableRecordingStatus &s) { return this->code != s.code; };
854 };
855 enum AbortableRecordingStatusCodes {
856     ARECORD_ERROR_code     = 0,
857     ARECORD_STOP_code      = 1,
858     ARECORD_ABORTED_code   = 2,
859     ARECORD_CONTINUE_code  = 3,
860     ARECORD_IMACRO_code    = 4,
861     ARECORD_IMACRO_ABORTED_code = 5,
862     ARECORD_COMPLETED_code = 6
863 };
864 AbortableRecordingStatus ARECORD_ERROR    = { ARECORD_ERROR_code };
865 AbortableRecordingStatus ARECORD_STOP     = { ARECORD_STOP_code };
866 AbortableRecordingStatus ARECORD_CONTINUE = { ARECORD_CONTINUE_code };
867 AbortableRecordingStatus ARECORD_IMACRO   = { ARECORD_IMACRO_code };
868 AbortableRecordingStatus ARECORD_IMACRO_ABORTED   = { ARECORD_IMACRO_ABORTED_code };
869 AbortableRecordingStatus ARECORD_ABORTED =  { ARECORD_ABORTED_code };
870 AbortableRecordingStatus ARECORD_COMPLETED =  { ARECORD_COMPLETED_code };
871
872 static inline AbortableRecordingStatus
873 InjectStatus(RecordingStatus rs)
874 {
875     AbortableRecordingStatus ars = { rs.code };
876     return ars;
877 }
878 static inline AbortableRecordingStatus
879 InjectStatus(AbortableRecordingStatus ars)
880 {
881     return ars;
882 }
883
884 static inline bool
885 StatusAbortsRecorderIfActive(AbortableRecordingStatus ars)
886 {
887     return ars == ARECORD_ERROR || ars == ARECORD_STOP;
888 }
889 #else
890
891 /*
892  * Normally, during recording, when the recorder cannot continue, it returns
893  * ARECORD_STOP to indicate that recording should be aborted by the top-level
894  * recording function. However, if the recorder reenters the interpreter (e.g.,
895  * when executing an inner loop), there will be an immediate abort. This
896  * condition must be carefully detected and propagated out of all nested
897  * recorder calls lest the now-invalid TraceRecorder object be accessed
898  * accidentally. This condition is indicated by the ARECORD_ABORTED value.
899  *
900  * The AbortableRecordingStatus enumeration represents the general set of
901  * possible results of calling a recorder function. Functions that cannot
902  * possibly return ARECORD_ABORTED may statically guarantee this to the caller
903  * using the RecordingStatus enumeration. Ideally, C++ would allow subtyping
904  * of enumerations, but it doesn't. To simulate subtype conversion manually,
905  * code should call InjectStatus to inject a value of the restricted set into a
906  * value of the general set.
907  */
908
909 enum RecordingStatus {
910     RECORD_STOP       = 0,  // Recording should be aborted at the top-level
911                             // call to the recorder.
912     RECORD_ERROR      = 1,  // Recording should be aborted at the top-level
913                             // call to the recorder and the interpreter should
914                             // goto error
915     RECORD_CONTINUE   = 2,  // Continue recording.
916     RECORD_IMACRO     = 3   // Entered imacro; continue recording.
917                             // Only JSOP_IS_IMACOP opcodes may return this.
918 };
919
920 enum AbortableRecordingStatus {
921     ARECORD_STOP      = 0,  // see RECORD_STOP
922     ARECORD_ERROR     = 1,  // Recording may or may not have been aborted.
923                             // Recording should be aborted at the top-level
924                             // if it has not already been and the interpreter
925                             // should goto error
926     ARECORD_CONTINUE  = 2,  // see RECORD_CONTINUE
927     ARECORD_IMACRO    = 3,  // see RECORD_IMACRO
928     ARECORD_IMACRO_ABORTED = 4, // see comment in TR::monitorRecording.
929     ARECORD_ABORTED   = 5,  // Recording has already been aborted; the
930                             // interpreter should continue executing
931     ARECORD_COMPLETED = 6   // Recording completed successfully, the
932                             // trace recorder has been deleted
933 };
934
935 static JS_ALWAYS_INLINE AbortableRecordingStatus
936 InjectStatus(RecordingStatus rs)
937 {
938     return static_cast<AbortableRecordingStatus>(rs);
939 }
940
941 static JS_ALWAYS_INLINE AbortableRecordingStatus
942 InjectStatus(AbortableRecordingStatus ars)
943 {
944     return ars;
945 }
946
947 /*
948  * Return whether the recording status requires the current recording session
949  * to be deleted. ERROR means the recording session should be deleted if it
950  * hasn't already. ABORTED and COMPLETED indicate the recording session is
951  * already deleted, so they return 'false'.
952  */
953 static JS_ALWAYS_INLINE bool
954 StatusAbortsRecorderIfActive(AbortableRecordingStatus ars)
955 {
956     return ars <= ARECORD_ERROR;
957 }
958 #endif
959
960 class SlotMap;
961 class SlurpInfo;
962
963 /* Results of trying to compare two typemaps together */
964 enum TypeConsensus
965 {
966     TypeConsensus_Okay,         /* Two typemaps are compatible */
967     TypeConsensus_Undemotes,    /* Not compatible now, but would be with pending undemotes. */
968     TypeConsensus_Bad           /* Typemaps are not compatible */
969 };
970
971 enum TracePointAction {
972     TPA_Nothing,
973     TPA_RanStuff,
974     TPA_Recorded,
975     TPA_Error
976 };
977
978 typedef HashMap<nanojit::LIns*, JSObject*> GuardedShapeTable;
979
980 #ifdef DEBUG
981 # define AbortRecording(cx, reason) AbortRecordingImpl(cx, reason)
982 #else
983 # define AbortRecording(cx, reason) AbortRecordingImpl(cx)
984 #endif
985
986 void
987 AbortProfiling(JSContext *cx);
988
989 class TraceRecorder
990 {
991     /*************************************************************** Recording session constants */
992
993     /* The context in which recording started. */
994     JSContext* const                cx;
995
996     /* Cached value of JS_TRACE_MONITOR(cx). */
997     TraceMonitor* const             traceMonitor;
998
999     /* Cached oracle keeps track of hit counts for program counter locations */
1000     Oracle*                         oracle;
1001
1002     /* The Fragment being recorded by this recording session. */
1003     VMFragment* const               fragment;
1004
1005     /* The root fragment representing the tree. */
1006     TreeFragment* const             tree;
1007
1008     /* The global object from the start of recording until now. */
1009     JSObject* const                 globalObj;
1010
1011     /* If non-null, the script of outer loop aborted to start recording this loop. */
1012     JSScript* const                 outerScript;
1013     
1014     /* If non-null, the pc of the outer loop aborted to start recording this loop. */
1015     jsbytecode* const               outerPC;
1016
1017     /* If |outerPC|, the argc to use when looking up |outerPC| in the fragments table. */
1018     uint32 const                    outerArgc;
1019
1020     /* If non-null, the side exit from which we are growing. */
1021     VMSideExit* const               anchor;
1022
1023     /* Instructions yielding the corresponding trace-const members of TracerState. */
1024     nanojit::LIns* const            cx_ins;
1025     nanojit::LIns* const            eos_ins;
1026     nanojit::LIns* const            eor_ins;
1027     nanojit::LIns* const            loopLabel;
1028
1029     /* Lazy slot import state. */
1030     unsigned                        importStackSlots;
1031     unsigned                        importGlobalSlots;
1032     TypeMap                         importTypeMap;
1033
1034     /*
1035      * The LirBuffer used to supply memory to our LirWriter pipeline. Also contains the most recent
1036      * instruction for {sp, rp, state}. Also contains names for debug JIT spew. Should be split.
1037      */
1038     nanojit::LirBuffer* const       lirbuf;
1039
1040     /*
1041      * Remembers traceAlloc state before recording started; automatically rewinds when mark is
1042      * destroyed on a failed compilation.
1043      */
1044     VMAllocator::Mark               mark;
1045
1046     /* Remembers the number of sideExits in treeInfo before recording started. */
1047     const unsigned                  numSideExitsBefore;
1048
1049     /*********************************************************** Recording session mutable state */
1050
1051     /* Maps interpreter stack values to the instruction generating that value. */
1052     Tracker                         tracker;
1053
1054     /* Maps interpreter stack values to the instruction writing back to the native stack. */
1055     Tracker                         nativeFrameTracker;
1056
1057     /* The start of the global object's slots we assume for the trackers. */
1058     Value*                          global_slots;
1059
1060     /* The number of interpreted calls entered (and not yet left) since recording began. */
1061     unsigned                        callDepth;
1062
1063     /* The current atom table, mirroring the interpreter loop's variable of the same name. */
1064     JSAtom**                        atoms;
1065     Value*                          consts;
1066
1067     /* An instruction yielding the current script's strict mode code flag.  */
1068     nanojit::LIns*                  strictModeCode_ins;
1069
1070     /* FIXME: Dead, but soon to be used for something or other. */
1071     Queue<jsbytecode*>              cfgMerges;
1072
1073     /* Indicates whether the current tree should be trashed when the recording session ends. */
1074     bool                            trashSelf;
1075
1076     /* A list of trees to trash at the end of the recording session. */
1077     Queue<TreeFragment*>            whichTreesToTrash;
1078
1079     /* The set of objects whose shapes already have been guarded. */
1080     GuardedShapeTable               guardedShapeTable;
1081
1082     /* Current initializer depth, and whether any of the initializers are unoptimized NEWINIT. */
1083     int                             initDepth;
1084     bool                            hadNewInit;
1085
1086 #ifdef DEBUG
1087     /*
1088      * If we are expecting a record_AddProperty callback for this instruction,
1089      * the shape of the object before adding the data property. Else NULL.
1090      */
1091     const js::Shape* addPropShapeBefore;
1092 #endif
1093
1094     /***************************************** Temporal state hoisted into the recording session */
1095
1096     /* Carry the return value from a STOP/RETURN to the subsequent record_LeaveFrame. */
1097     nanojit::LIns*                  rval_ins;
1098
1099     /* Carry the return value from a native call to the record_NativeCallComplete. */
1100     nanojit::LIns*                  native_rval_ins;
1101
1102     /* Carry the return value of js_CreateThis to record_NativeCallComplete. */
1103     nanojit::LIns*                  newobj_ins;
1104
1105     /* Carry the JSSpecializedNative used to generate a call to record_NativeCallComplete. */
1106     JSSpecializedNative*            pendingSpecializedNative;
1107
1108     /* Carry whether this is a jsval on the native stack from finishGetProp to monitorRecording. */
1109     Value*                          pendingUnboxSlot;
1110
1111     /* Carry a guard condition to the beginning of the next monitorRecording. */
1112     nanojit::LIns*                  pendingGuardCondition;
1113
1114     /* See AbortRecordingIfUnexpectedGlobalWrite. */
1115     js::Vector<unsigned>            pendingGlobalSlotsToSet;
1116
1117     /* Carry whether we have an always-exit from emitIf to checkTraceEnd. */
1118     bool                            pendingLoop;
1119
1120     /* Temporary JSSpecializedNative used to describe non-specialized fast natives. */
1121     JSSpecializedNative             generatedSpecializedNative;
1122
1123     /* Temporary JSValueType array used to construct temporary typemaps. */
1124     js::Vector<JSValueType, 256>    tempTypeMap;
1125
1126     /* Used to generate LIR.  Has a short name because it's used a lot. */
1127     tjit::Writer w;
1128
1129     /************************************************************* 10 bajillion member functions */
1130
1131     /*
1132      * These would be in Writer if they didn't modify TraceRecorder state.
1133      * They are invoked the via macros below that make them look like they are
1134      * part of Writer (hence the "w_" prefix, which looks like "w.").
1135      */
1136     nanojit::LIns* w_immpObjGC(JSObject* obj);
1137     nanojit::LIns* w_immpFunGC(JSFunction* fun);
1138     nanojit::LIns* w_immpStrGC(JSString* str);
1139     nanojit::LIns* w_immpShapeGC(const js::Shape* shape);
1140     nanojit::LIns* w_immpIdGC(jsid id);
1141
1142     #define immpObjGC(obj)        name(w_immpObjGC(obj), #obj)
1143     #define immpFunGC(fun)        name(w_immpFunGC(fun), #fun)
1144     #define immpStrGC(str)        name(w_immpStrGC(str), #str)
1145     #define immpAtomGC(atom)      name(w_immpStrGC(ATOM_TO_STRING(atom)), "ATOM_TO_STRING(" #atom ")")
1146     #define immpShapeGC(shape)    name(w_immpShapeGC(shape), #shape)
1147     #define immpIdGC(id)          name(w_immpIdGC(id), #id)
1148
1149     /*
1150      * Examines current interpreter state to record information suitable for returning to the
1151      * interpreter through a side exit of the given type.
1152      */
1153     JS_REQUIRES_STACK VMSideExit* snapshot(ExitType exitType);
1154
1155     /*
1156      * Creates a separate but identical copy of the given side exit, allowing the guards associated
1157      * with each to be entirely separate even after subsequent patching.
1158      */
1159     JS_REQUIRES_STACK VMSideExit* copy(VMSideExit* exit);
1160
1161     /*
1162      * Creates an instruction whose payload is a GuardRecord for the given exit.  The instruction
1163      * is suitable for use as the final argument of a single call to LirBuffer::insGuard; do not
1164      * reuse the returned value.
1165      */
1166     JS_REQUIRES_STACK nanojit::GuardRecord* createGuardRecord(VMSideExit* exit);
1167
1168     JS_REQUIRES_STACK JS_INLINE void markSlotUndemotable(LinkableFragment* f, unsigned slot);
1169
1170     JS_REQUIRES_STACK JS_INLINE void markSlotUndemotable(LinkableFragment* f, unsigned slot, const void* pc);
1171
1172     JS_REQUIRES_STACK unsigned findUndemotesInTypemaps(const TypeMap& typeMap, LinkableFragment* f,
1173                             Queue<unsigned>& undemotes);
1174
1175     JS_REQUIRES_STACK void assertDownFrameIsConsistent(VMSideExit* anchor, FrameInfo* fi);
1176
1177     JS_REQUIRES_STACK void captureStackTypes(unsigned callDepth, JSValueType* typeMap);
1178
1179     bool isVoidPtrGlobal(const void* p) const;
1180     bool isGlobal(const Value* p) const;
1181     ptrdiff_t nativeGlobalSlot(const Value *p) const;
1182     ptrdiff_t nativeGlobalOffset(const Value* p) const;
1183     JS_REQUIRES_STACK ptrdiff_t nativeStackOffsetImpl(const void* p) const;
1184     JS_REQUIRES_STACK ptrdiff_t nativeStackOffset(const Value* p) const;
1185     JS_REQUIRES_STACK ptrdiff_t nativeStackSlotImpl(const void* p) const;
1186     JS_REQUIRES_STACK ptrdiff_t nativeStackSlot(const Value* p) const;
1187     JS_REQUIRES_STACK ptrdiff_t nativespOffsetImpl(const void* p) const;
1188     JS_REQUIRES_STACK ptrdiff_t nativespOffset(const Value* p) const;
1189     JS_REQUIRES_STACK void importImpl(tjit::Address addr, const void* p, JSValueType t,
1190                                       const char *prefix, uintN index, JSStackFrame *fp);
1191     JS_REQUIRES_STACK void import(tjit::Address addr, const Value* p, JSValueType t,
1192                                   const char *prefix, uintN index, JSStackFrame *fp);
1193     JS_REQUIRES_STACK void import(TreeFragment* tree, nanojit::LIns* sp, unsigned stackSlots,
1194                                   unsigned callDepth, unsigned ngslots, JSValueType* typeMap);
1195     void trackNativeStackUse(unsigned slots);
1196
1197     JS_REQUIRES_STACK bool isValidSlot(JSObject *obj, const js::Shape* shape);
1198     JS_REQUIRES_STACK bool lazilyImportGlobalSlot(unsigned slot);
1199     JS_REQUIRES_STACK void importGlobalSlot(unsigned slot);
1200
1201     void ensureCond(nanojit::LIns** ins, bool* cond);
1202
1203     JS_REQUIRES_STACK RecordingStatus guard(bool expected, nanojit::LIns* cond, ExitType exitType,
1204                                             bool abortIfAlwaysExits = false);
1205     JS_REQUIRES_STACK RecordingStatus guard(bool expected, nanojit::LIns* cond, VMSideExit* exit,
1206                                             bool abortIfAlwaysExits = false);
1207     JS_REQUIRES_STACK nanojit::LIns* guard_xov(nanojit::LOpcode op, nanojit::LIns* d0,
1208                                                nanojit::LIns* d1, VMSideExit* exit);
1209
1210     nanojit::LIns* writeBack(nanojit::LIns* i, nanojit::LIns* base, ptrdiff_t offset,
1211                              bool shouldDemoteToInt32);
1212
1213 #ifdef DEBUG
1214     bool isValidFrameObjPtr(void *obj);
1215 #endif
1216     void assertInsideLoop();
1217
1218     JS_REQUIRES_STACK void setImpl(void* p, nanojit::LIns* l, bool shouldDemoteToInt32 = true);
1219     JS_REQUIRES_STACK void set(Value* p, nanojit::LIns* l, bool shouldDemoteToInt32 = true);
1220     JS_REQUIRES_STACK void setFrameObjPtr(void* p, nanojit::LIns* l,
1221                                           bool shouldDemoteToInt32 = true);
1222     nanojit::LIns* getFromTrackerImpl(const void *p);
1223     nanojit::LIns* getFromTracker(const Value* p);
1224     JS_REQUIRES_STACK nanojit::LIns* getImpl(const void* p);
1225     JS_REQUIRES_STACK nanojit::LIns* get(const Value* p);
1226     JS_REQUIRES_STACK nanojit::LIns* getFrameObjPtr(void* p);
1227     JS_REQUIRES_STACK nanojit::LIns* attemptImport(const Value* p);
1228     JS_REQUIRES_STACK nanojit::LIns* addr(Value* p);
1229
1230     JS_REQUIRES_STACK bool knownImpl(const void* p);
1231     JS_REQUIRES_STACK bool known(const Value* p);
1232     JS_REQUIRES_STACK bool known(JSObject** p);
1233     /*
1234      * The slots of the global object are sometimes reallocated by the
1235      * interpreter.  This function checks for that condition and re-maps the
1236      * entries of the tracker accordingly.
1237      */
1238     JS_REQUIRES_STACK void checkForGlobalObjectReallocation() {
1239         if (global_slots != globalObj->getSlots())
1240             checkForGlobalObjectReallocationHelper();
1241     }
1242     JS_REQUIRES_STACK void checkForGlobalObjectReallocationHelper();
1243
1244     JS_REQUIRES_STACK TypeConsensus selfTypeStability(SlotMap& smap);
1245     JS_REQUIRES_STACK TypeConsensus peerTypeStability(SlotMap& smap, const void* ip,
1246                                                       TreeFragment** peer);
1247
1248     JS_REQUIRES_STACK Value& argval(unsigned n) const;
1249     JS_REQUIRES_STACK Value& varval(unsigned n) const;
1250     JS_REQUIRES_STACK Value& stackval(int n) const;
1251
1252     JS_REQUIRES_STACK void updateAtoms();
1253     JS_REQUIRES_STACK void updateAtoms(JSScript *script);
1254
1255     struct NameResult {
1256         // |tracked| is true iff the result of the name lookup is a variable that
1257         // is already in the tracker. The rest of the fields are set only if
1258         // |tracked| is false.
1259         bool             tracked;
1260         Value            v;              // current property value
1261         JSObject         *obj;           // Call object where name was found
1262         nanojit::LIns    *obj_ins;       // LIR value for obj
1263         js::Shape        *shape;         // shape name was resolved to
1264     };
1265
1266     JS_REQUIRES_STACK nanojit::LIns* scopeChain();
1267     JS_REQUIRES_STACK nanojit::LIns* entryScopeChain() const;
1268     JS_REQUIRES_STACK nanojit::LIns* entryFrameIns() const;
1269     JS_REQUIRES_STACK JSStackFrame* frameIfInRange(JSObject* obj, unsigned* depthp = NULL) const;
1270     JS_REQUIRES_STACK RecordingStatus traverseScopeChain(JSObject *obj, nanojit::LIns *obj_ins, JSObject *obj2, nanojit::LIns *&obj2_ins);
1271     JS_REQUIRES_STACK AbortableRecordingStatus scopeChainProp(JSObject* obj, Value*& vp, nanojit::LIns*& ins, NameResult& nr, JSObject **scopeObjp = NULL);
1272     JS_REQUIRES_STACK RecordingStatus callProp(JSObject* obj, JSProperty* shape, jsid id, Value*& vp, nanojit::LIns*& ins, NameResult& nr);
1273
1274     JS_REQUIRES_STACK nanojit::LIns* arg(unsigned n);
1275     JS_REQUIRES_STACK void arg(unsigned n, nanojit::LIns* i);
1276     JS_REQUIRES_STACK nanojit::LIns* var(unsigned n);
1277     JS_REQUIRES_STACK void var(unsigned n, nanojit::LIns* i);
1278     JS_REQUIRES_STACK nanojit::LIns* upvar(JSScript* script, JSUpvarArray* uva, uintN index, Value& v);
1279     nanojit::LIns* stackLoad(tjit::Address addr, uint8 type);
1280     JS_REQUIRES_STACK nanojit::LIns* stack(int n);
1281     JS_REQUIRES_STACK void stack(int n, nanojit::LIns* i);
1282
1283     JS_REQUIRES_STACK void guardNonNeg(nanojit::LIns* d0, nanojit::LIns* d1, VMSideExit* exit);
1284     JS_REQUIRES_STACK nanojit::LIns* alu(nanojit::LOpcode op, jsdouble v0, jsdouble v1,
1285                                          nanojit::LIns* s0, nanojit::LIns* s1);
1286
1287     nanojit::LIns* d2i(nanojit::LIns* f, bool resultCanBeImpreciseIfFractional = false);
1288     nanojit::LIns* d2u(nanojit::LIns* d);
1289     JS_REQUIRES_STACK RecordingStatus makeNumberInt32(nanojit::LIns* d, nanojit::LIns** num_ins);
1290     JS_REQUIRES_STACK RecordingStatus makeNumberUint32(nanojit::LIns* d, nanojit::LIns** num_ins);
1291     JS_REQUIRES_STACK nanojit::LIns* stringify(const Value& v);
1292
1293     JS_REQUIRES_STACK nanojit::LIns* newArguments(nanojit::LIns* callee_ins);
1294
1295     JS_REQUIRES_STACK bool canCallImacro() const;
1296     JS_REQUIRES_STACK RecordingStatus callImacro(jsbytecode* imacro);
1297     JS_REQUIRES_STACK RecordingStatus callImacroInfallibly(jsbytecode* imacro);
1298
1299     JS_REQUIRES_STACK AbortableRecordingStatus ifop();
1300     JS_REQUIRES_STACK RecordingStatus switchop();
1301 #ifdef NANOJIT_IA32
1302     JS_REQUIRES_STACK AbortableRecordingStatus tableswitch();
1303 #endif
1304     JS_REQUIRES_STACK RecordingStatus inc(Value& v, jsint incr, bool pre = true);
1305     JS_REQUIRES_STACK RecordingStatus inc(const Value &v, nanojit::LIns*& v_ins,
1306                                           Value &v_out, jsint incr,
1307                                           bool pre = true);
1308     JS_REQUIRES_STACK RecordingStatus incHelper(const Value &v, nanojit::LIns*& v_ins,
1309                                                 Value &v_after,
1310                                                 nanojit::LIns*& v_ins_after,
1311                                                 jsint incr);
1312     JS_REQUIRES_STACK AbortableRecordingStatus incProp(jsint incr, bool pre = true);
1313     JS_REQUIRES_STACK RecordingStatus incElem(jsint incr, bool pre = true);
1314     JS_REQUIRES_STACK AbortableRecordingStatus incName(jsint incr, bool pre = true);
1315
1316     JS_REQUIRES_STACK RecordingStatus strictEquality(bool equal, bool cmpCase);
1317     JS_REQUIRES_STACK AbortableRecordingStatus equality(bool negate, bool tryBranchAfterCond);
1318     JS_REQUIRES_STACK AbortableRecordingStatus equalityHelper(Value& l, Value& r,
1319                                                                 nanojit::LIns* l_ins, nanojit::LIns* r_ins,
1320                                                                 bool negate, bool tryBranchAfterCond,
1321                                                                 Value& rval);
1322     JS_REQUIRES_STACK AbortableRecordingStatus relational(nanojit::LOpcode op, bool tryBranchAfterCond);
1323
1324     JS_REQUIRES_STACK RecordingStatus unary(nanojit::LOpcode op);
1325     JS_REQUIRES_STACK RecordingStatus binary(nanojit::LOpcode op);
1326
1327     JS_REQUIRES_STACK RecordingStatus guardShape(nanojit::LIns* obj_ins, JSObject* obj,
1328                                                  uint32 shape, const char* name, VMSideExit* exit);
1329
1330 #if defined DEBUG_notme && defined XP_UNIX
1331     void dumpGuardedShapes(const char* prefix);
1332 #endif
1333
1334     void forgetGuardedShapes();
1335
1336     JS_REQUIRES_STACK AbortableRecordingStatus test_property_cache(JSObject* obj, nanojit::LIns* obj_ins,
1337                                                                      JSObject*& obj2, PCVal& pcval);
1338     JS_REQUIRES_STACK RecordingStatus guardPropertyCacheHit(nanojit::LIns* obj_ins,
1339                                                             JSObject* aobj,
1340                                                             JSObject* obj2,
1341                                                             PropertyCacheEntry* entry,
1342                                                             PCVal& pcval);
1343
1344     void stobj_set_fslot(nanojit::LIns *obj_ins, unsigned slot, const Value &v,
1345                          nanojit::LIns* v_ins);
1346     void stobj_set_dslot(nanojit::LIns *obj_ins, unsigned slot,
1347                          nanojit::LIns*& slots_ins, const Value &v, nanojit::LIns* v_ins);
1348     void stobj_set_slot(JSObject *obj, nanojit::LIns* obj_ins, unsigned slot,
1349                         nanojit::LIns*& slots_ins, const Value &v, nanojit::LIns* v_ins);
1350
1351     nanojit::LIns* unbox_slot(JSObject *obj, nanojit::LIns *obj_ins, uint32 slot,
1352                               VMSideExit *exit);
1353
1354     JS_REQUIRES_STACK AbortableRecordingStatus name(Value*& vp, nanojit::LIns*& ins, NameResult& nr);
1355     JS_REQUIRES_STACK AbortableRecordingStatus prop(JSObject* obj, nanojit::LIns* obj_ins,
1356                                                     uint32 *slotp, nanojit::LIns** v_insp,
1357                                                     Value* outp);
1358     JS_REQUIRES_STACK RecordingStatus propTail(JSObject* obj, nanojit::LIns* obj_ins,
1359                                                JSObject* obj2, PCVal pcval,
1360                                                uint32 *slotp, nanojit::LIns** v_insp,
1361                                                Value* outp);
1362     JS_REQUIRES_STACK RecordingStatus denseArrayElement(Value& oval, Value& idx, Value*& vp,
1363                                                         nanojit::LIns*& v_ins,
1364                                                         nanojit::LIns*& addr_ins,
1365                                                         VMSideExit* exit);
1366     JS_REQUIRES_STACK nanojit::LIns *canonicalizeNaNs(nanojit::LIns *dval_ins);
1367     JS_REQUIRES_STACK AbortableRecordingStatus typedArrayElement(Value& oval, Value& idx, Value*& vp,
1368                                                                  nanojit::LIns*& v_ins);
1369     JS_REQUIRES_STACK AbortableRecordingStatus getProp(JSObject* obj, nanojit::LIns* obj_ins);
1370     JS_REQUIRES_STACK AbortableRecordingStatus getProp(Value& v);
1371     JS_REQUIRES_STACK RecordingStatus getThis(nanojit::LIns*& this_ins);
1372
1373     JS_REQUIRES_STACK void storeMagic(JSWhyMagic why, tjit::Address addr);
1374     JS_REQUIRES_STACK AbortableRecordingStatus unboxNextValue(nanojit::LIns* &v_ins);
1375
1376     JS_REQUIRES_STACK VMSideExit* enterDeepBailCall();
1377     JS_REQUIRES_STACK void leaveDeepBailCall();
1378
1379     JS_REQUIRES_STACK RecordingStatus primitiveToStringInPlace(Value* vp);
1380     JS_REQUIRES_STACK void finishGetProp(nanojit::LIns* obj_ins, nanojit::LIns* vp_ins,
1381                                          nanojit::LIns* ok_ins, Value* outp);
1382     JS_REQUIRES_STACK RecordingStatus getPropertyByName(nanojit::LIns* obj_ins, Value* idvalp,
1383                                                         Value* outp);
1384     JS_REQUIRES_STACK RecordingStatus getPropertyByIndex(nanojit::LIns* obj_ins,
1385                                                          nanojit::LIns* index_ins, Value* outp);
1386     JS_REQUIRES_STACK RecordingStatus getPropertyById(nanojit::LIns* obj_ins, Value* outp);
1387     JS_REQUIRES_STACK RecordingStatus getPropertyWithNativeGetter(nanojit::LIns* obj_ins,
1388                                                                   const js::Shape* shape,
1389                                                                   Value* outp);
1390     JS_REQUIRES_STACK RecordingStatus getPropertyWithScriptGetter(JSObject *obj,
1391                                                                   nanojit::LIns* obj_ins,
1392                                                                   const js::Shape* shape);
1393
1394     JS_REQUIRES_STACK RecordingStatus getCharCodeAt(JSString *str,
1395                                                     nanojit::LIns* str_ins, nanojit::LIns* idx_ins,
1396                                                     nanojit::LIns** out_ins);
1397     JS_REQUIRES_STACK nanojit::LIns* getUnitString(nanojit::LIns* str_ins, nanojit::LIns* idx_ins);
1398     JS_REQUIRES_STACK RecordingStatus getCharAt(JSString *str,
1399                                                 nanojit::LIns* str_ins, nanojit::LIns* idx_ins,
1400                                                 JSOp mode, nanojit::LIns** out_ins);
1401
1402     JS_REQUIRES_STACK RecordingStatus initOrSetPropertyByName(nanojit::LIns* obj_ins,
1403                                                               Value* idvalp, Value* rvalp,
1404                                                               bool init);
1405     JS_REQUIRES_STACK RecordingStatus initOrSetPropertyByIndex(nanojit::LIns* obj_ins,
1406                                                                nanojit::LIns* index_ins,
1407                                                                Value* rvalp, bool init);
1408     JS_REQUIRES_STACK AbortableRecordingStatus setElem(int lval_spindex, int idx_spindex,
1409                                                        int v_spindex);
1410
1411     JS_REQUIRES_STACK RecordingStatus lookupForSetPropertyOp(JSObject* obj, nanojit::LIns* obj_ins,
1412                                                              jsid id, bool* safep,
1413                                                              JSObject** pobjp,
1414                                                              const js::Shape** shapep);
1415     JS_REQUIRES_STACK RecordingStatus nativeSet(JSObject* obj, nanojit::LIns* obj_ins,
1416                                                 const js::Shape* shape,
1417                                                 const Value& v, nanojit::LIns* v_ins);
1418     JS_REQUIRES_STACK RecordingStatus addDataProperty(JSObject* obj);
1419     JS_REQUIRES_STACK RecordingStatus setCallProp(JSObject* callobj, nanojit::LIns* callobj_ins,
1420                                                   const js::Shape* shape, nanojit::LIns* v_ins,
1421                                                   const Value& v);
1422     JS_REQUIRES_STACK RecordingStatus setProperty(JSObject* obj, nanojit::LIns* obj_ins,
1423                                                   const Value& v, nanojit::LIns* v_ins,
1424                                                   bool* deferredp);
1425     JS_REQUIRES_STACK RecordingStatus recordSetPropertyOp();
1426     JS_REQUIRES_STACK RecordingStatus recordInitPropertyOp(jsbytecode op);
1427
1428     void box_undefined_into(tjit::Address addr);
1429 #if JS_BITS_PER_WORD == 32
1430     void box_null_into(tjit::Address addr);
1431     nanojit::LIns* unbox_number_as_double(tjit::Address addr, nanojit::LIns* tag_ins,
1432                                           VMSideExit* exit);
1433     nanojit::LIns* unbox_object(tjit::Address addr, nanojit::LIns* tag_ins, JSValueType type,
1434                                 VMSideExit* exit);
1435     nanojit::LIns* unbox_non_double_object(tjit::Address addr, nanojit::LIns* tag_ins,
1436                                            JSValueType type, VMSideExit* exit);
1437 #elif JS_BITS_PER_WORD == 64
1438     nanojit::LIns* non_double_object_value_has_type(nanojit::LIns* v_ins, JSValueType type);
1439     nanojit::LIns* unpack_ptr(nanojit::LIns* v_ins);
1440     nanojit::LIns* unbox_number_as_double(nanojit::LIns* v_ins, VMSideExit* exit);
1441     nanojit::LIns* unbox_object(nanojit::LIns* v_ins, JSValueType type, VMSideExit* exit);
1442     nanojit::LIns* unbox_non_double_object(nanojit::LIns* v_ins, JSValueType type, VMSideExit* exit);
1443 #endif
1444
1445     nanojit::LIns* unbox_value(const Value& v, tjit::Address addr, VMSideExit* exit,
1446                                bool force_double=false);
1447     void unbox_any_object(tjit::Address addr, nanojit::LIns** obj_ins, nanojit::LIns** is_obj_ins);
1448     nanojit::LIns* is_boxed_true(tjit::Address addr);
1449     nanojit::LIns* is_boxed_magic(tjit::Address addr, JSWhyMagic why);
1450
1451     nanojit::LIns* is_string_id(nanojit::LIns* id_ins);
1452     nanojit::LIns* unbox_string_id(nanojit::LIns* id_ins);
1453     nanojit::LIns* unbox_int_id(nanojit::LIns* id_ins);
1454
1455     /* Box a slot on trace into the given address at the given offset. */
1456     void box_value_into(const Value& v, nanojit::LIns* v_ins, tjit::Address addr);
1457
1458     /*
1459      * Box a slot so that it may be passed with value semantics to a native. On
1460      * 32-bit, this currently means boxing the value into insAlloc'd memory and
1461      * returning the address which is passed as a Value*. On 64-bit, this
1462      * currently means returning the boxed value which is passed as a jsval.
1463      */
1464     nanojit::LIns* box_value_for_native_call(const Value& v, nanojit::LIns* v_ins);
1465
1466     /* Box a slot into insAlloc'd memory. */
1467     nanojit::LIns* box_value_into_alloc(const Value& v, nanojit::LIns* v_ins);
1468
1469     JS_REQUIRES_STACK void guardClassHelper(bool cond, nanojit::LIns* obj_ins, Class* clasp,
1470                                             VMSideExit* exit, nanojit::LoadQual loadQual);
1471     JS_REQUIRES_STACK void guardClass(nanojit::LIns* obj_ins, Class* clasp,
1472                                       VMSideExit* exit, nanojit::LoadQual loadQual);
1473     JS_REQUIRES_STACK void guardNotClass(nanojit::LIns* obj_ins, Class* clasp,
1474                                          VMSideExit* exit, nanojit::LoadQual loadQual);
1475     JS_REQUIRES_STACK void guardDenseArray(nanojit::LIns* obj_ins, ExitType exitType);
1476     JS_REQUIRES_STACK void guardDenseArray(nanojit::LIns* obj_ins, VMSideExit* exit);
1477     JS_REQUIRES_STACK bool guardHasPrototype(JSObject* obj, nanojit::LIns* obj_ins,
1478                                              JSObject** pobj, nanojit::LIns** pobj_ins,
1479                                              VMSideExit* exit);
1480     JS_REQUIRES_STACK RecordingStatus guardPrototypeHasNoIndexedProperties(JSObject* obj,
1481                                                                            nanojit::LIns* obj_ins,
1482                                                                            VMSideExit* exit);
1483     JS_REQUIRES_STACK RecordingStatus guardNativeConversion(Value& v);
1484     JS_REQUIRES_STACK void clearReturningFrameFromNativeTracker();
1485     JS_REQUIRES_STACK AbortableRecordingStatus putActivationObjects();
1486     JS_REQUIRES_STACK RecordingStatus createThis(JSObject& ctor, nanojit::LIns* ctor_ins,
1487                                                  nanojit::LIns** thisobj_insp);
1488     JS_REQUIRES_STACK RecordingStatus guardCallee(Value& callee);
1489     JS_REQUIRES_STACK JSStackFrame      *guardArguments(JSObject *obj, nanojit::LIns* obj_ins,
1490                                                         unsigned *depthp);
1491     JS_REQUIRES_STACK nanojit::LIns* guardArgsLengthNotAssigned(nanojit::LIns* argsobj_ins);
1492     JS_REQUIRES_STACK void guardNotHole(nanojit::LIns* argsobj_ins, nanojit::LIns* ids_ins);
1493     JS_REQUIRES_STACK RecordingStatus getClassPrototype(JSObject* ctor,
1494                                                           nanojit::LIns*& proto_ins);
1495     JS_REQUIRES_STACK RecordingStatus getClassPrototype(JSProtoKey key,
1496                                                           nanojit::LIns*& proto_ins);
1497     JS_REQUIRES_STACK RecordingStatus newArray(JSObject* ctor, uint32 argc, Value* argv,
1498                                                  Value* rval);
1499     JS_REQUIRES_STACK RecordingStatus newString(JSObject* ctor, uint32 argc, Value* argv,
1500                                                   Value* rval);
1501     JS_REQUIRES_STACK RecordingStatus interpretedFunctionCall(Value& fval, JSFunction* fun,
1502                                                                 uintN argc, bool constructing);
1503     JS_REQUIRES_STACK void propagateFailureToBuiltinStatus(nanojit::LIns *ok_ins,
1504                                                            nanojit::LIns *&status_ins);
1505     JS_REQUIRES_STACK RecordingStatus emitNativeCall(JSSpecializedNative* sn, uintN argc,
1506                                                        nanojit::LIns* args[], bool rooted);
1507     JS_REQUIRES_STACK void emitNativePropertyOp(const js::Shape* shape,
1508                                                 nanojit::LIns* obj_ins,
1509                                                 bool setflag,
1510                                                 nanojit::LIns* addr_boxed_val_ins);
1511     JS_REQUIRES_STACK RecordingStatus callSpecializedNative(JSNativeTraceInfo* trcinfo, uintN argc,
1512                                                               bool constructing);
1513     JS_REQUIRES_STACK RecordingStatus callNative(uintN argc, JSOp mode);
1514     JS_REQUIRES_STACK RecordingStatus callFloatReturningInt(uintN argc,
1515                                                             const nanojit::CallInfo *ci);
1516     JS_REQUIRES_STACK RecordingStatus functionCall(uintN argc, JSOp mode);
1517
1518     JS_REQUIRES_STACK void trackCfgMerges(jsbytecode* pc);
1519     JS_REQUIRES_STACK void emitIf(jsbytecode* pc, bool cond, nanojit::LIns* x);
1520     JS_REQUIRES_STACK void fuseIf(jsbytecode* pc, bool cond, nanojit::LIns* x);
1521     JS_REQUIRES_STACK AbortableRecordingStatus checkTraceEnd(jsbytecode* pc);
1522
1523     AbortableRecordingStatus hasMethod(JSObject* obj, jsid id, bool& found);
1524     JS_REQUIRES_STACK AbortableRecordingStatus hasIteratorMethod(JSObject* obj, bool& found);
1525
1526     JS_REQUIRES_STACK jsatomid getFullIndex(ptrdiff_t pcoff = 0);
1527
1528     JS_REQUIRES_STACK JSValueType determineSlotType(Value* vp);
1529
1530     JS_REQUIRES_STACK RecordingStatus setUpwardTrackedVar(Value* stackVp, const Value& v,
1531                                                           nanojit::LIns* v_ins);
1532
1533     JS_REQUIRES_STACK AbortableRecordingStatus compile();
1534     JS_REQUIRES_STACK AbortableRecordingStatus closeLoop();
1535     JS_REQUIRES_STACK AbortableRecordingStatus endLoop();
1536     JS_REQUIRES_STACK AbortableRecordingStatus endLoop(VMSideExit* exit);
1537     JS_REQUIRES_STACK void joinEdgesToEntry(TreeFragment* peer_root);
1538     JS_REQUIRES_STACK void adjustCallerTypes(TreeFragment* f);
1539     JS_REQUIRES_STACK void prepareTreeCall(TreeFragment* inner);
1540     JS_REQUIRES_STACK void emitTreeCall(TreeFragment* inner, VMSideExit* exit);
1541     JS_REQUIRES_STACK void determineGlobalTypes(JSValueType* typeMap);
1542     JS_REQUIRES_STACK VMSideExit* downSnapshot(FrameInfo* downFrame);
1543     JS_REQUIRES_STACK TreeFragment* findNestedCompatiblePeer(TreeFragment* f);
1544     JS_REQUIRES_STACK AbortableRecordingStatus attemptTreeCall(TreeFragment* inner,
1545                                                                uintN& inlineCallCount);
1546
1547     static JS_REQUIRES_STACK MonitorResult recordLoopEdge(JSContext* cx, TraceRecorder* r,
1548                                                           uintN& inlineCallCount);
1549
1550     /* Allocators associated with this recording session. */
1551     VMAllocator& tempAlloc() const { return *traceMonitor->tempAlloc; }
1552     VMAllocator& traceAlloc() const { return *traceMonitor->traceAlloc; }
1553     VMAllocator& dataAlloc() const { return *traceMonitor->dataAlloc; }
1554
1555     /* Member declarations for each opcode, to be called before interpreting the opcode. */
1556 #define OPDEF(op,val,name,token,length,nuses,ndefs,prec,format)               \
1557     JS_REQUIRES_STACK AbortableRecordingStatus record_##op();
1558 # include "jsopcode.tbl"
1559 #undef OPDEF
1560
1561     JS_REQUIRES_STACK
1562     TraceRecorder(JSContext* cx, TraceMonitor *tm, VMSideExit*, VMFragment*,
1563                   unsigned stackSlots, unsigned ngslots, JSValueType* typeMap,
1564                   VMSideExit* expectedInnerExit, JSScript* outerScript, jsbytecode* outerPC,
1565                   uint32 outerArgc, bool speculate);
1566
1567     /* The destructor should only be called through finish*, not directly. */
1568     ~TraceRecorder();
1569     JS_REQUIRES_STACK AbortableRecordingStatus finishSuccessfully();
1570
1571     enum AbortResult { NORMAL_ABORT, JIT_RESET };
1572     JS_REQUIRES_STACK AbortResult finishAbort(const char* reason);
1573
1574     friend class ImportBoxedStackSlotVisitor;
1575     friend class ImportUnboxedStackSlotVisitor;
1576     friend class ImportGlobalSlotVisitor;
1577     friend class AdjustCallerGlobalTypesVisitor;
1578     friend class AdjustCallerStackTypesVisitor;
1579     friend class TypeCompatibilityVisitor;
1580     friend class ImportFrameSlotsVisitor;
1581     friend class SlotMap;
1582     friend class DefaultSlotMap;
1583     friend class DetermineTypesVisitor;
1584     friend class RecursiveSlotMap;
1585     friend class UpRecursiveSlotMap;
1586     friend MonitorResult RecordLoopEdge(JSContext*, TraceMonitor*, uintN&);
1587     friend TracePointAction RecordTracePoint(JSContext*, TraceMonitor*, uintN &inlineCallCount,
1588                                              bool *blacklist);
1589     friend AbortResult AbortRecording(JSContext*, const char*);
1590     friend class BoxArg;
1591     friend void TraceMonitor::sweep(JSContext *cx);
1592
1593   public:
1594     static bool JS_REQUIRES_STACK
1595     startRecorder(JSContext*, TraceMonitor *, VMSideExit*, VMFragment*,
1596                   unsigned stackSlots, unsigned ngslots, JSValueType* typeMap,
1597                   VMSideExit* expectedInnerExit, JSScript* outerScript, jsbytecode* outerPC,
1598                   uint32 outerArgc, bool speculate);
1599
1600     /* Accessors. */
1601     VMFragment*         getFragment() const { return fragment; }
1602     TreeFragment*       getTree() const { return tree; }
1603     bool                outOfMemory() const { return traceMonitor->outOfMemory(); }
1604     Oracle*             getOracle() const { return oracle; }
1605     JSObject*           getGlobal() const { return globalObj; }
1606
1607     /* Entry points / callbacks from the interpreter. */
1608     JS_REQUIRES_STACK AbortableRecordingStatus monitorRecording(JSOp op);
1609     JS_REQUIRES_STACK AbortableRecordingStatus record_EnterFrame();
1610     JS_REQUIRES_STACK AbortableRecordingStatus record_LeaveFrame();
1611     JS_REQUIRES_STACK AbortableRecordingStatus record_AddProperty(JSObject *obj);
1612     JS_REQUIRES_STACK AbortableRecordingStatus record_DefLocalFunSetSlot(uint32 slot,
1613                                                                          JSObject* obj);
1614     JS_REQUIRES_STACK AbortableRecordingStatus record_NativeCallComplete();
1615     void forgetGuardedShapesForObject(JSObject* obj);
1616
1617     bool globalSetExpected(unsigned slot) {
1618         unsigned *pi = Find(pendingGlobalSlotsToSet, slot);
1619         if (pi == pendingGlobalSlotsToSet.end()) {
1620             /*
1621              * Do slot arithmetic manually to avoid getSlotRef assertions which
1622              * do not need to be satisfied for this purpose.
1623              */
1624             Value *vp = globalObj->getSlots() + slot;
1625
1626             /* If this global is definitely being tracked, then the write is unexpected. */
1627             if (tracker.has(vp))
1628                 return false;
1629             
1630             /*
1631              * Otherwise, only abort if the global is not present in the
1632              * import typemap. Just deep aborting false here is not acceptable,
1633              * because the recorder does not guard on every operation that
1634              * could lazily resolve. Since resolving adds properties to
1635              * reserved slots, the tracer will never have imported them.
1636              */
1637             return tree->globalSlots->offsetOf((uint16)nativeGlobalSlot(vp)) == -1;
1638         }
1639         pendingGlobalSlotsToSet.erase(pi);
1640         return true;
1641     }
1642
1643 #ifdef DEBUG
1644     /* Debug printing functionality to emit printf() on trace. */
1645     JS_REQUIRES_STACK void tprint(const char *format, int count, nanojit::LIns *insa[]);
1646     JS_REQUIRES_STACK void tprint(const char *format);
1647     JS_REQUIRES_STACK void tprint(const char *format, nanojit::LIns *ins);
1648     JS_REQUIRES_STACK void tprint(const char *format, nanojit::LIns *ins1,
1649                                   nanojit::LIns *ins2);
1650     JS_REQUIRES_STACK void tprint(const char *format, nanojit::LIns *ins1,
1651                                   nanojit::LIns *ins2, nanojit::LIns *ins3);
1652     JS_REQUIRES_STACK void tprint(const char *format, nanojit::LIns *ins1,
1653                                   nanojit::LIns *ins2, nanojit::LIns *ins3,
1654                                   nanojit::LIns *ins4);
1655     JS_REQUIRES_STACK void tprint(const char *format, nanojit::LIns *ins1,
1656                                   nanojit::LIns *ins2, nanojit::LIns *ins3,
1657                                   nanojit::LIns *ins4, nanojit::LIns *ins5);
1658     JS_REQUIRES_STACK void tprint(const char *format, nanojit::LIns *ins1,
1659                                   nanojit::LIns *ins2, nanojit::LIns *ins3,
1660                                   nanojit::LIns *ins4, nanojit::LIns *ins5,
1661                                   nanojit::LIns *ins6);
1662 #endif
1663 };
1664
1665 #define TRACING_ENABLED(cx)       ((cx)->traceJitEnabled)
1666 #define REGEX_JIT_ENABLED(cx)     ((cx)->traceJitEnabled || (cx)->methodJitEnabled)
1667
1668 #define JSOP_IN_RANGE(op,lo,hi)   (uintN((op) - (lo)) <= uintN((hi) - (lo)))
1669 #define JSOP_IS_BINARY(op)        JSOP_IN_RANGE(op, JSOP_BITOR, JSOP_MOD)
1670 #define JSOP_IS_UNARY(op)         JSOP_IN_RANGE(op, JSOP_NEG, JSOP_POS)
1671 #define JSOP_IS_EQUALITY(op)      JSOP_IN_RANGE(op, JSOP_EQ, JSOP_NE)
1672
1673 #define TRACE_ARGS_(x,args)                                                   \
1674     JS_BEGIN_MACRO                                                            \
1675         if (TraceRecorder* tr_ = TRACE_RECORDER(cx)) {                        \
1676             AbortableRecordingStatus status = tr_->record_##x args;           \
1677             if (StatusAbortsRecorderIfActive(status)) {                       \
1678                 if (TRACE_RECORDER(cx)) {                                     \
1679                     JS_ASSERT(TRACE_RECORDER(cx) == tr_);                     \
1680                     AbortRecording(cx, #x);                                   \
1681                 }                                                             \
1682                 if (status == ARECORD_ERROR)                                  \
1683                     goto error;                                               \
1684             }                                                                 \
1685             JS_ASSERT(status != ARECORD_IMACRO);                              \
1686         }                                                                     \
1687     JS_END_MACRO
1688
1689 #define TRACE_ARGS(x,args)      TRACE_ARGS_(x, args)
1690 #define TRACE_0(x)              TRACE_ARGS(x, ())
1691 #define TRACE_1(x,a)            TRACE_ARGS(x, (a))
1692 #define TRACE_2(x,a,b)          TRACE_ARGS(x, (a, b))
1693
1694 extern JS_REQUIRES_STACK MonitorResult
1695 MonitorLoopEdge(JSContext* cx, uintN& inlineCallCount, JSInterpMode interpMode);
1696
1697 extern JS_REQUIRES_STACK TracePointAction
1698 RecordTracePoint(JSContext*, uintN& inlineCallCount, bool* blacklist);
1699
1700 extern JS_REQUIRES_STACK TracePointAction
1701 MonitorTracePoint(JSContext*, uintN& inlineCallCount, bool* blacklist,
1702                   void** traceData, uintN *traceEpoch, uint32 *loopCounter, uint32 hits);
1703
1704 extern JS_REQUIRES_STACK TraceRecorder::AbortResult
1705 AbortRecording(JSContext* cx, const char* reason);
1706
1707 extern bool
1708 InitJIT(TraceMonitor *tm);
1709
1710 extern void
1711 FinishJIT(TraceMonitor *tm);
1712
1713 extern void
1714 PurgeScriptFragments(TraceMonitor* tm, JSScript* script);
1715
1716 extern bool
1717 OverfullJITCache(JSContext *cx, TraceMonitor* tm);
1718
1719 extern void
1720 FlushJITCache(JSContext* cx, TraceMonitor* tm);
1721
1722 extern JSObject *
1723 GetBuiltinFunction(JSContext *cx, uintN index);
1724
1725 extern void
1726 SetMaxCodeCacheBytes(JSContext* cx, uint32 bytes);
1727
1728 extern void
1729 ExternNativeToValue(JSContext* cx, Value& v, JSValueType type, double* slot);
1730
1731 #ifdef MOZ_TRACEVIS
1732
1733 extern JS_FRIEND_API(bool)
1734 StartTraceVis(const char* filename);
1735
1736 extern JS_FRIEND_API(JSBool)
1737 StartTraceVisNative(JSContext *cx, uintN argc, jsval *vp);
1738
1739 extern JS_FRIEND_API(bool)
1740 StopTraceVis();
1741
1742 extern JS_FRIEND_API(JSBool)
1743 StopTraceVisNative(JSContext *cx, uintN argc, jsval *vp);
1744
1745 /* Must contain no more than 16 items. */
1746 enum TraceVisState {
1747     // Special: means we returned from current activity to last
1748     S_EXITLAST,
1749     // Activities
1750     S_INTERP,
1751     S_MONITOR,
1752     S_RECORD,
1753     S_COMPILE,
1754     S_EXECUTE,
1755     S_NATIVE,
1756     // Events: these all have (bit 3) == 1.
1757     S_RESET = 8
1758 };
1759
1760 /* Reason for an exit to the interpreter. */
1761 enum TraceVisExitReason {
1762     R_NONE,
1763     R_ABORT,
1764     /* Reasons in MonitorLoopEdge */
1765     R_INNER_SIDE_EXIT,
1766     R_DOUBLES,
1767     R_CALLBACK_PENDING,
1768     R_OOM_GETANCHOR,
1769     R_BACKED_OFF,
1770     R_COLD,
1771     R_FAIL_RECORD_TREE,
1772     R_MAX_PEERS,
1773     R_FAIL_EXECUTE_TREE,
1774     R_FAIL_STABILIZE,
1775     R_FAIL_EXTEND_FLUSH,
1776     R_FAIL_EXTEND_MAX_BRANCHES,
1777     R_FAIL_EXTEND_START,
1778     R_FAIL_EXTEND_COLD,
1779     R_FAIL_SCOPE_CHAIN_CHECK,
1780     R_NO_EXTEND_OUTER,
1781     R_MISMATCH_EXIT,
1782     R_OOM_EXIT,
1783     R_TIMEOUT_EXIT,
1784     R_DEEP_BAIL_EXIT,
1785     R_STATUS_EXIT,
1786     R_OTHER_EXIT
1787 };
1788
1789 enum TraceVisFlushReason {
1790     FR_DEEP_BAIL,
1791     FR_OOM,
1792     FR_GLOBAL_SHAPE_MISMATCH,
1793     FR_GLOBALS_FULL
1794 };
1795
1796 const unsigned long long MS64_MASK = 0xfull << 60;
1797 const unsigned long long MR64_MASK = 0x1full << 55;
1798 const unsigned long long MT64_MASK = ~(MS64_MASK | MR64_MASK);
1799
1800 extern FILE* traceVisLogFile;
1801 extern JSHashTable *traceVisScriptTable;
1802
1803 extern JS_FRIEND_API(void)
1804 StoreTraceVisState(JSContext *cx, TraceVisState s, TraceVisExitReason r);
1805
1806 static inline void
1807 LogTraceVisState(JSContext *cx, TraceVisState s, TraceVisExitReason r)
1808 {
1809     if (traceVisLogFile) {
1810         unsigned long long sllu = s;
1811         unsigned long long rllu = r;
1812         unsigned long long d = (sllu << 60) | (rllu << 55) | (rdtsc() & MT64_MASK);
1813         fwrite(&d, sizeof(d), 1, traceVisLogFile);
1814     }
1815     if (traceVisScriptTable) {
1816         StoreTraceVisState(cx, s, r);
1817     }
1818 }
1819
1820 /*
1821  * Although this runs the same code as LogTraceVisState, it is a separate
1822  * function because the meaning of the log entry is different. Also, the entry
1823  * formats may diverge someday.
1824  */
1825 static inline void
1826 LogTraceVisEvent(JSContext *cx, TraceVisState s, TraceVisFlushReason r)
1827 {
1828     LogTraceVisState(cx, s, (TraceVisExitReason) r);
1829 }
1830
1831 static inline void
1832 EnterTraceVisState(JSContext *cx, TraceVisState s, TraceVisExitReason r)
1833 {
1834     LogTraceVisState(cx, s, r);
1835 }
1836
1837 static inline void
1838 ExitTraceVisState(JSContext *cx, TraceVisExitReason r)
1839 {
1840     LogTraceVisState(cx, S_EXITLAST, r);
1841 }
1842
1843 struct TraceVisStateObj {
1844     TraceVisExitReason r;
1845     JSContext *mCx;
1846
1847     inline TraceVisStateObj(JSContext *cx, TraceVisState s) : r(R_NONE)
1848     {
1849         EnterTraceVisState(cx, s, R_NONE);
1850         mCx = cx;
1851     }
1852     inline ~TraceVisStateObj()
1853     {
1854         ExitTraceVisState(mCx, r);
1855     }
1856 };
1857
1858 #endif /* MOZ_TRACEVIS */
1859
1860 }      /* namespace js */
1861
1862 #else  /* !JS_TRACER */
1863
1864 #define TRACE_0(x)              ((void)0)
1865 #define TRACE_1(x,a)            ((void)0)
1866 #define TRACE_2(x,a,b)          ((void)0)
1867
1868 #endif /* !JS_TRACER */
1869
1870 namespace js {
1871
1872 /*
1873  * While recording, the slots of the global object may change payload or type.
1874  * This is fine as long as the recorder expects this change (and therefore has
1875  * generated the corresponding LIR, snapshots, etc). The recorder indicates
1876  * that it expects a write to a global slot by setting pendingGlobalSlotsToSet
1877  * in the recorder, before the write is made by the interpreter, and clearing
1878  * pendingGlobalSlotsToSet before recording the next op. Any global slot write
1879  * that has not been whitelisted in this manner is therefore unexpected and, if
1880  * the global slot is actually being tracked, recording must be aborted.
1881  */
1882 static JS_INLINE void
1883 AbortRecordingIfUnexpectedGlobalWrite(JSContext *cx, JSObject *obj, unsigned slot)
1884 {
1885 #ifdef JS_TRACER
1886     if (TraceRecorder *tr = TRACE_RECORDER(cx)) {
1887         if (obj == tr->getGlobal() && !tr->globalSetExpected(slot))
1888             AbortRecording(cx, "Global slot written outside tracer supervision");
1889     }
1890 #endif
1891 }
1892
1893 }  /* namespace js */
1894
1895 #endif /* jstracer_h___ */